一条线上最近点的坐标

时间:2014-06-25 18:20:54

标签: python distance geos shapely

有一条折线,顶点的坐标列表= [(x1,y1),(x2,y2),(x3,y3),...]和点(x,y)。在Shapely中,geometry1.distance(geometry2)返回两个几何之间的最短距离。

>>> from shapely.geometry import LineString, Point
>>> line = LineString([(0,0),(5,7),(12,6)])         #geometry2
>>> list(line.coords)
[(0.0, 0.0), (5.0, 7.0), (12.0, 6.0)]
>>> p = Point(4,8)     #geometry1
>>> list(p.coords)
[(4.0, 8.0)]
>>> p.distance(line)
1.4142135623730951

但我还需要找到最接近点(x,y)的线上的点的坐标。在上面的示例中,这是LineString对象上距离Point(4,8)1.4142135623730951单位的点的坐标。方法distance()在计算距离时应该有坐标。有没有办法让它从这个方法返回?

2 个答案:

答案 0 :(得分:28)

您所描述的GIS术语是linear referencingShapely has these methods

# Length along line that is closest to the point
print(line.project(p))

# Now combine with interpolated point on line
np = line.interpolate(line.project(p))
print(np)  # POINT (5 7)

答案 1 :(得分:0)

如果你有一个单独的段(例如:一行,指的是标题)而不是一个段列表,这就是我所做的,并且通过测试用例。请注意,此页面上的某些用户正在查看来自Google搜索的标题。

Python代码:

def sq_shortest_dist_to_point(self, other_point):
    dx = self.b.x - self.a.x
    dy = self.b.y - self.a.y
    dr2 = float(dx ** 2 + dy ** 2)

    lerp = ((other_point.x - self.a.x) * dx + (other_point.y - self.a.y) * dy) / dr2
    if lerp < 0:
        lerp = 0
    elif lerp > 1:
        lerp = 1

    x = lerp * dx + self.a.x
    y = lerp * dy + self.a.y

    _dx = x - other_point.x
    _dy = y - other_point.y
    square_dist = _dx ** 2 + _dy ** 2
    return square_dist

def shortest_dist_to_point(self, other_point):
    return math.sqrt(self.sq_shortest_dist_to_point(other_point))

测试用例:

def test_distance_to_other_point(self):
    # Parametrize test with multiple cases:
    segments_and_point_and_answer = [
        [Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
        [Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
        [Segment(Point(0.0, 0.0), Point(0.0, 3.0)), Point(1.0, 1.0), 1.0],
        [Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
        [Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
        [Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
        [Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3.0, -4.0), 1],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-4.0, -3.0), 1],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(1, 2), 1],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(2, 1), 1],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3, -1), math.sqrt(2.0)],
        [Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-1, -3), math.sqrt(2.0)],
        [Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
        [Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)],
        [Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
        [Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)]
    ]

    for i, (segment, point, answer) in enumerate(segments_and_point_and_answer):
        result = segment.shortest_dist_to_point(point)
        self.assertAlmostEqual(result, answer, delta=0.001, msg=str((i, segment, point, answer)))

注意:我假设此函数位于Segment类中。 如果您的行是无限的,请不要仅将lerp从0限制为1,但仍至少提供两个不同的ab点。