Nuevo: Explorador de fotos · Encuentre cualquier foto de viaje cartografiada.

Diario de ingeniería.

Cómo Mapsake creó su geográfico de viajes sin conexión.

Convertir una coordenada de foto en un país, región, ciudad y aeropuerto requiere más que una simple consulta del lugar más cercano. Aquí es donde Mapsake combina datos de lugares abiertos, geometría de límites, reglas deterministas e indexación local.

Por. 12 minuto de lectura
Atlas de Mapsake que muestra un mapa mundial detallado construido a partir de límites geográficos agrupados.

Una coordenada aún no es un lugar.

Una foto de viaje puede contener una latitud y una longitud con una precisión impresionante. Esos dos números aún no indican si la cámara estaba en Japón, prefectura de Kioto, Kioto o en el Aeropuerto Internacional de Kansai de camino a casa. Mapsake necesita esa jerarquía antes de que un punto pueda convertirse en un registro de viaje útil.

El componente que responde a esas preguntas es un directorio geográfico: un directorio estructurado de lugares geográficos con nombre. Mapsake incluye su directorio geográfico dentro de la aplicación, junto con las líneas de límite utilizadas para dibujar y probar países y regiones de primer nivel. La búsqueda, la marca manual, la importación de fotos, las historias de lugares, las estadísticas de Passport, los logros e incluso algunas vistas de amigos dependen de él.

Sería más sencillo enviar cada coordenada a un geocodificador web. También habría hecho que una gran importación de fotos fuera más lenta, dependiente de la red, más difícil de reproducir y menos privada. El enfoque sin conexión requirió más ingeniería inicial, pero le dio a Mapsake un vocabulario geográfico estable que funciona de la misma manera en un avión, en casa y años después de que un conjunto de datos de origen cambie.

Esta es la historia de cómo se construyó esa capa, dónde los puntos y las líneas no coinciden y por qué “ciudad más cercana” es solo el comienzo de una respuesta correcta.

Cuatro conjuntos de datos abiertos, cuatro trabajos diferentes

Ninguna fuente única contiene todo lo que Mapsake necesita, por lo que el proceso de compilación combina cuatro tipos de datos abiertos:

  • GeoNames proporciona países, regiones administrativas de primer nivel, lugares habitados, identificadores estables, nombres alternativos, coordenadas y población.
  • Nuestros aeropuertos proporciona aeropuertos, códigos IATA y OACI, nombres, municipios y coordenadas.
  • Natural Earth proporciona la geometría de las fronteras del país (admin-1) y puntos de etiqueta de mapa útiles.
  • Una capa pequeña y propiedad de Mapsake registra decisiones del producto, como el número de países admitidos, alias y correcciones que no se pueden inferir de forma segura de una fuente genérica.

Cada fuente es buena en algo diferente. GeoNames sabe que una ciudad pertenece a una región y un país, pero una coordenada de ciudad es un punto, no una frontera. Natural Earth sabe dónde se dibuja un polígono, pero sus identificadores de características no siempre coinciden limpiamente con GeoNames. OurAirports sabe que KLAX y LAX se refieren al mismo aeropuerto, pero no es una jerarquía de todos los lugares alrededor del aeropuerto.

El script de compilación descarga y almacena en caché los archivos de origen, los normaliza, valida las relaciones y genera dos artefactos compilados: una base de datos SQLite de solo lectura y una geometría GeoJSON simplificada. La aplicación entrega estos resultados. No descarga una base de datos mundial al inicio ni depende de que los sitios de origen estén en línea durante un viaje.

El compromiso de los artefactos generados también hace que la versión sea reproducible. Una versión enviada tiene un mundo geográfico conocido. Actualizar las fuentes es un cambio de código intencional que se puede probar y revisar, no un cambio invisible del lado del servidor que altera el mapa de alguien de la noche a la mañana.

Una base de datos SQLite deliberadamente simple.

