Micromapping trees and lights

Demo: trees ¦ lights (select layer)


Trees are an important feature of the Jura Mountains in general and of the village of Saint-Cergue in particular in addition to lights, especially lights at night.

The map for Saint-Cergue now uses top-down view symbols for trees and street lamps at night based on an alternative OpenStreetMap (OSM) Carto map style. Called osm-carto-alternative colors, the map style is a fork of the standard CartoCSS gravitystorm/openstreetmap-carto map style used by the OpenStreetMap for its Standard map layer.

The thinking behind the design concept and its implementation has been described by Christoph Hormann, the developer, in a series of blog posts in four parts (1, 2, 3, 4).

While the osm-carto-alternative-colors style implements several very valuable alternatives to the standard OSM Carto style, we summarise here the rendering of trees, tree rows, shrubs and hedges (corresponding to the OSM tags: natural=tree, natural=tree_row, natural=shrub and natural=hedge) that are differentiated by size (crown_diameter) , leaf_type and leaf_cycle tags.

The application to street lamps at night is then summarised following a discussion of the rendering of trees and hedges (but not shrubs and bushes).

1. Rendering trees

As the starting point we have an Ubuntu Linux 18.04 LTS server with a standard switch2osm set-up for serving OSM tiles as well as an OpenStreetMap "Rails Port" website for editing a self-hosted OSM databse. For the map-tile server, the aim is to replace the section in the gravitystorm amentity-points.mss style that deals with trees with the relevant part of the osm-carto-alternative-colors style. The approach is simply to create an osm-carto-alternative-colors renderer for trees and to remove the section of the gravitystorm mapnik.xml that is used to render all features except trees, tree rows, shrubs and hedges .

This approach entails cloning the osm-carto-alternative-colors repository to a "/home/usr/src/osm-carto-alternative-colors" directory and:

  • adding a table called "carto_symbols" to the postgres/postgis database called "gis" that is used to render OSM tiles;
  • using the osm-carto-alternative-colors' "assemble-project.py" script and a "layers.yml" file to generate a "project.mml" file for trees;
  • using osm-carto-alternative-colors' carto in the normal way (carto project.mml > mapnik.mml) to generate a "mapnik.xml" file for trees;
  • adding a section in the renderd configuration file ("renderd.conf") for trees that refers to the "mapnik.xml" trees file in the osm-carto-alternative-colors directory.

The "layers.yml" need only be a cut-down version of the "layers.yml" file given in the osm-carto-alternative-colors repository:


layers:

.. header:

.... source: layers/header.mml

.... stylesheets:

...... - style/style.mss

...... - style/fonts.mss

.. trees:

.... source:layers/project.mml

.... stylesheets:

...... - style/amenity-points.mss

.... tags:

...... - ac


It appeared to be important to use a limited number of versions of the relevant software. In our case, in a virtual environment (in a command terminal: "python3 - m venv ."):

  • python --version (3.6.9)
  • carto --version (1.2.0)
  • mapnik-config --version (3.0.24)
  • sudo -u postgres -i ¦ psql ¦ \c gis ¦ SELECT version(); gives PostgresSQL = 10.22
  • sudo -u postgres -i ¦ psql ¦ \c gis ¦ SELECT PostGIS full version(); gives POSTGIS = 2.4.3 and GDAL 2.4.2

The osm-carto-alternative-colors contributing.md indicates that yaml is needed. Installing PyYAML was adequate (a terminal command "pip install pyyaml" from memory).

Setting up the "carto_symbols" table in the "gis" database was the most troublesome aspect. The sql scripts given in the osm-carto-alternative-colors "sql" directory each needed to be executed using a terminal command of the form:

  • psql -d gis /home/user/src/osm-carto-alternative-colors/sql/z.sql

It is unclear if all six sql statements are needed for trees. To be safe, all were executed. The "symbols.sql" gave errors. First, executing "symbols.sql" did not create the "carto_symbols" table ("relation carto_symbols does not exist"). lxml needed to be installed ("sudo pip3 -m install lxml").

Executing the "generate_symbols.py" script in the osm-carto-alternative-colors "scripts" directory gave the error "No such file or directory: 'inkscape'" and "inkscape error when converting symbol". From memory the terminal command "sudo apt install inkscape" may have installed inkscape successfully. Whatever was done, the command "inkscape --version" gave "Inkscape 0.92.3" once inkscape was installed.

At the beginning, the most important error on executing "generate_symbols.py" was :

  • postgresql "st_scale" geometry srid (0) does not match column srid

Two sets of psql commands were required, the first for the "carto_symbols" table and the second for the table's "way" column:


ALTER TABLE carto_symbols ADD CONSTRAINT enforce_srid_way CHECK (ST_Srid(way) = 3857);

