Segments assortis de différentes longueurs

13

J'essaie de faire correspondre de petits segments avec un segment plus grand auquel ils sont le plus probablement liés: relèvement relativement proche et similaire, et face à face.

Voici un exemple typique des données dont je dispose:

segments

Ici, je devrais faire correspondre le segment 652 à 198969, tout en ayant 711 et 707 ne correspondant à rien.

J'ai cherché différentes méthodes, en particulier la distance de Hausdorff (basée sur les réponses ici ). Je l'ai calculé à l'aide de PostGIS mais j'obtiens des résultats étranges: la distance la plus courte que j'obtiens se situe entre 707 et 198985, et 652 a une distance plus grande avec 198969 qu'avec 198985 par exemple (je peux ajouter la requête et les résultats si nécessaire).

Hausdorff est-il réellement la bonne méthode pour résoudre ce problème? Existe-t-il d'autres approches? J'ai pensé à simplement créer un ensemble de contrôles sur les paramètres que j'ai mentionnés (distance, relèvement, etc.) mais j'ai peur d'avoir à ajouter tout un tas de conditions pour gérer les cas de bord ou des choses comme le seuil sur combien ils sont l'un face à l'autre.

Mise à jour: j'ai trouvé une méthode qui semble être un compromis acceptable:

  • Je trouve d'abord les 10 segments noirs les plus proches du bleu que j'essaie de faire correspondre (en utilisant l' <->opérateur PostGIS ) qui sont à moins de 10 mètres.
  • Je crée ensuite un nouveau segment en trouvant les points les plus proches des extrémités du segment bleu sur chacun des noirs (en utilisant ST_ClosestPoint) et filtre les résultats dont la longueur est inférieure à 90% du bleu (ce qui signifie que les segments ne sont pas face ou que la différence d'appui est supérieure à ~ 20 °)
  • Ensuite, j'obtiens le premier résultat trié par distance et par distance de Hausdorff, le cas échéant.

Il pourrait y avoir un réglage fin à faire, mais il semble faire un travail acceptable pour l'instant. Toujours à la recherche d'autres méthodes ou de vérifications supplémentaires à exécuter si j'ai raté des cas marginaux.

Jukurrpa
la source
1
Pourquoi ne pas simplement utiliser les points d'extrémité des segments (bleus) pour identifier les correspondances potentielles parmi les segments (noirs) cibles? Les correspondances de segment que vous recherchez se produisent lorsque les deux points de terminaison sont proches d'une cible commune, ce qui est une requête simple à exécuter. Cette méthode gère les écarts qui sont dus à des erreurs dans les emplacements des points de terminaison du segment, qui autrement pourraient être difficiles à gérer: notez qu'un segment très court (bleu) a un roulement beaucoup moins précis qu'un segment plus long.
whuber
1
Oui, je suis en train d'essayer quelque chose dans ce sens, je mettrai à jour la question avec les détails.
Jukurrpa
1
Je ne sais pas si je vous comprends bien, mais avez-vous essayé de créer des centroïdes pour les lignes bleues, puis de vérifier les distances entre elles et les lignes les plus proches, en laissant la distance la plus courte en conséquence?
Cyril M
1
Salut Cyril, je ne travaille plus sur ce problème, mais le problème était également de faire correspondre les segments bleus en fonction de leur orientation et de la mesure dans laquelle ils "font face" aux segments noirs. Ce qui signifie dans ce cas que le 711 ne devrait correspondre à rien, même s'il est assez proche des segments noirs
Jukurrpa

Réponses:

1

Voici quelques fonctions que j'ai écrites qui devraient vous permettre de faire ce que vous devez faire. Vérifiez et voyez si la ligne est polyligne ou segment si la polyligne explose la ligne, puis comparez l'azimut et l'inverse du premier point et du dernier point sur les lignes, définissez-vous des critères acceptables pour que le code prenne une décision pour vous. Ce sont des méthodes arcpy mais pourraient être modifiées.

retour azimut du segment de ligne ESRI @shape

def returnAzimuth(shape):
    point1 = shape.firstPoint
    point2 = shape.lastPoint
    dX = point2.X-point1.X
    dY = point2.Y-point1.Y
    az = math.atan2(dX,dY)*180/math.pi
    if az<0:
        az = az+360
        return az
    return az

retour inverse des points ESRI

def returnInverse(point1,point2):
    dX = point2.X-point1.X
    dY = point2.Y-point1.Y
    dis = sqrt(dX**2+dY**2)
    az = math.atan2(dX,dY)*180/math.pi
    if az<0:
        az = az+360
        return az,dis
    return az,dis

exploser la polyligne en segment de ligne

def explodePolyline(shape):
    sr = "insert your spatial reference"
    lines=[]
    pnts = shape.getPart(0)
    for x in range(len(pnts)-1):
        array = arcpy.Array()
        point1 = arcpy.Point(pnts.getObject(x).X,pnts.getObject(x).Y,pnts.getObject(x).Z)
        point2 = arcpy.Point(pnts.getObject(x+1).X,pnts.getObject(x+1).Y,pnts.getObject(x+1).Z)
        array.add(point1)
        array.add(point2)
        line = arcpy.Polyline(array,sr,True,True)
        print(line)
        lines.append(line)
    return lines

courir à travers votre table comme ça

for shape in Table:
    for shape2 in Table:
         check if shape is polyline:
            if yes, explode and compare returned line segments with shape2
                for seg in returnedlinesegments
                    if seg.firstpoint=shape2.lastpoint and shape.az=shape2.az
                        do stuff.....
            if no, compare shape and shape2
                if shape.firstpoint=shape2.lastpoint and shape.az=shape2.az
                   do stuff.....

ces propriétés devraient être disponibles dans postgis - firstpoint, lastpoint, pointarray Je suppose que les propriétés esri ci-dessus parce que c'est ce que je connais le mieux, mais ce qui précède peut facilement être modifié pour fonctionner avec postgis.

Gary Lester
la source