El primer Gazetteer contenía 252 países, 3,861 regiones, 33,744 ciudades y 4,564 aeropuertos en aproximadamente 14 MB. Utilizó la biblioteca SQLite que ya proporciona el sistema operativo y una pequeña capa local en lugar de agregar un marco de base de datos más grande.

El esquema es intencionalmente directo. Los continentes contienen países. Los países contienen regiones. Las regiones contienen ciudades. Los aeropuertos tienen códigos de país y coordenadas. Los identificadores de origen estables se convierten en los identificadores almacenados con una marca de Mapsake: ISO alpha-2 para un país, un código de administrador de GeoNames para una región, un ID de GeoNames para una ciudad y un código IATA para un aeropuerto.

Mapsake: También desnormaliza el nombre legible por humanos y el linaje en cada marca guardada. Esta duplicación es útil. Un registro de viaje personal debe permanecer legible si un gazetario posterior renombra un lugar, elimina un registro o no está presente durante una exportación. El identificador sirve para la coincidencia; la instantánea mantiene los datos del usuario autocontenidos.

SQLite es adecuada para esta carga de trabajo porque la base de datos se genera una vez y se consulta muchas veces. Admite índices, transacciones durante la compilación y búsqueda de texto completo sin un proceso de servicio. La aplicación abre el archivo incluido solo de lectura, por lo que no hay riesgo de migración para los datos de referencia y no hay posibilidad de que una escritura interrumpida lo corrompa.

La búsqueda es más que 'contiene(texto)'

El marcado manual comienza con un solo campo de búsqueda que abarca continentes, países, regiones, ciudades y aeropuertos. Una búsqueda de "san" debe encontrar ciudades relevantes antes de registros oscuros; "LAX" debe encontrar el aeropuerto; y un nombre escrito sin sus acentos debe funcionar.

El script de compilación crea una tabla FTS5 con nombres de visualización, nombres alternativos seleccionados, códigos, ascendencia, coordenadas, tipo y un valor de importancia. El tokenizador Unicode elimina los diacríticos para la coincidencia. Durante la consulta, Mapsake normaliza mayúsculas y minúsculas y diacríticos, elimina los caracteres que podrían convertirse en sintaxis de texto completo, agrega una coincidencia de prefijo a cada token y clasifica los nombres exactos por encima de los prefijos y las coincidencias generales.

La importancia resuelve los empates restantes. Los continentes y países no deben desaparecer por debajo de pueblos con nombres similares. La población de una ciudad le da un peso adecuado a los lugares importantes. Los aeropuertos grandes se clasifican por encima de los pequeños cuando la coincidencia de texto es comparable.

Los nombres alternativos están intencionalmente limitados. GeoNames puede proporcionar una lista muy larga y multilingüe para un lugar popular. Copiar cada ortografía en el índice del dispositivo agregaría ruido y tamaño. El constructor mantiene un conjunto limitado y desduplicado de variantes útiles y conserva el nombre de visualización original por separado de su formulario de búsqueda plegado.

Los resultados de la búsqueda muestran el mismo modelo GazetteerPlace que se utiliza en la navegación jerárquica. Un usuario puede buscar directamente o navegar por continente, país, región y ciudad sin crear dos sistemas geográficos que puedan diferir.

Las líneas responden a una pregunta diferente que los puntos.

El primer resolvedor de fotos eligió la ciudad más cercana y heredó el país y la región de esa ciudad. En áreas densas, esto a menudo parece perfecto. Cerca de una frontera, puede ser incorrecto de una manera que es difícil de notar.

Imagine una foto tomada justo dentro de Montana cuando el lugar poblado más cercano en la base de datos está al otro lado de la frontera en Dakota del Norte. El cálculo de la ciudad más cercana se comporta correctamente, pero el resultado no es el lugar administrativo donde se tomó la foto. El mismo problema ocurre en las fronteras internacionales, cerca de enclaves y a través del agua donde una costa escasa no tiene un punto poblado cercano.

