MS RFC 124:改进MapServer中的SLD支持¶
- 最后更新
2020-04-05
- 作者
Jérome Boué
- 联系
- 状态
草稿
- 版本
(针对MapServer 8.0)
概述¶
目前在MapServer中实现SLD/SE有很多缺点。本RFC建议解决其中一些问题,以获得更好的支持。到目前为止,已查明下列问题:
算术表达式 :SLD的MapServer实现不处理<SvgParameter>中的<Add>、<Sub>、<Mul>、<Div>操作或<Literal>或<PropertyName>元素,也不处理希望保存算术表达式的其他元素。
WMS GetStyles请求 :WMS GetStyles请求仅基于映射文件配置返回SLD文件,即使请求中存在SLD或SLD_BODY参数。
样式分层 :当多个样式规则应用于一个要素时,只考虑第一个规则,而不是通过遵循 画家模型 如符号编码规范所述。
线符号中的标记或外部图形 :SLD的MapServer实现不处理<linesymboler>元素中的<Mark>或<ExternalGraphic>元素。
规则中的线性符号和多进制符号化器 :SLD的MapServer实现不能在同一个<Rule>元素中同时处理<linesymboler>和<PolygonSymbolizer>(这比在同一个<PolygonSymbolizer>元素中同时处理<Fill>和<Stroke>更具表现力)。
本RFC的下一节将描述每个问题和建议的解决方案。
建议的解决方案¶
一。文字常量、变量和算术表达式¶
目前,MapServer只支持<CssParameter>或<SvgParameter>标记中的原始常量,例如:
<SvgParameter name="stroke">#0000ff</SvgParameter>
<SvgParameter name="stroke-width">2.0</SvgParameter>
目标是支持<Literal>和<PropertyName>以及算术表达式,例如:
<!-- 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>
此RFC建议将此语法扩展到以下标记:
父标记层次结构 |
目标标记 |
---|---|
<PolygonSymbolizer><Fill>
|
<SvgParameter name=“fill”>
<SvgParameter name=“fill opacity”>
|
<PolygonSymbolizer>Stroke>
<linesymboler><Stroke>
|
<SvgParameter name=“stroke”>
<SvgParameter name=“笔划宽度”>
<SvgParameter name=“笔划不透明度”>
|
<pointsymboler><Graphic>
|
<大小>
<不透明度>
<旋转>
|
<pointsymboler><Graphic><Displacement>
|
<位移x>
<位移>
|
<pointsymboler><Graphic><Mark><Fill>
|
<SvgParameter name=“fill”>
|
<pointsymboler><Graphic><Mark><Stroke>
|
<SvgParameter name=“stroke”>
<SvgParameter name=“笔划宽度”>
|
<textSymboler>
|
<旋转>
|
<textSymboler><Font>符号
|
<SvgParameter name=“font size”>
|
<textSymboler><Fill>
|
<SvgParameter name=“fill”>
|
<textSymboler><Halo><Fill>
|
<SvgParameter name=“fill”>
|
向样式和标注属性添加算术表达式支持涉及到创建名为 exprBindings[] ,in styleObj 和 labelObj 数据结构。此字段数组存储从SLD语法转换为MapFile语法的表达式字符串。它的处理方式与现有的 bindings[] 字段数组,用于存储属性名称。
此外,还创建了一个新函数来解析SLD算术表达式并执行语法转换: msSLDParseOgcExpression() 。
副产品的一个效果是,在MapFile样式中添加对算术表达式的支持将是毫不费力的。
2。WMS公司 GetStyles 请求¶
WMS GetStyles 请求提供基于映射文件内容的SLD文档。当前此请求不考虑通过的SLD文档 SLD 或 SLD_BODY URL参数。此外,这种转换缺少输入映射文件中的许多基本样式特性。
该RFC提出了集成输入SLD文档和增强从映射文件的转换。生成的SLD文档 GetStyles 请求将是请求中指定的MapFile和SLD的组合,尽可能接近应用的实际样式。
增强涉及以下项目:
描述 |
MapFile |
SLD(突出显示的行显示增强功能) |
---|---|---|
SYMBOL (<pointsymboler>): 同时生成颜色和轮廓颜色,包括不透明度(可以在输入SLD中指定)。 ANGLE , OFFSET 和全球 OPACITY 生成。 |
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>): 将生成轮廓不透明度。 |
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 (<textSymboler>): 轮廓颜色,也就是光晕,是生成的。 |
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>
|
三。样式分层¶
MapServer设计为仅使用图层内的第一个适用类来渲染要素(请参见 CLASS description in LAYER page )。
另一方面,SLD/SE定义了一个名为“ 画家模型 其中,所有适用的规则(类的SLD等效项)都用于呈现要素(请参见 OpenGIS Symbology Encoding Implementation Specification ,p.7)。
下面是两个渲染的比较示例。同样的样式表用MapFile和SLD编写,并应用于法国地区的草图。样式表规范是:
类1:多边形填充绿色
第2类:3到5条边的多边形用红色填充
类3:边正好为4的多边形填充蓝色
Mapfile |
SLD |
---|---|
只有第一个适用的类用于呈现 |
所有适用的类都用于呈现,每个类都在前面的类的基础上 |
![]() |
![]() |
为了在各自的上下文中处理这两种呈现模式,一个名为 rendermode 添加到 layerObj 数据结构。这是用在 msDrawVectorLayer() 中的函数 mapdraw.c 文件。此字段的两个可能值为:
- MS_FIRST_CLASS
默认渲染模式,在 Mapfile 中定义的层上设置。在此模式下, msDrawVectorLayer() 获取每个形状的第一个适用类,并仅使用该类进行渲染。
- MS_PAINTERS_MODEL
SLD渲染模式,在SLD文档中定义的层上设置。在此模式下, msDrawVectorLayer() 循环访问每个形状的所有适用类,并逐个使用它们进行呈现。此外,由于 msDrawShape() 更改形状坐标值,并且由于可能会多次绘制形状,因此必须在调用 msDrawShape() 并在此之后进行修复。
对于算术表达式,在映射文件中提供渲染模式的选择,例如,通过添加 RENDERMODE 参数在 LAYER 部分,从技术上来说并不难。
四。线符号中的标记或外部图形¶
当前在MapServer中实现SLD/SE时,无法在行(<linesymboler>标记)上呈现符号(<Mark>或<ExternalGraphic>标记)。作为一个例子,让我们画一条蓝色的线来表示多瑙河,上面有改变的圆圈(由<Mark>标记实现)和船(由<ExternalGraphic>标记实现)。下面,第一张图片由映射文件生成,第二张图片由SLD文档生成。
MapFile (正确渲染) |
![]() |
---|---|
SLD (渲染不正确) |
![]() |
源代码检查显示:
必须根据授权模式验证<ExternalGraphic>参数(请参见 mapogcsld.c L2140-L2145 )。这涉及到设置 "sld_external_graphic" 中的属性 VALIDATION 映射文件的块 WEB 部分,例如:
WEB VALIDATION "sld_external_graphic" "^.*/sld/data/.*" END [...] END
在没有指定的情况下,<Mark>的当前实现在呈现符号时失败:始终将<Stroke>颜色分配给 OUTLINECOLOR 变量(请参见 mapogcsld.c L1697-L1703 )。当<Fill>标记不存在时,应将其分配给 COLOR 变量。
建议的解决方案包含一个文档更新(在 SLD 文档)第一个问题和第二个问题的错误修复。
5个。规则中的线性符号和多进制符号化器¶
当前在MapServer中实现SLD/SE并不期望在同一个<Rule>中混合<linesymboler>和<PolygonSymbolizer>,因此在这种情况下会产生不正确的呈现。作为一个例子,让我们通过使用两个SLD变体绘制一个蓝色多边形和一个黄色轮廓。
第一个是一个单独的<PolygonSymbolizer>包含轮廓的<Stroke>部分和内部区域的<Fill>部分。
第二个是一个<linesymboler>包含轮廓的<Stroke>部分,然后是一个<PolygonSymbolizer>包含内部区域的<Fill>部分。
<Stroke>和<Fill>内部<PolygonSymbolizer> |
<linesymboler>和<PolygonSymbolizer>内部<Rule> |
---|---|
<FeatureTypeStyle>
<Rule>
<PolygonSymbolizer>
<Stroke>
<SvgParameter name="stroke">
<Literal>#FFFF00</Literal>
</SvgParameter>
</Stroke>
<Fill>
<SvgParameter name="fill">
<Literal>#0000FF</Literal>
</SvgParameter>
</Fill>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
|
<FeatureTypeStyle>
<Rule>
<LineSymbolizer>
<Stroke>
<SvgParameter name="stroke">
<Literal>#FFFF00</Literal>
</SvgParameter>
</Stroke>
</LineSymbolizer>
<PolygonSymbolizer>
<Fill>
<SvgParameter name="fill">
<Literal>#0000FF</Literal>
</SvgParameter>
</Fill>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
|
![]() 正确渲染¶ |
![]() 渲染不正确¶ |
A source code inspection 显示考虑了所有SLD/SE标记。建议的解决方案包含一个简单的错误修复,其目的是 mapObj 两种情况的数据结构都是相同的。
在当前的实现中 STYLE 为每个<Stroke>或<Fill>标记生成。但在第一种情况下,<Fill>标记在<Stroke>标记之前处理,而在第二种情况下,<linesymboler>标记(仅包含<Stroke>标记)在<PolygonSymbolizer>标记之前处理,能够同时包含<Stroke>和<Fill>标记。
此外,将<LineSymbolizer><Stroke>颜色分配给 COLOR 变量,而将<PolygonSymbolizer><Stroke>轮廓颜色分配给 OUTLINECOLOR 变量。
提出的解决方案一方面是在标记之前处理<PolygonSymbolizer>标记,另一方面是移动 COLOR 价值到 OUTLINECOLOR 对于由<linesymboler>定义但适用于多边形层的样式。
测试¶
这个 msautotest/sld 将创建套件,并使用集中于这些新功能或改进功能的测试用例进行填充。
此外, msautotest/{{gdal,misc,query,renderers,wxs}} 测试套件将在开发期间运行,以确保不会发生回归。
文档¶
MapServer SLD 文档页面将根据本RFC中描述的建议功能进行更新。
向后兼容性问题¶
不希望出现兼容性问题。目标是在不改变任何其他现有行为的情况下提供更好的SLD支持。
受影响的文件¶
mapcopy.c
mapdraw.c
mapfile.c
maplayer.c
mapogcsld.c
mapogcsld.h
mapserver.h
maputil.c
mapwms.c
信用¶
多亏了法国国防部的资助。
投票历史¶
由PSC成员SethG、MikeS、JukkaR、TomK、jefm、evener、SteveL、DanielM、JeromeB的+1收养。