目录

上一个主题

8.4. 绘制栅格影像

下一个主题

8.6. 绘制多边形

>>> from env_helper import info; info()
页面更新时间: 2022-12-28 08:26:07
运行环境:
    Linux发行版本: Debian GNU/Linux 11 (bullseye)
    操作系统内核: Linux-5.10.0-20-amd64-x86_64-with-glibc2.31
    Python版本: 3.9.2

8.5. 绘制线

Mapnik提供了两种绘制线状要素的方法: LineSymbolizer 和LinePatternSymbolizer。让我们依次来看一看:

8.5.1. LineSymbolizer

LinesSymbolizer可以绘制线状要素,也可以用来表征多边形轮廓,如下图所示:

LinesSymbolizer是Mapnik中最有用的symbolizers之一。这里是用于创建绘制虚线的LinesSymbolizer的Python的代码,例如:

>>> import mapnik
>>>
>>> symbolizer = mapnik.LineSymbolizer()
>>> symbolizer.stroke = mapnik.Color("#008000")
>>> symbolizer.stroke_width = 1.0

LineSymbolizer使用Mapnik的 Stroke 对象来定义绘制线。 为了使用LineSymbolizer,首先你需要创建stroke对象和绘制线形的各种选项。 然后,可以创建 LineSymbolizer,传递 stroke 对象到 LineSymbolizer 的构造器中。

symbolizer = mapnik.LineSymbolizer(stroke)

让我们来更仔细的看一下由stroke对象提供的绘制线型的各种选项。

默认情况下,线将会被绘制成黑色。你可以通过设置 strokecolor 属性到Mapnik的颜色对象中来改变颜色。

stroke.color = mapnik.Color("red")

在默认情况下,LineSymbolizer绘制的线有一个像元的宽。 你可以设置stroke的width属性改变线的宽度;你也可以通过设置stroke的opacity属性改变线的透明程度:

stroke.width = 1.5
stroke.opacity = 0.8

注意:你可以通过改变微小的线的宽度来对你的线的宽度进行细粒度的控制。

透明度的范围是从0.0(完全透明)到1.0(完全不透明)。如果没有定义透明度,则线将会完全不透明。

line_cap定义的是绘制线的结尾。Mapnik支持三种水平的line_cap的设置。

默认情况下,线会使用BUTT_CAP格式,但是你可以通过设置strokeline_cap属性来改变这种状况,例如:

stroke1.line_cap = mapnik.line_cap.BUTT_CAP
stroke2.line_cap = mapnik.line_cap.ROUND_CAP
stroke3.line_cap = mapnik.line_cap.SQUARE_CAP

image0

线的连接

改变一条线的方向,可以通过三种标准的方式之一来绘制它的转折端:

默认的行为就是使用MITER_JOIN, 你可以通过设置stroke为一个不同的值的line_join,来得到不同的效果。

>>> # stroke1.line_join = mapnik.line_join.MITER_JOIN
>>> # stroke2.line_join = mapnik.line_join.ROUND_JOIN
>>> # stroke3.line_join = mapnik.line_join.BEVEL_JOIN

image0

8.5.2. 绘制道路和其他复杂的线性要素

你可以通过叠加两个symbolizers来在地图上绘制道路。 第一个LineSymbolizer是用来绘制道路的轮廓, 第二个LineSymbolizer 是用来绘制道路的内部。例如:

>>> import mapnik
>>> # stroke = mapnik.Stroke()
>>> # stroke.color = mapnik.Color("#bf7a3a")
>>> # stroke.width = 7.0
>>> # roadEdgeSymbolizer = mapnik.LineSymbolizer(stroke)
>>> # stroke = mapnik.Stroke()
>>> # stroke.color = mapnik.Color("#ffd3a9")
>>> # stroke.width = 6.0
>>> # roadInteriorSymbolizer = mapnik.LineSymbolizer(stroke)

在绘制街道地图方面这项技术已被普遍应用了。 我们刚刚定义的两个symbolizers将会被叠加并产生道路。

这项技术不仅能够被用来绘制道路;还能够创造性的运用symbolizers,symbolizers是利用Mapnik来实现复杂视觉效果的一个主要技巧。

下面来看一下如何绘制虚线和点线:

你可以添加“breaks”使其出现虚线和点线。

你可以通过调用stroke的add_dash()的方法在线上添加少许线段:

  • all text stuff

  • dash arrays

    stroke.add_dash(5, 5)

这将会给线一个5像元的短划线,接下来是5像元的间隔: 你不能被限制到只有一个虚线片段: 如果调用add_dash()多次,你将创建一个拥有更多片段的线。 这些虚线片段也会被依次处理,并允许你创建更多虚线和点的模式。例如:

>>> # stroke.add_dash(10, 2)
>>> # stroke.add_dash(2, 2)
>>> # stroke.add_dash(2, 2)

这样就会生成重复的线的图案。

渲染道路的标准样式,即内置浅色填充标签、边缘有稀薄的轮廓, 这些都可以通过重复图层来实现。 首先,你放下一个厚厚的深色道路的图层,比如14像素宽; 其次,你放置另一个薄薄的,浅色道路图层,比如12像素宽。 二者结合,便能准确的显现出网格的街道轮廓, 而且看起来不会有一条路覆盖另一条路的交织的街道十字路口。 很多复杂的视觉效果可以通过类似的方式实现,即通过反复的分层来实现特别的效果。

image0

>>> import os
>>> import mapnik
>>>
>>>
>>> stylesheet = '/gdata/world_map_dash.xml'
>>>
>>> m = mapnik.Map(600, 300)
>>> mapnik.load_map(m, stylesheet)
>>> m.zoom_all()
>>>
>>>
>>> bbox = mapnik.Box2d(118, 36.6, 124.6, 40.7)
>>>
>>> m.zoom_to_box(bbox)
>>>
>>> mapnik.render_to_file(m, 'xx_line_jv.png', 'png')

8.5.3. LinePatternSymbolizer

LinePatternSymbolizers通常是用在一些特殊状况的,例如:当你使用一个单一的Stroke对象来绘制一条线而不能显现出来的时候。 LinePatternSymbolizers可以接受PDF或TIFF格式的文件, 且沿着线的长度的方向或者多边形轮廓的周围重复绘制图像:

image2

图 8.4 image2

注意:线性要素和多边形的轮廓都有一个方向,即线和多边形的边界按照几何图形被创建时点被定义的顺序从一个点移动到下一个点。

例如,组成上述图顶部的线段的点是从左到右来定义的,即最先被定义的是最左边的点,其次是中间的点,最后是右边的点。

一个要素的方向是很重要的,因为它影响LinePatternSymbolizers绘制图像的方式。如果我们刚刚看到的线串定义的是相反的方向, 那么LinePatternSymbolizers将把其绘制成这个样子:

LinePatternSymbolizers绘制图像面向线的最左端, 因为它是从一个点移动到下一个点。 要想绘制一幅朝向为右的图像,你将不得不在你的要素范围之内调转点的顺序。 要想在你的Python代码中使用LinePatternSymbolizers, 你只需创建一个mapnik.LinePatternSymbolizer的例子, 并给它一个图像文件的名字,文件的格式(PNG或TIFF),图像像元大小:

>>> # symbolizer = mapnik.LinePatternSymbolizer("image.png","png", 11, 11)
>>> import mapnik
>>> line_symbolizer2 = mapnik.LinePatternSymbolizer()
>>> line_symbolizer2.stroke = mapnik.Color('rgb(50%,50%,50%)')
>>> #  dir(line_symbolizer2.symbol)
>>> line_symbolizer2.stroke_linecap = mapnik.stroke_linecap.ROUND_CAP
>>> dir(line_symbolizer2.symbol)
['__call__',
 '__class__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__func__',
 '__ge__',
 '__get__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__self__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__']
>>> line_symbolizer2.stroke_linecap
2
>>> line_symbolizer2.stroke_linecap = mapnik.stroke_linecap.SQUARE_CAP
>>> line_symbolizer2.stroke_linecap
1
>>>
>>> import os
>>>
>>> import mapnik
>>>
>>>
>>> def renderit(line_sym = None, fig_index = 0):
>>>
>>>     # mapnik.Color('y')
>>>     m = mapnik.Map(600, 300, "+proj=latlong +datum=WGS84")
>>>     # m.background = mapnik.Color('steelblue')
>>>     s = mapnik.Style()
>>>     r = mapnik.Rule()
>>>
>>>     r.symbols.append(line_sym)
>>>     s.rules.append(r)
>>>     m.append_style('My Style', s)
>>>     lyr = mapnik.Layer('world', "+proj=latlong +datum=WGS84")
>>>     lyr.datasource = mapnik.Shapefile(file='/gdata/GSHHS_c.shp')
>>>     lyr.styles.append('My Style')
>>>     m.layers.append(lyr)
>>>
>>>     bbox = mapnik.Box2d(118, 36.6, 124.6, 40.7)
>>>     m.zoom_to_box(bbox)
>>>     mapnik.render_to_file(m, 'xx_line_{idx}_em.png'.format(idx = fig_index), 'png')
>>>
>>>
>>> line_symbolizer = mapnik.LineSymbolizer()
>>> line_symbolizer.stroke = mapnik.Color('rgb(50%,50%,50%)')
>>>
>>> # sss = mapnik.Stroke(mapnik.Color('green'),0.1)
>>> line_symbolizer.stroke_linecap = mapnik.stroke_linecap.ROUND_CAP
>>> line_symbolizer.stroke_width = 5.0
>>>
>>> fig_index = 0
>>> fig_index += 1
>>> renderit(line_symbolizer, fig_index)
>>>
>>> #######################
>>> line_symbolizer.stroke_linecap = mapnik.stroke_linecap.BUTT_CAP
>>> # line_symbolizer.stoke_dasharray = [5,10]
>>> fig_index += 1
>>> renderit(line_symbolizer, fig_index)
>>>
>>> #############################################
>>> fig_index += 1
>>> line_symbolizer.stroke_opacity = 0.5
>>> renderit(line_symbolizer, fig_index)
>>>
>>> #####################################
>>> line_symbolizer2 = mapnik.LinePatternSymbolizer()
>>> # line_symbolizer2.file = os.path.join(os.path.split(os.path.realpath(__file__))[0], 'tri.png')
>>> line_symbolizer2.file = '/gdata/tri.png'
>>> # line_symbolizer2.stroke_width
>>>
>>> print('x'* 40)
>>> print(dir(line_symbolizer2))
>>> print('x'* 40)
>>> line_symbolizer2.stroke = mapnik.Color('rgb(50%,50%,50%)')
>>> line_symbolizer2.stroke_linecap = mapnik.stroke_linecap.ROUND_CAP
>>> line_symbolizer2.stroke_width = 1
>>>
>>> fig_index += 1
>>> renderit(line_symbolizer2, fig_index)
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__instance_size__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_c___module__', '_c___qualname__', 'filename', 'symbol']
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>>> ###############################################
>>>
>>> roadEdgeSymbolizer = mapnik.LineSymbolizer()
>>> roadEdgeSymbolizer.stroke = mapnik.Color("#bf7a3a")
>>> roadEdgeSymbolizer.stroke_width = 7
>>>
>>> roadInteriorSymbolizer = mapnik.LineSymbolizer()
>>> roadInteriorSymbolizer.stroke = mapnik.Color("#ffd3a9")
>>> roadInteriorSymbolizer.stroke_width = 6
>>>
>>> m = mapnik.Map(600, 300, "+proj=latlong +datum=WGS84")
>>> # m.background = mapnik.Color('steelblue')
>>> s = mapnik.Style()
>>> r = mapnik.Rule()
>>>
>>> r.symbols.append(roadEdgeSymbolizer)
>>> s.rules.append(r)
>>> m.append_style('My Style', s)
>>> lyr = mapnik.Layer('world', "+proj=latlong +datum=WGS84")
>>> lyr.datasource = mapnik.Shapefile(file='/gdata/GSHHS_c.shp')
>>> lyr.styles.append('My Style')
>>> m.layers.append(lyr)
>>>
>>>
>>> m.zoom_all()
>>>
>>> fig_index += 1
>>> mapnik.render_to_file(m, 'xx_line_kz.png', 'png')

上面生成的结果为:

>>> from IPython.display import Image
>>> Image('./xx_line_kz.png')
_images/mapnik-mapnik-line_28_0.png