DEV Community

Cover image for Automatización para la limpieza masiva de gaps basada en Python, QGIS headless y NextGIS Toolbox SDK
claudio matko
claudio matko

Posted on Edited on

Automatización para la limpieza masiva de gaps basada en Python, QGIS headless y NextGIS Toolbox SDK

Imaginá que tenés más de 12000 registros en una base de datos espacial, cada uno con un polígono que representa una parcela, una zona urbana o un hábitat. Al primer análisis visual, descubrís que:

  • Algunos polígonos tienen auto-intersecciones (mal dibujados).
  • Los bordes de polígonos adyacentes no coinciden (cada uno tiene sus propios nodos).
  • Entre muchos de ellos hay huecos (gaps) que deberían estar cerrados.

La corrección manual mediante herramientas convencionales de digitalización es inviable en conjuntos de datos de gran escala, por lo que se propone un flujo automatizado.

En este artículo te muestro cómo construir un pipeline en Python que combina:

  • NextGIS Toolbox (nube, vía SDK) para reparar geometrías inválidas.
  • QGIS Process (local, sin interfaz gráfica) para cerrar gaps y limpiar residuos.

El resultado: una capa con un mismo número de features, pero con geometrías válidas y aristas coincidentes.


El problema: dos tipos de errores

En el mundo de los datos geográficos, los polígonos pueden sufrir dos tipos de problemas muy distintos:

Problema Naturaleza Ejemplo
Auto-intersección (Self‑intersection) Validez OGC (intra‑polígono) Un lazo que se cruza a sí mismo.
Bordes no coincidentes y Gaps Topología (inter‑polígonos) Dos polígonos vecinos que deberían tocarse pero dejan un hueco.

La solución no es única: reparar la validez no cierra gaps, y cerrar gaps sin reparar inválidas genera resultados impredecibles. Para resolver este problema es necesario contar con un flujo de trabajo combinado.


Arquitectura del pipeline

  • NextGIS Toolbox en la nube (a través de su SDK Python) → nos da la validez.
  • QGIS local (vía qgis_process sin GUI) → resuelve la topología.

El flujo sería el siguiente:

Capa original (+12k polígonos)
├─ [NextGIS Toolbox] check_geometries → diagnóstico de inválidas
├─ [NextGIS Toolbox] fix_geometries → repara auto‑intersecciones
├─ [QGIS local] snapgeometries → cierra gaps (mueve vértices)
└─ [QGIS local] fixgeometries → limpia residuos de validez

Capa final (+12k polígonos válidos + aristas coincidentes)

Esquema del flujo de trabajo

Esquema del flujo de trabajo

¿Por qué este orden?

  • Primero validar, porque un snap sobre geometrías inválidas puede producir resultados impredecibles o introducir nuevos errores topológicos.
  • Después del snap, algunos vértices movidos pueden crear nuevas auto‑intersecciones; fixgeometries las barre.

¿Por qué se mantienen +12000 features?
Las herramientas snapgeometries y fixgeometries editan geometrías en el lugar: no parten ni fusionan features (a diferencia de otras aplicaciones como v.clean, que genera nuevos nodos, divide las aristas y multiplica los registros).

Nota: En los GIS, 'snap' (o 'snapping') es el proceso de ajustar o 'pegar' los vértices de una geometría a los vértices o aristas más cercanos de otra geometría, siempre que estén dentro de una distancia máxima (tolerancia).


El código: antigaps.py

El script se encuentra en GitHub. Acá profundizo en las partes más relevantes.

1. Parámetros de entrada


TU_API_KEY = '' # API key de NextGIS Toolbox (*)
RUTA = ''       # Ruta de la capa (vacío → selector gráfico)
GAPS = 20       # Ancho típico de los gaps (tolerancia de snap)

Enter fullscreen mode Exit fullscreen mode

(*) Para obtener una API key de NextGIS Toolbox, basta con obtener una cuenta de usuario en my.nextgis.com. Luego logueado en toolbox.nextgis.com seleccionar cualquier herramienta y clic en el botón code, allí:

toolbox = ToolboxClient('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')

La API key se puede proporcionar mediante variable de entorno TOOLBOX_API_KEY o archivo ~/.toolbox_key.

2. Selección de capa (con o sin GUI)

El script usa tkinter si está disponible (selector gráfico). Otra opción es utilizar la ruta por consola. Esto lo hace versátil para entornos de escritorio o servidores.

3. Paso en la nube (NextGIS Toolbox SDK)


toolbox = ToolboxClient(API_KEY)

# Diagnóstico
check = toolbox.tool('check_geometries')({'input_file': toolbox.upload_file(CAPA)})
toolbox.download_results(check, CARPETA)

# Reparación
tarea = toolbox.tool('fix_geometries').submit({'input_file': toolbox.upload_file(CAPA)})
fixed = tarea.wait_for_completion(timeout=3600, poll_interval=15)
toolbox.download_results(fixed, CARPETA)

Enter fullscreen mode Exit fullscreen mode

check_geometries genera dos archivos: errors.csv y errors.geojson.
fix_geometries devuelve fixed.gpkg.

4. Paso local (QGIS headless)


subprocess.run(['qgis_process', 'run', 'native:snapgeometries', '--',
    f'INPUT={CAPA}', f'REFERENCE_LAYER={CAPA}',
    f'TOLERANCE={TOL_SNAP}', 'BEHAVIOR=0',
    f'OUTPUT={GPKG_SNAP}'], check=True)

subprocess.run(['qgis_process', 'run', 'native:fixgeometries', '--',
    f'INPUT={GPKG_SNAP}', f'OUTPUT={FINAL}'], check=True)

