Smrender - A rule-based Renderer for OSM Data

Bernhard R. Fischer


1  Release Notes
2  Name
3  Synopsis
4  Description
    4.1  Rendering Window
    4.2  Options
5  Ruleset Definition
    5.1  Match Operations
    5.2  Rule Actions
        5.2.1  Captions
        5.2.2  Drawing and Filling
        5.2.3  Calling External Functions
        5.2.4  Placing Images
        5.2.5  Output of OSM Data
        5.2.6  Adding Tags to Objects
        5.2.7  Standard Shapes
        5.2.8  Create Formatted Strings
        5.2.9  Concatenating Split Ways
        5.2.10  Executing Programs and Scripts
        5.2.11  Special Purpose Actions
6  Signals
7  Extensions
    7.1  Libsmfilter and Smfilter
        7.1.1  Generating Light Sectors with vsector()
        7.1.2  Compatibility to Smfilter
        7.1.3  Generating Light Description Strings
        7.1.4  Generating Circles around Depth Soundings
8  Examples
    8.1  Generating a PDF
    8.2  Generating a KAP File
9  Files
10  Bugs and Caveats
11  Author
12  Copyright
A  Compiling and Installing
B  Writing Own Rendering Functions
    C.1  Why is Smrender not written in C++?
    C.2  Is it possible to create other maps, such as road maps?
D  Todo

0  Release Notes

This document describes the current (2013/06/03) version of Smrender which is tagged as version 3.0 and corresponds to the internal SVN revision number 1535. Starting with version 3.0 Smrender supports libcairo1 instead of libgd as its graphical library. There are some major changes after SVN revision 1240, thus this document does not apply to revisions 1240 and earlier. The format of the ruleset changed and are not compatible.
Unfortunately, this documentation is not complete yet, but I will continue to work on it.
contains several functions which are experimental. Those functions are namely the auto-rotation and the polygon-size dependent captions (see Section 5.2.1).

0  Name

Smrender is a universal rule-based rendering engine for OSM data. Because smrender is a very generic and flexible OSM processing engine, it may be used for different tasks such as data filtering or data modification.

0  Synopsis

smrender [OPTIONS] [window]

0  Description

Smrender reads an OSM file and applies a set of rules to this input data to create an output image. The input is an OSM file and a second file containing the rule set. The output (currently) is a PNG image having the desired resolution and density and probably additional output files. The latter is explained later.
The primary goal of Smrender is to create a sea chart which is well-suited for print-out on paper. Nevertheless, it is a universal rendering engine and may be used for different tasks.
The input file should be an OSM/XML file as defined by the OSM standard. The file is required to be well-formed in that sense because Smrender itself does no XML validation, thus the rendering process might fail if the file is not well-formed. The data should also be complete. This means that it should contain all nodes to which is referred by the ways. Smrender will remove nodes from ways which are missing.
The rules are also defined in OSM format (see Section 5). The rules are applied iteratively in a loop depending on their version. Within the loop, Smrender always applies first all relation rules, then way rules, and then all node rules of the same version. All rules of the same version are applied in the order of their id.
Invisible objects are ignored by the renderer. Invisible objects are such which have set the attribute visible="false". If objects have no such attribute Smrender sets it to "true" by default.

0.0  Rendering Window

Smrender renders an area which is specified by the window. It is a compound argument as defined below.
   <window>      := <center> | <bbox>
   <bbox>        := <left lower>:<right upper>
   <left lower>  := <coords>
   <right upper> := <coords>
   <center>      := <coords> ':' <size>
   <coords>      := <dec_coords> | <naut_coords>
   <dec_coords>  := <lat> ':' <lon>
   <naut_coords> := ( <naut_lat> ':' <naut_lon ) | 
                    ( <naut_lon> ':' <naut_lat> )
   <size>        := <scale> | <length> 'd' | <length> 'm'