ALTER TABLE carto_symbols ALTER COLUMN way type geometry(MultiPolygon,3857) using ST_Multi(way);


UPDATE way SET geom.STSrid=3857;

UPDATE way SET geom=ST_SetSRID(geom,3857) WHERE to_update;

ALTER COLUMN way TYPE geometry(MULTIPOLYGON,3857) USING ST_SetSRID(way,3857)


However, as time passed the "carto_symbols" table could be filled using "./generate_symbols.py" via conversion to PDF without modifying columns. The reason for this change is unclear.

The kosmtik mapping framework can be used to test the osm-carto-alternative-colors project-trees.mml by runnning:

  • kosmtik serve /home/user/src/osm-carto-alternative-colors/project.mml

Here, kosmtik is intalled in /home/user/src/kosmtik ("npm install -g kosmtik*) with node set to version 9.3.0 ("node --version" gives v9.3.0) by having nvm installed and running "nvm use 9.3.0".

Finally, when the OpenStreetMap rendering database call "gis" is updated using an "osm.xml" file generated from the OpenStreetmap database:

  • osmosis --read-apidb host="localhost" database="openstreetmap" user="user" password="user" validateSchemaVersion="no" --write-xml file="/home/user/osm.xml"

we in fact use the the gravitystorm style:

  • osm2pgsql -W -d gis -H localhost --slim --hstore --multi-geometry --style /home/user/src/openstreetmap-carto-gravity/openstreetmap-carto.style --tag-transform-script /home/user/src/openstreetmap-carto-gravity/openstreetmap-carto.lua --input-reader xml /home/user/osm.xml --expire-tiles 17 --expire-output /home/user/osm-site/expired-tiles.list

where the OpenStreetMap "Rails Port" website is installed in the "osm-site" directory.

Top-down veiew symbols are obviously attractive for micromapping features such as trees in urban settings.

2. Historic tree rendering

Having crown-diameters specified by the data (every 10 years in our case) with tags such as start_date: 2005, crown_diameter_2010: 5 and crown_diameter_2020: 10 can be used with dynamically scaled, parametrised symbol geometries to monitor the evolution of trees, as is demonstrated in the Trees layer of the Saint-Cergue map.

3. Rendering street lights at night

Actively discussed by urban communities is the ecological and environmental impact of lighting at night and the role of lighting in providing security. Being a village without extensive commercial and industrial districts, Saint-Cergue has most of its obtrusive and more permanently lit lighting focussed on street and related pedestrian lighting.

Focussing on street lamps, as rules of thumb, the spacing between street lamps should be 2.5 to 3 times their height and the diameter of a street-lamp's light cone is approximately equal to their height., with height being the most important parameter in mapping terms.

Street lamps are suspended or supported in various ways that may be useful to tag (wall mounted decorative fixture; pole-mounted; hanging catenary; ground mounted) as proposed for the OpenStreetMap tagging of light sources (i.e., key:light_source).

According to the proposal (which is supported by the street lamps in OSM map), street lamps with light cones roughly the same diameter as the height of the light fixture from the ground usually make use of a design feature referred to as the street-lamp type (cut-off; shielded; unshielded; upright). Preferred are directed light designs where light cones are clearly defined (i.e., cut off) or at least shielded to help minimise glare and light pollution. Unshielded designs with essentially cylindrical and spherical light shapes should be avoided. These shapes are generally tagged as light:shape = directed, spherical, cylindrical, other by the OSM light_source proposal, OSM street_lamp proposal, JOSM light-sources' presets, and a gLTF light schema.

Since one expects a reasonable level of illumination to exist at the mid-points between two street lamps in a row one can perhaps assume that street lamps at night should be mapped as shapes with a maximum extent of 4 times the height of the lamp.

The height of street lamps is mainly determined by the location. A master plan for Munich (see PDF) for example envisaged: downtown city squares: 14 m; pedestrian zones: 6.0 m; main traffic axes/collective roads: 10 m; pedestrian and cycle path axes: 6 m; residential main and secondary roads: 6 m: paths in parks: 4 m; "green" zones/green belt: 4 m.

So the two-dimentional mapping of street lamps involves zones of light extending up to about 4 x 14 = 56 m, say 60 m. This extent is slightly larger than the maximum of 50 m for the rendering of trees discussed above.

Given that street-lamp light sources are in most cases cut-off or shielded, a starting point is to assume that the sources can be directed or directed and tilted. To test map rendering with parameterised street-lamp tagging using the approach used for trees we simply adopted the same tagging scheme:

  • natural:tree > light_source:light
  • tree_type: palm, broadleafed, needleleafed > light_type: streetlamp, lantern, floodlight
  • tree_cycle: deciduous, evergreen > light:cycle: directed, directedtilt
  • diameter_crown: * > diameter_crown: * ( light height x 4)

The example shown on the "lights" layer of the Saint-Cergue map assumes that all the village's street lamps are of the directed type with a tilt of -90 degrees. This is in fact the case. Nonetheless, the next stage will be to see how a tilting angle and direction can be implemented.

To recall implementation:

a) create a "layers.yml"


