地图美化器之多种方式生成SLD样式文件

目录

前言

一、编程式生成

1、简单样式创建

二、模板生成

1、模板示例

三、外部桌面工具生成

1、SLDEditor

2、QGIS和UDig

四、GeoServer生成

1、GeoServer的样式管理器

五、总结


前言

        在Web的世界中,我们用Style的css或者less来进行页面的装饰。在地理信息的世界中,我们可以采用SLD文件来进行地图美化。跟css一样,我们可以采用多种方式来创建SLD文件,既可以使用记事本、文本编辑器等传统文本工具来进行编写,也可以采用VsCode等现代的编辑器来进行设置。

        与CSS一致,生成SLD文件的方式也有很多种。比如有代码生成法、模板生成法、外部工具创建法等等。本文即重点讲解在开发过程中,如何使用多方式来生成SLD样式文件。文章首先介绍Java中来使用代码进行编程式生成,然后介绍如何基于SLD的模板文件进行生成,其次介绍基于桌面生成工具SLDEditor和QQis来进行样式生成,最后介绍如何利用GeoServer来进行样式生成。通过不同的SLD创建方式,让您掌握不同的样式生成方式。希望本文对学习SLD的同学有所帮助。

一、编程式生成

        编程式生成具体是指使用编码的方式来创建SLD样式,以Java为例,我们使用GeoTools这个项目来进行样式的创建。这里其实可以分两种情况,第一种,使用默认的样式,比如最简单的样式,只要区分点、线、面等不同的空间数据类型等。第二种是在简单的样式上面进行扩展,进行丰富的样式信息的创建。下面分两种模式来进行说明。

1、简单样式创建

        简单的样式创建,即是最简单的生成模式,即不会进行过多的样式控制。在进行样式表达时,仅仅考虑空间对象的类型,如点、线、面。然后根据不同的空间对象类型来创建最简单的样式。在之前的GeoTools的系列教程中,我们即采用过这种实现模式。

        第一步、创建简单样式,关键代码如下所示:

private void initMap() {
	try {
		FileDataStore store = FileDataStoreFinder
					.getDataStore(this.getClass().getClassLoader().getResource("maps/countries.shp"));
		SimpleFeatureSource featureSource = store.getFeatureSource();
		map = new MapContent();
		map.setTitle("Quickstart");
		Style style = SLD.createSimpleStyle(featureSource.getSchema());
		FeatureLayer layer = new FeatureLayer(featureSource, style);
		map.addLayer(layer);
		map.getViewport().setScreenArea(new Rectangle((int) canvas.getWidth(), (int) canvas.getHeight()));
	} catch (IOException e) {
		e.printStackTrace();
	}
}

        在上面的代码中,重点是Style style = SLD.createSimpleStyle(featureSource.getSchema());通过SLD对象来创建默认样式。我们可以来看一下SLD具体是如何创建默认样式。

        第二步、具体样式生成。我们通过debug跟踪代码,见如下关键代码:

/**
 * Create a minimal style to render features of type {@code type}.
 *
 * @param type the feature type
 * @return a new Style instance
 */
public static Style createSimpleStyle(FeatureType type) {
    return createSimpleStyle(type, Color.BLACK);
}

          可以看到,这里需要传入空间对象的类型,也就是FeatureType,对应前面我们所说的点、线、面等不同的类型。根据不同类型的对象来进行相应样式的创建。

public static Style createSimpleStyle(FeatureType type, Color color) {
        GeometryDescriptor desc = type.getGeometryDescriptor();
        Class<?> clazz = desc.getType().getBinding();
        Color fillColor = null;

        if (Polygon.class.isAssignableFrom(clazz) || MultiPolygon.class.isAssignableFrom(clazz)) {
            if (color.equals(Color.BLACK)) {
                fillColor = null;
            } else {
                fillColor = color;
            }
            return createPolygonStyle(color, fillColor, 0.5f);

        } else if (LineString.class.isAssignableFrom(clazz)
                || MultiLineString.class.isAssignableFrom(clazz)) {
            return createLineStyle(color, 1.0f);

        } else if (Point.class.isAssignableFrom(clazz)
                || MultiPoint.class.isAssignableFrom(clazz)) {
            if (color.equals(Color.BLACK)) {
                fillColor = null;
            } else {
                fillColor = color;
            }
            return createPointStyle("Circle", color, fillColor, 0.5f, 3.0f);
        }

        throw new UnsupportedOperationException("No style method for " + clazz.getName());
    }

        如果是Polygon面数据,可以看到面数据的默认样式创建代码如下:

