web-dev-qa-db-fra.com

Trouver les coordonnées du point le plus proche sur le polygone dans Shapely

Disons que j'ai le polygone et le point suivants:

>>> poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
>>> point = Point(12, 4)

enter image description here

Je peux calculer la distance du point au polygone ...

>>> dist = point.distance(poly)
>>> print(dist)
2.49136439561

... mais je voudrais connaître la coordonnée du point sur la frontière du polygone où cette distance la plus courte mesure.

Mon approche initiale consiste à tamponner le point par sa distance au polygone et à trouver le point auquel ce cercle est tangent au polygone:

>>> buff = point.buffer(dist) 

enter image description here Cependant, je ne sais pas comment calculer ce point. Les deux polygones ne se croisent pas donc list(poly.intersection(buff)) ne me donnera pas ce point.

Suis-je sur la bonne voie avec ça? Existe-t-il une méthode plus simple?

21
AJG519

Il existe un moyen simple de le faire en s'appuyant sur les fonctions Shapely. Tout d'abord, vous devez obtenir l'anneau extérieur du polygone et projeter le point sur l'anneau. Il est obligatoire d'avoir l'extérieur comme LinearRing car les polygones n'ont pas la fonction de projection. Contrairement à l'intuition, cela donne une distance, la distance entre le premier point de l'anneau et le point de l'anneau le plus proche du point donné. Ensuite, vous utilisez simplement cette distance pour obtenir le point avec la fonction d'interpolation. Voir le code ci-dessous.

from shapely.geometry import Polygon, Point, LinearRing

poly = Polygon([(0, 0), (2,8), (14, 10), (6, 1)])
point = Point(12, 4)

pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
closest_point_coords = list(p.coords)[0]

Il est important de mentionner que cette méthode ne fonctionne que si vous savez que le point est en dehors de l'extérieur du polygone. Si le point se trouve à l'intérieur de l'un de ses anneaux intérieurs, vous devez adapter le code à cette situation.

Si le polygone n'a pas d'anneaux intérieurs, le code fonctionnera même pour les points à l'intérieur du polygone. C'est parce que nous travaillons en fait avec l'anneau extérieur comme une chaîne de lignes et ignorons si la chaîne de lignes provient d'un polygone ou non.

Il est facile d'étendre ce code au cas général de calcul de la distance de tout point (à l'intérieur ou à l'extérieur du polygone) au point le plus proche de la frontière du polygone. Il vous suffit de calculer le point (et la distance) le plus proche du point à tous les anneaux de ligne: l'anneau extérieur et chaque anneau intérieur du polygone. Ensuite, vous n'en gardez que le minimum.

enter image description here

30
eguaio

Alors que la réponse de eguaio fait le travail, il existe un moyen plus naturel d'obtenir le point le plus proche en utilisant shapely.ops.nearest_points fonction:

from shapely.geometry import Point, Polygon
from shapely.ops import nearest_points

poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
point = Point(12, 4)
# The points are returned in the same order as the input geometries:
p1, p2 = nearest_points(poly, point)
print(p1.wkt)
# POINT (10.13793103448276 5.655172413793103)

Le résultat est le même que dans l'autre réponse:

from shapely.geometry import LinearRing
pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
print(p.wkt)
# POINT (10.13793103448276 5.655172413793103)
print(p.equals(p1))
# True
16
Georgy

Il existe deux cas que deux considèrent: (1) le point le plus proche se trouve sur une arête et (2) le point le plus proche est un sommet. Le cas (2) est facile à vérifier - il suffit de prendre la distance à chaque sommet et de trouver le minimum. Le cas (1) implique un peu plus de maths mais n'est pas trop mal. Vous devez faire deux choses pour le cas (1): (a) trouver où la normale du point au bord intersecte le bord, et (b) vérifier qu'elle se trouve dans le segment de ligne (par opposition à s'étendre au-delà de l'un des prend fin). S'il n'est pas sur le segment de ligne, ignorez-le (l'un des sommets sera le point le plus proche sur cette arête).

0
Tom Karzes