layers:

.. header:

.... source: layers/header.mml

.... stylesheets:

...... - style/style.mss

...... - style/fonts.mss

.. source:

.... source:layers/project-lights.mml

.... stylesheets:

...... - style/amenity-points.mss

.... tags:

...... - ac


b) edit amenity-points.mss


Add: "@light-icon: #4d9945;" and "@light-text: @light-icon;".

Add a "#lights" section which can simply be the "#trees" section with "light" replacing "tree".


c) create "project.mml"

Edit the "project.mml" file used for trees by changing the Layer id to "lights" and replacing "tree" by "light". Then execute "./assemble_project.py" in terminal.

One can of course simplify "project.mml" significantly. And simple changes involve for instance changing:

"FROM tree_points

WHERE width_px >= 5"

to "px >= 1" so that light sources can start to be be rendered at zoom levels as low as 13 instead of 16.

As described above kosmtik can be ised to check "project.mml" by executing in terminal:

kosmtik serve /home/ertert/src/osm-carto-alternative-colors/project.mml

d) edit symbols

We had difficulty loading our own symbols into the database's "carto_symbols" table so we ended up by using Inkscape to edit the symbols used for trees.

The edited symbols were loaded by deleting the folder "PDF" and executing in terminal:

  • ./generate_symbols.py

The "generate_symbols.py" file needed to be edited by simply replacing "tree" by "light".

Symbols for light-sources need some attention. Currently, the desired radial gradient effect with bright centres and less-bright outer rims is achieved using the approach used for larger tree symbols with a known life-cycle (i.e., tagged as "deciduous" or "evergreen") For these symbols, according to osm-carto-alternative-colors: "using basic PDF support" with the "OGR_PDF_READ_NON_STRUCTURED configuration option set to YES" .... "the center portion (indicating the leaf_cycle) is rendered at a constant size while the outer rim (which does not change with leaf_cycle) is scaled according to the symbol size". At this stage it is unclear how a "scaled SVG based design and additional parametrized modification via PostGIS " should be used to render different tilt angles and directions.

e) edit "symbols.yml"

In keeping with the tagging scheme for light_sources, the following replacements were made respectfully;

  • "broadleafed", "needleleafed" and "palm" by "lantern", "streetlamp" and "floodlight"
  • "deciduous" and "evergreen" by "directed" and "directedtilt"

The svg icons in symbols were renamed accordingly: For example, "tree_needleleafed_deciduous_49.svg" became "light_streetlamp_directedtilt_49.svg"

f) postgresql database functions

Since for simplicity at this early stage "tree" was replaced by "light" in "project.mml", the database functions "carto_light_diameter_mapped", "carto_tree_type_classify" and "carto_treerow_line_width" were renamed (replace "tree by "light") and the "carto_light_type_classify" function needed editing to something like:


SELECT

_ CASE

__ WHEN lower($5) IN ('arecaceae') THEN 'floodlight'

__ WHEN lower($4) IN ('arecaceae') THEN 'floodlight'

__ WHEN lower($3) IN ('arecaceae') THEN 'floodlight'

__ WHEN $1 IN ('streetlamp', 'lantern') THEN $1

__ WHEN ($6 IS NOT NULL) AND $1 IN ('mixed') THEN

___ CASE

_____ WHEN (($6 % 2) = 0) THEN 'lantern'

_____ ELSE 'streetlamp'

___ END

__ ELSE NULL

END


The references to "arecaceae" are to identify "palms" (now "floodlight") on the basis of tags for a plant's genus, family and taxonomic level. Clearly the equivalents of these tags for trees need to be adjusted or removed in the case of lights.

g) generate mapnik.xml

Using osm-carto-alternative-colors' carto in the normal way ("carto project.mml > mapnik.mml"), to generate a "mapnik.xml" file for lights.

4. Historic lights rendering

In some use case it may be appropriate to use dated tagging (e.g., crown_diameter_2020) to map changes in lighting over time using parametrised symbol geometries. These time-related tags may be applied to a chronology relation that is associated with a tree or light (see the OpenHistoricalMap). Moreover, other tagging schemes have been proposed such as having a suffix attached to a key to allow the specification of a year or date range (e.g., light_source:2020=*)

5. Other features

Other features dealt with in the OSM Carto amenity-points.mss style file do not seem to warrant a similar treatment. Elsewhere, water-related features such as basins (landuse:basin) and wetlands (natural:wetland) may benefit from size- and property-dependant top-down view symbols.


Updated 28 July 2024

PeterBoswell.com