Comprender si una location CL representa una tierra u océano.

Estoy tratando de crear una API que permita comprender si una CLLocation representa o no la tierra. Necesito que esto funcione sin connection, ya que espero que la mayoría de mis usuarios no tengan conectividad. Estoy usando MapBox como un server de mosaico, pero sigue siendo una pregunta de MapKit porque no estoy usando el SDK de MapBox.

He intentado varios enfoques para averiguar si una determinada coorderada representa una location de tierra u océano:

  • Base de datos sin connection de coorderadas que componen aproximadamente la costa del mundo. Sigue siendo un problema para determinar si un punto determinado está dentro o fuera del contorno.
  • Análisis de color de un recurso de mosaico png (¡DEBE ser una mejor manera! También requiere una gran cantidad de datos fuera de línea para estar disponible para ser un enfoque eficaz)

También (después de lo anterior se trata) ¿hay una forma efectiva de decidir dada una coorderada de mosaico (x, y, z) sea o no un mosaico de tierra / mar / costa?

Si alguien alguna vez ha tenido problemas con este problema, le agradecería que me asesorara aquí.

No te preocupes, parece que Apple ya ha pensado en la pregunta!

Si echa un vistazo a la class CLGeocoder (CoreLocation), hay un reverseGeocodeLocation:completionHandler:

En el manejador de finalización puede recuperar una matriz de objects CLPlacemark

CLPlacemark tiene dos properties interesantes:

[placemark inlandWater]

Para las coorderadas que se encuentran sobre un cuerpo de agua del interior, esta propiedad contiene el nombre de ese cuerpo de agua, el nombre de un lago, arroyo, río u otra vía fluvial.

y [placemark ocean]

coorderadas que se encuentran sobre un océano, esta propiedad contiene el nombre del océano.

Por lo tanto, solo tiene que invertir-geocodificar su location y verificar si ocean propiedad del ocean está configurada en los objects CLPlacemark resultantes.

Pasé un time buscando un algorithm robusto para hacer esto en la esfera para la búsqueda de zona horaria y ni siquiera encontré un buen pseudocódigo, y mucho less c / c ++. Estaba completamente contento . Voy a analizar lo que encontré. Terminaré con resources que podrían usarse para unir esto con bastante facilidad.

Es fácil … en el plano

El problema se conoce como "punto en polígono" .

Un algorithm POP de uso frecuente y simple es "Ray Casting" . El POP en el plano 2D depende de un punto en el infinito. En el avión esto es muy fácil. Hay infinitos puntos en el infinito. ¡Elija uno! Pero no hay tal punto en la esfera.

Puede salirse con la suya si tiene un punto conocido dentro o fuera de cualquier polígono de consulta determinado. Dado su caso de uso, este no es un requisito oneroso: puede elegir fácilmente cualquier punto único en el mar, y esto estará fuera de todos los polígonos de la tierra.

El algorithm POP "Winding Number" también falla (por lo que puedo ver) porque en la esfera puedes acercarte a cualquier borde en cualquiera de las dos direcciones.

Un algorithm

Quería un enfoque que funcione sin un punto auxiliar y sin heurística (usado para generar un punto auxiliar desde los datos de borde). Si soy honesto , quería esto porque estaba convencido de que debería ser posible, no porque realmente lo necesitaba.

Para su caso de uso, puede salirse con la suya con el algorithm de conversión de rayos habitual y un único punto conocido en el océano, por lo que no necesita depender de la heurística, aunque probablemente funcione bastante bien de todos modos.

El enfoque que se me ocurrió funciona así …

  • Tendrá que recorrer sus polígonos usted mismo. Por cada polígono …
  • Encuentre un gran círculo a través de su punto de consulta y a través de al less un borde de su polígono (un punto medio entre dos esquinas).
  • Intersecta el círculo grande con los bordes de tu polígono.
  • El interior del polígono se encuentra a su derecha mientras camina sus bordes en secuencia (o hacia la izquierda, si lo prefiere). Esto proporciona a cada punto de intersección información suficiente para saber en qué lado está el interior o el exterior.
  • Desde el punto de intersección más cercano, puede determinar si su punto de consulta está dentro o fuera.

Consejos de implementación

Si planea implementar este (o cualquiera de los otros algorithms POP), no intente trabajar en seno o coseno.

Representa tus puntos (esquinas de polígono y punto de consulta) como vectores unitarios. Representa tus grandes círculos (bordes de polígonos y el círculo en el que se encuentra el punto de consulta) como vectores unitarios normales al plano en el que se encuentra el gran. Use el producto punto y el producto cruzado. No pienses en los angularjs. Piensa en vectores.

No debería ser demasiado difícil, no lo necesitaba lo suficiente como para implementarlo. Póngase en contacto si lo desea por escrito independiente.

Enlaces desde los cuales podría crear una solución

La biblioteca de impulso de C ++ tiene una implementación de POP que también no me gustó, pero esto se debe en gran parte a que soy perfeccionista, me imagino que servirá al propósito en casi todos los casos.

La database tz_world contiene polígonos para masas terrestres, y existe una variante GeoJSON . Puede analizar esto muy bien con la class de NSJSONSerialization .

Aquí hay algunos algorithms de la NASA para puntos y esferas (aunque no me gustó su POP).

Puede ver la interactividad UTFGrid de Mapbox, que puede funcionar sin connection (ya sea al colocar en caching los mosaicos de la cuadrícula, que son esencialmente text, o agruparlos previamente en un file MBTiles).

Echa un vistazo a la tercera pestaña del ejemplo de Mapbox iOS , que se muestra en el README , que básicamente codifica y recupera información sobre qué país se toca. Esto se realiza a un nivel de resolución de píxeles, básicamente pre-rasterizado, para que no necesite grandes cantidades de datos; no se almacena con una resolución más alta porque no puede tocar a una resolución superior a la de un píxel.

Utilizar:

 mapView.visibleFeatures(at: CGPoint, styleLayerIdentifiers: Set<String>) 

Ver esta pregunta