The choice to select to area to be rendered is either to specify the center point of the are or to specify a bounding box.
If it is chosen to use a center point specification then lat and lon set the center coordinates in latitude and longitude in degrees in WGS84 reference system. Although it can be any valid coordinate, it is suggested to choose an "even" value rounded to 10 minutes (e.g. 43.666667 which is 43° 40').
Alternatively, the coordinates can be given in nautical notation which is dd C mm.m where dd is degrees as integer value, C is one of 'N', 'S', 'E', or 'W', and mm.m are minutes, for example 43N40. In case of nautical notation, Smrender automatically detects which of the the values is the latitude and which is the longitude dependent on the character used for the cardinal direction.
defines the length of the mean latitude (parallel) in degrees if 'd' is appended or in nautical miles if 'm' is appended. Alternatively, the scale of the chart can be specified. Smrender calculates the size of the area to meet the scale. Obviously, this depends on the size of the output image. The height (the length of the mean longitude) is calculated automatically by Smrender in such a way that the output image is projected correctly using a spherical transversal Mercartor projection. The height depends on the size of the output image (page format).
If it is chosen to use a bounding box specification then the coordinates of the left lower (southern western) and the right upper (northern eastern) point shall be specified. Because of the projection the bounding box must not necessarily fit to the page dimension in which case Smrender will automatically resize the bounding box to fit to the page. If a fixed bounding box is desired the option -P is needed with either the width or the height set to zero. In this case Smrender will calculate a page dimension which fits to the bounding box according to the projection.
If this argument is omitted The value 0:0:100000 is chosen as default and the option -a is set implicitly.

0.0  Options

0  Ruleset Definition

The rule set is also defined in OSM format. It contains nodes, ways, and relations together with tags. Nodes are considered to be rules for rendering nodes and ways are rules applied to ways. Each object (node, way, or relation) has a list of tags. These tags represent patterns which are matched against the tags of the objects which are to be rendered. The values of a tag's key (k="...") and/or value (v="...") may be either just a string which is directly matched in a case-sensitive manner or a special match operation (see Section 5.1). The match operations can be used for the key as well as for the value.
Each object has to have a special tag which defines the action that should be carried out in case of a match. This tag has the form _action_=*. The actions are described below in Section 5.2.
The match algorithm always applies all tags to match, and all of them have to match in order to execute the action. If just a single tag does not match, the node is skipped.
As defined by the OSM specification2 all objects (nodes, ways, relations, also called elements) have common attributes. Smrender uses the attributes version and id to determine the order of rule execution. All rules of the same version are rendered in the order of their id ascendingly. This is repeated for each version ascendingly until the last rule (highest version and highes id).
Rules with a version greater or equal to 216 = 0x10000 = 65536 are ignored. The number of iterations, i.e. the number of different versions is limited to MAX_ITER which is defined in rdata.h. Run Smrender with option -V to see its value.
If the version attribute is missing it is set to 1 by default. All objects without id are numbered ascendingly in the order in which they occur in the rules file starting with some low negative value.
The attribute visible can be set to either true (which is default if omitted) or false. Rules which are "invisible" are not executed. This can be used to enable or disable a rule by default and can further be used for conditional rendering (see enable_rule in Section 5.2.11).

0.0  Match Operations

Basically there are the four different match operations string compare, regular expression match, greater than, and less than. Additionally, all of them may be inverted, or excluded.

0.0  Rule Actions

supports a few powerful built-in actions which are carried out upon successful match. As already mentioned at the beginning of this Section, actions are defined simply with the tag _action_=*. The actions are actually function calls either within the code of Smrender or externally from a dynamic library. Thus, there is an unlimited range of extendability of smrender. A number of paramters may optionally be passed to the function. The order of the parameters do not matter.
The following example shows an action which places an image at the position of a node.
<tag k='_action_' v='img:file=icons/Light_Minor.png'/>

The basic format of an action is defined as follows.
   <action> := <ref> [ ':' <param> [ ';' <param> [ ... ] ] ]
   <ref>    := <func> [ '@' <library> ]
   <param>  := <tparam> | <bparam>
   <tparam> := [ SEP ] <name> [ SEP ] '=' [ SEP ] <value> [ SEP ]
   <bparam> := [ SEP ] <name> [ SEP ] '=' [ SEP ] <bool> [ SEP ]
   <bool>   := 'yes' | 'no' | 'true' | 'false' | <num>
   <num>    := any decimal number
   SEP      := '`' | '"'

Every action contains of a symbol name ref which is used to find the appropriate function in the code or in a shared object and an optional set of parameters. These are attribute/value pairs. The names of the attributes are case-sensitive. A special type exists which is the boolean type. It can be set to the case-insensitive strings 'yes', 'no', 'true', or 'false', or to any decimal number. 0 is interpreted as false all other values are considered to be true.
is shipped with a set of basic functions for rendering. Those are capable to place captions (Section 5.2.1), drawing and filling (Section 5.2.2), placing icons (Section 5.2.4), generating OSM files (Section 5.2.5), do some special purpose operations (Section 5.2.11), and calling external library functions (Section 5.2.3). The latter is thought to be a simple but powerful interface for third-party modules.
The following sections describe these actions.

0.0.0  Captions

The action type cap is used to place a caption. If the action is carried out in a node-rule, the caption is placed at the node's position with the specified properties. The formal definition looks like the following.
   <action>       := 'cap:' <param>
   <param>        := <name> '=' <value>
   <name>         := 'font' | 'size' | 'key' | 'color' | 'angle' |
                     'weight' | 'phase' | 'valign' | 'halign' |

The parameters font, size, and key are mandatory, the others are optional.
If fontconfig is available, font is defined as specified by fontconfig (see fontconfig documentation). This is e.g. "font=serif:bold". If fontconfig is not available, font must be a full path to a TTF font file.
defines the size of the font in millimeters as a deciaml value, for example "size=2.4".
specifies the key of the tag whose value should be printed. If a caption rule is applied to a node which does not have such a key, the rule simply does nothing. If the key is preceded by an asterisk '*', all letters are capitalized.
and halign specify the alignment of the caption in respect to its center point which is given by the coordinates of the node. There is a horizontal alignment (halign) which could be either east or west and a vertical alignment (valign) which is one of north or south. If no alignment is specified the caption will be centered.
defines the color in which the caption should be set. This is either an X11 color preset3 such as "white", "yellow", "darkgreen" ..., or a color definition similar to the HTML standard. The color presets reflect the colors of traditional sea charts. The HTML-style color definition has the pattern #[aa]rrggbb. The values rr, gg, and bb reflect the RGB values as a hexadecimal number from 00 to ff. Optionally a transparency may be specified with aa. It ranges from 00 (opaque) to 7f which is absolute transparent. The most signifficant bit is always cleared, hence, setting values greater than 7f has no effect.
The angle defines how the caption should be rotated. It is given as usual in trigonometrics which is degrees counterclockwise from 0 to 360 being 0 the regular left-to-write orientation.4
Alternatively, the angle may be set to "auto". This causes Smrender to try to find an angle in such a way that it does not colide (or at least as little as possible) possible which other objects that have already been rendered. In case of auto-rotation, the additional parameters weight, and phase may be set.
virtually rotates the caption from 0 to 360 degrees and calculates the color difference between the foreground (the caption) and the background for each angle. It then chooses the angle with the greatest color difference which should be the place where it is best visible. If the angle is between 90 and 270 degrees, Smrender automatically flips the caption that it does not read upside-down.
The parameters weight and phase may influence the auto-rotation if specified. The weight is a decimal value between 0 and 1 (1 is default) which allows to weight the angles of 90 plus phase and 270 plus phase less than the others (a phase of 0 is default). This allows to e.g. prefer left-right angles above top-bottom angles. This makes sense because reading left-right is more easy than reading top-bottom.
For example if "weight=0.7" is defined, northerly and southerly test samples are taken into account only with 70% which leads to the fact that the the caption tends to be rather east-west aligned.
The parameter 'anglekey' defines a key which can be used if the caption shall be rotated based on the value of a tag. The value of the parameter angle is added additionally. The parameter angle=auto is ignored if a anglekey is set.
Captions on ways   are handled a little bit different from captions on nodes. Actually, captions on ways (polylines) are not supported yet but captions on areas (closed polygons) are supported very well, although it is still in development.
will calculate the centroid and the area of the polygon. The caption is than placed at the position of the centroid5. If the parameter size is omitted or set to 0, the font size is chosen dependent on the square root of the area. Thus, larger polygons get larger captions and smaller ones get smaller captions.

0.0.0  Drawing and Filling

The draw action is used to draw lines of various styles and fill polygons. This action uses solid colors for its operation. If you wish to fill an area with an image as pattern please have a look at Section 5.2.4. The following shows the basic rule format.
   <action>       := 'draw:' <param> [ ';' <param> ... ]
   <param>        := <name> '=' <value>
   <name>         := 'color' | 'width' | 'style' |
                     'bcolor' | 'bwidth' | 'bstyle' |
                     'directional' | 'ignore_open'

The action behaves a little bit different if it is a polyline (open way, e.g. a river) or a polygon (closed way, i.e. an area, e.g. a lake).
Independently if it is an open or a closed polygon there is always a filled part which is enclosed with a border. The filled part is defined by color, width, and style at which just color is honored for closed polygons. The border part is defined by bcolor, bwidth, and bstyle.
The arguments to style and bstyle are one of dashed or dotted. If a style parameter is omitted, a solid line is drawn.
and bwidth are given in millimeters. A width of 0 draws the thinnest possible line with a width of one pixel.
If ignore_open is set to "1", the rule is applied to closed polygons only.
#1Directional filling.
A special fill mode is used if directional is set to "1". Usually, Smrender always fills the inner part of a polygon independently of its direction, i.e. if the nodes of the polygon (way) are ordered clockwise or counterclockwise. This mode is useful if areas of same type (same tags) are enclosed within each other. This may result in unexpected rendering results. The main reason for that is that OSM is just a two-dimensional database. OpenStreetmap provides special tagging facilities to handle such cases, for example multi-poly relations.
A typical application for the directional fill mode on sea charts is the rendering of depth contours, in particular if they are filled in shallow inshore areas. Smrender takes care on the direction of the polygons.6 It always fills the portion which is left of the way. Figure 1 shows an example. Shallow water with a depth less than 10 meters is rendered blue, deeper areas are white (transparent). The white area northeast of the islet Radelj is such a 20 meters area which is enclosed by a more shallow area and than again by a deeper area on the west side of this chart detail.
Filling polygons using this mode works only if the polygons are edited correctly, i.e. their direction is correct. Furthermore it is slightly slower than the regular fill mode.

0.0.0  Calling External Functions

has the ability to call user-defined library functions. This feature provides modularity and the flexibility to be extended on the fly without modifying the core. Thus, Smrender can be used for nearly every kind of rule-based OSM file processing. The library calls dlopen(3) and dlsym(3) are used to dynamically import those functions.
The basic rule format is defined in the following.
   <definition>  := <function> '@' <library> [':' <param>
                    [ ';' <param> ... ]]
   <library>     := path/name of shared library
   <param>       := <name> '=' <value>

is the name of the function as it is exported by the shared object library. In particular, the exported symbol has to be named act_function_main(), i.e. it has to be prefixed by "act_" and suffixed by "_main". If library contains a '/', the path is resolved and the shared object loaded from that location. Otherwise the dynamic linker tries to find the library in the appropriate system directories.7
Beside linking the function itself, Smrender tries to import the optional functions act_function_ini() and act_function_fini(). These two functions may be used for initialization and finalization of the main function.
The function is called on each match of an OSM node. The initialization function act_function_ini() is called once directly after the rules file was parsed before the first match. The finalization function act_function_fini() is called onced directly after the last match.
The prototypes are defined as follows.
int (*act_function_ini)(smrule_t*);
int (*act_function_main)(smrule_t*, osm_obj_t*);
int (*act_function_fini)(smrule_t*);

Act_function_main() gets a pointer to the rule structure and the OSM object which matched the rule. The object can be either a node, a way, or a relation.
typedef struct smrule smrule_t;
typedef struct action action_t;

struct smrule
   osm_obj_t *oo;
   void *data;       // arbitrary data
   action_t *act;

char *get_param(const char*, double*, const action_t*);
char *get_parami(const char*, int*, const action_t*);

The rule structure contains three pointers. The first one points to the OSM object of the rule as defined in the ruleset. The _action_ tag was removed by the rules parser. The Second pointer is initialized to NULL by Smrender and is not touched any further. It is thought to be used by the external functions to store arbitrary data. Please note that all resources that have been claimed by the _ini() function (such as heap memory) have to be freed again by the finalization function _fini(). The third pointer of type action_t contains all data which needs Smrender for rule processing. Its contents should not be touched except you know what you are doing. It is important that the action structure (action_t) contains the paramters which may have been passed to the function through the ruleset. The function get_param() shall be used to retrieve their values. The first parameter is a constant string to the name of the parameter. The second parameter is a pointer to a double variable which will receive the converted value of the parameter. Of course this works only if the parameter contains a decimal value. This pointer may be set to NULL if it is not used. The third parameter to get_param() is a pointer to the action structure of the rule.
typedef struct osm_obj
   // type of object: {OSM_NODE, OSM_WAY, OSM_REL}
   short type;
   // visibility: {0, 1}
   short vis;
   // OSM id
   int64_t id;
   // version, changeset, user id
   int ver, cs, uid;
   // Unix timestamp
   time_t tim;
   // number of tags
   short tag_cnt;
   // Pointer to tags
   struct otag *otag;
} osm_obj_t;

