OpenStreetMap部分介质:隐藏数据可视化

我们都习惯于查看Internet上的经典基础内容,以查看定居点,道路及其名称,房屋及其编号。 但是,即使这些属性对象也不仅仅是名称或数字。 对于建筑物来说,这是许多楼层,对于道路,则是许多车道;对于城市,则是​​许多居民。 但这只是冰山一角-OpenStreetMap包含各种空间数据,以至于您根本看不到其中的一些。 如果没有专门的渲染,您将永远看不到,除非您有兴趣编辑带有奇怪标签的这一行的数据。 今天,我们将制作一个超专业的渲染图来显示森林邻里。


森林街区


步骤1.调查。
您当然可以用手指在天空中猜测如何表示它们,但是使用Wiki-osm更为安全。 在那里,我们可以找到以下内容: boundary = forest_compartment


因此,森林块由标记boundary=forest_compartment多边形指定。 的确,有一个澄清说明,最初将其指定为boundary=forestry_compartment ,但是它的文化程度较低。 而且,由于旧名称的使用次数非常多(根据taginfo大约有4000次),因此我们不会予以折扣。


步骤2.数据。
Geofabrik获取数据。 下载整个俄罗斯的文件russia-latest.osm.pbf 。 使用osmconvert我们以o5m格式获取数据以进行后续过滤。


 osmconvert russia-latest.osm.pbf -o=russia-latest.o5m 

现在我们使用osmfilter只过滤我们需要的数据


 osmfilter russia-latest.o5m --keep="boundary=forest_compartment =forestry_compartment" -o=forest_compartment-local.o5m 

步骤3.矢量瓷砖。
简短的理论。 旧方法是从大型数据库中请求一些数据,从中获取图片,然后保存以供将来提供给客户端。 在新的数据库中,从大型数据库中请求少量数据并将其保存以供随后传输到客户端。 并让客户将它们变成图片。 从表面上看,利润-我们将渲染图像的重担转移到了客户的肩膀上。 缺点-在咖啡壶上,您可能看不到地图,需要WebGL支持。


因此,Mapbox以sqlite数据库的形式提出了矢量图块的格式和用于它们的容器。 因此,它现在不是分散在文件夹中的文件,而是整洁的孤独文件。 矢量图块包含由几何和属性组成的逻辑层(房屋,道路等)。


在这里,我们将为森林社区做好准备。 我将使用TileMaker工具。 它接收pbf格式的OSM数据作为输入,因此在过滤之后,我们需要转换回该格式。


 osmconvert forest_compartment-local.o5m -o=forest_compartment-local.pbf 

现在,根据文档 ,我们需要向TileMaker解释我们需要哪些层以及具有哪些属性。


步骤4.图层?
我们需要什么层? 这取决于我们展示的内容。 即 首先,我们必须以某种方式想象视觉部分。 以及如何从可用数据中实现。 根据OSM数据,我们有一个多边形及其属性的网格。 该属性具有林业名称和季度编号。


OSM原始数据


由此,最简单的方法是显示季度并用您的数字签名。 即 我们需要一个多边形层,在多边形的中心,我们将显示一个铭文及其编号。
然后弹出矢量图块的第一个功能。 当较大的源多边形落入不同的图块时,只有其一部分会落入图块中。 并且在渲染时,结果分别是两个不同的多边形,对于它们,在其一半的中心将有两个签名。



因此,对于矢量图块,当仍然存在有关几何图形的所有必要信息时,将准备一个单独的带有铭文的图层。


底线:我们需要两层,用于填充的多边形和用于签名的点。 创建config.json文件。


 { "layers": { }, "settings": { "minzoom": 11, "maxzoom": 11, "basezoom": 14, "include_ids": false, "author": "freeExec", "name": "Forest Compartment RUS", "license": "ODbL 1.0", "version": "0.1", "description": "Forest compartment from OpenStreetMap", "compress": "gzip", "metadata": { "attribution": "<a href=\"http://www.openstreetmap.org/copyright/\" target=\"_blank\">&copy;  OpenStreetMap</a>", "json": { "vector_layers": [ ] } } } } 

在“层”部分中,指定我们需要的内容


  "layers": { "forest_compartment": { "minzoom": 11, "maxzoom": 11 }, "forest_compartment_label": { "minzoom": 11, "maxzoom": 11 } }, 

指示了各层的名称,并以多大的比例显示它们。


  "json": { "vector_layers": [ { "id": "forest_compartment", "description": "Compartment", "fields": {}}, { "id": "forest_compartment_label", "description": "Compartment", "fields": {"ref":"String"}} ] } 

在元数据中,我们告诉未来的可视化工具我们可以使用哪些属性。 对于标记层,我们将在ref有四分之一数字。


