OpenStreetMap has – despite its British origin – not a very strong maritime focus. Reason for that is probably that only a small percentage of mappers in OpenStreetMap live in a coastal setting. And even for those who live in a coastal city, everyday life rarely focuses on this aspect.
As a result, tagging of human infrastructure specific to coastal settings is relatively under-developed in OSM. And a lot of tags that have been invented and established over time are not widely interpreted by data users – and when they are, this is often done in a rather undifferentiated way.
I wrote about natural coastal features in OpenStreetMap quite extensively – as well as their depiction in maps. This blog post is going to focus on human constructions in coastal settings and features related to human activities.
Most of the design work i present here was already developed last year. But there were some details that i only found the time to finish recently.
Symbols
Starting point for me is one of the big symbology mistakes in OSM-Carto – the choice of symbol for amenity=ferry_terminal
.
amenity=ferry_terminal
in OpenStreetMap is used to map a place at the coast where ferries take on or offload passengers. And the term ferry is used very widely in OSM for any kind of water vehicle regularly transporting people between specific locations over water.

amenity=ferry_terminal
is OSM-Carto (link goes to double resolution version)
In OSM-Carto amenity=ferry_terminal
is displayed with an anchor symbol. This is a poor and misleading choice in my opinion since the anchor symbol in cartography in most cases is used for places where ships or boats can anchor or moor – not necessarily regularly and not necessarily for on- and off-loading passengers. The anchor symbol to many map user therefore will imply a certain meaning while de facto it indicates something rather different.
The more intuitive choice of symbol would be that of a moored passenger ship – which is the concept i chose for the AC-Style now.

New amenity=ferry_terminal
design is the AC-Style
This is going to appear somewhat off in case of smaller boats serving as ferry. This will, however, not be as grossly misleading semantically as the anchor symbol.
Note there is a subtle difference between the symbol for polygon features and the symbol for nodes: Nodes are rendered with a symbol where the ship has a fill color while the symbol used for polygons is outlines only so the background color shines through – normally in the transportation fill color that is also used for the symbol fill.

Filled symbol for nodes and unfilled symbol for polygons (double resolution rendering)
The reason is that the ferry terminal node is often located at locations where several line features meet (coastline, ferry route and whatever road or path leads there). Hence the background is often fairly noisy and the symbol would be poorly readable without a fill. This is less of a problem when the ferry terminal is mapped with a polygon and the symbol is placed somewhere within the polygon.
The other symbol change i implemented is the addition of a symbol for emergency=life_ring
. This has been a request in the past in OSM-Carto but the difficulty is to design a symbol that, at z19 and in terms of visual weight – relates well to the other small point features shown at that scale (like amenity=bench
, amenity=waste_basket
). Creating a small enough symbol that is not out of balance with those and that is still recognizable as a life ring is somewhat difficult.

New emergency=life_ring
rendering

Life ring at z19 in context of other small point symbols
Coastal Constructions

The three types of coastal constructions rendered in OSM-Carto
Piers
Piers as mapped in OpenStreetMap with man_made=pier
are walk-able constructions over water, often used to access boats moored to the pier. They can be either swimming or erected on poles above the water. These are traditionally rendered in OSM-Carto in land color – i.e. they appear like land, but with no further indication that they are a constructed feature. That works reasonably well and avoids map users having to understand a separate design element. But it also does not differentiate the display of piers in any way.
The most common additional differentiations of piers in tagging in OpenStreetMap are (a) if the pier is floating (floating=yes
) or mounted on poles or other support structures (floating=no
) and if the pier is used for mooring boats or ships (mooring=*
, most common values being yes
and private
). I have developed a design to show these with a distinct rendering now:

New rendering of piers differentiated by secondary tags floating=*
and mooring=*
Floating piers are indicated with a dark blue edge line on the water side – which is only shown where the pier is mapped over water. This is relatively straight away to implement with the existing framework to differentiate rendering over water and over land.
Explicitly non-floating piers (floating=no
) are indicated with a dark shadow towards the lower right – similar to the one used for planters – and a very thin outline.
mooring=*
is indicated with subtle anchor symbols on the pier – adjusted in size to the display size of the pier. This is shown with a single symbol pattern for polygons and with repeating symbols along the line for piers mapped with linear ways – as illustrated here:

Mooring symbols on piers of different length mapped with linear ways
Also visible in that is that the line width is adjusted based on width=*
tagging. Note that if the pier is double tagged as a road or path the name is displayed only for the road and not the pier. In OSM-Carto this is labeled twice.
I also integrated the piers into the road layer so a non-floating pier will be shown above a footway on the beach underneath with the appropriate additional tags applied.

Layering of piers in OSM-Carto (left) and in the AC-Style (right)
Breakwaters
The second water edge construction rendered in OSM-Carto is man_made=breakwater
. The tag is used in OpenStreetMap to map coastal constructions meant to protect coasts and harbors from the sea. These are rendered in OSM-Carto as shown above in plain dark gray color in a common design with man_made=groyne
(which is discussed in the next section). I made the following changes here:
- introduced ground unit rendering of linear ways based on
width=*
tagging.
- added differentiation in rendering for
material=stone
(the most commonly used material tag on man_made=breakwater
) using a structure pattern – both on polygons and on linear ways of sufficient size for the pattern to be readable.

New rendering of man_made=breakwater
Groynes
The third and last water edge construction currently shown in OSM-Carto is man_made=groyne
. This tag is used for constructions that are meant to reduce movement of sediment and thereby counteract coastal erosion. It is also used for similar constructions along rivers serving the same purpose.
As mentioned this tag is rendered the same as man_made=breakwater
in OSM-Carto. Practically a much higher percentage of these features are mapped with linear ways than for man_made=breakwater
– so i am focusing on those.
Like with man_made=breakwater
i do ground unit rendering of these at the high zoom levels. And i am differentiating by material – with the most common value here being wood
rather than stone
– hence i developed a special rendering for that starting at z17.

New rendering of man_made=groyne
with material=wood
compared to material=stone
:

New rendering of man_made=groyne
with material=stone
The rendering for material=wood
is meant to depict a dense line of wooden posts – which is a common design for groynes made from wood. To be clear – as far as practically rendering groynes as mapped in OpenStreetMap is concerned, this rendering is a bit academic at the moment because there are currently no occurrences in the OSM database of man_made=groyne
with material=wood
and width=*
. Also wooden groynes generally have a very small width so they will rarely be rendered above the minimum drawing width even at z20. In the above example i manually set the width to 0.75 to make the line width progression to show in a meaningful way at 40 degrees latitude. So you should take this primarily as a demonstration case for a map design technique.
The most suitable method to implement this kind of design in Mapnik would seem to be a line pattern – as i have discussed it in the past. The challenge here is to not have a cut symbol at the start or end of the line, but to start and end with a full symbol. I demonstrated how this can be done with dashing patterns in a previous post. But SVG based line patterns are a bit more limited in that regard. While Mapnik and CartoCSS in principle offer a line-pattern-transform
function to scale the pattern, that approach neither offers the rendering quality nor the precision necessary here.
So in the end i chose to render the individual symbols of the line pattern using a similar technique as i had introduced with trees and tree rows. But i do not cut the individual symbols against each other like i did for tree rows. Most groynes are much longer than wide and tend to be fairly straight and – unlike for tree rows – the design does not require the cutting of symbols. So just rendering the static symbols works fine and this means a significantly better rendering efficiency than with the trees.

Individual symbol placement for the rendering of wooden groynes

Line width progression for visualizing width at very large scales
Note the dark linework of the symbols is rendered from symbol data stored in the rendering database and transformed as needed – a technique i discussed in more detail with trees. The brighter background fill of the symbols, on the other hand, is rendered using marker symbolizers.
Quays
What is – so far – not rendered in OSM-Carto is man_made=quay
. This tagging is used to map solid coastal constructions where ships moor in harbors – unlike piers, which are either floating or above the water. A quay in OpenStreetmap is essentially a retaining wall directly at the waterline erected as a place where ships can be fastened to in a port and can be boarded or loaded.
Given how widespread quays are in harbors world wide it is remarkable how little the tag is used (less than 7000 times). This is of course partly because it is not much interpreted by data users.
Part of the reason for the lack of use of the tag in maps is that mapping conventions are much less defined than for many other features:
man_made=quay
can be and is used both on linear ways and on polygons (with there not being a clear definition of the landward extent of a quay).
- when
man_made=quay
is used on linear ways there is no established convention for the mapping direction. This contrasts with other oriented linear features like barrier=retaining_wall
, natural=coastline
or natural=cliff
.
The second point of course makes sense because man_made=quay
is, by definition, always directly at the edge of a waterbody. Hence its orientation clearly derives from the geometric context and having a defined orientation of the feature is – strictly speaking – redundant information. This makes rendering these in a map a bit more challenging though, because you cannot fully derive the design from the feature tagged man_made=quay
alone.
The most natural approach to rendering in a Mapnik/Carto based map style would be to perform a compound query of the quay and any intersecting waterbodies. But there is not necessarily a 1:1 relationship between quays and water polygons. And you have to gracefully deal with mapping errors and ambiguous situations with waterbodies being present on both sides of the quay line. Bottom line: While this is perfectly doable it is definitely non-trivial.
I decided to take a different approach and to do the rendering of quays with the help of raster post processing using the GMIC interface i developed for Mapnik some time ago. Here is how this looks like design wise:

New rendering of man_made=quay
On the landward side the quay is rendered like a retaining wall with a solid line at the edge and – at the higher zoom level – a dashed line behind. Towards the sea this is supplemented by a dark blue line like the one drawn around floating piers (see above). For polygon features this drawing is done at the water line and slightly beyond where the polygon continues over land – this way hinting at the fact that the geometry continues without drawing a line where there is no semantically meaningful delineation.
Here is how this is done:
The blue outlining over water is rendered together with that of piers by treating quay features like man_made=pier
+ floating=yes
in the piers-casing layer. The piers-casing layer is rendered together with the landcover-water layer in a way that only shows up over water using classic Mapnik compositioning techniques.
The landward retaining wall style rendering first requires retaining the rendering of the water features in the ocean
and water-areas
layers in the GMIC image buffer stack – a technique i explained in a previous blog post. As described there the way to do that, which is used on the ocean layer without further changes is
#ocean {
gmic: '+to_rgba. -name. use';
}
As already explained in the linked to earlier blog post this is independent of the ocean layer using comp-op: dst-out;
– which is an operation performed in Mapnik after the GMIC processing.
For the water-areas
layer things are not quite as easy because water-areas
also renders intermittent water areas, which are shown with a partly transparent pattern. And we don’t want that pattern to be part of the water mask to use for the quays. So we need to render the water areas separately – which can most efficiently be accomplished with attachments:
#water-areas::mask {
polygon-fill: @water-color;
gmic: '-to_rgba.';
}
This essentially means: render the water areas layer in plain color, store it in the GMIC buffer stack and otherwise don’t use it (since we have no -name. use
). Now we have two buffers on the GMIC stack named ocean
and water_areas_mask
(attachments get named using the attachment name in addition to the layer name, separated by an underscore).
What we then do in the actual quays
layer is first rendering the retaining wall signature on the quay features and doing so symmetrically on both sides of the line for linear ways and then applying the following GMIC script (line breaks added for readability):
-if !$_mapnik_render_trivial
zoom={round(log2(559082264.028/$_mapnik_scale_denominator))}
+channels[quays] 3 -name. quays_mask
-channels[ocean] 3
-channels[water_areas_mask] 3
-max[ocean] [water_areas_mask]
+dilate_circ[ocean] {1.0+if($zoom>=17,8.0,2.0)*$_mapnik_scale_factor}
-name. water_mask_buffer
-sub[water_mask_buffer] [ocean]
-min[quays_mask] [water_mask_buffer]
-to_rgb[quays] -append[quays] [quays_mask],c
-keep[quays]
-name. use
-fi
What this does is:
- since the whole process involves slightly more expensive steps than just trivial mask compositioning, it is wrapped in a conditional based on the variable
$_mapnik_render_trivial
predefined by Mapnik to indicate if the buffer of this layer is trivial (i.e. uniform color) – then the GMIC processing is skipped and the layer not rendered.
- define a named variable
zoom
representing the zoom level that is calculated in the same way as the z()
SQL function does in PostGIS with the help of $_mapnik_scale_denominator
– which is made available to the GMIC script in a similar fashion as !scale_denominator!
in PostGIS.
- duplicate the alpha channel of the
quays
layer (which was just rendered – image 1 below) as quays_mask
(image 2).
- reduce the previously stored
ocean
buffer to its alpha channel (image 3).
- reduce the previously stored
water_areas_mask
buffer to its alpha channel (image 4).
- combine the
water_areas_mask
buffer into the ocean
buffer so that what is opaque on one of them is opaque on the combination (image 5).
- create a new buffer by dilating (in the sense of expanding the opaque areas) the
ocean
buffer (now containing the combined water mask) with a circular filter kernel, the size of which depends on the zoom level – larger for z17+, smaller for lower zoom levels. Name the new buffer water_mask_buffer
(image 6).
- subtract the
ocean
buffer (containing the original combined water mask) from the dilated buffer (water_mask_buffer
). The result is a mask that is opaque in the dilated areas, i.e. what is close to the water but not within the water (image 7).
- combine the result of that into the
quays_mask
buffer (the alpha channel of the newly drawn quay line signatures) so that only what is opaque in both is opaque in the combination (image 8).
- replace the alpha channel of the original
quays
buffer with the modified quays_mask
buffer from the previous step (image 9).
- remove all buffers except
quays
.
- use the remaining buffer for composing this layer – the final rendering result is shown in image 10.
Here the corresponding images based on a test data set with a simple quay polygon on top and a linear quay on the bottom next to water and ocean polygons on the right.

The different buffers at the different steps in the GMIC sequence with the numbers referenced above – rendered in double resolution and with bright gray indicating transparent background
You might think the logic of using a different dilation kernel size for different zoom levels could also have been implemented on the CartoCSS level by using different GMIC sequences for different zoom levels – but that is not possible. The GMIC integration in Mapnik is implemented as a parameter to the style in a similar fashion as layer level opacity. Hence it cannot be made conditional to CartoCSS selectors. $_mapnik_scale_factor
is necessary to account for rendering at different resolutions.
Conclusions
I have shown a number of design concepts here for more differentiated depiction of coastal infrastructure based on OpenStreetMap data. In doing so i have, in particular, demonstrated a number of techniques:
- how careful selection and design of pictorial symbols, in the right size, with a fitting motive and use of subtle design variations – like adding a bright fill to a dark outline drawing to block noisy backgrounds – can help achieving a balanced and well readable map appearance (
amenity=ferry_terminal
and emergency=life_ring
).
- use of various combinations of outline drawing to differentiate features otherwise rendered with a plain fill (
floating=*
on man_made=pier
, man_made=quay
).
- use of repeated non-blocking symbols along a linear way in a similar fashion as single symbol patterns on polygons (
mooring=*
on man_made=pier
).
- further applications of ground unit rendering of linear features according to
width=*
.
- showing precisely length-adjusted line patterns of a data defined width (with the line starting and ending with a whole symbol) by drawing individual symbols from a database representation (
man_made=groyne
with material=wood
).
- use of raster processing using GMIC to render a directed line signature based on undirected mapping and context adjusted display of polygon features only adjacent to other elements (
man_made=quay
next to water).
- in contrast to previous uses of the GMIC integration, which were based exclusively on compositioning using multiple alpha masks, this also relies on morphological operations.

The different designs of coastal structures introduced here in context at z19
As usual the changes shown here can be found in the AC-Style. If you want to test the changes yourself you need to make sure you also have the latest version of my Mapnik extensions.
Practical examples
Here a few examples based on real world data:

Breakwaters with different materials on Reunion at z18

Breakwaters and floating piers near Sankt Petersburg, Russia at z16

Industrial quay in Sankt Petersburg, Russia at z16

Floating piers on the Rhine River, Germany at z18

Ferry terminals and life ring on Langeoog, Germany at z19

Quay line (obscured by boundary), ferry terminals and piers in Spiekeroog, Germany at z17

Floating piers and ferry terminals in Marseille, France at z18