Creation of a Geopackage database for ENC maps (part 2: add symbology)

The first part of the Collaborative Financing for the Integration of Marine Data in QGIS project has been completed, thanks to contributions from ORANGE Marine, Geoconceptos Uruguay, Janez Avzec and Gaetan Mas. Our warmest thanks to all of them. We hereby publish the final content of this part of the project.
The first part deals with the creation and management of the database, and this second part with the S57 symbology in QGis.

Adding symbology to a geopackage

The default symbology of a geopackage’s tables is contained in a table named layer_styles, which is only created if you use the save default option of the style button.

After cloning the tables in the ENC file, the table does not exist. So we’re going to import the table containing all ENC map symbology.

Download layer_natsurfV1.gpkg

This geopackage contains a table, named layer_styles, with symbology definitions for all S57 tables, as well as a table named natsurf, which will be used to format the rendering of the “nature of seabed” table (SBDARE).

To integrate these tables into your ENC file (here ENC.gpkg):

In QGis, open the database manager.

  1. You should already have the geopackage->ENC.gpkg connection. If not, right-click on ‘Geopackage’->new connection, then point to your ENC.gpkg file.
  2. Connect to the downloaded layers_natsurf.gpkg table (right-click on ‘Geopackage’->new connection, then point to the downloaded geopackage)
  3. Select layer_styles in layers_natsurf.gpkg, then right-click->add to canvas, and you’ll have the layer_styles table in the list of loaded layers.
  4. Select natsurf in layers_natsurf.gpkg, then right-click->Add to canvas, and the natsurf table will appear in the list of loaded layers.
  5. Select the ENC.gpkg geopackage in the database manager.
  6. In the Table menu, select Import layer/file.
  7. In the layer list, select layer_styles, then OK
  8. Repeat the operation for the natsurf layer.

The current version of layer_styles contains symbology layouts for 153 layers. Please check regularly for updates available for download.

This symbology uses svg symbols that you need to download to your machine. Clicking here will download a ‘nautical’ directory containing all the necessary svg symbols, as well as a directory called “XML” with additional symbols for QGis.

SVG symbols

By default, references to svg symbols are made to a ‘C:/nautical’ directory. You have several options:

1- Unzip the nautical file into a c:/nautical directory on your machine

In this case, you don’t need to do anything else. Layer_styles will find the svg symbols with no problem.

2- You want to save the nautical directory in a directory of your choice

In this case, you need to modify the layer_styles table so that it finds the symbols.

Open the QGis database manager.

  1. Select the layer_styles table in your geopackage
  2. Open an SQL window
  3. Enter the query:
  4. UPDATE layer_styles
  5. SET styleQML = REPLACE(styleQML, ‘C:/nautical’, ‘Your path’);
  6. Click on the Execute button

3- You wish to save the nautical directory in your ENC geopackage directory.

In this case, references to svg symbols will be relative to the Geopackage and you’ll be able to use it from several machines. We’ll follow the same procedure as above, but the SQL query will be:

UPDATE layer_styles
SET styleQML = REPLACE(styleQML, ‘C:/nautical’, ‘nautical’);

Of course, the project must be configured to store relative paths (Project properties -> General->Save paths->Relative).

XML symbols

Uploaded XML symbols correspond to additional QGis symbologies. They are used in the formatting of some of the S57 symbols. You can search for them and install them from their classic repositories, but to simplify the work we’ve put all the necessary XML files in the download file.

Here’s how,

  1. open the Style Manager (Preferences->Style Manager)
  2. Click on the Import/Export button
  3. In the File field, point to the XML file you wish to upload, then click on Import
  4. Repeat for all uploaded XML files

Some special symbologies

The vast majority of S57 layer symbologies require no special care. The symbology is defined by default in the geopackage and is loaded and displayed automatically.
But there are three layers that require particular attention.

1- The LIGHTS layer

The various lights on ENC maps can be of two types: sector lights, i.e. the color of the light is different depending on the angle from which it is observed, or simple lights, visible on 360°.

On the other hand, the symbology used on paper charts and that used by digital ENC visualization software is not the same.

The symbology we’ve implemented meets all these criteria.

When you load the LIGHTS layer, you’ll see it in the layer panel:

By default, the symbology of ENC visualizers is displayed.

The first line corresponds to sector lights, the second to simple lights.

For sector lights, the symbology is the same whether you use a viewer or a paper map. For simple traffic lights, however, you can choose the type of symbology. If you uncheck the second line and check the third, you’ll have a “paper” symbology:

SOUNDG layer (bathymetric soundings)

The display of sounding values depends on their quality: if they are reliable, the font should be italic, but if they are not completely reliable, they should be displayed in a regular font.

Probe quality is stored in the M_QUAL layer of S57 files.

By default, the SOUNDG layer symbology takes probe quality into account. The pl_M_QUAL layer must therefore be loaded into the QGis project. This is invisible when displayed, but is used to label SOUNDG entities:

The process involves crossing the two layers to obtain the quality value for each probe from the pl_M_qual polygons. Of course, the number of probes can make this step quite time-consuming. If you’re working with large zoners and a high number of probes, you can choose to ignore quality. To do this, download the following qml file: soundg.qml. You’ll have two qml files: the one that uses M_qual and the one that doesn’t.

Open the SOUNDG layer properties, click on the Style button (bottom left), then on Load Style and point to the downloaded file. All probes will be displayed very quickly, regardless of quality.

The SBDARE layer (type of background)

Managing the symbology of this layer is rather complicated, as it involves processing two list-type fields. The list of bottom types must be combined with the granulometry of each fraction.

The following code is the expression used to generate the labels, which is included by default:

étiquettes SBDARE

CASE 
  WHEN regexp_substr("NATSUR", '\\((\\d+):') = '1'THEN 
	CASE
		WHEN "NATQUA" IS NOT NULL THEN  
		with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))
		WHEN "NATQUA" IS NULL THEN  
		with_variable('NTS',regexp_substr("NATSUR", ':(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS))
		ELSE '?'
		
	END
 WHEN regexp_substr("NATSUR", '\\((\\d+):') = '2' THEN 
	CASE
		WHEN  regexp_substr("NATQUA", '\\((\\d+):') = '1' THEN  
		with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))  || '.'  || with_variable('NTS2',regexp_substr("NATSUR", ',(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS2))
			
		WHEN "NATQUA" IS NULL THEN  
		with_variable('NTS',regexp_substr("NATSUR", ':(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS))  || '.' || 
			with_variable('NTS2',regexp_substr("NATSUR", ',(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS2))
		WHEN  regexp_substr("NATQUA", '\\((\\d+):') = '2' THEN  
	 with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))  || '.'  || 
			with_variable('NTS2',lpad(regexp_substr("NATSUR", ',(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ',(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS2,2)) AND "NATSURT" = trim(left(@NTS2,2))))
			end
WHEN regexp_substr("NATSUR", '\\((\\d+):') = '3' THEN 	 
		CASE
		WHEN  regexp_substr("NATQUA", '\\((\\d+):') = '1' THEN  
		with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))  || '.'  || with_variable('NTS2',regexp_substr("NATSUR", ',(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS2))|| '.' || 
			with_variable('NTS3',regexp_substr("NATSUR", ',(\\d+)\\)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS3) )
			
		WHEN "NATQUA" IS NULL THEN  
		with_variable('NTS',regexp_substr("NATSUR", ':(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS))  || '.' || 
			with_variable('NTS2',regexp_substr("NATSUR", ',(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS2))|| '.' || 
			with_variable('NTS3',regexp_substr("NATSUR", ',(\\d+)\\)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS3) )
		WHEN  regexp_substr("NATQUA", '\\((\\d+):') = '2' THEN  
	 with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))  || '.'  || 
			with_variable('NTS2',lpad(regexp_substr("NATSUR", ',(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ',(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS2,2)) AND "NATSURT" = trim(left(@NTS2,2)))) || '.' || 
			with_variable('NTS3',regexp_substr("NATSUR", ':(\\d+)'),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" IS NULL AND "NATSURT" = @NTS3) )
		WHEN  regexp_substr("NATQUA", '\\((\\d+):') = '3' THEN  
	 with_variable('NTS',lpad(regexp_substr("NATSUR", ':(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ':(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS,2)) AND "NATSURT" = trim(left(@NTS,2))))  || '.'  || 
			with_variable('NTS2',lpad(regexp_substr("NATSUR", ',(\\d+)\\)'),2,'  ') || lpad(regexp_substr("NATQUA", ',(\\d+)\\)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS2,2)) AND "NATSURT" = trim(left(@NTS2,2)))) || '.' || 
			with_variable('NTS4',lpad(regexp_substr("NATSUR", ',(\\d+)'),2,'  ') || lpad(regexp_substr("NATQUA", ',(\\d+)'),2,'  '),
			aggregate(layer:= 'natsurf',aggregate:='max',expression:= "ETIQ",
			filter:= "NATQUAT" = trim(right(@NTS4,2)) AND "NATSURT" = trim(left(@NTS4,2))))
			end
		
END
   

This code has been simplified (yes!) by storing the 143 possible combinations of nature and fraction in an external table: natsurf.

For the symbology to work, the natsurf table must be added to the list of project layers:

BONUS: Some ways of working with multiple layers

Load all Geopackage layers

You can load all Geopackage layers directly by clicking and dragging the geopackage name from the explorer panel to the layers panel.

A window opens where you can select which layers to load. To load all layers, simply click on Select all, then on Add layer.

All layers are now loaded. Depending on the number of S57 files loaded in your database, window formatting can take a long time.

Layers that consume a lot of resources are the ones we saw above (lights, probes and bottom type). You can uncheck them to speed up loading.

Another, more efficient way is to define the minimum display scale for your layers. With 150 layers loaded, defining them one by one is out of the question. We provide you with a Python script that allows you to define the minimum display scale for all layers selected in the Layers panel. Once your project has been saved, these settings will be used each time the project is opened.

The Python script for setting the minimum display scale for selected layers is as follows:

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

[/stextbox ]

You can download it here.

The S57 database project with Geopackage has come to an end. We are now in the process of setting up an equivalent procedure using a PostgreSQL/Postgis database. Help us bring this project to a successful conclusion!

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

Leave a Reply

Your email address will not be published. Required fields are marked *