The type of object can be determined on examination of osm_obj_t.type. The variable may be set to either of OSM_NODE, OSM_WAY, or OSM_REL. The object can then be type-casted to either a osm_node_t, a osm_way_t, or a osm_rel_t. All those OSM types are defined in osm_inplace.h.
The return value of the function controls the further behavior of Smrender while applying this same rule. A return value of 0 means no error. Smrender will call the function again at the next matching object. If the return value is greater than 0 it behaves similar but outputs a message in the log file. The message contains the return value. If a negative value is returned, Smrender immediately stops applying this rule, calls the _fini() function and processes the next rule.
Section B explains how to write own (rendering) functions more in detail.
Security Implications  
This feature basically allows any user to call arbitrary functions on the system. Thus, Smrender should never ever be installed with file modes SUID/GUID-root! This would be a potential security risk and might allow an attacker with access to your system to compromise it.

0.0.0  Placing Images

Smrender allows to place images at the position of nodes or to fill areas using an image as pattern.
   <definition>  := 'img:' [ <param> [ ';' <param> ... ]]
   <param>       := <name> '=' <value>
   <name>        := 'file' | 'angle' | 'scale' | 'mkarea'

The parameter file is mandatory and contains a path to a PNG file. The image is placed with its center directly at the position of the matching node without any modifications.
The parameter angle specifies an angle between 0 and 360 degrees to which to image may be rotated before it is placed onto the map.
if angle is set to "auto", Smrender tries to find a rotation angle. This works as described in Section 5.2.1. The rotation function does not take the image itself into account except its size. The rotation test starts at direction East and rotates counterclockwise. Obviously, this makes only sense if it is applied to asymmetric non-centered images, such as light flares. On areas, "auto" has no effect.
The parameter scale allows to scale the image. A value greater than 1 will enlarge the image, if scale is less than 1 it will shrink the image.
The parameter mkarea is a boolean parameter. If set to yes, the auto-rotation function will add nodes and ways to the data which indicate the level priority of the angles around the node. This is mainly intended for debugging.

