Ferramentas para projetos de mapas marinhos ENC no QGis

Este artigo completa a série de artigos sobre a criação de um banco de dados de geopacote para gerenciar as cartas náuticas ENC no QGis e a simbologia das várias camadas de dados. Trabalhar com um pequeno número de mapas não apresenta problemas específicos, mas, assim que o número aumenta, há uma série de operações que se tornam complicadas ou demoradas.
Desenvolvemos uma série de scripts Python que simplificam o trabalho em grandes bancos de dados de geopacotes.

1- Carregamento de camadas

O primeiro problema é o grande número de camadas a serem carregadas no projeto QGis. Embora um mapa possa ter cerca de vinte camadas, assim que o número de mapas aumenta, você pode se deparar rapidamente com mais de cem camadas para carregar.

O QGis permite que você carregue todas as camadas em um geopackage em bloco. Assim, você não precisa carregar as centenas de camadas uma a uma. Porém, depois de carregadas, há duas tarefas a serem executadas:

  • remover camadas irrelevantes, como camadas de metadados
  • ordenar a exibição de camadas para evitar que determinadas camadas fiquem completamente invisíveis por estarem sobrepostas a outras camadas. As camadas de superfície, como DEPARE e LNDARE (profundidades e terreno), devem estar sempre abaixo dos objetos marinhos e terrestres, caso contrário, esses objetos não serão visíveis.

Além disso, é sempre mais agradável trabalhar com escalas mínimas de exibição, de modo que apenas determinadas camadas sejam exibidas quando o zoom for aplicado em escalas muito pequenas e as informações detalhadas sejam exibidas apenas quando o zoom for aplicado em uma escala maior.

Seleção de camadas a serem carregadas

Fornecemos um script python que resolve todos esses problemas por conta própria, que pode ser baixado neste link.

O script inclui uma lista de 210 camadas S57, ordenadas para exibição correta:

Camadas de superfície representadas por polígonos sólidos, depois camadas de superfície representadas por polígonos vazios (somente os perímetros são exibidos), depois camadas do tipo linear e, por fim, camadas do tipo ponto. Dentro de cada categoria, a ordem foi projetada para evitar o mascaramento de informações.

Cada camada é acompanhada por um valor mínimo de escala de exibição, sendo o padrão 100000000.

Veja um exemplo:

#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),

Se não quiser que o script carregue camadas que não lhe interessam, você pode simplesmente comentar a linha correspondente adicionando um ‘#’ no início da linha:

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

Nesse exemplo, as camadas TIDEWY e DAMCON não serão carregadas.

Além disso, se você quiser definir uma escala mínima de exibição para uma camada, basta alterar o valor correspondente:

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

Nesse exemplo, a camada TIDEWY só será exibida quando o valor de zoom da janela do mapa for menor que 100000 e a camada OBSTRN quando o valor for menor que 50000.

Para usar o script

  • Abra a janela do Editor (1)
  • Clique no ícone Browse (2) e aponte para o arquivo .py baixado
  • Altere o caminho do geopackage para o caminho e o nome do seu geopackage (3)
  • Execute o script (4)

Antes de executá-lo, você pode fazer alterações para evitar que as camadas sejam carregadas ou para atribuir a elas uma escala mínima diferente. Não se esqueça de salvar essas alterações antes de fechar o projeto.

O código do script é o seguinte:

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é.")

Gerenciamento da escala de exibição

O script anterior é usado para definir uma escala mínima quando as camadas são carregadas pela primeira vez no projeto. Quando você salva o projeto, o valor no campo Min_scale da camada é salvo. Quando o projeto é aberto, as configurações de exibição no momento em que o projeto é fechado são levadas em consideração. Portanto, você só usará o script anterior no início do trabalho em um projeto. Entretanto, as escalas definidas no script load_layers podem não ser adequadas para sua área de trabalho. Portanto, talvez seja necessário modificar os valores mínimos de escala para determinadas camadas.

Fornecemos um script Python que permite definir a escala mínima de exibição para todas as camadas selecionadas no painel Layers. Depois que seu projeto for salvo, essas configurações serão usadas sempre que o projeto for aberto.

Para usá-lo, primeiro carregue-o no console do QGis Python, selecione (destaque) as camadas que deseja modificar no painel Layers (Camadas) e, o mais importante, altere a linha

#Defina a escala mínima (por exemplo, 1:50000)

min_scale = 250000

com o valor desejado para a escala mínima de exibição.

O script Python para definir a escala mínima de exibição para as camadas selecionadas é o seguinte:

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}.")


Você pode baixá-lo aqui.

Um script Python para filtrar camadas por “finalidade”

As tabelas em seu geopackage incluem um atributo chamado “purpose” (finalidade), que é um valor entre 1 e 6 e corresponde à finalidade principal do mapa:

  • 1: Visão geral
  • 2: Geral
  • 3: Litoral
  • 4: Aproximação
  • 5: Porto
  • 6: Atracação

Se você tiver mapas com finalidades diferentes cobrindo a mesma área, por exemplo, um mapa do tipo General e um mapa do tipo Approach, haverá informações duplicadas. Se as entidades em dois mapas não forem do mesmo tipo (uma entidade de superfície em um mapa de Aproximação corresponderá a uma entidade de ponto no mapa Geral, por exemplo), a renderização poderá se tornar rapidamente muito confusa. A solução proposta é simples

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”)

Você pode fazer o download do script aqui.

Carregue o script no console do Python e modifique a linha:

#Defina o valor do atributo “purpose” a ser filtrado

purpose_value = 5

com o valor de finalidade desejado e, em seguida, execute o script. Todas as camadas presentes no painel Layers do projeto serão filtradas.

Se quiser remover todos os filtros ativos de todas as camadas do projeto, o script a seguir permite que você faça isso:

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()}")

Você pode fazer o download do script aqui.

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é !

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *