Herramientas para proyectos de mapas marinos ENC en QGis

Este artículo completa la serie de artículos sobre la creación de una base de datos geopackage para gestionar las cartas náuticas ENC en QGis y la simbología de las distintas capas de datos. Trabajar con un número reducido de mapas no presenta especiales problemas, pero en cuanto el número aumenta se producen una serie de operaciones que se complican o consumen mucho tiempo.
Hemos desarrollado una serie de scripts en Python que simplifican el trabajo con grandes bases de datos de geopaquetes.

1- Carga de capas

El primer problema es el gran número de capas que hay que cargar en el proyecto QGis. Mientras que un mapa puede tener unas veinte capas, en cuanto el número de mapas aumenta puedes encontrarte rápidamente con más de cien capas que cargar.

QGis permite cargar todas las capas de un geopackage en bloque. Así no tienes que cargar el centenar de capas una a una. Pero una vez cargadas, hay dos tareas que realizar:

  • eliminar capas irrelevantes, como las capas de metadatos
  • ordenar la visualización de las capas para evitar que ciertas capas sean completamente invisibles por estar superpuestas a otras capas. Las capas superficiales como DEPARE y LNDARE (profundidades y terreno) deben estar siempre por debajo de los objetos marinos y terrestres, de lo contrario estos objetos no serán visibles.

Además, siempre es más agradable trabajar con escalas de visualización mínimas, de forma que sólo se muestren determinadas capas al ampliar a escalas muy pequeñas y la información detallada sólo se muestre al ampliar a una escala mayor.

Selección de capas a cargar

Hemos proporcionado un script en python que resuelve todos estos problemas por sí solo. Puede descargarlo desde este enlace.

El script incluye una lista de 210 capas S57, ordenadas para su correcta visualización:

Capas de superficie representadas por polígonos sólidos, luego capas de superficie representadas por polígonos vacíos (sólo se muestran los perímetros), luego capas de tipo lineal y finalmente capas de tipo puntual. Dentro de cada categoría, el orden se ha diseñado para evitar enmascarar la información.

Cada capa va acompañada de un valor mínimo de escala de visualización, siendo el valor por defecto 100000000.

He aquí un ejemplo:

#Liste des couches dans l’ordre de chargement
couches_a_charger = [
(‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
(‘pl_TIDEWY’, 100000000),
(‘pl_DAMCON’, 100000000),
(‘pl_CAUSWY’, 100000000),
(‘pl_HULKES’, 100000000),
(‘pl_LOKBSN’, 100000000),
(‘pl_OBSTRN’, 100000000),
(‘pl_PONTON’, 100000000),
(‘pl_PYLONS’, 100000000),

Si no quieres que el script cargue capas que no te interesan, puedes simplemente comentar la línea correspondiente añadiendo un ‘#’ al principio de la línea:

#Liste des couches dans l’ordre de chargement
couches_a_charger = [
(‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
#(‘pl_TIDEWY’, 100000000),
#(‘pl_DAMCON’, 100000000),

En este ejemplo, las capas TIDEWY y DAMCON no se cargarán.

Además, si desea definir una escala de visualización mínima para una capa, basta con cambiar el valor correspondiente:

‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
(‘pl_TIDEWY’, 100000),
#(‘pl_DAMCON’, 100000000),
#(‘pl_CAUSWY’, 100000000),
(‘pl_HULKES’, 100000000),
(‘pl_LOKBSN’, 100000000),
(‘pl_OBSTRN’, 50000),

En este ejemplo, la capa TIDEWY sólo se mostrará cuando el valor del zoom de la ventana del mapa sea inferior a 100000 y la capa OBSTRN cuando el valor sea inferior a 50000.

Para utilizar el script

  • descargue el archivo .py
  • guárdelo en un directorio de su elección
  • Abra la consola Python de QGis (Extensiones ->Consola Python)

  • Abra la ventana Editor (1)
  • Haga clic en el icono Examinar (2) y apunte al archivo .py descargado
  • Cambie la ruta del geopackage por la ruta y el nombre de su geopackage (3)
  • Ejecute el script (4)

Antes de ejecutarlo, puedes hacer cambios para evitar que se carguen las capas o para asignarles una escala mínima diferente. No olvides guardar estos cambios antes de cerrar el proyecto.

El código del script es el siguiente:

load_layers.py

from qgis.core import QgsProject

# Chemin vers le geopackage
chemin_geopackage = 'c:/testgpkgV3/ENC2.gpkg'

## Liste des couches dans l'ordre de chargement
couches_a_charger = [
    ('pl_DEPARE', 100000000),
    ('pl_UNSARE', 100000000),
    ('pl_TIDEWY', 100000000),
    ('pl_DAMCON', 100000000),
    ('pl_CAUSWY', 100000000),
    ('pl_HULKES', 100000000),
    ('pl_LOKBSN', 100000000),
    ('pl_OBSTRN', 100000000),
    ('pl_PONTON', 100000000),
    ('pl_PYLONS', 100000000),
    ('pl_SBDARE', 100000000),
    ('pl_DRGARE', 100000000),
    ('pl_TSEZNE', 100000000),
    ('pl_WRECKS', 100000000),
    ('pl_FLODOC', 100000000),
    ('pl_LNDARE', 100000000),
    ('pl_CANALS', 100000000),
    ('pl_LAKARE', 100000000),
    ('pl_RIVERS', 100000000),
    ('pl_BUAARE', 100000000),
    ('pl_BUISLG', 100000000),
    ('pl_CHKPNT', 100000000),
    ('pl_CONVYR', 100000000),
    ('pl_DOCARE', 100000000),
    ('pl_ROADWY', 100000000),
    ('pl_RUNWAY', 100000000),
    ('pl_DRYDOC', 100000000),
    ('pl_DYKCON', 100000000),
    ('pl_FORSTC', 100000000),
    ('pl_GATCON', 100000000),
    ('pl_LNDMRK', 100000000),
    ('pl_SLCONS', 100000000),
    ('pl_BRIDGE', 100000000),
    ('pl_WEDKLP', 100000000),
    ('pl_WATTUR', 100000000),
    ('pl_VEGATN', 100000000),
    ('pl_TWRTPT', 100000000),
    ('pl_TUNNEL', 100000000),
    ('pl_TSSLPT', 100000000),
    ('pl_TESARE', 100000000),
    ('pl_SWPARE', 100000000),
    ('pl_SPLARE', 100000000),
    ('pl_SNDWAV', 100000000),
    ('pl_SMCFAC', 100000000),
    ('pl_SLOGRD', 100000000),
    ('pl_SILTNK', 100000000),
    ('pl_SEAARE', 100000000),
    ('pl_RESARE', 100000000),
    ('pl_RCTLPT', 100000000),
    ('pl_PRDARE', 100000000),
    ('pl_PRCARE', 100000000),
    ('pl_PIPARE', 100000000),
    ('pl_PILBOP', 100000000),
    ('pl_OSPARE', 100000000),
    ('pl_OFSPLF', 100000000),
    ('pl_MORFAC', 100000000),
    ('pl_MIPARE', 100000000),
    ('pl_MARCUL', 100000000),
    ('pl_LOGPON', 100000000),
    ('pl_LNDRGN', 100000000),
    ('pl_ISTZNE', 100000000),
    ('pl_ICEARE', 100000000),
    ('pl_HRBFAC', 100000000),
    ('pl_HRBARE', 100000000),
    ('pl_GRIDRN', 100000000),
    ('pl_FSHZNE', 100000000),
    ('pl_FSHGRD', 100000000),
    ('pl_FSHFAC', 100000000),
    ('pl_FRPARE', 100000000),
    ('pl_FERYRT', 100000000),
    ('pl_FAIRWY', 100000000),
    ('pl_EXEZNE', 100000000),
    ('pl_DWRTPT', 100000000),
    ('pl_DMPGRD', 100000000),
    ('pl_CTSARE', 100000000),
    ('pl_CTNARE', 100000000),
    ('pl_CBLARE', 100000000),
    ('pl_BERTHS', 100000000),
    ('pl_AIRARE', 100000000),
    ('pl_ADMARE', 100000000),
    ('pl_ACHBRT', 100000000),
    ('pl_ACHARE', 100000000),
    ('pl_CRANES', 100000000),
	('li_RAPIDS', 100000000),
	('li_MARCUL', 100000000),
	('li_FLODOC', 100000000),
	('li_LNDMRK', 100000000),
	('li_FERYRT', 100000000),
	('li_CBLSUB', 100000000),
	('li_COALNE', 100000000),
	('li_DEPARE', 100000000),
	('li_DEPCNT', 100000000),
	('li_LNDARE', 100000000),
	('li_RIVERS', 100000000),
	('li_SLCONS', 100000000),
	('li_PIPOHD', 100000000),
	('li_MAGVAR', 100000000),
	('li_RECTRC', 100000000),
	('li_PIPSOL', 100000000),
	('li_BRIDGE', 100000000),
	('li_CONVYR', 100000000),
	('li_SBDARE', 100000000),
	('li_LNDELV', 100000000),
	('li_SLOTOP', 100000000),
	('li_DAMCON', 100000000),
	('li_OBSTRN', 100000000),
	('li_RADLNE', 100000000),
	('li_RAILWY', 100000000),
	('li_ROADWY', 100000000),
	('li_CAUSWY', 100000000),
	('li_WATFAL', 100000000),
	('li_CBLOHD', 100000000),
	('li_TSSBND', 100000000),
	('li_WATTUR', 100000000),
	('li_MORFAC', 100000000),
	('li_GATCON', 100000000),
	('li_TSELNE', 100000000),
	('li_DYKCON', 100000000),
	('li_VEGATN', 100000000),
	('li_RUNWAY', 100000000),
	('li_FNCLNE', 100000000),
	('li_RDOCAL', 100000000),
	('li_STSLNE', 100000000),
	('li_NAVLNE', 100000000),
	('li_OILBAR', 100000000),
	('li_CANALS', 100000000),
	('li_FORSTC', 100000000),
	('li_DWRTCL', 100000000),
	('li_TIDEWY', 100000000),
	('li_TUNNEL', 100000000),
	('li_BERTHS', 100000000),
	('li_RCRTCL', 100000000),
	('li_FSHFAC', 100000000),
	('li_PONTON', 100000000),
	('pt_ROADWY', 100000000),
	('pt_BUAARE', 100000000),
	('pt_DMPGRD', 100000000),
	('pt_BOYCAR', 100000000),
	('pt_BOYSAW', 100000000),
	('pt_ACHARE', 100000000),
	('pt_BOYINB', 100000000),
	('pt_PILBOP', 100000000),
	('pt_OFSPLF', 100000000),
	('pt_BOYSPP', 100000000),
	('pt_FOGSIG', 100000000),
	('pt_LNDARE', 100000000),
	('pt_LNDELV', 100000000),
	('pt_SPLARE', 100000000),
	('pt_LNDRGN', 100000000),
	('pt_LIGHTS', 100000000),
	('pt_SILTNK', 100000000),
	('pt_WATTUR', 100000000),
	('pt_ICNARE', 100000000),
	('pt_MIPARE', 100000000),
	('pt_TS_TIS', 100000000),
	('pt_OBSTRN', 100000000),
	('pt_PILPNT', 100000000),
	('pt_RTPBCN', 100000000),
	('pt_SBDARE', 100000000),
	('pt_RETRFL', 100000000),
	('pt_SOUNDG', 100000000),
	('pt_TOPMAR', 100000000),
	('pt_HULKES', 100000000),
	('pt_LOGPON', 100000000),
	('pt_WEDKLP', 100000000),
	('pt_WRECKS', 100000000),
	('pt_NEWOBJ', 100000000),
	('pt_UWTROC', 100000000),
	('pt_AIRARE', 100000000),
	('pt_CURENT', 100000000),
	('pt_LNDMRK', 100000000),
	('pt_LOCMAG', 100000000),
	('pt_SEAARE', 100000000),
	('pt_LITFLT', 100000000),
	('pt_BOYISD', 100000000),
	('pt_CTNARE', 100000000),
	('pt_FSHFAC', 100000000),
	('pt_HRBFAC', 100000000),
	('pt_MORFAC', 100000000),
	('pt_VEGATN', 100000000),
	('pt_PIPSOL', 100000000),
	('pt_GATCON', 100000000),
	('pt_SMCFAC', 100000000),
	('pt_BUISGL', 100000000),
	('pt_BCNLAT', 100000000),
	('pt_BCNSPP', 100000000),
	('pt_CTRPNT', 100000000),
	('pt_FORSTC', 100000000),
	('pt_RDOSTA', 100000000),
	('pt_DAMCON', 100000000),
	('pt_LITVES', 100000000),
	('pt_BCNCAR', 100000000),
	('pt_RUNWAY', 100000000),
	('pt_PYLONS', 100000000),
	('pt_CGUSTA', 100000000),
	('pt_RCTLPT', 100000000),
	('pt_TS_FEB', 100000000),
	('pt_BRIDGE', 100000000),
	('pt_SPRING', 100000000),
	('pt_ACHBRT', 100000000),
	('pt_RDOCAL', 100000000),
	('pt_BOYLAT', 100000000),
	('pt_TS_PAD', 100000000),
	('pt_TS_PRH', 100000000),
	('pt_DISMAR', 100000000),
	('pt_SLOGRD', 100000000),
	('pt_SNDWAV', 100000000),
	('pt_PRDARE', 100000000),
	('pt_SISTAW', 100000000),
	('pt_RADSTA', 100000000),
	('pt_CRANES', 100000000),
	('pt_MARCUL', 100000000),
	('pt_BERTHS', 100000000),
	('pt_RSCSTA', 100000000),
	('pt_BCNSAW', 100000000),
	('pt_SISTAT', 100000000),
	('pt_SLCONS', 100000000),
	('pt_BCNISD', 100000000),
	('pt_DAYMAR', 100000000),
	('pt_WATFAL', 100000000)

    # Ajoutez d'autres noms de couche avec leur échelle minimale dans le même format
]

# Récupérer le projet en cours
projet = QgsProject.instance()

# Charger chaque couche dans l'ordre spécifié
for nom_couche, echelle_min in couches_a_charger:
    # Construire le chemin complet de la couche
    chemin_couche = '{}|layername={}'.format(chemin_geopackage, nom_couche)
    # Charger la couche
    couche = QgsVectorLayer(chemin_couche, nom_couche, 'ogr')
    # Vérifier si la couche est valide
    if couche.isValid():
        # Ajouter la couche au projet
        projet.addMapLayer(couche)
        # Définir l'échelle minimale pour la couche
        couche.setScaleBasedVisibility(True)
        couche.setMinimumScale(echelle_min)
        print(f"L'échelle d'affichage de la couche {nom_couche} a été définie sur {echelle_min}.")
    else:
        print("Impossible de charger la couche :", nom_couche)

print("Chargement des couches terminé.")

Gestión de la escala de visualización

El script anterior se utiliza para definir una escala mínima cuando las capas se cargan por primera vez en el proyecto. Al guardar el proyecto, se guarda el valor del campo Escala_mínima de la capa. Cuando se abre el proyecto, se tiene en cuenta la configuración de visualización en el momento de cerrar el proyecto. Por lo tanto, sólo se utilizará el guión anterior al empezar a trabajar en un proyecto. Sin embargo, las escalas definidas en el script load_layers pueden no ser adecuadas para su área de trabajo. Por lo tanto, es posible que tenga que modificar los valores mínimos de escala para determinadas capas.

Le proporcionamos un script Python que le permite definir la escala mínima de visualización para todas las capas seleccionadas en el panel Capas. Una vez guardado el proyecto, estos ajustes se utilizarán cada vez que se abra el proyecto.

Para usarlo, primero cárgalo en la consola Python de QGis, selecciona (resalta) las capas que quieras modificar en el panel Capas y, lo más importante, cambia la línea

#Define la escala mínima (por ejemplo, 1:50000)

min_escala = 250000

con el valor deseado para la escala mínima de visualización.

El script de Python para definir la escala mínima de visualización de las capas seleccionadas es el siguiente:

setminscale.py

# Récupérer la vue des couches
layer_tree_view = iface.layerTreeView()

# Récupérer les couches sélectionnées
selected_layers = layer_tree_view.selectedLayers()

# Définir l'échelle minimale pour chaque couche sélectionnée
for layer in selected_layers:
    # Définir l'échelle minimale (par exemple, 1:50000)
    min_scale = 250000
    
    # Définir l'échelle minimale d'affichage pour la couche
    layer.setScaleBasedVisibility(True)
    layer.setMinimumScale(min_scale)
    print(f"L'échelle d'affichage de la couche {layer.name()} a été définie sur {min_scale}.")


Puede descargarlo aquí.

Un script de Python para filtrar capas por «propósito»

Las tablas de su geopackage incluyen un atributo llamado «propósito», que es un valor entre 1 y 6 y corresponde al propósito principal del mapa:

  • 1: Visión general
  • 2: General
  • 3: Litoral
  • 4: Aproximación
  • 5: Puerto
  • 6: Atraque

Si tiene mapas con propósitos diferentes cubriendo la misma área, por ejemplo un mapa de tipo General y un mapa de tipo Aproximación, tendrá información duplicada. Si las entidades de dos mapas no son del mismo tipo (una entidad de superficie en un mapa de Aproximación corresponderá a una entidad de punto en el mapa General, por ejemplo), la representación puede volverse rápidamente muy desordenada. La solución propuesta es sencilla

filter_purpose.py

# Importer le module QGIS
from qgis.core import QgsProject, QgsMapLayerType

# Définir le valeur de l’attribut «purpose» à filtrer
valeur_purpose = 3

# Obtenir le projet actif
projet = QgsProject.instance()

# Obtenir la liste des couches chargées dans le projet
couches = projet.mapLayers().values()

# Parcourir toutes les couches
for couche in couches:
# Vérifier si la couche est de type vecteur
if couche.type() == QgsMapLayerType.VectorLayer:
# Vérifier si la couche a un champ nommé «purpose»
if couche.fields().indexFromName(‘purpose’) != -1:
# Vérifier si le nom de la couche commence par l’un des préfixes spécifiés
if couche.name().startswith((‘pt_’, ‘li_’, ‘pl_’)):
# Définir le filtre sur l’attribut «purpose» égal à la valeur spécifiée
filtre = f'»purpose» = {valeur_purpose}’
couche.setSubsetString(filtre)
print(f»Filtre défini pour la couche {couche.name()}»)
else:
print(f»La couche {couche.name()} ne commence pas par ‘pt_’, ‘li_’, ou ‘pl_'»)
else:
print(f»La couche {couche.name()} n’a pas d’attribut ‘purpose'»)
else:
print(f»La couche {couche.name()} n’est pas une couche vecteur»)

Puedes descargar el script aquí.

Cargue el script en la consola de python, modifique la línea:

#Define el valor del atributo «purpose» a filtrar

valor_propósito = 5

con el valor de propósito deseado, luego ejecute el script. Se filtrarán todas las capas presentes en el panel Capas del proyecto.

Si desea eliminar todos los filtros activos de todas las capas del proyecto, el siguiente script le permite hacerlo:

unfilter.py

# Importer le module QGIS
from qgis.core import QgsProject

# Obtenir le projet actif
projet = QgsProject.instance()

# Obtenir la liste des couches chargées dans le projet
couches = projet.mapLayers().values()

# Parcourir toutes les couches
for couche in couches:
    # Vérifier si la couche est une couche vectorielle
    if couche.type() == QgsMapLayer.VectorLayer:
        # Supprimer le filtre de la couche
        couche.setSubsetString('')
        print(f"Filtre supprimé pour la couche {couche.name()}")

Puede descargar el script aquí.

Si cet article vous a intéressé et que vous pensez qu'il pourrait bénéficier à d'autres personnes, n'hésitez pas à le partager sur vos réseaux sociaux en utilisant les boutons ci-dessous. Votre partage est apprécié !

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *