En Especificaciones se describen las solucciones a algunos de los problemas a los que se enfrenta la herramienta desarrollada para esta importación. Si quieres participar activamente pasa a la guía de importación.
Transformaciones sobre los datos
Algoritmo para separar edificios multiparte
Motivación: edificios y otros conjuntos de datos con geometría multiparte.
Pasos:
- Se recorre cada edificio del conjunto de datos que contiene los edificios.
- Si su geometría es de tipo WKBMultiPolygon:
- Para cada polígono dentro del edificio, se añade un nuevo edificio con ese polígono copiando los campos del original.
- Se borra el edificio original.
A partir de este momento, el campo 'localId' deja de ser un identificador único del edificio.
Implementación: layer.PolygonLayer.explode_multi_parts
Partes exteriores a edificios
Motivación: Eliminar partes de edificio bajo el nivel del suelo y partes externas a edificios, crear contorno para partes sin edificio asociado.
Pasos:
- Seleccionar las partes con 'numberOfFloorsAboveGround' = 0.
- Eliminarlas.
- Para cada característica en la capa.
- Si corresponde a una parte de un edificio.
- Si tiene plantas bajo rasante ('numberOfFloorsBelowGround' < 0) y no tiene plantas sobre rasante ('numberOfFloorsAboveGround' = 0), la elimina.
- Si tiene edificio asociado y no está dentro, la elimina. Se considera que tiene edificio asociado si existe un edificio con el valor de la referencia catastral en el campo 'base:localId'.
- Si no tiene edificio asociado, la añade a un diccionario agrupada por la referencia del edificio.
- Con el diccionario de partes que no tienen edificio asociado, para cada referencia de edificio, genera el contorno del edificio a partir de la unión de todas las partes.
Implementación: layer.ConsLayer.remove_outside_parts
Reducción del número de partes
Motivación: Reducción del número de partes.
Pasos
- Para cada edificio y sus partes (coincide la referencia catastral).
- Calcula los valores mínimo y máximo del número de niveles bajo y sobre rasante en las partes del edificio.
- Asigna estos valores al contorno.
- Comprueba los pares de valores de niveles bajo y sobre rasantes distintos que hay en las partes del edificio y que partes corresponden a cada par de valores.
- Si sólo hay un par, elimina sus partes.
- En caso contrario, para cada par de valores y conjunto de partes con esos valores.
- Fusiona las partes adyacentes.
Implementación:: layer.ConsLayer.merge_building_parts
Detección de piscinas dentro de edificios
Motivación: Detección de piscinas dentro de edificios.
Pasos
- Para cada edificio y sus partes (coincide la referencia catastral).
- Para cada piscina que está en la misma parcela (coincide la referencia catastral).
- Si la piscina está dentro del edificio le asigna el valor layer=1.
- Si el contorno del edificio coincide con la piscina elimina el edificio.
- En otro caso,
- Elimina los anillos interiores de la geometría del edificio que coincidan con la piscina.
- Elimina las partes del edificio que coincidan con la piscina.
Implementación:: layer.ConsLayer.merge_building_parts
Geometrías no válidas
Motivación: Eliminar geometrías basura y vértices con ángulo demasiado bajo.
Parámetros:
- 'acute_inv' = 5o
- 'min_area' = 0,05 m2
- 'dist_inv' = 10 cm
- 'straigth_thr' = 2
Pasos:
- Para cada geometría 'geom' en la capa.
- Para cada anillo con índice 'i' en la geometría.
- Para cada vértice 'v' en el anillo.
- Si el ángulo del vértice es agudo ('angle_v' < 'acute_inv').
- Prueba a eliminar el vértice.
- Si la geometría resultante no es válida o su área menor que 'min_area'.
- Si el anillo es el contorno exterior (i == 0) la geometría no es válida, la elimina.
- Si el anillo es interior (i > 0) elimina el anillo de la geometría.
- En otro caso y si el anillo tiene más de cuatro vértices.
- Obtiene el ángulo 'angle_a' del vértice adyacente más cercano ('va').
- Obtiene la distancia 'c' de 'va' al segmento formado por 'v' y el vértice adyacente más alejado ('vb').
- Si 'va' es agudo ('angle_a' < 'acute_inv') y supera un filtro ('c' < 'dist_inv'), 'v' y 'va' forman un zig-zag, los elimina.
- Si 'va' no es llano (|180 - angle_a| < 'straigth_thr') y supera un filtro ('c' < 'dist_inv') es un vértice en punta.
- Calcula el punto 'vx' formado por la proyección del segmento siguiente a 'va' sobre el segmento 'v'-'vb'.
- Elimina 'v'.
- Desplaza 'va' a la posición 'vx' y anota en un diccionario el movimiento 'va'->'vx'.
- Si hay movimientos pendientes, recorre cada geometría.
- Si encuentra un vértice igual a 'va' lo desplaza a la posición 'vx'.
Implementación: layer.PolygonLayer.delete_invalid_geometries
Algoritmo para añadir nodos topológicos y simplificar nodos duplicados
Motivación: Nodos duplicados y Errores topológicos.
Precondiciones:
- Este problema se produce tanto en los edificios, como en el conjunto de datos de partes de edificios y en la de otras construcciones. Su resolución es interdependiente; es decir, puede haber un nodo de un edificio que no esté duplicado en un principio pero sí lo está si consideramos los otros conjuntos de datos. Por ese motivo hay que copiar en un mismo almacén de datos los elementos de los tres conjuntos de datos. Al decir elemento geográfico nos referimos a edificios, sus partes y otras construcciones (piscinas).
- Las coordenadas se mantienen en la proyección UTM original para simplificar el cálculo de distancias.
Parámetros:
- 'dup_thr' = 1,2 cm. Este valor se ha establecido mediante pruebas observando que JOSM dibuja coordenadas con cualquier precisión, pero la validación de nodos duplicados redondea al séptimo dígito decimal. Un ángulo de 10-7 grados en latitud corresponde aproximadamente a 0,011 metros.
- 'dist_thr' = 2 cm.
- 'straight_thr' = 2o.
Pasos:
- Para cada geometría 'geom' en la capa.
- Para cada vértice 'point' en su contorno exterior.
- Si sus coordenadas no han sido visitadas previamente.
- Se buscan geometrías que se intersecten con un cuadrado de radio 'dist_thr' en torno a 'point'.
- Para cada geometría candidata.
- Busca el vértice más cercano a 'point' en la geometría candidata.
- Si la distancia al vértice más cercano ('dist_v') es 0, pertenece a 'geom'.
- Si cualquiera de los vértices adyacentes 'va' y 'vb' está a una distancia inferior a 'dup_thr' lo elimina.
- Si 0 < 'dist_v' < 'dup_thr', no pertenece a 'geom'. Lo desplaza a la posición 'point'.
- Si 'dist_v' > 'dup_thr', no pertenece a 'geom'. 'point' es punto topológico si cumple todas estas condiciones:
- La distancia desde 'point' al segmento más cercano en la geometría candidata es inferior a 'dist_thr' y el punto más cercano a 'point' en este segmento no coincide con sus extremos.
- El ángulo que forma 'point' con los extremos del segmento es llano (la diferencia con 180º es inferior a 'ang_thr').
- Insertarlo como vértice en la geometría candidata no genera una geometría inválida.
- Si 'point' es punto topológico se inserta como nuevo vértice en la geometría candidata.
Error topológico sin corregir.
Error topológico corregido.
Implementación: layer.PolygonLayer.topology
Algoritmo para simplificar geometrías
Motivación: Nodos innecesarios. El uso de una herramienta externa para simplificar no permite todo el control que desearíamos ni depurar los resultados. Por eso se desarrolla un algoritmo propio.
Se pretenden eliminar vértices excesivos en líneas rectas, como los vértices rojos en la imagen.
Nodos excesivos en una línea recta.
Para ello se examina cada vértice de una geometría. El vértice es candidato a ser eliminado si no es una esquina. Se considera que no es esquina si el ángulo que forma con los vértices anterior y posterior no difiere mucho de 180o (es llano).
El nodo rojo es candidato a eliminar.
La condición del ángulo llano no es suficiente. Si la distancia que separa los vértices anterior y posterior es suficientemente grande, aunque el ángulo sea casi llano, el cateto puede medir metros y eliminar el vértice supondría una modificación excesiva del edificio. El cateto es la distancia menor entre el vértice y la línea que une los vértices anterior y posterior.
Eliminar este nodo provoca un desplazamiento de varios metros.
No se puede eliminar un vértice si en otra geometría hay un vértice en la misma posición. Eso daría lugar a errores topológicos. En la siguiente imagen los nodos verdes se pueden eliminar, el rojo no, por que pertenece a las partes del edificio (gris claro).
Nodo perteneciente a varias geometrías.
Hay que comprobar el ángulo en todas las geometrías que tengan un nodo en esa posición. En la imagen anterior los nodos verdes pertenecen a dos geometrías: el contorno del edificio y las partes del mismo.
Precondiciones:
- Deben estar en un mismo almacén de datos los elementos de los conjuntos de edificios, partes de edificios y otras construcciones (piscinas).
- Se han eliminado los nodos duplicados.
- Se han añadido nodos topológicos.
- Las coordenadas se mantienen en la proyección UTM original para simplificar el cálculo de distancias.
Parámetros:
Pasos:
- Para cada nodo 'point' en la capa.
- Comprueba si 'point' es una esquina en alguna de las geometrías que tengan un nodo en las mismas coordenadas.
- Si no es esquina en ninguna, puede borrar 'point' de todas esas geometrías.
Implementación: layer.PolygonLayer.simplify
Operaciones sobre los datos
Algoritmo para generar ficheros de límites para el gestor de tareas
Motivación: La creación de proyectos en el gestor de tareas para dividir los datos en tareas.
Pasos:
- Se crea un conjunto de datos para rústica 'rustic_zoning' y otro para urbana 'urban_zoning'.
- Se copian los elementos con valor 'POLIGONO' en el campo levelName del conjunto 'zoning' al conjunto 'rustic_zoning' y los que tienen el valor 'MANZANA' a 'urban_zoning', separando las geometrías multiparte.
- Se fusionan los elementos 'MANZANA' adyacentes (si tienen algún segmento en común) para evitar colocar en distintas tareas edificios que tengan paredes comunes.
- Se asigna un identificador único a cada polígono.
Resultado: Se generan dos ficheros de salida: urban_zoning.geojson y rustic_zoning.geojson.
Implementación: catatom2osm.CatAtom2Osm.get_zoning
Algoritmo para dividir los datos en tareas
Motivación: Generar ficheros para dividir los datos en tareas.
Pasos:
- Para cada característica de tipo edificio o piscina del conjunto de datos 'building'.
- Si no tiene asignada etiqueta de tarea.
- Busca una parcela de urbana que lo contenga y le asigna su etiqueta.
- Si no encuentra, busca un polígono de rústica que lo contenga y le asigna su etiqueta.
- Las características tipo parte de edificio reciben la misma etiqueta de tarea que su edificio asociado.
Una vez asignadas las etiquetas de tarea, se extraen las características que corresponden a cada una y se crean los ficheros OSM correspondientes.
Implementación: layer.ConsLayer.set_tasks y catatom2osm.CatAtom2Osm.process_tasks
Combinación de nombres de viales
Motivación: Corrección de los nombres de viales.
Pasos:
La corrección se realiza en dos fases.
- En la primera ejecución del programa sobre un municipio, de forma automática:
- Descargar de OSM las vías y relaciones con las etiquetas highway=* y name=* y las plazas place=square con name=*.
- Para cada nombre de vial de Catastro.
- Encontrar en OSM el nombre de vía más similar que esté cerca de los nodos que representan las direcciones con ese nombre de vía.
- Si no encuentra ninguno, convertir según las reglas de normalización.
- Las abreviaturas tipo de vía de Catastro (especificadas en este documento) se expanden usando un diccionario, personalizable por el usuario.
- Generar un archivo de corrección con los nombres de vías en Catastro y la transformación propuesta para cada uno.
- A continuación se realiza una revisión manual del archivo de corrección. Este archivo será usado por el programa en la siguiente ejecución para transformar los nombres de Catastro. Para algunos tipos de vías, se colocará el nombre en una etiqueta addr:place=* en lugar de addr:street=*
Implementación: catatom2osm.CatAtom2Osm.get_translations
|