Dopasowane segmenty o różnych długościach

13

Próbuję dopasować małe segmenty do większego segmentu, z którym są najprawdopodobniej powiązane: stosunkowo blisko, podobne namiarowanie i zwrócone do siebie.

Oto typowy przykład danych, które posiadam:

segmenty

Tutaj musiałbym dopasować segment 652 do 198969, mając 711 i 707, które niczego nie pasują.

Szukałem różnych metod, w szczególności odległości Hausdorffa (na podstawie odpowiedzi tutaj ). Obliczyłem to za pomocą PostGIS, ale otrzymuję dziwne wyniki: najkrótsza odległość, jaką mam, wynosi między 707 a 198985, a 652 ma większy dystans na przykład do 198969 niż na przykład do 198985 (w razie potrzeby mogę dodać zapytanie i wyniki).

Czy Hausdorff jest właściwie właściwą metodą rozwiązania tego problemu? Czy są inne podejścia? Myślałem o stworzeniu zestawu kontroli parametrów, o których wspomniałem (odległość, łożysko itp.), Ale obawiam się, że muszę dodać całą masę warunków, aby obsłużyć przypadki krawędziowe lub takie rzeczy, jak próg określający ich wysokość stawiać sobie czoła.

Aktualizacja: Znalazłem metodę, która wydaje się akceptowalnym kompromisem:

  • Najpierw znajduję 10 najbliższych czarnych segmentów z niebieskiego, które próbuję dopasować (za pomocą <->operatora PostGIS ), które są w odległości mniejszej niż 10 metrów.
  • Następnie tworzę nowy segment, znajdując najbliższe punkty na końcach niebieskiego segmentu na każdym z czarnych (używając ST_ClosestPoint) i odfiltrowuję wyniki, których długość jest mniejsza niż 90% niebieskiego (co oznacza, że ​​segmenty nie są okładzina lub że różnica łożysk jest większa niż ~ 20 °)
  • Następnie otrzymuję pierwszy wynik posortowany według odległości i odległości Hausdorffa, jeśli istnieje.

Może być trochę dostrojenia, ale wydaje się, że na razie wykonuje zadowalającą pracę. Wciąż szukam innych metod lub dodatkowych kontroli do uruchomienia, jeśli przegapiłem niektóre przypadki krawędzi.

Jukurrpa
źródło
1
Dlaczego nie wykorzystać punktów końcowych (niebieskich) segmentów do zidentyfikowania potencjalnych dopasowań wśród docelowych (czarnych) segmentów? Dopasowania segmentów, których szukasz, występują, gdy oba punkty końcowe znajdują się w pobliżu wspólnego celu, co jest prostym zapytaniem do wykonania. Ta metoda radzi sobie z rozbieżnościami wynikającymi z błędów w lokalizacjach punktów końcowych segmentu, co w innym przypadku może być trudne: zwróć uwagę, że bardzo krótki (niebieski) segment ma znacznie mniej precyzyjne ustawienie niż dłuższy segment.
whuber
1
Tak, próbuję czegoś w tym stylu, zaktualizuję pytanie o szczegóły.
Jukurrpa
1
Nie jestem pewien, czy dobrze cię rozumiem, ale czy próbowałeś utworzyć centroidy dla niebieskich linii, a następnie sprawdzić odległości od nich do najbliższych linii, pozostawiając w rezultacie najmniejszą odległość?
Cyryl Mikhalchenko
1
Cześć Cyryl, nie pracuję już nad tym problemem, ale problemem było również dopasowanie niebieskich segmentów w zależności od ich orientacji i tego, jak bardzo „naprzeciwko” są czarne segmenty. Co oznacza w tym przypadku, że 711 nie powinien się z niczym równać, mimo że jest całkiem blisko czarnych segmentów
Jukurrpa

Odpowiedzi:

1

Oto kilka funkcji, które napisałem, które powinny pozwolić ci robić to, co musisz zrobić. Sprawdź, czy linia jest polilinią czy segmentem, jeśli polilinia eksploduje linię, a następnie porównaj azymut i odwrotność pierwszego punktu i ostatniego punktu na liniach, ustaw dopuszczalne kryteria dla kodu, aby podjąć decyzję za Ciebie. Są to metody Arcpy, ale można je modyfikować.

zwraca azymut z segmentu linii 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

zwraca odwrotność od punktów 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

rozbij polilinię na segment linii

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

przebiegnij przez swój stół w ten sposób

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.....

właściwości te powinny być dostępne w postgis - firstpoint, lastpoint, pointarray Zakładam, że właściwości esri powyżej, ponieważ to jest to, co wiem najlepiej, ale powyższe można łatwo zmienić, aby działały z postgis.

Gary Lester
źródło