离线GIS完整解决方案包含换肤2020-02-18

简介

公司项目需要用到离线GIS应用,因此做了一个详细的技术调研。时间大概两天,方案选型确定,到服务的搭建,及包含具体应用场景需要的换肤功能。
首先方案大概是有3个。
1.采用拼接地图资源采用image方式渲染整个地图,然后在每个层级的图片上进行点位标注,和数据加载。优点,加载速度快,直接渲染业务需要的地图部分即可,缺点前端工作量大,不利于后续产品化的发展。
2.采用开源的openstreetmap,缺点openstreetmap开源的地图不够详细,没有需要展示的详细资源。
3.采用arcgis方式,下载最新地图的瓦片google,高德等等,自己搭建离线gis服务。缺点,项目应用需要搭建单独的gis服务,优点利于后续产品化的发展,不用单独再造轮子。一次搭建,后续项目可以直接应用。
大体需要的工具及服务, geowebcache+全能电子地图下载器+leaflet
geowebcache为arcgis提供基础的服务,简单说就是把所有的地图资源放到这个服务里面,供你来调用加载,渲染。
全能电子地图下载器,为你提供基础的地图资源(png)图片。
leaflet是地图组件,就是提供地图内的标点,范围等等的一个组件。可以从官网看到,不做过多阐述。

本文只对第三点展开讨论。从0开始的搭建,部署,及展示,以及产品后续需要的换肤功能。服务搭建参考
1.https://www.cnblogs.com/luxiaoxun/p/5022333.html
2.https://www.cnblogs.com/ChineseMoonGod/p/6934928.html
虽然参考博客园的帖子,但是还会单独重新写一遍搭建流程,方便后面小伙伴整体参考吧,会比之前更详细。

服务搭建(geowebcache):

服务下载地址:
https://www.geowebcache.org/

image.png
image.png

这里要说明,我下载了最新版本,但是地图服务一直没加载出来,具体就是下载了相应的瓦片,但是整个界面是空白。因为时间仓促,这里不得不降级,采用了1.8.0,1.9.0版本均可以正常显示,具体原因未知。后续采用了1.9.0版本。具体调研的版本有:


image.png

1.运行服务

   geowebcache下载之后是一个war包,就是我们传统的web服务。放在tomcat的webapps目录下首先运行起来。

image.png

服务运行效果
地址:http://localhost:8080/geowebcache

image.png

2.修改配置

打开此文件


image.png

image.png

配置完之后重启tomcat,会看到


image.png

到这里我们暂时停止配置,下载我们需要的地图瓦片。

3.地图资源下载

地图资源下载我采用的是,全能电子地图下载器(破解版)。


image.png

工具操作不做过多阐述,应该看看就懂了。
下载好瓦片后,需要进行地图拼接


image.png

选择此参数


image.png

拼接完成后会生成以下文件


image.png
image.png

_alllayers内存放就是我们地图的瓦片资源,就是一堆png图片。实际地图渲染的效果就是在服务资源内将png拼在在一起,并且加载web内。

image.png

每个层级的地图瓦片资源。

备注:之前参考,说conf.cdi,和conf.xml需要打开,然后保存为unt-8无bom格式,我就直接跟着操作了,具体有bom,和无bom区别我没有具体操作过。操作流程就是,用nodepad++打开两个文件,然后再保存一下。

image.png

4.继续修改配置

打开我们上一步自动生成的,geowebcache.xml文件。
添加如下几行字符


image.png
<arcgisLayer>
    <name>ARCGIS-Demo</name>
    <tilingScheme>D:\\GisMap\\Layer\\conf.xml</tilingScheme>
    <tileCachePath>D:\\GisMap\\Layer\\_alllayers</tileCachePath>
</arcgisLayer>

很明显conf.xml,_alllayers就是我们之前拼接完地图的绝对路径。
接下来重启服务,查看效果。


image.png

可以看到我们刚刚配置的服务,点击png即可预览效果


image.png

image.png

5.对外提供服务

正常应用时,肯定不是预览效果就达到了我们的目的。我们需要调用类似,百度,google地图那种,在我们项目内加载服务,并且根绝第三方的接口进行地图相关的操作,例如标点位信息,做一些面积图处理等等。
服务调用脚本如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Leaflet - Offline Demo</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
</head>
<body>

<div id="map" style="height:100vh;background-color: #033345" ></div>
<script type="text/javascript">
//地图的中心
var mapCenter = new L.LatLng(28.80748,104.593578);
var map = new L.Map('map', {
    center : mapCenter,
    zoom:5,//默认展开的地图层级,注意根据业务需求自己调整。
    maxZoom:18,//最大层级,注意根据业务需求自己调整。
    minZoom:15,//最小层级,注意根据业务需求自己调整。
    attribution : '高德普通地图'
});
var wmsLayer = L.tileLayer.wms("http://localhost:8080/geowebcache/service/wms", {
    layers: 'ARCGIS-Demo1',//注意这里要和geowebcache.xml内的 <name>ARCGIS-Demo</name>对应
    format: 'image/png'
});
wmsLayer.addTo(map);
//点位标记
var marker = new L.Marker([28.80748,104.593578]);
var marker1 = new L.Marker([28.814023,104.571005]);
map.addLayer(marker);
map.addLayer(marker1);
marker.bindPopup("<br>五粮液厂区!</br><button onclick='alert(1);'>进入</button></p>").openPopup();
marker1.bindPopup("<p>红若小学!</br><button onclick='alert(2);'>进入</button></p>").openPopup();
//标记面积
var latlngs2 =  [[28.812089,104.589441],[28.810779,104.583208],[28.808918,104.579024],[28.808072,104.579432],[28.805609,104.579432],[28.790829,104.591148]
    ,[28.802412,104.599473]]; //区域坐标组
var areaLayer = L.polygon(latlngs2, {color:     'red',fillColor:'blue',weight:1}).addTo(map); //添加到地图
</script>
</body>
</html>

这里有两点要说明

1.name属性

layers的name必须配置正确,否则地图不加载。


image.png

2.地图中心点

地图点位中心的坐标,就是mapcenter节点的配置,如果不正确,也会导致看不到地图。这里我用的高德在线的取点坐标进行标记。
地址:https://lbs.amap.com/console/show/picker
要注意坐标不要配置反了,例如

image.png

image.png

5.查看服务运行效果

这样已经达到,调用地图服务资源返回到我们的内部应用中。


image.png

6.换肤功能

因为不用应用场景下,可能要求地图的皮肤颜色不同。这里我调研,发现没有直接可应用的地图换肤资源。因此就得动脑子了,因为我们_alllayers文件目录内存储的是默认的所有瓦片资源。那我应该用脚本,把每个对应png的色值重新调整,再保存到目录内,然后调用即可。脚本内容如下:

# *_*coding:utf-8 *_*
from PIL import Image
import os

#
# 遍历文件夹
def walkFile(file):
for root, dirs, files in os.walk(file):

    # root 表示当前正在访问的文件夹路径
    # dirs 表示该文件夹下的子目录名list
    # files 表示该文件夹下的文件list

    # 遍历文件
    for f in files:
        path = os.path.join(root, str(f));
        i = 0
        j = 0
        # path = path.replace("\\","\\")
        img = Image.open(path)  # 读取系统的内照片
        # img = Image.open("D:\\GisMap\\Layer1\\_alllayers\\L05\\R0000000A\\C0000001A.png")  # 读取系统的内照片
        print (img.size)  # 打印图片大小
        print (img.getpixel((4, 4)))

        width = img.size[0]  # 长度
        height = img.size[1]  # 宽度
        for i in range(0, width):  # 遍历所有长度的点
            for j in range(0, height):  # 遍历所有宽度的点
                data = (img.getpixel((i, j)))  # 打印该图片的所有点
                if isinstance(data, tuple) and len(data) == 3:
                    print (data)  # 打印每个像素点的颜色RGBA的值(r,g,b,alpha)
                    print (data[0])  # 打印RGBA的r值
                    if (data[0] >= 170 and data[1] >= 170 and data[2] >= 170):  # RGBA的r值大于170,并且g值大于170,并且b值大于170
                        img.putpixel((i, j), (3,52,71,255))  # 则这些像素点的颜色改成大红色
                    elif (data[0] >= 68 and data[1] >= 68 and data[2] >= 68 and data[0] >= 111 and data[1] >= 111 and data[2] >= 111):  # RGBA的r值大于170,并且g值大于170,并且b值大于170
                        img.putpixel((i, j), (0,94,94,255))  # 则这些像素点的颜色改成大红色
                    elif (data[0] >= 0 and data[1] >= 0 and data[2] >= 0 and data[0] <= 68 and data[1]<= 68 and data[2]<= 68):  # RGBA的r值大于170,并且g值大于170,并且b值大于170
                        img.putpixel((i, j), (0, 94, 94, 255))  # 则这些像素点的颜色改成大红色

        img = img.convert("RGB")  # 把图片强制转成RGB
        img.save(path)  # 保存修改像素点后的图片
def main():
walkFile("D:\\GisMap\\Layer1\\_alllayers")


if __name__ == '__main__':
main()

这里我是随便在高德的皮肤中,取了几个颜色进行替换。但是这里有个遗留问题就是,单线程对每个像素进行替换,效率还是蛮差的。这里还是有很大的优化空间,多线程,对每个层级不同的瓦片资源进行批量更新。

高德官方皮肤截图如下:


image.png

脚本处理效果如下:


image.png

这里只是粗略的进行几个大的色值替换,同样也有很大的优化空间。

7换肤资源切换

同理,因为我们处理好了另一个皮肤的所有文件后,保存在一个新的_alllayers文件夹内。


image.png

再次编辑geowebcache.xml,增加新皮肤的节点信息,然后重启服务。

<arcgisLayer>
    <name>ARCGIS-Demo1</name>
    <tilingScheme>D:\\GisMap\\Layer1\\conf.xml</tilingScheme>
    <tileCachePath>D:\\GisMap\\Layer1\\_alllayers</tileCachePath>
</arcgisLayer>
image.png

总结:其实很简单的思路,希望可以帮助到后续遇到过类似需求的小伙伴。我的QQ337241905,有相关问题可以联系我。工具具体可以百度搜一下,或者找我要。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342