Tengo un mapa de Google con un montón de polígonos.
Aquí hay un problema que me interesa: dado un punto lat, lng, ¿cuál es la mejor manera de determinar todos los polígonos en los que se encuentra este punto?
La forma obvia es ejecutar un algoritmo de "punto en el polígono" de forma iterativa para cada polígono, pero me preguntaba si existe un algoritmo eficiente para responder a esas consultas, especialmente si tiene miles de polígonos.
Respuestas:
Como con casi todas estas preguntas, el enfoque óptimo depende de los "casos de uso" y de cómo se representan las características. Los casos de uso se distinguen típicamente por (a) si hay muchos o pocos objetos en cada capa y (b) si cualquiera de las capas (o ambas) permiten precalcular algunas estructuras de datos; es decir, si uno o ambos son suficientemente estáticos e inmutables para que la inversión en precomputación valga la pena.
En el presente caso, esto produce los siguientes escenarios. Normalmente los puntos son dinámicos: es decir, no se dan de antemano. (Si están disponibles por adelantado, o en grupos muy grandes, algunas optimizaciones basadas en su clasificación estarán disponibles). Deje que Q sea el número de puntos de consulta y P el número de vértices de polígono .
Datos poligonales vectoriales
(1) Pocos puntos, pocos vértices poligonales en toto . Utilice un procedimiento de fuerza bruta, como el clásico algoritmo de apuñalamiento de línea . Para cualquier método decente, el costo es O (P * Q), porque le cuesta a O (1) tiempo comparar un punto con un borde de polígono y todas esas comparaciones deben hacerse.
(2) Posiblemente muchos vértices de polígonos, pero son dinámicos: cada vez que se usa un punto en la consulta, los polígonos podrían haber cambiado. Nuevamente use un algoritmo de fuerza bruta. El costo sigue siendo O (P * Q), que será grande porque P será grande, pero eso no ayuda. Si los cambios son pequeños o controlados ( por ejemplo , los polígonos cambian ligeramente de forma o simplemente se mueven lentamente), puede utilizar una versión de la próxima solución y encontrar una manera eficiente de actualizar las estructuras de datos a medida que cambian los polígonos. Eso probablemente sería un tema de investigación original.
(3) Muchos vértices de polígonos y polígonos estáticos (es decir, la capa de polígonos rara vez cambiará). Precalcule una estructura de datos para admitir la búsqueda (que podría basarse en un barrido de línea o un algoritmo quadtree ). El costo de la precomputación para estos algoritmos es O (P * log (P)), pero el costo de las consultas se convierte en O (Q * log (P)), por lo que el costo total es O ((P + Q) * log ( PAG)).
Algunas mejoras están disponibles en casos especiales , como
(a) Todos los polígonos son convexos (el preprocesamiento de los polígonos se puede hacer más rápidamente ),
(b) Todos los interiores de polígonos son disjuntos , en cuyo caso puede pensar que su unión es un polígono único (que permite algoritmos directos eficientes, como los basados en triangulación, y
(c) La mayoría de los polígonos no son muy tortuosos , es decir, ocupan grandes porciones de sus cuadros delimitadores, en cuyo caso puede hacer una prueba inicial basada solo en los cuadros delimitadores y luego refinar esa solución. Esta es una optimización popular.
(d) El número de puntos es grande. Ordenarlos podría mejorar el tiempo. Por ejemplo, al implementar un algoritmo de barrido de línea de izquierda a derecha de punto en polígono, debe ordenar los puntos en su primera coordenada, lo que le permite barrer sobre los puntos al mismo tiempo que barre sobre los bordes del polígono. No estoy al tanto de que tal optimización haya sido publicada. Sin embargo, uno que se ha publicado es realizar una triangulación restringida de la unión de todos los puntos y vértices poligonales: una vez que se completa esa triangulación, la identificación de los puntos interiores debe ser rápida. El costo computacional se escalará como O (Q * log (Q) + (P + Q) * log (P + Q)).
Datos de polígono ráster
Esto es increíblemente fácil: vea la capa de polígono como un ráster indicador binario (1 = dentro de un polígono, 0 = afuera). (Esto podría requerir una tabla de búsqueda para convertir los valores ráster en indicadores internos / externos). Cada sonda puntual ahora requiere un esfuerzo O (1) para indexar la celda ráster y leer su valor. El esfuerzo total es O (Q).
En general
Una buena solución híbridaen el caso de muchos polígonos de vectores estáticos (el caso del vector 3 anterior) es inicialmente rasterizar los polígonos, quizás incluso con una resolución aproximada, esta vez distinguiendo las celdas que intersecan cualquier parte de un límite de polígono (dándoles un valor de 2, por ejemplo) . El uso de una sonda ráster (costo: O (1)) generalmente da como resultado una respuesta definitiva (se sabe que el punto está dentro o fuera), pero ocasionalmente da como resultado una respuesta indefinida (el punto cae en una celda a través de la cual al menos un borde pasa), en cuyo caso se realiza la consulta vectorial O (log (P)) más costosa. Este método incurre en un costo de almacenamiento adicional para el ráster, pero en muchos casos incluso un ráster pequeño (un MB permitirá un ráster 2000 por 2000 que almacena {0,1,2, nulo} valores) puede conferir enormes ventajas en el tiempo computacional . Asintóticamente
fuente
Si tuviera los cuadros delimitadores de polígonos almacenados en algo así como un árbol cuádruple, entonces podría usarlos para determinar rápidamente qué polígonos verificar. Como mínimo, podría ver si el punto está dentro de cada cuadro delimitador del polígono en lugar de hacer un punto completo en el polígono para cada polígono. Personalmente, configuraría un servicio web que almacenaría en caché los polígonos en la memoria y usaría algo como JTS o NetTopology para hacer la consulta de intersección por mí.
fuente
En postgis, ST_Intersects usa índices para encontrar primero si el punto está dentro del cuadro delimitador del polígono y luego realiza una nueva verificación para ver si realmente está dentro del polígono. Eso es rápido, a menudo muy rápido.
Si ha almacenado sus datos en PostGIS, no debe haber ninguna duda de que la base de datos es el lugar correcto para hacer el cálculo. En otros casos, deberá enviar sus polígonos a algún programa intermedio o de cliente. Eso, en sí mismo, tomará mucho más tiempo que hacer los cálculos y solo obtendrá los polígonos relevantes.
/ Nicklas
fuente