0.0.0  Output of OSM Data

With the action out it is possible to create an OSM file which contains all the objects which match. Smrender will create one file for each action. This means that if the same file name is used in several out actions, the latter will overwrite the earlier ones. The action takes just one argument, the path to the file.
   <definition>  := 'out:' [ <param> [ ';' <param> ... ]]
   <param>       := <name> '=' <value>
   <name>        := 'file'

0.0.0  Adding Tags to Objects

The action set_tags allows to add an arbitrary number of OSM tags to an object. The tags have to be defined through an object within the rules file. This object may have no action tag. The template should have an id because the action set_tags needs to have a reference to it. To format simple looks like the following.
   <action>    := 'settags:' <param>
   <param>     := <name> '=' <value>
   <name>      := 'id'

Please note that the object type of the rule must be the same as the object type of the template.

0.0.0  Standard Shapes

is able to generate standard shapes like triangles, or circles using this action. The formal definition looks like the following.
   <action>       := 'shape:' <param>
   <param>        := <name> '=' <value>
   <name>         := 'nodes' | 'style' | 'radius' |  'angle' |
                     'key' | 'weight' | 'phase'

This action internally generates an ellipse8 with the given radius (the semi-major axis a) and places a number of nodes on its circumference.
Because OSM does not support any kind of arcs natively, they are constructed using ways with a specific number of nodes. The parameter nodes specifies this number of nodes. Thus, for example, if nodes is set to 3, the result will be a triangle.
The parameter weight is set to 1 by default if it is omitted. It is a multiplier which is used to calculate the semi-minor axis b = weight ×a. Thus, if weight = 1 a circle is generated. The parameter phase shifts the points along the circumference in a counterclockwise order. Thus, the following action creates a rectangle of the dimension 4×1.2 millimeters which is rotated by 20 degrees counterclockwise.
   <tag k='_action_'

One of the parameters nodes or style is mandatory. The latter argument is a preset for a specific number of nodes. Currently the styles triangle (= 3 nodes), square (= 4 nodes), and circle (= maximum nodes) are supported.
The radius is given in millimeters and the optional parameter angle may be used to rotate the shape at any degrees counterclockwise. If radius is omitted 1 millimeter is used as a default value.
With key the shape may be rotated dependent on the value of a tag of a node. Key defines the key of this tag.
This action does not render anything itself. It generates an according set of new nodes which are connected together with a way. All these nodes and the way get the tag generator=smrender. The way additionally inherits all tags of the original node which was matched by the rule set to invoke this action. These tags can then be used to render the shape with a way rule. See the following snippet as an example.
    <node version='-1'>
       <tag k='natural' v='peak'/>
       <tag k='_action_' v='shape:style=triangle;radius=.7'/>
       <tag k='natural' v='peak'/>
       <tag k='_action_' v='draw:color=#906030'/>

0.0.0  Create Formatted Strings

This action is intended to create formatted strings out of a set of tags. It works in a similar but yet more simple manner as printf(3) does. The newly constructed string will be added as a new tag to the OSM object. This tag may then be used to match on in subsequent rules.
   <action>       := 'strfmt:' <param>
   <param>        := <name> '=' <value>
   <name>         := 'addtag' | 'format' | 'key'

Strfmt() has two mandatory arguments. The first one is addtag which contains the name for the new tag which will be added to this object. The second parameter is format which specifies a format string. It may contain any characters and a set of format symbols. The format symbols are the % character followed by one of the following characters.
All regular characters are directly copied to the output string without conversion. The action must contain a key for each format symbol in the format string. The keys are used exactly in the order as they appear in the action line of ruleset.
Format String Example  
The following example shows how to create a new string for all peaks. It shows the name of the peak and its elevation in parentheses. This string is then rendered in the second rule.
   <tag k='natural' v='peak'/>
   <tag k='_action_' v='strfmt:format=%s (%s);
   <tag k='peak_string' v=''/>
   <tag k='_action_' v='cap:font=serif;size=2;key=peak_string'/>

0.0.0  Concatenating Split Ways

This function closes open polygons. To have closed polygons is highly important because just such polygons can be filled with a background color.
Polygons which are literally closed, such as the coastline or lakes are very often found as a set of open ways whose beginning and end share the same nodes. This is because different tags may be attached to different parts of the polygon. Furthermore, just partial data sets are used as input because typically just a small area out of the world's data is selected.
Cat_poly has three optional parameters: ign_incomplete, no_corner, and copy. The first two can both be set to either 0 or 1. If these parameters are omitted, both are internally set to 0 by default.
If ign_incomplete is set to 1, cat_poly will only close such polygons which are formed by a collection of ways where the end point of each way directly is the starting point of the next way.
If ign_incomplete is set to 0 (which is the default) cat_poly will also close polygons which are still open even if all ways which have direct neighbors are connected by inserting artificial ways. This is done by connecting the end of each way to the beginning of the next way in the clockwise order of the bearing from the center point of the image to the start/end nodes of the ways.
Please note that the insertion of artificial ways only works properly if the ways have a specific direction. This is true at least for the ways which are tagged with natural=coastline.
The parameter copy can occur multiple times and it is used to specify the keys of the tags of the ways which should be copied to the newly joined long way. If the values of these keys differ than Smrender takes just the first one. All others are ignored. This is because OSM defines that a tag can appear just excatly one time in an OSM object.
If cat_poly is applied in a way rule than Smrender tries to close all ways which match the criteria of the rule. The function finds all adjacent ways and closes them properly. The original data is not changed furthermore it creates and inserts new ways. Those new ways are tagged with all tags that where defined in the rule set plus the tag generator=smrender plus all tags which have been specified by the copy parameters.
As already mentioned, a typical application for this function is to close the coastline which will be open in most cases. The coastline is always tagged with natural=coastline.
If cat_poly is applied to a relation then Smrender closes all ways of each relation separately. It creates a new closed way which will receive all tags of the relation, respectively. Additionally, it adds the tag generator=smrender. The tags of the way segments are join to the new way if they are listed with the parameter copy as explained above.
Cat_poly applied to relations is useful for example in the Agean Sea, where all partial ways of an island are grouped together using relations. The tags of this relation contains global information about each island, such as its name or population.
Please note that cat_poly() may create ways with more the 2000 nodes which violates the OSM standard definition.9. This may cause problems if an output file is created (e.g. with option -w) and used in other OSM applications. Smrender supports ways of up to 231 nodes. It is assumed that most other OSM processing tools do not care about this artifical boundary.

0.0.0  Executing Programs and Scripts

is able to run external 3rd-party programs and scripts. Smrender communicates through stdin, stdout, and stderr of the program. The new process is executed by the system call execvp(3) or execvpe(3) if available.
   <action>       := 'exec:' <param>
   <param>        := <name> '=' <value>
   <name>         := 'cmd' | 'arg' | 'env' | 'osmhdr'

The mandatory parameter cmd defines the path to program. Optionally, one or more arguments can be passed to the program by multiply specifying arg. The arguments are passed exactly in the same order as in the action.
The optional parameter env can be used to set environmant variables. By default, the program is executed with an empty environment. Smrender provides an interactive interface to communicate with the process.
The parameter osmhdr is an optional boolean argument and influences the communication protocol as explained in the following Section.
The Communication Protocol   is an interactive hybrid command line protocol. All information from Smrender to the process is sent in XML format. In turn for simplicity, the process can use simple commands.
The communication is initiated by Smrender with an XML header and the Smrender header. The latter contains the version of the protocol and the a string for the XML generator, similar to the OSM format.
<?xml version='1.0' encoding='UTF-8'?>
<smrender version='0.1' generator='smrender 3.0.r1535'>

After this header all OSM objects which machted the rule are sent, one after the other in OSM format version 0.6. If the action has the parameter osmhdr set, each object is included in an OSM header as well. The following shows an example of an object including the OSM header, i.e. osmhdr=yes.
<osm version='0.6' generator='smrender'>
<node id="39273652" version="5" timestamp="2009-02-05T06:45:28Z"
   uid="67265" visible="true" lat="44.2128480" lon="15.4482687">
<tag k="created_by" v="Merkaartor 0.13"/>

If osmhdr is omitted or set to no, the first and the last line of the above stanza are suppressed. After each OSM object, Smrender waits for commands of the process. Every command will generate some output and finally send a status code. The status code may be used by the process determine if a command could be executed successfully.
<status code="200">OK</status>

The following commands are currently implemented:

0.0.0  Special Purpose Actions

Currently, Smrender provides the following functions.

0  Signals

installs two signal handlers, one for SIGUSR1 and one for SIGINT.
If Smrender receives a USR1 signal during the process of reading OSM input data, it outputs some statistics about the current position of reading and data throughput. It may be used as progress indicator if huge files are used as input. If Smrender receives a INT signal (which is typically generated by pressing ^C) during rendering, it immediately aborts rendering of further objects and saves the image in its current state and exits normally. If SIGINT is caught twice, Smrender exits immediately.

0  Extensions

As explained in Section 5.2.3, Smrender is able to call functions of shared objects through dynamic linking at runtime. Thus it is very easy to extend the core functionality of Smrender. Currently, it comes with one additional library which is libsmfilter.

0.0  Libsmfilter and Smfilter

Smfilter10 is a preprocessor for Osmarender. It adds some sea chart specific virtual nodes and ways to simplify the rendering process. The functionality of smfilter is now integrated into Smrender with libsmfilter. As a result, smfilter is no longer supported. Libsmfilter exports three functions: vsector(), pchar(), and sounding(). The first is the replacement for smfilter, the next is a new function which generates combined strings for light descriptions, and the latter generates nodes and ways for depth soundings as used in sea charts.

0.0.0  Generating Light Sectors with vsector()

This function is a full replacement for smfilter. Smfilter took several options11 to adjust the rendering behavior. These are the options -a, -b, -d, and -r in particular. Libsmfilter now takes exactly the same parameters since it is just a port. The parameters must be fed to it within the rules file. This was commonly described in Section 5.2.3. In detail the format looks like the following.
   <param-str>   := <a-v-pair>[';' <a-v-pair>[';' ...]]
   <a-v-pair>    := <attribute> '=' <value>
   <attribute>   := 'a' | 'b' | 'd' | 'r'
   <value>       := decimal number

This is an example for calling vsector() from the rule set.
   <tag k='seamark:type' v=''/>

A full description of the output produced by vsector() is found in the smfilter(1) man page12 and in the OSM wiki.13

0.0.0  Compatibility to Smfilter

The function vsector() does exactly the same as the original smfilter tool. Thus, they are considered to be nearly 100% compatible. The functionality is exactly the same but the file structure will still be different because Smrender processes the OSM file in a different way than smfilter.
The following shows two exchangable command lines, the first for smfilter and the second for Smrender.
smfilter -a 0.05 -d 20 -r 0.5 < in.osm > out.osm

smrender -i in.osm -o /dev/null -M -G -w out.osm

The following rules file has to be used in conjunction with Smrender to be a replacement for smfilter. Of course, the file may be extended with other rendering rules.
<?xml version='1.0' encoding='UTF-8'?>
<osm version='0.6'>
      <tag k='seamark:type' v=''/>
      <tag k='_action_'

0.0.0  Generating Light Description Strings