La geometría de la frontera responde a la contención en lugar de la proximidad. Mapsake decodifica los polígonos de países y administraciones de Natural Earth-1, verifica qué anillos contienen la coordenada y utiliza ese resultado para proteger la asignación de país y región. Luego, puede buscar la ciudad más cercana restringida al país o región del polígono.

Esto crea una división de trabajo útil:

  1. El contención de polígonos establece el área administrativa.
  2. La jerarquía del gazetario proporciona ID y nombres estables.
  3. Una búsqueda de la ciudad más cercana restringida proporciona una ubicación útil sin cruzar la línea que acaba de establecerse.
  4. Una verificación de aeropuerto cercano agrega un aeropuerto solo dentro de una distancia deliberadamente ajustada.

Ni los datos de la línea ni el directorio de lugares son suficientes por sí solos. Juntos, transforman una coordenada en una cadena verificable.

La auditoría de admin-1 reveló discrepancias sistémicas.

Los polígonos de países y los polígonos de regiones provienen de diferentes capas de Natural Earth, y los identificadores de la capa de regiones no siempre coincidían con GeoNames. Algunos errores eran obvios, mientras que otros produjeron resultados plausibles pero incorrectos.

En una conversión temprana, se asignó a Quebec la geometría de Nueva Brunswick. Otras funciones carecían de un código, tenían un código de un sistema vecino o representaban una unidad administrativa de manera diferente al directorio. Una mirada visual al mapa del mundo no podía encontrar de manera confiable todos esos errores.

El mecanismo de reemplazo trata a las ciudades como una fuente de oráculos. Para cada polígono candidato, pregunta a qué región del Gazetteer pertenecen las ciudades que realmente se encuentran dentro de él. Los códigos Natural Earth existentes se validan en lugar de confiarse ciegamente. Las características que no pasan la validación se pueden reasignar espacialmente, dividir o excluir. La salida generada utiliza luego los ID de región exactos que ya están presentes en SQLite.

Esto es una forma práctica de prueba entre conjuntos de datos. Un polígono que afirma ser una región debe contener una muestra convincente de ciudades que afirman ser la misma región. Cuando las dos fuentes no coinciden, el sistema genera evidencia en lugar de elegir silenciosamente el valor que se cargó primero.

La misma auditoría encontró casos especiales, como dependencias habitadas que se integran en la geometría de un país. Mapsake corrige un pequeño número de esos casos para que una foto pueda resolverse al mismo país que entienden la configuración del Gazetteer y el contador de países.

Líneas más nítidas sin enviar el mundo en tamaño original.

La primera versión utilizó la capa de países de 1:110 millones de Natural Earth. Era compacta y rápida, pero las líneas costeras se volvieron visiblemente toscas cuando Mapsake agregó mapas más detallados, historias de lugares y vistas regionales.

El mapa se trasladó posteriormente a la capa de 1:10 millones. Esa fuente es mucho más detallada, por lo que incluirla y renderizarla sin cambios habría aumentado el almacenamiento, el tiempo de decodificación, la construcción de la superposición y el trabajo de recoloración. El proceso de compilación simplifica cada anillo mediante Douglas-Peucker con una tolerancia de aproximadamente 0.004 grados, y luego redondea las coordenadas a una precisión estable.

El archivo de país resultante tiene aproximadamente 6.5 MB. Mantiene detalles útiles de la costa a los niveles de zoom que Mapsake muestra, al tiempo que elimina los vértices que caerían sobre los mismos píxeles. La geometría Admin-1 pasa por una ruta de validación y simplificación similar.

La simplificación tiene una restricción de corrección: un polígono más pequeño aún debe tomar las mismas decisiones para las coordenadas reales de las fotos. Los arreglos de referencia posteriores colocan deliberadamente puntos alrededor de los bordes y comparan la detección de impactos optimizada con una referencia congelada. Las líneas más rápidas solo son útiles cuando aún responden a la misma pregunta de contención.