步骤5.数据处理。
为此,使用lua语言的脚本,该脚本将决定我们需要的OSM数据中的哪些对象,在哪一层发送它们以及具有哪些属性。


让我们从process.lua文件模板开始。


 -- Nodes will only be processed if one of these keys is present node_keys = { } -- Initialize Lua logic function init_function() end -- Finalize Lua logic() function exit_function() end -- Assign nodes to a layer, and set attributes, based on OSM tags function node_function(node) end -- Similarly for ways function way_function(way) end 

我们在这里拥有:


node_keys-OSM数据中有很多点,如果我们每个都戳这个脚本,那么处理将花费很长时间。 这是一个过滤器,用于告诉我们我们感兴趣的关键点。


function node_function(节点)-在上一段中我们感兴趣的每个点上都会调用该函数。 在这里,我们必须决定如何处理它。


function way_function(way)-将在任何行以及与多边形和边界类型的关系上调用的函数,因为 它们被视为面对象。


我们开始编写代码。 首先,我们指出我们需要哪些点:


 node_keys = { "boundary" } 

现在我们编写用于处理它们的函数:


 function node_function(node) local boundary = node:Find("boundary") if boundary == "forestry_compartment" or boundary == "forest_compartment" then local ref = node:Find("ref") if ref ~= "" then node:Layer("forest_compartment_label", false) node:Attribute("ref", ref) end end end 

这里发生了什么:我们通过node:Find("")读取boundary键的值node:Find("") 。 如果这是forest_compartment ,则从ref标签读取四分之一数字。 如果不为空,则通过Layer("_", ___)带有标签的对象添加到我们的图层中。 在ref层的属性中,我们保存四分之一数字。
正方形方块几乎一样简单:


 function way_function(way) local boundary = way:Find("boundary") if way:IsClosed() and ( boundary == "forestry_compartment" or boundary == "forest_compartment" ) then way:Layer("forest_compartment", true) way:AttributeNumeric("nomerge", way:Id()) local ref = way:Find("ref") if ref ~= "" then way:LayerAsCentroid("forest_compartment_label", false) way:Attribute("ref", ref) end end end 

在这里,我们另外检查该行是否关闭,因为 碰巧标签仅出现在片段上。 值得注意的是forest_compartment图层forest_compartment area(因此是Layer("", true))函数的第二个参数Layer("", true)) ,并且我们将签名的位置作为LayerAsCentroid的中心。


尽管我们没有在config- nomerge指定它,但也值得关注它添加的属性。 需要取消另一个功能,这次是TileMaker转换器(尽管禁用它的参数已出现在新版本中)。


特殊之处在于,为了进行优化,当一层中有许多具有相同属性的对象时,它们的转换器将几何形状合并为一个。 例如,我们有一条由三个独立的路段组成的街道,结果将被发送三次以进行渲染。 与我们将一个对象发送到渲染这一事实相比,这要更长一些,但是几何形状稍微复杂一些(将所有对象联合在一起)。


在我们的情况下,所有相邻的四分之一都将合并为一个大的多边形,但是我们不需要这样做。 因此,我们添加对象编号,以使它们不同且不合并。


现在是时候开始创建矢量切片的过程了。


 tilemaker forest_compartment-local.pbf --output forest_compartment-local.mbtiles 

结果,我们应该拥有文件forest_compartment-local.mbtiles


步骤6.创建一个样式。
我们在mapbox.com上创建一个帐户。 在Mapbox Studio的Tileset部分中,通过将我们先前创建的文件拖到下载窗口中来创建新的tileet。 请在一分钟内将其处理并添加到列表中。


现在,我们转到“样式”部分,并根据完成的“ Light”创建一个新的图层,以便我们可以看到地图的主要元素,例如道路,居民点等。 我们去切博克萨雷(Cheboksary),因为那里有林木。


我们下降到比例尺的11级(我们只为他创建了图块),然后单击“添加图层”按钮。 在数据源选项卡中,我们找到了forest_compartment-local-XXXXX数据源,在其中选择了多边形图层。 它应该在右侧以绿色突出显示。


图层添加


接下来,在样式选项卡上,将填充颜色设置为绿色,并将描边设置为棕色。


色彩调整


现在仍然需要添加签名。 添加一个新层,仅这次我们在数据中选择forest_compartment_label ,然后选择type symbol ,数字应显示在右侧。


添加标签层。


在样式选项卡中,指定我们需要显示ref属性。


签名属性


就是这样,单击发布屏幕的右侧,我们可以共享链接,以便其他人可以查看我们的创作。 但是,与其他地方一样,显示卡不是免费的,所以我不会给您链接,以免掉入habreffect。


PS:也许在另一篇文章中,我将告诉您我是如何在其中包含的一组块上以林业名称实现签名的位置的。

Source: https://habr.com/ru/post/zh-CN441296/


All Articles