Rendering Rules Advanced

This page gives an advanced look into how Maperitive rendering rules function. Although the whole concept might seem complicated at first, it's actually pretty simple. From this simplicity you can get a number of ways of how to define the rules. Sometimes these different ways end up with the same result on the map, sometimes they can differ slightly and sometimes the differences can be substantial.

But let's start from the beginning.

Rules Properties And Flow

If you want to draw something, you need to know what color to use, what is the thickness of the line etc. This is controlled through Rendering Properties (TODO) like line-color, border-width etc.

It's important to know that all of rendering properties have default values. When Maperitive starts processing a rule, it starts by assigning these default values to properties. So, for example, you don't need to specify

define
	text : name

since the value "name" is already a default value of the text property.

You can set your own default values in the properties section of the ruleset, for example

properties
	text : name:fr

will tell Maperitive to use names in French by default.

Inside each of the rules you can change the value of a rendering property using the "define" command. You need to understand the scope of this change:

  1. the new value will only affect rule commands that come after your "define" command
  2. the new value will not affect any other rules. So the scope of the new value ends with the last command of the rule.

Example is worth a hundred words, so let's illustrate this with an example (I've left out feature definitions, but I think you can figure those out for yourself):

...
properties
	font-family : Tahoma
	
target : place country
	define
		font-family : Times New Roman
	draw : text
	
target : place city
	draw : text

The results of these rules are:

Conditional Flow And Decision Trees

The real power of Maperitive rules lies in the ability to define a decision tree within a single rule. This is achieved using commands like "if", "elseif", "for", "elsefor" and "else".

Let's start with a simple decision tree:

target : *road
	if : major road				
		define					(A)
			line-width : 20
	else
		define					(B)
			line-width : 10
	draw : line					(C)

I've marked the key commands with symbols so I can present the flow of the command more easily. Let's say we have three features: major road, medium road and minor road (specified in that order). Based on the rule match string ("*road"), Maperitive will execute the rule commands on these features in the following order:

  1. major road: A, C
  2. medium road: B, C
  3. minor road: B, C

I've indicated which of the commands will be executed for each of the features (I've left out the conditional commands since they can be deduced from the context).

This is not the only way to achieve the same result:

target : *road
	if : major road				
		define					(A)
			line-width : 20
		draw : line				(B)
	else
		define					(C)
			line-width : 10
		draw : line				(D)

Notice that we have now moved the "draw" command to the inside block of each of the conditional commands (using tabs identation). The flow now is as follows:

  1. major road: A, B
  2. medium road: C, D
  3. minor road: C, D

But in our case this amounts to the same thing (setting the appropriate line width and drawing a line).

We can nest the conditional commands:

target : *road
	if : major road				
		define						(A)
			line-width : 20
	else
		if : medium road
			define					(B)
				line-width : 15
		else
			define					(C)
				line-width : 10
	draw : line						(D)

with the flow being

  1. major road: A, D
  2. medium road: B, D
  3. minor road: C, D

We can even stop some of the flows:

target : *road
	if : major road				
		define						(A)
			line-width : 20
	else
		if : medium road
			define					(B)
				line-width : 15
		else
			stop					(C)
	draw : line						(D)

with the flow being

  1. major road: A, D
  2. medium road: B, D
  3. minor road: C (doesn't draw anything)

I gave the above two examples to illustrate the ability to nest conditional commands within other conditional commands. But a more proper way to define the rule which results with the same effect on the map would be

target : *road
	if : major road				
		define						(A)
			line-width : 20
	elseif : medium road
		define						(B)
			line-width : 15
	else
		define						(C)
			line-width : 10
	draw : line						(D)

again, the flow is exactly the same as in the example before the previous one:

  1. major road: A, D
  2. medium road: B, D
  3. minor road: C, D

The only difference is that the rule is more readable, since we only use one level of nesting.

TO BE CONTINUED

See also: