【问题标题】:Find equidistant points between two coordinates查找两个坐标之间的等距点
【发布时间】:2014-01-04 16:58:47
【问题描述】:

我有一个函数需要取出屏幕上两点之间的等距点(2d)。
像这样——

|--------------|

距离已经确定。比如我这里取为2,那么我需要的点就是-

|--.--.--.--.--|

这些点可以在 2d 平面上的任何位置,这意味着如果我在两点之间画一条线,它可以是 2d 平面中可能的任何方向,即对角线、水平等。
我不知道如何在 python 中做到这一点。

我不知道用谷歌搜索什么...我 14 岁,所以我不知道任何类型的数学。
我知道如何计算直线的距离和坡度,但我不知道如何进行。
提前致谢!

【问题讨论】:

  • “取出”是什么意思?如果点之间的距离不是距离的整数倍怎么办?
  • @jonrsharpe,我想我会通过从中扣除 mod 来使其可分。
  • 你想在这样的一条平线上取出点,或者这条线可以沿着屏幕的对角线倾斜一个角度吗?
  • @richard,二维平面中的任何方向
  • 恐怕我不知道你会怎么画……但我会尽力帮助……

标签: python algorithm geometry points


【解决方案1】:

给定两个端点,您可以将“参数”形式的直线方程表示为

x = x1 + (x2-x1) * t
y = y1 + (y2-y1) * t

如您所见,当t == 0(x,y) == (x1,y1)t == 1(x,y) == (x2,y2) 时。通过更多调查,您可以看到当 t 介于 0 和 1 之间时,(x,y) 位于连接线段上,并且要获得点之间距离的某个分数,请将 t 设置为分数。

例如,要在距离为 10 的线上获得间隔为 2 的点,如您的示例所示,请在 t = 0.2、0.4、0.6 和 0.8 处评估 xy