Ampliando desde 34,000 hasta 234,000 ciudades.

La primera base de datos utilizó ciudades de GeoNames con poblaciones superiores a 15,000. Esto mantuvo el paquete compacto, pero dejó los viajes rurales, las pequeñas islas, los pueblos de senderismo y muchos lugares de residencia con una etiqueta innecesariamente distante.

Mapsake adoptó posteriormente GeoNames. ciudades500, que cubre lugares habitados con una población de aproximadamente 500 o más, además de sedes administrativas. La tabla de ciudades creció aproximadamente siete veces, hasta unos 234,000 registros, y la base de datos incluida creció de aproximadamente 14 MB a aproximadamente 69 MB.

Ese intercambio se realizó después de que se eliminó el App Clip. El límite de descarga del Clip había sido la razón más fuerte para restringir la base de datos. Una vez que la aplicación principal fue el único consumidor, una mejor cobertura fue más valiosa que preservar un límite artificial para ciudades pequeñas.

El índice de texto completo sigue siendo selectivo con los nombres alternativos de lugares menores, y la navegación por regiones aún limita lo que renderiza a la vez. Los datos pueden ser amplios sin requerir que cada pantalla materialice toda la tabla.

La cobertura es más importante donde un geocodificador de red sería menos confiable. Un pueblo pequeño en un viaje remoto no debe etiquetarse como una ciudad a horas de distancia simplemente porque el conjunto de datos compacto lo omitió.

La búsqueda de la ciudad más cercana se convirtió en un problema de rendimiento compartido.

La consulta original de la ciudad más cercana ampliaba una caja de latitud y longitud, solicitaba a SQLite que calculara una distancia ponderada para cada candidato, creaba una clasificación temporal y devolvía la fila más cercana. Esto era fácil de entender y lo suficientemente preciso, pero una biblioteca de fotos 82,000 convirtió un pequeño costo por consulta en segundos de trabajo repetido durante las importaciones, los recuerdos, la derivación del mapa y Constellations.

La primera mejora agregó una búsqueda de prueba de 0.4 grados de ancho antes de usar opciones más amplias. Las ubicaciones densas generalmente encontraban una ciudad de un conjunto de candidatos mucho más pequeño. La memorización y una caché persistente de celdas geográficas también impidieron que las fotos cercanas repitieran el mismo trabajo.

La mejora más importante carga las coordenadas numéricas de las ciudades 234,000 en un índice en memoria ordenado por latitud. Una búsqueda binaria encuentra la sección dentro de la ventana de latitud actual, un bucle limitado verifica la longitud y la distancia ponderada, y solo se recupera la fila ganadora de SQLite. Un pequeño caché de registros mantiene los ganadores repetidos a bajo costo.

El comportamiento de ajuste automático no cambió. La función optimizada aún elige la ciudad más cercana dentro de la primera ventana de búsqueda no vacía, incluyendo una resolución determinista de empates. Una copia de referencia del antiguo código SQL verifica cientos de coordenadas cerca de fronteras para una equivalencia de ID exacta.

En el simulador, el tiempo promedio para la derivación de la ciudad más cercana se redujo de 2.11 segundos a 5.2 milisegundos. En un iPhone físico, el tiempo se redujo de 3.06 segundos a 6.35 milisegundos. Estas mejoras permitieron varias funciones porque el geodatos es una infraestructura compartida en lugar de un detalle de implementación privado de la pantalla de importación.

Se encontraron polígonos superpuestos, lo que reveló un error de corrección.

El mecanismo de verificación de rendimiento detectó un error que existía antes de la optimización. Algunos admin-1 polígonos se superponen intencionalmente, especialmente las regiones de capitales dentro de una región circundante. Berlín y Brandeburgo, Seúl y Gyeonggi, y la ciudad de Kiev y su oblast son ejemplos.