Pchar() generates a string which contains the characteristics of the light as it is used in official sea charts and the List of Lights. See Section P and P.16 in particular if the Chart No. 1.14
The function analyzes the tags of an object. If it contains valid OpenSeamap tags15 it generates the light string and adds the new OSM tag seamark:ligh_character=* to the object. The value of the tag contains the string which may be rendered by a subsequent rule.

0.0.0  Generating Circles around Depth Soundings

Libsmfilter provides the function sounding() which generates small circles around depth soundings.
It generates symbols such as I.4 of Chart No. 1 and circles with a dashed line used for approximate depths (I.31).
Tags use for it is seamark:sounding=* containing the depth in meters, and optional seamark:sounding: quality = {approx | reported_unconfirmed}. See "Rendering Depths with Smrender"16 for more details.

0  Examples

There is a very simple example for your first rendered map. Before, download, compile, and install Smrender as explained in Section A.
Create a working directory somewhere. From the Smrender download URL17 get the seamap icons package (icons.tbz2) and extract it.
tar xvfj icons.tbz2

Now we have to get some OSM data. We just use the Overpass API18 to get a small window.
wget -O cr.osm \

Now we can start Smrender by using the rule set rules.osm which comes with the Smrender package. Copy it to your working directory. By default it is installed into /usr/local/share/smrender.

0.0  Generating a PDF

PDF files are the best choice if you intend to print something. The following command line renders the OSM file cr.osm to the output image cr.png having the dimension of an A4 landscape page. 43° N 52.8' 15° E 12.8' are the center coordinates and the scale is chosen to be 1:100000 which is typical for sea charts.
smrender -i cr.osm -o cr.png -P A4 -l 43N52.8:15E12.8:100000

The result is the PNG image cr.png. You may look at it using your favorite image viewer. To get a correct non-distorted print-out it usually is a good idea to use the PDF format instead. If you try to print the image with a graphics program it most probably will be rescaled to fit the print margins. This will usually not happen if you print a PDF which has valid paper dimensions. To create a PDF file use the option -O instead.
smrender -i cr.osm -O cr.pdf -P A4 -l 43N52.8:15E12.8:100000

0.0  Generating a KAP File

