MS RFC 124: Improving SLD Support in MapServer

Last Updated

2019-07-24

Author

Jérome Boué

Contact

jbo-ads@laposte.net

Status

Draft

Version

TBD

Bemerkung

The present document is still a work in progress. Sections will be added over time when they are ready to be published. This aims at collecting comments and advices as early as possible.

Overview

The current implementation of SLD/SE in MapServer has many drawbacks. This RFC proposes to address some of them towards a better support. So far, the following issues have been identified:

  1. Arithmetic expressions: MapServer implementation of SLD doesn’t handle <Add>, <Sub>, <Mul>, <Div> operations or <Literal> or <PropertyName> elements in <SvgParameter> or in other elements expected to hold arithmetic expressions.

  2. WMS GetStyles request: A WMS GetStyles request returns a SLD file based only on Mapfile configuration even if a SLD or SLD_BODY parameter is present in the request.

  3. Style layering: When several styling rules apply to a feature, only the first one is taken into account, instead of appliyng them all by following the painters model as described in Symbology Encoding specification.

  4. Mark or ExternalGraphic in LineSymbolizer: MapServer implementation of SLD doesn’t handle <Mark> or <ExternalGraphic> elements in a <LineSymbolizer> element.

  5. LineSymbolizer and PolygonSymbolizer in Rule: MapServer implementation of SLD doesn’t handle both <LineSymbolizer> and <PolygonSymbolizer> in the same <Rule> element (which is more expressive than both <Fill> and <Stroke> in the same <PolygonSymbolizer>).

  6. UserLayer: MapServer implementation of SLD doesn’t handle <UserLayer> element.

The next sections of this RFC develop a description of each issue and the proposed solution.

Technical solution

1. Literal constants, variables and arithmetic expressions

Currently, MapServer only supports raw constants in <CssParameter> or <SvgParameter> tags, e.g.:

<SvgParameter name="stroke">#0000ff</SvgParameter>
<SvgParameter name="stroke-width">2.0</SvgParameter>

The objective is to support <Literal> and <PropertyName> as well as arithmetic expressions, e.g.:

<!-- Literal, PropertyName -->
<SvgParameter name="stroke"> <Literal>#0000ff</Literal> </SvgParameter>
<SvgParameter name="stroke-width"> <PropertyName>LINE_WIDTH</PropertyName> </SvgParameter>

<!-- Arithmetic expression -->
<SvgParameter name="stroke-width">
  <Mul>
    <PropertyName>CATEGORY</PropertyName>
    <Literal>3</Literal>
  </Mul>
</SvgParameter>

This RFC proposes to extent this syntax to the following tags:

Parent tag hierarchy

Target tags

<PolygonSymbolizer><Fill>

<SvgParameter name=“fill“>
<SvgParameter name=“fill-opacity“>
<PolygonSymbolizer><Stroke>
<LineSymbolizer><Stroke>

<SvgParameter name=“stroke“>
<SvgParameter name=“stroke-width“>
<SvgParameter name=“stroke-opacity“>
<PointSymbolizer><Graphic>


<Size>
<Opacity>
<Rotation>
<PointSymbolizer><Graphic><Displacement>

<DisplacementX>
<DisplacementY>
<PointSymbolizer><Graphic><Mark><Fill>
<SvgParameter name=“fill“>
<PointSymbolizer><Graphic><Mark><Stroke>

<SvgParameter name=“stroke“>
<SvgParameter name=“stroke-width“>
<TextSymbolizer>
<Rotation>
<TextSymbolizer><Font>
<SvgParameter name=“font-size“>
<TextSymbolizer><Fill>
<SvgParameter name=“fill“>
<TextSymbolizer><Halo><Fill>
<SvgParameter name=“fill“>

Adding arithmetic expression support to style and label properties involves the creation of a new field array, named exprBindings[], in styleObj and labelObj data structures. This field array stores expression strings converted from SLD syntax to MapFile syntax. It is handled in a way similar to existing bindings[] field array, used to store attribute names.