La prueba de colisión original aceptaba el polígono coincidente que aparecía primero en un diccionario de Swift. El orden de iteración de un diccionario cambia entre procesos, por lo que la misma coordenada podría adquirir una región diferente después de reiniciar la aplicación.

Mapsake ahora ordena los candidatos superpuestos por área de polígono y permite que la característica más pequeña y específica gane. La implementación de referencia sigue la misma regla. Una foto de referencia 82,000 debe producir cero diferencias entre las rutas de derivación en frío y en caliente antes de que se acepte una optimización de geometría.

Este error es un buen recordatorio de que "dentro de un polígono" no siempre es una pregunta de sí o no. Los datos geográficos contienen enclaves, capitales anidados, cruces de antimeridianos, multipolígonos, agujeros, fronteras disputadas y convenciones de origen. Una política determinista es tan importante como el algoritmo de punto dentro del polígono.

El modo sin conexión es una función de privacidad y una función del producto.

La importación de fotos de Mapsake puede procesar una gran biblioteca sin enviar sus coordenadas a un servicio de geocodificación de terceros. Esto protege las ubicaciones de viaje y del hogar confidenciales, elimina la tarificación por solicitud, evita la limitación de velocidad y hace que el progreso sea predecible.

También hace que la edición sea coherente. La búsqueda manual, la importación de fotos, las tarjetas de pasaporte, los logros, las instantáneas de amigos, la coincidencia de sellos y las historias de lugares hablan el mismo idioma porque utilizan los mismos ID de ubicación estables. Un aeropuerto importado desde un registro de vuelo puede eliminarse con el mismo aeropuerto detectado cerca de una foto. Una ciudad encontrada mediante una búsqueda puede coincidir con la ciudad utilizada por Then & Now.

Este paquete no se considera perfecto ni permanente. Los atributos de origen son visibles en la aplicación. Los scripts de compilación se mantienen junto con el código. Las correcciones conocidas son explícitas. Los elementos de referencia protegen el comportamiento en coordenadas difíciles. La actualización del mundo geográfico es un evento de lanzamiento con consecuencias revisables.

Lo que mantendría si lo reconstruyera

Las opciones más duraderas no eran algoritmos individuales. Eran los límites de las responsabilidades:

  • Utilice puntos para nombres, identidades estables, búsqueda y jerarquía.
  • Utilice líneas y polígonos para el contorno.
  • Genera un artefacto de producto de solo lectura en lugar de analizar cuatro formatos de origen en un teléfono.
  • Guarde una instantánea legible con datos del usuario, manteniendo al mismo tiempo el ID de origen para la coincidencia.
  • Haz que la ruta de acceso sin conexión habitual sea determinista antes de acelerarla.
  • Mantén una implementación de referencia lenta el tiempo suficiente para demostrar que la salida optimizada es equivalente.

El gazetario comenzó como una función de búsqueda temprana. Se convirtió en uno de los sistemas fundamentales de Mapsake porque casi todas las funciones más avanzadas eventualmente necesitan responder a la misma pregunta humilde: ¿qué lugar es este?

Obtener la respuesta correcta significa aceptar que la geografía no es una sola base de datos ni una consulta inteligente. Es un acuerdo cuidadoso entre nombres, puntos, líneas, reglas del producto y el registro de viajes que una persona espera reconocer.

Ícono de la aplicación Mapsake

Desarrollador independiente de Mapsake, que escribe sobre el producto, el mapeo, la privacidad y el trabajo de la plataforma Apple detrás de la aplicación.

Crea tu propio atlas.

Comience con el historial de viajes que ya tiene.

Mapsake es gratuito, no requiere una cuenta de Mapsake para su uso principal y mantiene el reconocimiento de fotos admitido en su dispositivo.

Obtén Mapsake gratis