KAP files are used by many applications that deal with marine navigation (e.g. OpenCPN, or GPS chart plotters or smart phones (e.g. Marine Navigator for Android, Very often those files are also referred to as BSB files or also RNC files.
The following command generates a KAP file. It assumes that you have an input OSM file cr.osm. See the beginning of this Section (Section 8) on how to retrieve it. The density is reduced to 200 dpi (option -d) to save resources of your smart phone or chart plotter. Option -G disables the grid since most applications are able to generate a grid on their own. The KAP file is saved to cr.kap. The option -s 1 disables antialiasing. This also reduces resource usage because it limits the color space. Many plotting applications may have their built-in antialiasing.
smrender -i cr.osm -d 200 -G -k cr.kap -s 1 43N52.8:15E12.8:100000

Please note that a PNG file and a KAP file may be generated at the same time by simply adding option -o. The file cr.kap can be used by your favorite application. If you use e.g. Marine Navigator on Android you have to copy the file to a folder named BSB_ROOT in the root directory of your SD card.

0  Files

The Smrender package contains all source C files and headers. A configure script is provided to create appropriate Makefiles and build Smrender (see Section A). It contains all sources for the smfilter library (see Section 7.1) in the directory libsmfilter/ and a skeleton libary in the directory libskel/ which may be used as a starting point for own functions (see Section B). Due to an internal code reorganization many general purpose functions are moved to the separate library libsmrender. All respective sources are found in the directory libsmrender/.
The package contains futhermore different rule sets which may also be used as a basis for own rule sets. The main ruleset is found in the directory rules_100000 which is actively maintained. Older files are rules.osm, rulesbig.osm, and rules_land.osm which are still provided with Smrender.

0  Bugs and Caveats

does not validate the well-formedness of the OSM files. Thus, you may get unexpected rendering results if the file format is incorrect.
For more information please look at the project homepage at

0  Author

is written by Bernhard R. Fischer, The idea of the project was born in summer of 2010. The actual development started in October of 2011.

0  Copyright

Copyright 2011-2013 Bernhard R. Fischer.
This file is part of Smrender.
is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Smrender. If not, see < > .

@  Compiling and Installing

should be simple to compile. It depends on libcairo19 if it is used to render charts. If libcairo is not installed, Smrender will still compile and it can be used for OSM data processing but not for rendering images.
Download the most recent Smrender package from and extract the package with tar xvfj smrender-rxxxx.tbz2. Change into the newly extracted directory. Then run the configure script ./configure, then build it with make. It should compile fine. Finally, there is the executable smrender and the The latter is not mandatory for running Smrender since it may just be loaded dynamically by the rule set (see Section 7.1). Those files may be installed into the appropriate directories on your system with sudo make install.20
is known to compile with gcc 4.x on Debian Linux (Lenny and Squeeze), FreeBSD version 8.x, OpenBSD 5.x, and Mac OSX. It should compile on most Unixoid plattforms without further troubles, maybe even on Windows with Cygwin.

@  Writing Own Rendering Functions

The Smrender package includes a skeleton library in the directory libskel/. It implements the library constructor and destructor, and the actual rule function together with its initialization and de-initialization functions.
The directory contains also a Makefile which shows how to compile the library.
exports several functions which may be called by the library. The following list shows the most imported ones. The prototypes are defined in smrender.h, smlog.h, or osm_inplace.h.
// Use smrender's standard logging. This function is defined in 'smlog.h' and
// works similar to syslog(3).
void log_msg(int, const char*, ...);

// Get an OSM object (OSM_NODE, OSM_WAY, OSM_REL) with the specifed id. This
// function returns a pointer to either an osm_node_t or osm_way_t or_osm_rel_t
// structure on success, or NULL on error.
void *get_object(int, int64_t);

// Add an OSM object to the memory. The function returns 0 on success,
// otherwise -1 is returned. Preexisting objects with the same id are simply
// overwritten.
int put_object(osm_obj_t*);

// These functions return unique ids for nodes and ways.
int64_t unique_node_id(void);
int64_t unique_way_id(void);

// Initialize an OSM object. The number of tags (type short) and the number of
// node references (type int) must be supplied. Currently, the functions always
// return a valid pointer to an object. The objects returned are just partially
// initialized (see 'osm_func.c').
osm_node_t *malloc_node(short);
osm_way_t *malloc_way(short, int);
osm_rel_t *malloc_rel(short, short);

@  FAQ

This section covers some questions and answer which might arise.

@.0  Why is Smrender not written in C++?

On closer examination, the software architecture suggests an object-oriented programming language such as C++ but Smrender is written in C. The short answer is that C is always my first choice and the code was already too mature to switch to C++ without a high effort. The long answer is that Smrender is able to dynamically link libraries at runtime. Interfacing from C++ to a library written in C (currently) seems to be difficult (although not impossible).
But I still have in mind to rewrite Smrender in C++ when time comes.

@.0  Is it possible to create other maps, such as road maps?

Yes of course! The appearance of the map solely depends on the ruleset. A very simple first "land" ruleset is found in the rules directory. The only thing which is fixed is that Smrender uses a transversal Mercartor projection which typically is not used for "land maps".

@  Todo


1  h t t p : / / w w w . c a i r o g r a p h i c s . o r g / 
2  h t t p : / / w i k i . o p e n s t r e e t m a p . o r g / w i k i / E l e m e n t s 
3  h t t p : / / e n . w i k i p e d i a . o r g / w i k i / X 1 1 _ c o l o r _ n a m e s 
4 P l e a s e n o t e t h a t t h i s i s d i f f e r e n t t o t h e a n g l e d e f i n i t i o n o f m a r i t i m e n a v i g a t i o n w h i c h i s d e g r e e s c l o c k w i s e f r o m 0 t o 3 6 0 b e i n g 0 u p w a r d s ( N o r t h ) .
5 T h i s i s s i m i l a r t o w h a t O s m a r e n d e r d o e s .
6 A f e w f e a t u r e s e x i s t i n O S M a s w e l l o f w h i c h t h e r e n d e r i n g d e p e n d s o n t h e d i r e c t i o n . M o s t i m p o r t a n t l y t h i s i s n a t u r a l = c o a s t l i n e . O t h e r e x a m p l e s a r e w a t e r w a y = c a n a l a n d n a t u r a l = c l i f f .
7 S e e d l o p e n ( 3 ) f o r d e t a i l s .
8 W i k i p e d i a : E l l i p s e ,  h t t p : / / e n . w i k i p e d i a . o r g / w i k i / E l l i p s e  .
9 S e e  h t t p : / / w i k i . o p e n s t r e e t m a p . o r g / w i k i / W a y  .
1 0 S e e  h t t p : / / w w w . a b e n t e u e r l a n d . a t / s m f i l t e r / 
1 1 S e e  h t t p : / / w w w . a b e n t e u e r l a n d . a t / s m f i l t e r / s m f i l t e r . h t m l 
1 2  h t t p : / / w w w . a b e n t e u e r l a n d . a t / s m f i l t e r / s m f i l t e r . h t m l 
1 3  h t t p : / / w i k i . o p e n s t r e e t m a p . o r g / w i k i / O p e n S e a M a p / s m f i l t e r 
1 4  h t t p : / / w w w . n a u t i c a l c h a r t s . n o a a . g o v / m c d / c h a r t 1 / C h a r t N o 1 . p d f 
1 5 S e e  h t t p : / / w i k i . o p e n s t r e e t m a p . o r g / w i k i / O p e n S e a M a p / L i g h t s _ D a t a _ M o d e l  .
1 6  h t t p : / / w w w . c y p h e r p u n k . a t / 2 0 1 2 / 0 3 / 1 1 / r e n d e r i n g - d e p t h s - w i t h - s m r e n d e r / 
1 7  h t t p : / / w w w . a b e n t e u e r l a n d . a t / s m r e n d e r / d o w n l o a d / 
1 8  h t t p : / / w i k i . o p e n s t r e e t m a p . o r g / w i k i / O v e r p a s s _ A P I  .
1 9  h t t p : / / w w w . c a i r o g r a p h i c s . o r g / 
2 0 R o o t p r i v i l e g e s a r e r e q u i r e d t o i n s t a l l .

File translated from TEX by TTH, version 4.03.
On 13 Nov 2013, 22:43.