Enter fullscreen mode Exit fullscreen mode

El parámetro BEHAVIOR define la estrategia de ajuste del algoritmo. En este script usamos BEHAVIOR=0, que es el modo por defecto: mueve cada vértice al punto más cercano (nodo o segmento) dentro de la tolerancia, e inserta nuevos vértices si es necesario. Es el comportamiento más adecuado para cerrar gaps entre polígonos. Para otros casos, la herramienta ofrece hasta 7 modos distintos (ver tabla). El resultado intermedio es snap.gpkg; el final, resultado.gpkg.

Valor Descripción ¿Cuándo usarlo?
0 Mueve los vértices al punto más cercano (nodo o segmento). Si es necesario, inserta nuevos vértices en el segmento para ajustar la geometría. El más común. Ideal para cerrar gaps y alinear geometrías complejas.
1 Mueve los vértices al punto más cercano, pero no inserta nuevos vértices en los segmentos. Para minimizar cambios en la estructura de vértices.
2 Prioriza alinear con nodos existentes (vértices de referencia). Si no hay nodo cerca, usa el segmento más cercano. Inserta vértices si es necesario. Para respetar los vértices originales de la referencia.
3 Prioriza alinear con nodos existentes, pero no inserta nuevos vértices. Para mover vértices solo a otros vértices, sin crear nuevos.
4 Solo mueve los vértices extremos (inicio y fin de cada línea). Prioriza alinear con nodos. Ideal para líneas (no polígonos) o para conectar extremos de caminos.
5 Solo mueve vértices extremos, priorizando el punto más cercano (nodo o segmento). Similar al 4, pero más flexible.
6 Engancha solo a nodos ancla de la misma capa. Caso muy específico para redes o topología compleja.
7 Engancha a nodos ancla de cualquier capa. Similar al 6, pero con varias capas de referencia.

Archivos de salida: ¿qué hace cada uno?

Archivo Origen Contenido Utilidad
errors.csv check_geometries (toolbox.nextgis) Tabla con índices (num) y coordenadas de cada auto‑intersección. Diagnóstico: saber qué polígonos están mal dibujados y en qué punto exacto.
errors.geojson check_geometries (toolbox.nextgis) Los mismos errores representados como puntos georreferenciados (FeatureCollection de Point). Visualización: cargar en QGIS para localizar espacialmente las zonas problemáticas.
fixed.gpkg fix_geometries (toolbox.nextgis) Capa completa con las geometrías inválidas reparadas (auto‑intersecciones convertidas en multipolígonos válidos). Base intermedia: capa limpia en cuanto a validez OGC, aunque los gaps persisten.
snap.gpkg snapgeometries (qgis_process) Capa con los vértices pegados dentro de la tolerancia; los gaps quedan cerrados. Archivo de depuración: útil para inspeccionar cómo ha actuado el snap antes de la limpieza final.
resultado.gpkg fixgeometries (qgis_process) Capa final: geometrías válidas + aristas perfectamente coincidentes (sin gaps). El entregable: es el archivo que debes usar para tus análisis posteriores.

La tolerancia: el parámetro + crítico

TOLERANCE (la variable GAPS del script) es la distancia máxima que el snap considera para mover un vértice. Actúa como un umbral:

  • Si la tolerancia es menor que el gap → el algoritmo no detecta los bordes cercanos y el gap persiste.
  • Si es igual al gap → lo cierra justo.
  • Si es mayor → mueve límites que no deberían moverse, distorsionando el polígono.

Consejo práctico: mide el ancho de los gaps reales de tu capa (con herramientas de medición en QGIS), usar el valor más grande que encuentres como tolerancia.

Resultados

Total

Zoom

Nota sobre los datos

Los datos de entrada utilizados corresponden a un dataset sintético, generado por un script, para pruebas, no corresponde a ninguna región real.

Estos datos fueron creados mediante una cuadrícula regular a la que se le aplicaron desplazamientos aleatorios en sus vértices, generando así los gaps y las auto-intersecciones que buscamos reparar.

Al ser artificial, contiene errores topológicos controlados que permiten demostrar el flujo de trabajo de forma clara y reproducible.

En tu propia capa de datos reales, el script debería funcionar exactamente igual, sólo no olvides de ajustar la tolerancia a tu caso (TOL_SNAP).

Tanto los datos de entrada como los resultados se encuentran a disposición en el repositorio, para poder ensayar el uso del script sin problemas.

Este pipeline puede ser útil en diversos escenarios: Catastro y ordenamiento territorial; Planificación urbana; Análisis de cobertura de suelo; Migración de datos heredados; entre otros.

Mejoras futuras

El script actual es funcional, pero como todo puede mejorar. Próximos pasos: Medición automática de gaps; Eliminación de superposiciones; Validación final y Logs estructurados para depuración y seguimiento. Con estas mejoras, el script se convertiría en un pipeline CI/CD para datos espaciales, más completo y automatizado.

Requisitos para replicar esta solución

Reflexiones finales

Vimos cómo combinar herramientas en la nube y locales con Python nos permite resolver problemas topológicos complejos de forma automatizada. El pipeline parte de una capa con gaps y bordes no coincidentes (sin coalición). El resultado es una capa donde los bordes adyacentes comparten exactamente los mismos vértices, eliminando gaps y logrando una buena coalición entre polígonos.

Claves:

  • Comprender la naturaleza de cada error (validez vs. topología).
  • Aplicar las herramientas en el orden correcto.
  • Elegir una tolerancia adecuada.
  • Mantener el mismo número de features, no romper la integridad de la capa.

El resultado es una capa lista para análisis posteriores, y todo con menos de 100 líneas de Python.

Enlaces

Top comments (0)