【讨论】:

    【解决方案2】:

    你需要做的是在两点之间interpolate

    例如,假设您的两个端点具有坐标(x1, y1)(x2, y2),并且您想将它们之间的距离分成n 相等的部分,那么您可以像这样计算它们之间的n-1 新点:

    points = []
    for i in range(1, n):
        a = float(i) / n             # rescale 0 < i < n --> 0 < a < 1
        x = (1 - a) * x1 + a * x2    # interpolate x coordinate
        y = (1 - a) * y1 + a * y2    # interpolate y coordinate
        points.append( (x,y) )
    

    这里,a 是插值点在原始点之间的线上的位置,经过缩放后,a = 0a = 1 的值对应于原始点本身。


    或者,如果您想让您的插值点相隔固定距离d,那么您可以使用Pythagorean theorem 计算原始点之间的距离d_full,将d 除以该距离得到@ 987654335@,然后将a从0到1递增s

    d_full = ( (x2 - x1)**2 + (y2 - y1)**2 )**0.5
    s = d / d_full
    
    points = []
    a = s                           # start at s so we don't duplicate (x1, y1)
    while a < 1:
        x = (1 - a) * x1 + a * x2
        y = (1 - a) * y1 + a * y2
        points.append( (x,y) )
        a += s
    

    请注意,这可能会导致将新点放置在(x2, y2) 或非常靠近它,具体取决于d 如何精确划分点之间的距离。如果您想避免这种情况,可以将条件 a &lt; 1 替换为 a &lt; 1 - s/2

    编辑: 上面的代码将点放置在d 的间隔处开始(x1, x2)。这意味着如果d = 2 和原始点位于(0,0)(0,5),您将在(0,2)(0,4) 获得新点。 如果您希望新点位于原始点之间的中心(即示例中的 (0,1)(0,3)),您可以修改代码以将起点 a = s 替换为 @987654353 @。

    %modulo 或余数运算符,因此1 % s 在将0 到1 的距离拆分为长度为s 的片段后给出“剩余”距离。

    【讨论】:

    • 哦,普通!!!我 14 岁并不意味着我不会编程!看在上帝的份上,看看我的名声!我知道模数是什么
    • @svineet:好的,但是以后可能没有同样问题的其他人在谷歌上找到了这个答案,所以解释得太多总比解释不够好。
    【解决方案3】:

    使用线的参数表示最容易解决这个问题,它涉及字母向量数学。不过别担心,这很容易。

    假设您的行由以下公式很好地指定:

    y=ax+b
    

    其中a 是斜率,b 是 y 轴截距。

    那么你的线有一个由向量​​&lt;1,a&gt; 给出的方向,这意味着线每水平运行一个1 单位就会上升m 单位。

    我们可以通过除以它的大小来规范化这个向量。

    向量的大小由下式给出

    m=sqrt(a**2+b**2)
    

    归一化向量由v=&lt;1/m,a/m&gt;给出。

    现在,我们可以画你的线如下:

    for t in range(50):
      xp=0+t*v[0]
      yp=b+t*v[1]
      plot_point(xp,yp,'-')
    

    你看到我在那里做了什么吗?我将循环的变量从x 更改为t。这使我们可以分别处理等式的xy 部分。

    如果我的线由它的端点指定,我可以写成如下等式:

    for t in range(0,1,0.01):
      xp=x1+t*(x2-x1)
      yp=y1+t*(y2-y1)
      plot_point(xp,yp,'-')
    

    由于x1是直线x部分的起点,x2-x1是直线x点之间的距离,因为t0走到1,它通过了所有的线的 x 点。 y 工作方式类似。

    现在,我们可以抽象我们的画线函数,让它看起来像这样:

    def draw_line(a,b,len,skip,sym):
      m=sqrt(a**2+b**2)
      v=(1/m,a/m)
      for t in range(0,len,skip):
        xp=0+t*v[0]
        yp=b+t*v[1]
        plot_point(xp,yp,sym)
    

    现在,我们通过键入以下内容来画线:

    draw_line(a,b,50,1,'-')
    

    并用

    画出差距
    draw_line(a,b,50,3,'.')
    

    其中50 是线的长度,3 是间隙之间的距离。

    如果我们使用直线的起点和终点,我们的函数将如下所示:

    def draw_line(x1,y1,x2,y2,skip,sym):
      dist=sqrt((x1-x2)**2)+(y1-y2)**2)
      skip=skip/dist
      for t in range(0,1,skip):
        xp=x1+t*(x2-x1)
        yp=y1+t*(y2-y1)
        plot_point(xp,yp,sym)
    

    这会将您要跳过的距离转换为线路总长度的一部分。您可能希望使用 1 或更小的跳跃值来绘制线条,并使用较大的跳跃值来取出等距点。

    您可能希望考虑使用 Bresenham's Line Algorithm 为您绘制 - 当您有字符像素网格时,这是找出近似线条的最佳方法的好方法。

    而且,如果您在屏幕上绘制字符,您可能会对ANSI escape codes 感兴趣,它可用于移动光标、显示颜色和清除屏幕。

    【讨论】:

    • 我不关注@svineet - 我怎么暗示你是 n00b?
    • 当您有一个字符像素网格时,这是找出近似线条的最佳方法的好方法。而且,如果您在屏幕上绘制字符,您可能会对 ANSI 转义码感兴趣,它可用于移动光标、显示颜色和清除屏幕。
    • 这里 ^^ 我使用字符示例只是为了演示。 “在屏幕上绘制字符,移动光标等。” ?
    • 像这里的大多数人一样,我想提供帮助,而不是踩到你的自尊心。 Dwarf fortressNetHack 都基于 ASCII 艺术。图形通常会分散提高编程和算法专业知识的注意力,而构建渲染器是很好的体验。由于您没有提及渲染器,因此请使用 ASCII 字符来表达您的问题,并且由于您问题的未来访问者可能会感兴趣,因此我认为这些链接是合理的。
    • 根据 wiki 文章:“Dwarf Fortress 以复杂的物理引擎为模型,并以纯文本代码页 437 图形和各种颜色呈现。......该游戏因其丰富的内容和玩法,深奥难于精通。” ASCII 不仅仅是 n00bs 的领域。
    【解决方案4】:

    暂时忘记python方面,我们可以看看所需的数学。很有可能在 14 岁时您已经涵盖了其中的一些内容,但可能没有意识到它适用,我们需要的是一些三角函数。

    让我们把两点放在一个计划中

    Point 1 = (x1,y1)
    Point 2 = (x2,y2)
    

    想象一下,这两个点是一个直角三角形的角,第三个假想点构成三角形的第三个角。

    P1-----I
      -    |
       -   |
        -  |
         -P2
    

    在 P1 和 P2 之间移动时找到点。

    Start point = P1 (x1,y1)
    First point = (x1+u,y1+t)S
    Second point = (x1+2u,y1+2n)
    Nth point = (x1+nu,y1+nu)
    

    我们需要 u 和 t 的值。为了解决这些问题,我们首先需要从 P1 的起点开始的角度(向内移动的方位)。 atan2 函数可以得到这个方位,以弧度为单位。

    import math
    bearing = math.atan2(y2-y1,x2-x1)
    

    如需进一步阅读,请参阅 (http://en.wikipedia.org/wiki/Atan2)

    给定方位,我们现在可以使用正弦和余弦来计算 u 和 t 的值。这些函数基本上为我们提供了每一步的总移动量在 x 轴和 y 轴上的比率。

    u = d * cos(bearing)
    t = d * sin(bearing)
    

    其中 d 是固定距离。

    看看教科书中的 sin 和 cos 函数的定义 - 在 python 中,看看当你从 sin(0) 移动到 sin(math.pi) 和 cos(0) 到 cos(math.pi) 时会发生什么。 pi)。

    总的来说,我们的脚本是这样的

    import math
    #CONSTANTS -- modify these 
    POINT1 = (0,0)
    POINT2 = (10,10)
    STEP_SIZE = 2
    
    dx = POINT2[0] - POINT1[0]
    dy = POINT2[1] - POINT1[1]
    
    bearing = math.atan2(dy,dx)
    print "Bearing: {b}".format(b=bearing)
    #Use pythagoras to work out the distance
    distance_between_points = math.sqrt(dx**2+dy**2) 
    
    for p in range(0,int(round(distance_between_points,0)),STEP_SIZE):
        x = POINT1[0] + p * math.cos(bearing)
        y = POINT1[1] + p * math.sin(bearing)
        print "Intermediate point {x},{y}".format(x=x,y=y)
    

    【讨论】:

    • 这个问题真的没有必要使用三角函数:你需要的最高级数学是勾股公式的平方根。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 1970-01-01
    • 2010-11-23
    • 2013-07-27
    • 2019-09-16
    • 2020-08-06
    • 1970-01-01
    相关资源
    最近更新 更多