/**
 * Create a polygon style with the given colors and opacity.
 *
 * @param outlineColor color of polygon outlines
 * @param fillColor color for the fill
 * @param opacity proportional opacity (0 to 1)
 * @return a new Style instance
 */
public static Style createPolygonStyle(Color outlineColor, Color fillColor, float opacity) {
    Stroke stroke = sf.createStroke(ff.literal(outlineColor), ff.literal(1.0f));
    Fill fill = Fill.NULL;
    if (fillColor != null) {
         fill = sf.createFill(ff.literal(fillColor), ff.literal(opacity));
    }
    return wrapSymbolizers(sf.createPolygonSymbolizer(stroke, fill, null));
}
/**
     * Wrap one or more symbolizers into a Rule / FeatureTypeStyle / Style
     *
     * @param symbolizers one or more symbolizer objects
     * @return a new Style instance or null if no symbolizers are provided
     */
    public static Style wrapSymbolizers(Symbolizer... symbolizers) {
        if (symbolizers == null || symbolizers.length == 0) {
            return null;
        }

        Rule rule = sf.createRule();

        for (Symbolizer sym : symbolizers) {
            rule.symbolizers().add(sym);
        }

        FeatureTypeStyle fts = sf.createFeatureTypeStyle(rule);

        Style style = sf.createStyle();
        style.featureTypeStyles().add(fts);

        return style;
    }

        可以在上述的代码中看到,面数据主要是设置填充的信息等。这都是比较简单,尤其是凸显边界。下面来看一下线数据的默认样式信息:

/**
 * Create a line style with given color and line width
 *
 * @param lineColor color of lines
 * @param width width of lines
 * @return a new Style instance
 */
public static Style createLineStyle(Color lineColor, float width) {
    Stroke stroke = sf.createStroke(ff.literal(lineColor), ff.literal(width));
    return wrapSymbolizers(sf.createLineSymbolizer(stroke, null));
}

/**
 * Wrap one or more symbolizers into a Rule / FeatureTypeStyle / Style
 *
 * @param symbolizers one or more symbolizer objects
 * @return a new Style instance or null if no symbolizers are provided
 */
public static Style wrapSymbolizers(Symbolizer... symbolizers) {
     if (symbolizers == null || symbolizers.length == 0) {
         return null;
     }

     Rule rule = sf.createRule();

     for (Symbolizer sym : symbolizers) {
         rule.symbolizers().add(sym);
     }

     FeatureTypeStyle fts = sf.createFeatureTypeStyle(rule);

     Style style = sf.createStyle();
     style.featureTypeStyles().add(fts);

     return style;
}

        最后来看一下点数据的默认样式信息如下关键代码所示:

/**
     * Create a point style, optionally with text labels
     *
     * @param wellKnownName one of: Circle, Square, Cross, X, Triangle or Star
     * @param lineColor color for the point symbol outline
     * @param fillColor color for the point symbol fill
     * @param opacity a value between 0 and 1 for the opacity of the fill
     * @param size size of the point symbol
     * @param labelField name of the feature field (attribute) to use for labelling; mauy be {@code
     *     null} for no labels
     * @param labelFont GeoTools Font object to use for labelling; if {@code null} and {@code
     *     labelField} is not {@code null} the default font will be used
     * @return a new Style instance
     */
    public static Style createPointStyle(
            String wellKnownName,
            Color lineColor,
            Color fillColor,
            float opacity,
            float size,
            String labelField,
            Font labelFont) {

        Stroke stroke = sf.createStroke(ff.literal(lineColor), ff.literal(1.0f));
        Fill fill = Fill.NULL;
        if (fillColor != null) {
            fill = sf.createFill(ff.literal(fillColor), ff.literal(opacity));
        }

        Mark mark =
                sf.createMark(
                        ff.literal(wellKnownName), stroke, fill, ff.literal(size), ff.literal(0));

        Graphic graphic = sf.createDefaultGraphic();
        graphic.graphicalSymbols().clear();
        graphic.graphicalSymbols().add(mark);
        graphic.setSize(ff.literal(size));

        PointSymbolizer pointSym = sf.createPointSymbolizer(graphic, null);

        if (labelField == null) {
            return wrapSymbolizers(pointSym);

        } else {
            Font font = (labelFont == null ? sf.getDefaultFont() : labelFont);
            Fill labelFill = sf.createFill(ff.literal(Color.BLACK));
            AnchorPoint anchor = sf.createAnchorPoint(ff.literal(0.5), ff.literal(0.0));
            Displacement disp = sf.createDisplacement(ff.literal(0), ff.literal(5));
            LabelPlacement placement = sf.createPointPlacement(anchor, disp, ff.literal(0));

            TextSymbolizer textSym =
                    sf.createTextSymbolizer(
                            labelFill,
                            new Font[] {font},
                            null,
                            ff.property(labelField),
                            placement,
                            null);

            return wrapSymbolizers(pointSym, textSym);
        }
    }

        在代码中可以看到传入的默认样式是:

if (color.equals(Color.BLACK)) {
    fillColor = null;
} else {
    fillColor = color;
}
return createPointStyle("Circle", color, fillColor, 0.5f, 3.0f);

        以上就是默认的简单样式创建的代码说明。当然,使用默认的简单样式创建方式比较简单,直接调用GeoTools的相关API即可,后面的关于如何生成点、线、面的样式属于扩展问题。与简单样式生成的方式不一样的是,我们可以在实际运用过程中使用更复杂的API来进行更复杂也更酷炫的样式生成

二、模板生成

        模板生成方法与编程式生成有所区别,模板生成顾名思义就是按照一定的模板来进行生成。而模板的寻找有很多地方,我们可以在互联网上寻找公开的模板,将模板拷贝到工程中,当成默认的样式库进行使用。

1、模板示例

        网上有很多分享SLD模板的网站,大家可以发挥自己的聪明才智来开发自己的SLD模板库。这里分享几个公开的模板。第一个是发表在知乎上的常用SLD模板常用SLD模版,打开网站后可以看到如下信息:

         在这个网站中可以看到很多常见的模板库,比如点数据的、线数据的、面数据的、道路的、铁路的、DEM的等等。

<?xml version="1.0" encoding="UTF-8"?>
   <StyledLayerDescriptor version="1.0.0"
       xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
       xmlns="http://www.opengis.net/sld"
       xmlns:ogc="http://www.opengis.net/ogc"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <NamedLayer>
       <Name>person_point_heat</Name>
       <UserStyle>
         <Title>person_point_heat</Title>
         <Abstract>A heatmap </Abstract>
         <FeatureTypeStyle>
           <Transformation>
             <ogc:Function name="gs:Heatmap">
               <ogc:Function name="parameter">
                 <ogc:Literal>data</ogc:Literal>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>weightAttr</ogc:Literal>
                 <ogc:Literal>count</ogc:Literal>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>radiusPixels</ogc:Literal>
                 <ogc:Function name="env">
                   <ogc:Literal>radius</ogc:Literal>
                   <ogc:Literal>60</ogc:Literal>
                 </ogc:Function>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>pixelsPerCell</ogc:Literal>
                 <ogc:Literal>2</ogc:Literal>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>outputBBOX</ogc:Literal>
                 <ogc:Function name="env">
                   <ogc:Literal>wms_bbox</ogc:Literal>
                 </ogc:Function>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>outputWidth</ogc:Literal>
                 <ogc:Function name="env">
                   <ogc:Literal>wms_width</ogc:Literal>
                 </ogc:Function>
               </ogc:Function>
               <ogc:Function name="parameter">
                 <ogc:Literal>outputHeight</ogc:Literal>
                 <ogc:Function name="env">
                   <ogc:Literal>wms_height</ogc:Literal>
                 </ogc:Function>
               </ogc:Function>
             </ogc:Function>
           </Transformation>
          <Rule>
            <RasterSymbolizer>
            <!-- specify geometry attribute to pass validation -->
              <Geometry>
                <ogc:PropertyName>geometry</ogc:PropertyName>
              </Geometry>
              <Opacity>1</Opacity>
                <ColorMap type="ramp" >
                  <ColorMapEntry color="#FFFFFF" quantity="0" opacity="0" label="低" />
                  <ColorMapEntry color="#7F95E6" quantity="0.1" opacity="0.5" label="" />
                  <ColorMapEntry color="#7DFC3F" quantity="0.3" opacity="0.5" label="" />
                  <ColorMapEntry color="#F6FD01" quantity="0.4" opacity="0.5" label="" />
                  <ColorMapEntry color="#EF8C07" quantity="0.5" opacity="0.5" label="" />
                  <ColorMapEntry color="#FE0409" quantity="0.7" opacity="0.5" label="" />
                  <ColorMapEntry color="#FE0409" quantity="1" opacity="0.5" label="高" />
                  </ColorMap>
            </RasterSymbolizer>
           </Rule>
         </FeatureTypeStyle>
       </UserStyle>
     </NamedLayer>
    </StyledLayerDescriptor>

        还有对应的铁路路线图SLD样式图等,

         除了在知乎上这个分享的公开的模板,关于路网(公路和铁路的数据模板)在CSDN上有一个老师也进行了分享,分享两个线+标注的SLD样式

        大家可以将上面分享的模板样式拷贝到自己的样式中,在这个模板样式的基础上进行微调,修改成符合我们项目需要的SLD文件,然后进行样式发布,最后再制作成地图。 

