Deep Map™ Rule specification¶
Rules are style definitions which override the feature style definition of a named feature. For the specifications, see Deep Map™ Style Specification. The criteria are checked for each possibly visible object on the map in realtime, and when the criteria within the rule’s condition are met, the style definition in the rule’s body overrides the feature style definition for the object. The style definitions within the rule are the same as the feature style definition. The rules are defined in the .mapRule file.
The rule syntax is defined as follows:
rule <ruleName> ( <feature1> , ... , <featureN> ) [" <rule expression> "] { <property> : <propertyValue> ; <nestedRule> }
rule
is the keyword to start a new rule
definition. <ruleName>
is a unique name for the rule. The feature
name is followed by a list of feature names, enclosed by parentheses.
Those are the features the rule is applied to. All features must be of
the same basic type (point, icon, line,
polygon). ["
and "]
mark the beginning and end of the rule
condition. The <rule expression>
is a boolean expression which
specifies if the rule should be applied or not. We will take a closer
look at the rule expression later. The rule condition is optional. If
left out, the rule is always applied. The body of a rule is the same as
the body of a feature, and the properties must match the assigned
feature type. Additionally, it is possible to nest rules within another
rule. The nested rule is then only executed if the embracing rules
conditions are met. More on nested rules later.
Rule expression¶
The rule expression mimics closely a SQL-WHERE clause. There are two key differences: the SQL data fields are replaced by feature attributes, and the rule body is applied if something matches the clause, instead of returning a data set. All functions from SQL are usable, but there are some additional functions for querying the map state.
Expression syntax:
- Logical expressions:
AND, OR
- Comparative expressions:
<, <=, >, >=, =, !=, NOT, IS NULL, NOT NULL, IN (1,2,3, ..), BETWEEN x AND y
- Math operators:
+, -, *, /
- Functions:
distance(), isSelected(), isHighlighted(), “any SQLITE function”
- Data fields:
feature type attributes, map attributes
The new function for querying the map are:
function
return value
runtime complexity
version
distance()
double: 3D distance from object to the camera
point/icon/polygon: O(1), lines: O(lineSegments)
v2.0.0
isSelected()
int: 1 if object is selected, otherwise 0
std::set lookup: Ω(1), O(n)
v2.0.0
isHighlighted()
int: 1 if object is highlighted, otherwise 0
std::set lookup: Ω(1), O(n)
v2.0.0
cameraHeight()
double: distance from the camera to the ground
O(1)
v2.1.2
currentZoomlevel()
int: the current Zoomlevel
O(1)
v2.1.2
Examples:
//rule applied to a single feature type using the distance() function rule distanceVisibility(building) [" distance() > 1000 "] { visibility: none; } //rule applied to multiple feature types using the isSelected() function rule selectionColor(building, room, stand) [" isSelected() "] { fill-color: #FF0000; } //this rule is true, if a room has the attribute "iAmSpecial" and the value of the attribute is "yes" rule specialRoom(room) [" iAmSpecial = 'yes' "] { fill-color: #00FF00; }
Multiple rules can set the same property. In the above example, selectionColor and specialRoom modify both the fill-color of an object. If this happens, the first defined rule wins. In this case, a room with the attribute “iAmSpecial: yes” will be blue, but as soon as it is selected it turns red. If the two rules were switched, the room would always be blue, and selection would have no effect.
Rule inheritance¶
If one feature inherits from another, it inherits not only the properties, but the rules as well! This can be useful if multiple feature have a similar style and should share the same behaviour. For example:
feature building:polygon {} feature specialBuilding:building {} rule highlightBuilding(building) [" isHighlighted() "] { fill-outline-width: 2.0; fill-outline-color: #FFFFFF; }
In this case, all objects of the type “building” and “specialBuilding” will get a thick, white outline when they are highlighted. Inherited rules have a lower priority than rules directly defined for the feature type in question. The further up in the ancestry, the lower the priority of a rule.
feature building:polygon {} feature specialBuilding:building {} rule buildingRule(building) [" isHighlighted() "] { fill-outline-width: 2.0; fill-outline-color: #FFFFFF; } //this rule wins; if a specialBuilding has the attribute "isVerySpecial: yes", its outline will be blue //the fill-outline-width is still set to 2.0, because the property is only set in buildingRule rule highlightSpecial(specialBuilding) [" isHighlighted() AND isVerySpecial = 'yes'] { fill-outline-color: #0000FF; }
Rule nesting¶
It is possible to define rules inside the body of another rule:
rule outerRule(building) [" isSelected() "] { rule innerRule(room) { visibility: none; } }
A nested rule is conditionally depending on the outer rule. In this case “innerRule” is only evaluated if the condition of the “outerRule” if fulfilled. So all rooms of a building will now be hidden if the building is selected.
There are several limitations which need to be considered when nesting rules:
The feature types of the nested rules are not allowed to be related to the feature types of the outer rules over the Deep Map™ Style definitions. This is because the behaviour of a rule can become undefined due to rule inheritance
The map objects affected by the outer rule have to be ancestors of the map objects affected by the nested rule to take effect.
The following example shows valid and invalid nested rules:
feature building:polygon {} feature specialBuilding:building {} feature room:polygon {} feature tree:polygon {} rule distanceVisibility(building) ["distance() > 200"] { text-visiblity: visible; rule roomVisiblity(room) //valid rule, since room is not related by style to building. { visibility: none; text-visibility: none; } rule specialVisibility(specialBuilding) //invalid rule, because specialBuilding and building are related in the styling { visibility: none; text-visibility: none; } rule treeVisibility(tree) //valid rule, but unlikely to have an effect, since trees are seldom inside buildings { visibility: none; text-visibility: none; } }
Nested rules have the highest priority, since they are the most specific. The deeper a rule is nested, the higher is its priority. The following diagram illustrates again in which order style properties are evaluated:
Property Rules (Version 2.1)¶
In some scenarios a user might want to set many different values for a single property. Doing this with the normal rules would be cumbersome, because this would require one rule for each individual value. These cases are better handled by property rules.
A property rule is defined by setting a rule-clause instead of the normal property-value:
feature building : polygon{ fill-color: [" <SELECT Statement> [WHERE <Where statement>] " ]; }
The selected value has to match the string-format of the value type. For example, a custom set color value could be set in the following way:
feature building:polygon { fill-color: ["CASE WHEN customColor NOT NULL THEN customColor ELSE '#ff0000' END"]; }
In this case, the value of customColor needs to be a string representing a hex-color value. The query is discarded if the return-type does not match the property-type.