In addition, a new function is created to parse SLD arithmetic expressions and perform syntax conversion: msSLDParseOgcExpression().

A by-product effect is that adding support for arithmetic expressions in MapFile styles would be effortless.

2. WMS GetStyles request

WMS GetStyles request provides a SLD document based on MapFile contents. Currently this request doesn’t take into account an SLD document passed through SLD or SLD_BODY URL parameters. Moreover this translation lacks many basic styling features present in input MapFile.

This RFC proposes both to integrate input SLD document and enhance conversion from MapFile. The resulting SLD document generated by GetStyles request will be a combination of MapFile and SLD specified in the request, as close as possible to the actual styles being applied.

Enhancements concern the following items:

Description

MapFile

SLD (highlighted lines show enhancements)

SYMBOL (<PointSymbolizer>):

Both color and outline color are generated, including opacity (can be specified in input SLD).

ANGLE, OFFSET and global OPACITY are generated.

LAYER
  TYPE POINT
  STYLE
    COLOR 0 0 255
    OUTLINECOLOR 255 0 0
    OPACITY 50
    SYMBOL "star"
    SIZE 20
    ANGLE 180
    OFFSET 2 2
  END
END
<se:PointSymbolizer>
  <se:Graphic>
    <se:Mark>
      <se:WellKnownName>star</se:WellKnownName>
      <se:Stroke>
        <se:SvgParameter name="stroke">#ff0000</se:SvgParameter>
        <se:SvgParameter name="stroke-opacity">1</se:SvgParameter>
        <se:SvgParameter name="stroke-width">1</se:SvgParameter>
      </se:Stroke>
      <se:Fill>
        <se:SvgParameter name="fill">#0000ff</se:SvgParameter>
        <se:SvgParameter name="fill-opacity">0.10</se:SvgParameter>
      </se:Fill>
    </se:Mark>
    <se:Size>20</se:Size>
    <se:Rotation>180</se:Rotation>
    <se:Displacement>
      <se:DisplacementX>2</se:DisplacementX>
      <se:DisplacementY>2</se:DisplacementY>
    </se:Displacement>
    <se:Opacity>0.5</se:Opacity>
  </se:Graphic>
</se:PointSymbolizer>

POLYGON (<PolygonSymbolizer>):

Outline opacity is generated.

LAYER
  TYPE POLYGON
  CLASS
    STYLE
     WIDTH 1
      OPACITY 50
      COLOR 0 255 255
      OUTLINECOLOR 255 0 255
    END
  END
END
<se:PolygonSymbolizer>
  <se:Fill>
    <se:SvgParameter name="fill">#00ffff</se:SvgParameter>
    <se:SvgParameter name="fill-opacity">0.50</se:SvgParameter>
  </se:Fill>
  <se:Stroke>
    <se:SvgParameter name="stroke">#ff00ff</se:SvgParameter>
    <se:SvgParameter name="stroke-width">1.00</se:SvgParameter>
    <se:SvgParameter name="stroke-opacity">0.50</se:SvgParameter>
  </se:Stroke>
</se:PolygonSymbolizer>

LABEL (<TextSymbolizer>):

Outline color, aka Halo, is generated.

LAYER
  CLASS
    LABEL
      TEXT "[name]"
      COLOR 255 255 255
      OUTLINECOLOR 0 255 0
      OUTLINEWIDTH 2
      TYPE TRUETYPE
      FONT vera-bold
      SIZE 12
      OFFSET 2 20
      ANGLE 15
    END
  END
END
<se:TextSymbolizer>
  <se:Label>
    <se:PropertyName>name</se:PropertyName>
  </se:Label>
  <se:Font>
    <se:SvgParameter name="font-family">vera</se:SvgParameter>
    <se:SvgParameter name="font-weight">bold</se:SvgParameter>
    <se:SvgParameter name="font-size">12</se:SvgParameter>
  </se:Font>
  <se:Fill>
    <se:SvgParameter name="fill">#ffffff</se:SvgParameter>
  </se:Fill>
  <se:LabelPlacement>
    <se:PointPlacement>
      <se:Displacement>
        <se:DisplacementX>2</se:DisplacementX>
        <se:DisplacementY>20</se:DisplacementY>
      </se:Displacement>
    </se:PointPlacement>
    <se:AnchorPoint>
      <se:AnchorPointX>0.5</se:AnchorPointX>
      <se:AnchorPointY>0.5</se:AnchorPointY>
    </se:AnchorPoint>
    <se:Rotation>15</se:Rotation>
  </se:LabelPlacement>
  <se:Halo>
    <se:Radius>2</se:Radius>
    <se:Fill>
      <se:SvgParameter name="fill">#00ff00</se:SvgParameter>
    </se:Fill>
  </se:Halo>
</se:TextSymbolizer>

3. Style layering

Mapserver is designed to use only the first applicable class inside a layer for the rendering of a feature (see CLASS description in LAYER page).

On the other hand, SLD/SE defines a policy named „painters model“ in which all applicable rules (SLD equivalent of classes) are used for the rendering of a feature (see OpenGIS Symbology Encoding Implementation Specification, p.7).

Here is a comparison example of both renderings. The same stylesheet is written in MapFile and in SLD and applied on a sketch of France regions. Stylesheet specification is:

  • Class #1: Polygons are filled with green color

  • Class #2: Polygons with 3 to 5 edges are filled with red color

  • Class #3: Polygons with exactly 4 edges are filled with blue color

Example of MapFile vs. SLD Style rendering policies

Mapfile

SLD

Only the first applicable class is used for rendering

All applicable classes are used for rendering, each on top of the previous ones

../../_images/stylefirst.png ../../_images/stylepainter.png

In order to handle both rendering modes in their respective contexts, a new field named rendermode is added to layerObj data structure. This is used in msDrawVectorLayer() function in mapdraw.c file. The two possible values for this field are:

MS_FIRST_CLASS

Default rendering mode, set on layers defined in a MapFile. In this mode, msDrawVectorLayer() fetches the first applicable class for each shape and uses only that class for rendering.

MS_PAINTERS_MODEL

SLD rendering mode, set on layers defined in a SLD document. In this mode, msDrawVectorLayer() iterates over all applicable classes for each shape and uses them one after the other for rendering. Moreover, as msDrawShape() changes shape coordinates values and as shapes are potentially drawn multiple times, shapes must be saved before calls to msDrawShape() and restored after.

As for arithmetic expressions, offering choice of rendering mode in MapFiles, e.g., by adding a RENDERMODE parameter in LAYER section, would not be technically difficult.

4. Mark or ExternalGraphic in LineSymbolizer

Bemerkung

Work in progress

5. LineSymbolizer and PolygonSymbolizer in Rule

Bemerkung

Work in progress

6. UserLayer

Bemerkung

Work in progress

Testing

The msautotest/sld suite will be created and populated with test cases focusing on these new or improved features.

Moreover the msautotest/{gdal,misc,query,renderers,wxs} test suites will be run during development in order to make sure that no regression occurs.

Documentation

Mapserver SLD documentation page will be updated according to the proposed features described in this RFC.

Backwards compatibility issues

No compatibility issues are expected. The goal is to provide a better SLD support without changing any other existing behaviour.

Affected Files

  • mapcopy.c

  • mapdraw.c

  • mapfile.c

  • maplayer.c

  • mapogcsld.c

  • mapogcsld.h

  • mapserver.h

  • maputil.c

  • mapwms.c

Bemerkung

Work in progress

Credits

Thanks to funding from the French Ministry of Defence.

Voting history