三、外部桌面工具生成

        模板生成不能解决自己项目定制化的问题,因此需要我们自己来根据实际情况进行正式标绘,制作完全符合自己要求的样式信息。本小节将重点介绍几种采用外部桌面工具的方式进行生成的方式。包括SLDEdtitor、Qgis等桌面客户端软件。

1、SLDEditor

        SLDEditor是一款使用Java开发的桌面端应用程序,专门是为了在桌面端进行样式绘制的软件。使用Java进行开发,因此可以运行在不同的操作的系统中,比如Linux、Windows等不同的操作系统中。下载好SLDEditor后,打开我们的应用程序,可以看到如下的程序界面。

         这款软件主要还是用来进行配图的,在上方的tab页中可以进行方便的切换,进行样式的设置。同时可以在map视图中及时预览这些效果。

        在这里可以快速的进行样式的配置,可以添加不同的Filter,也可以添加layer图层。配置好之后,也可以直接在SLD页面看到具体的xml格式的样式结果。

         可以直接将上面的XML格式的SLD样式文件进行数据配图就可以发布出来就好。

2、QGIS和UDig

        除了前面介绍过的SLDEditor,我们还可以选择Qgis和UDig,  其中,Qgis是一款对比Arcgis的桌面软件,功能也是非常的强大。另外一个UDig是一款Java开发的桌面软件。关于在QGIS中如何进行标注,相信大家非常熟悉了,在之前的博客中也进行了详细的解释,大家可以看一下QGis的标绘配置界面。

        UDig也是一款用的比较多的系统,感兴趣的同学大家可以自己研究一下。 篇幅有限,这里不再赘述。

四、GeoServer生成

        与前面的各种生成方式相比,GeoServer其实并没有样式的生成能力。但是其自带了很多的样式模板,我们可以把GeoServer来进行模板的生成,站在GeoServer的肩膀上,看得更远。

1、GeoServer的样式管理器

        在服务器上启动GeoServer之后,我们可以打开GeoServer的管理界面,在管理窗口中可以看到相关的启动界面。

        在这个界面中就可以看到GeoServer自带的和我们上传的样式文件。我们可以点击样式名称标题就可以进入看到不同的样式信息。

        在这个界面中,可以看到在GeoServer中也自带了简单的样式生成器,帮助我们来轻松的构造SLD样式文件,方便操作。 

五、总结

        以上就是本文的主要内容,本文即重点讲解在开发过程中,如何使用多方式来生成SLD样式文件。文章首先介绍Java中来使用代码进行编程式生成,然后介绍如何基于SLD的模板文件进行生成,其次介绍基于桌面生成工具SLDEditor和QQis来进行样式生成,最后介绍如何利用GeoServer来进行样式生成。通过不同的SLD创建方式,让您掌握不同的样式生成方式。希望本文对学习SLD的同学有所帮助。行文仓促,定有许多不足支持,针对不足之处,还请各位专家朋友在评论区中留言指出,不甚感激。

        博文编写过程中,参考以下内容,在此表示感谢:

        1、常用SLD模版

        2、分享两个线+标注的SLD样式

评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜郎king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值