Algoritmos para segmentos coincidentes

23

¿Cuáles son los mejores algoritmos para unir segmentos?

Estoy tratando de hacer coincidir los segmentos correspondientes de dos fuentes de mapas, uno menos preciso pero con nombres de segmento, y otro más preciso sin nombres de segmento. Quiero aplicar semiautomáticamente los nombres de segmento al mapa más preciso.

El algoritmo solicitado tiene una descripción bastante vaga porque una "coincidencia" no está bien definida y muchos factores (orientación, longitud relativa, distancia) pueden tener diferente peso en diferentes escenarios; Sin embargo, estoy buscando un conocimiento básico sobre los enfoques generales para manejar este problema.

Las implementaciones de trabajo para el entorno de código abierto (PostGIS, bien proporcionado, ...) son bienvenidas.

Segmentos de muestra : Ver descripción debajo de las imágenes.

Adam Matan
fuente
¿Podría publicar una instantánea de sus datos para proporcionar una visión general de la densidad del segmento y cuán diferentes son?
julien
1
He publicado algunas ilustraciones en flickr, ver enlace.
Adam Matan el
1
Puede intentar buscar "fusión".
Kirk Kuykendall

Respuestas:

14

Se puede utilizar la distancia de Hausdorff : los segmentos coincidentes podrían ser segmentos "cercanos" de acuerdo con esta distancia. Es bastante simple calcular en segmentos.

Una implementación gratuita de Java está disponible en JTS ; consulte el Paquete de distancia JTS . También puede echar un vistazo a JCS Conflation Suite (ahora abandonada, copia de las fuentes, por ejemplo, en https://github.com/oschrenk/jcs ).

julien
fuente
2
La distancia de Hausdorff también está en PostGIS, desde GEOS, por lo que es el mismo algoritmo que JTS
Nicklas Avén
10

No sé cuál sería el "mejor", porque eso dependerá de los detalles de sus segmentos.

Un enfoque generalmente bueno es dividir los segmentos en información geométrica crucial . Esto incluiría, como mínimo, la ubicación del centro (x, y), orientación (0 a 180 grados) y longitud. Con los pesos apropiados aplicados y un poco de refinamiento de la orientación (debido a que 180 "se ajusta" a 0), podría aplicar casi cualquier algoritmo de agrupamiento estadístico a la colección de todos los segmentos. ( K-means sería una buena opción, pero la mayoría de los métodos jerárquicos deberían funcionar bien. Tales análisis de conglomerados tienden a ser rápidos y fáciles de aplicar). Idealmente, los segmentos se producirán en pares (o singletons para segmentos no coincidentes) y el resto es fácil.

Una forma de abordar el problema de orientación es hacer una copia de los segmentos etiquetados. Agregue 180 grados a la orientación de la primera copia, si es menor a 90, y reste 180 grados de la orientación. Esto amplía su conjunto de datos (obviamente), pero de lo contrario no cambia el algoritmo de ninguna manera.

Los pesos son necesarios porque las diferencias de coordenadas, longitudes y orientaciones pueden significar cosas muy diferentes con respecto a las similitudes de sus segmentos correspondientes. En muchas aplicaciones, las diferencias entre segmentos surgen de las diferencias en la ubicación de sus puntos finales. Como una aproximación aproximada, podemos esperar que la variación típica en las longitudes de los segmentos sea aproximadamente la misma que la variación típica entre sus puntos finales. Por lo tanto, los pesos asociados con x, y, y la longitud deberían ser aproximadamente los mismos. La parte difícil es la orientación de ponderación, porque la orientación no puede equipararse con la distancia y, lo que es peor, los segmentos cortos tendrían más probabilidades de estar mal orientados que los segmentos largos. Considere un método de prueba y error que iguale algunos grados de desorientación con el tamaño de una brecha típica entre segmentos y luego ajuste eso hasta que el procedimiento parezca funcionar bien. Para orientación, dejemosL sea ​​una longitud de segmento típica. Un cambio de orientación en un ángulo pequeño t grados barrerá una distancia de aproximadamente L / 2 * t / 60 (el 60 se aproxima al número de grados en un radián), que es L / 120 veces t . Eso sugiere comenzar con pesos unitarios para x, y, longitud y un peso de L / 120 para la orientación.

En resumen , esta sugerencia es:

  1. Haga copias de los segmentos etiquetados (como se describe en el párrafo sobre cómo afinar la orientación).

  2. Convierta cada segmento en el cuádruple (x, y, longitud, orientación L / 120 *) donde L es una longitud de segmento típica.

  3. Realizar un análisis de conglomerados de los cuádruples. Use un buen paquete estadístico ( R es gratis).

  4. Utilice el resultado del análisis de conglomerados como una tabla de búsqueda para asociar segmentos etiquetados con segmentos no etiquetados cercanos.

whuber
fuente
4

Trabajé en un proyecto con un requisito similar hace unos 5 años. Implicaba combinar coordenadas de las líneas centrales de las calles (con una precisión de coordenadas relativamente alta) con enlaces de red de tráfico del Sistema de Monitoreo de Desempeño de Carreteras (HPMS).

En ese momento, la FHWA no proporcionó ninguna herramienta para hacer este tipo de cosas. Eso puede haber cambiado, es posible que desee verificar. Incluso si no está trabajando con datos de autopistas, las herramientas podrían ser relevantes.

Lo escribí con ArcGIS, pero el algoritmo debería funcionar en código abierto, siempre que proporcione capacidades de rastreo similares a ISegmentGraph :

// features is a collection of features with higher geometry
// Links are a collection features with attributes but low res geometry
For each Link in lowResFeatureclass
    point startPoint = SnapToClosestPoint(Link.StartPoint, hiResfeatures);
    if(startPoint == null)
       continue;
    point endPoint = SnapToClosest(Link.EndPoint, hiResfeatures);
    if(endPoint == null)
       continue;
    polyline trace = Trace(hiResfeatures,startPoint,endPoint);
    if(polyline != null)
    {
        // write out a link with high precision polyline
        Write(Link,polyline);
    }
Next Link
Kirk Kuykendall
fuente
4

Aqui viene una idea

Si separa una de las cadenas de líneas para comparar y prueba si los puntos de vértice están a cierta distancia de la otra cadena de líneas para comparar, puede controlar la prueba de muchas maneras.

esos ejemplos funcionan en PostGIS (quién podría adivinar :-))

Primero, si decimos que hay una coincidencia si todos los puntos de vértice en una cadena lineal en la tabla_1 son 0.5 metros (unidades de mapa) o más cerca de una cadena lineal en la tabla_2:

SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points,
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a 
INNER JOIN 
table_2 b 
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(*)=num_of_points;

Entonces podemos decir que hay una coincidencia si más del 60% de los puntos de vértice en una cadena lineal en la tabla_1 está dentro de la distancia de una cadena lineal en la tabla_2

SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points, 
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a 
INNER JOIN 
table_2 b 
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(b.id)/num_of_points::float > 0.6

O podemos aceptar que un punto no está dentro del rango:

SELECT a.id, b.id FROM
(SELECT ST_NPoints(the_geom) as num_of_points, 
(ST_Dumppoints(the_geom)).geom as p, id FROM table_1) a 
INNER JOIN 
table_2 b 
ON ST_DWithin(a.p, b.the_geom, 0.5) GROUP BY a.id, b.id
HAVING COUNT(b.id)-num_of_points <= 1;

También deberá ejecutar la consulta con table_1 y table_2 en roles invertidos.

No sé qué tan rápido será. ST_Dumppoints es actualmente una función sql en PostGIS y no una función C, lo que lo hace más lento de lo que debería ser. Pero creo que será bastante rápido de todos modos.

Los índices espaciales ayudarán mucho a que ST_Dwithin sea efectivo.

HTH Nicklas

Nicklas Avén
fuente
1
+1 Esto es muy similar al enfoque que finalmente utilicé (publicaré una respuesta pronto).
Adam Matan
4

He escrito código para manejar la coincidencia de segmentos de línea descuidada (y superponerlos) en Boundary Generator. Escribí las matemáticas (bastante elementales) detrás de esto aquí: http://blog.shoutis.org/2008/10/inside-boundary-generator-computational.html . El código es de código abierto y está vinculado desde esa publicación de blog.

El código sigue un enfoque realmente simple:

  • Una prueba de segmento-segmento que le dirá si dos segmentos de línea se superponen dentro de las tolerancias de ángulo y distancia dadas, y la cantidad de superposición.
  • Un índice espacial rápido y sucio que elimina la necesidad de probar cada segmento de línea en el conjunto de datos contra todos los demás segmentos de línea en el conjunto de datos.

La principal ventaja de este enfoque es que obtiene perillas muy precisas para ángulos válidos, distancias y longitud de superposición; En el lado negativo, no es una forma de medir generalmente la similitud de dos segmentos de línea, por lo que es mucho más difícil, por ejemplo, hacer un agrupamiento estadístico para determinar coincidencias probables: está atascado con las perillas precisas.

Nota: Supongo que con suficientes chops de SQL podría incluir la prueba segmento-segmento en una cláusula WHERE ... :)

¡Aclamaciones!

Dan S.
fuente
+1 Este es un buen enfoque; construir el quadtree lo hace computacionalmente superior. Pero se necesita cuidado en los detalles: al determinar la proximidad o similitud del segmento (en lugar de la intersección), debe tener en cuenta el hecho de que su estructura de datos no proporciona una representación única de un segmento: el segmento que se origina en x , en la dirección v , de longitud t es igualmente el segmento que se origina en x + t v en la dirección -v de longitud t .
whuber
1

He implementado un prototipo aproximado para la correspondencia de mapas aquí , que es relativamente fácil de usar. Se basa en el motor de enrutamiento de código abierto y está escrito en Java. El algoritmo utilizado se describe aquí .

Karussell
fuente