Search code examples
pythonpolygondistancepointshapely

Y-distance from point to polygon


I try to calculate the Y-distance from a point inside a polygon to this polygon in positive and negative Y-directions. So far I use shapely to create the polygon, but i am not bound to this.

There might be the case, that multiple edges are above the point (case 2 in my image). Then I would like to have the smallest distance.

The point can be below and above of only one edge each (case 1) or multiple edges (case 2) or a mixture of both.

One solution I thought about was to generate an array containing Y-Coordinates from 0 to lets say 100 in small steps and iteratively add up those coordinates to the Y-coordinate of my point and check for every iteration, if the point is still inside the polygon. However, I hope there is a more elegant way to do this.

I know, that shapely offers the possibility to calculate the minimum distance from a point to a polygon (poly.exterior.distance(point)), but I don´t see, how this can help me, as this is not in Y-direction.

Thank you for your help!


Solution

  • IIUC, here is one way to compute the distances from the point to the closest edges (vertically) :

    from shapely import LineString, MultiLineString
    
    def dis_to(p, poly):
        lines = LineString(
            [
                (p.x, poly.bounds[1::2][0]),
                (p.x, poly.bounds[1::2][1]),
            ]
        ).intersection(poly)
    
        lines = (
            lines if type(lines) == MultiLineString else MultiLineString([lines])
        )
        out_line = next(_l for _l in lines.geoms if p.intersects(_l))
        
        return out_line, [
            round(p.distance(_p), 2)
            for _p in out_line.boundary.geoms
        ]
    
    l1, dist1 = dis_to(p1, poly1)
    l2, dist2 = dis_to(p2, poly2)
    l3, dist2 = dis_to(p3, poly3)
    

    Output :

    >>> l1, dist1
    # (<LINESTRING (4.5 1.417, 4.5 7)>, [2.58, 3.0])
    
    >>> l2, dist2
    # (<LINESTRING (5.5 1.3, 5.5 6.75)>, [3.7, 1.75])
    
    >>> l3, dist3
    # (<LINESTRING (6 4, 6 9.6)>, [2.0, 3.6])
    
    

    Plot (see full code) :

    enter image description here