通过 OpenLayers 加载CAD导出位图 和 math.js 构造的仿射变换实现地理坐标系到任意CAD图上像素坐标系的互转
WebGIS开发过程中会遇到这样一种情况:需要使用OpenLayers加载一个未校准的CAD导出的位图;并且还需要通过经纬度坐标数据在这个位图上做一些标记,还需要能通过在OpenLayers取得的图上要素的像素坐标获知实际的经纬度。
总结起来就是两个需求:
加载位图
经纬度坐标与像素坐标互转
分析:
由于从CAD导出的位图并不带有定位信息,所以需要通过仿射变换将图上的像素坐标转换到地理坐标。
即:(左边为某厂的卫星地图,右边为该厂的CAD导出位图,最终实现效果就是用OpenLayers加载位图,并实现坐标转换)
关于求解仿射变换的过程请见这里。主要的算法思想如下:
Arcgis中就带有了仿射变换的计算模块,OpenLayers没有仿射变换计算的能力,所以使用math.js这个数学库来进行实现。
代码:
算法在上面的截图已经有了,直接用相应的API实现就好:
//定义仿射变换函数function affineTransform(point, from, to) {if (from.length != to.length) return;//根据参数构造仿射变换所需的矩阵 var X = [];var Y = [];var I = [];var U = [];var V = [];from.forEach((item, index) => {X.push(item[0]);Y.push(item[1]);I.push(1);U.push([to[index][0]])V.push([to[index][1]])})//开始最小二乘法的计算过程var XYIt = [X, Y, I];var resultINV = math.inv(math.multiply(XYIt, math.transpose(XYIt)))var resultMulti = math.multiply(resultINV, XYIt);var vec1 = math.multiply(resultMulti, U)var vec2 = math.multiply(resultMulti, V)//使用vec1和vec2计算转换后的坐标return [vec1[0][0] * point[0] + point[1] * vec1[1][0] + vec1[2][0], vec2[0][0] * point[0] + point[1] * vec2[1][0] + vec2[2][0]]}
CAD导出的位图直接使用ImageStatic加载,并自定义一个像素坐标系:
//定义地图的像素坐标四至var extent = [0, 0, 4000, 2000];//定义地图的投影坐标系,像素坐标var projection = new ol.proj.Projection({code: 'factory-image',units: 'pixels',extent: extent});//初始化地图var map = new ol.Map({layers: [new ol.layer.Image({source: new ol.source.ImageStatic({url: './data/10-9.png',projection: projection,imageExtent: extent})})],target: 'map',view: new ol.View({projection: projection,center: ol.extent.getCenter(extent),zoom: 2,maxZoom: 8})});
概略分别获取图上厂区四角的坐标,图片像素坐标是用potoshop量取的,经纬度坐标是在google地图上拾取的:
var upperLeft = [119.071450, 39.309006];var lowerLeft = [119.074536, 39.305893];var upperRight = [119.075858, 39.311641];var lowerRight = [119.078934, 39.308527];var upperLeftPixel = [959, 1897];var lowerLeftPixel = [959, 112];var upperRightPixel = [2924, 1897];var lowerRightPixel = [2924, 112];
包括使用旗杆坐标打点测试的完整代码:
<!DOCTYPE html>
<html><head><title>厂区地图计算</title><link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css"><script src="https://unpkg.com/mathjs@6.2.3/dist/math.js"></script><script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script></head>
<style></style><body><div id="map" class="map"></div><script>//定义仿射变换函数function affineTransform(point, from, to) {if (from.length != to.length) return;var X = [];var Y = [];var I = [];var U = [];var V = [];from.forEach((item, index) => {X.push(item[0]);Y.push(item[1]);I.push(1);U.push([to[index][0]])V.push([to[index][1]])})var XYIt = [X, Y, I];var resultINV = math.inv(math.multiply(XYIt, math.transpose(XYIt)))var resultMulti = math.multiply(resultINV, XYIt);var vec1 = math.multiply(resultMulti, U)var vec2 = math.multiply(resultMulti, V)return [vec1[0][0] * point[0] + point[1] * vec1[1][0] + vec1[2][0], vec2[0][0] * point[0] + point[1] * vec2[1][0] + vec2[2][0]]}//Google坐标var upperLeft = [119.071450, 39.309006];var lowerLeft = [119.074536, 39.305893];var upperRight = [119.075858, 39.311641];var lowerRight = [119.078934, 39.308527];var upperLeftPixel = [959, 1897];var lowerLeftPixel = [959, 112];var upperRightPixel = [2924, 1897];var lowerRightPixel = [2924, 112];//定义地图的像素坐标四至var extent = [0, 0, 4000, 2000];//定义地图的投影坐标系,像素坐标var projection = new ol.proj.Projection({code: 'factory-image',units: 'pixels',extent: extent});//初始化地图var map = new ol.Map({layers: [new ol.layer.Image({source: new ol.source.ImageStatic({url: './data/10-9.png',projection: projection,imageExtent: extent})})],target: 'map',view: new ol.View({projection: projection,center: ol.extent.getCenter(extent),zoom: 2,maxZoom: 8})});//这里用旗杆的坐标演示坐标转换的使用var flagPole = [119.077710, 39.309195];var flagPolePixel = affineTransform(flagPole, [upperLeft, lowerLeft, upperRight, lowerRight], [upperLeftPixel, lowerLeftPixel, upperRightPixel, lowerRightPixel])var p=affineTransform(flagPolePixel, [upperLeftPixel, lowerLeftPixel, upperRightPixel, lowerRightPixel],[upperLeft, lowerLeft, upperRight, lowerRight])console.log(flagPole);console.log(p);var f = new ol.Feature(new ol.geom.Point(flagPolePixel));var vSource = new ol.source.Vector();var vLayer = new ol.layer.Vector({source: vSource})vSource.addFeature(f);f.setStyle(new ol.style.Style({image: new ol.style.Icon({src: './data/icon.png',anchor: [0.5, 1],scale: 0.3}),}))map.addLayer(vLayer);map.getView().fit(extent, map.getSize())map.render()</script>
</body></html>
这里使用旗杆的坐标进行了转换和逆转换,并在console里输出,结果如下:
更多请见:http://www.mark-to-win.com/tutorial/175096.html
通过 OpenLayers 加载CAD导出位图 和 math.js 构造的仿射变换实现地理坐标系到任意CAD图上像素坐标系的互转相关推荐
- vue openlayers 加载高德地图等 gcj02 的图层偏移问题
vue openlayers 加载高德地图等 gcj02 的图层偏移问题 这个问题是在使用 openlayers 地图引擎加载高德地图或者是谷歌地图都会遇到的问题,所以说呢这篇博文稍微说一下解决办法. ...
- Vue+Openlayers加载Geoserver发布的TileWMS后更换shp数据源的流程
场景 Vue中使用Openlayers加载Geoserver发布的TileWMS: Vue中使用Openlayers加载Geoserver发布的TileWMS_BADAO_LIUMANG_QIZHI的 ...
- Android中使用WebChromeClient显示Openlayers加载本地GeoJson文件显示地图(跨域问题解决)
场景 Openlayers中加载GeoJson文件显示地图: Openlayers中加载GeoJson文件显示地图_BADAO_LIUMANG_QIZHI的博客-CSDN博客 上面加载显示GeoJso ...
- Vue中使用Openlayers加载Geoserver发布的TileWMS时单击获取shp文件的坐标信息
场景 Vue中使用Openlayers加载Geoserver发布的TileWMS: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/ ...
- Vue中使用Openlayers加载Geoserver发布的TileWMS
场景 Openlayers下载与加载geoserver的wms服务显示地图: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/114 ...
- Vue中使用Openlayers加载Geoserver发布的ImageWMS
场景 Openlayers下载与加载geoserver的wms服务显示地图: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/114 ...
- Vue中使用Openlayers加载OSM(Open Street Map)显示街道地图
场景 Openlayers下载与加载geoserver的wms服务显示地图: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/114 ...
- WebGIS——Openlayers加载图层
Openlayers加载图层 一.创建Html文件并在body中放入一个Div作为地图显示的容器 <body><div id="map" class=" ...
- OpenLayers 加载天地图模糊的问题 OpenLayers 地图缩放模糊
openlayers 加载天地图模糊的问题,OpenLayers 地图缩放几次之后模糊 2021年12月20日 纠正模糊原因: 地图加载瓦片实质上还是图片,一般来说是256&256,将一个静态 ...
最新文章
- Unity SRP自定义渲染管线 -- 1.Custom Pipeline
- Google Go Programming In Eclipse
- ajax post 提交无法进入controller 请求200
- TimeQuest就一定要搞定——时序分析基本公式
- Hadoop学习笔记(五):MapReduce的类型与格式
- Linux:init 0~6
- 【Python】9×9数独计算器
- ajax前后端通信的头部消息之请求头与响应头
- 高质量单幅图片运动去模糊
- 【python】获取当前时间(年月日时分秒)
- 基于高通410c开发板,开发android端家庭控制中心APP(1)
- 关闭华为的触摸屏+查看自己电脑主板型号顺便推荐了个全能检测工具+进入华为的bios看看
- 怎么搭建自己的播客_如何开始自己的播客(逐步)
- [HNOI2017]影魔
- 区块链之区块结构-学习笔记
- Webix UI JavaScript 10.0.6 Crack
- [Weex 学习]Weex Debug模式
- python制表符是什么
- matlab误差分析报告,误差理论与数据处理实验报告
- 分发文件到服务器,Linux 把文件分发到不同服务器
热门文章
- HTML期末大学生网页设计作业——奇恩动漫HTML (1页面) HTML+CSS+JS网页设计期末课程大作业
- 【LeetCode】496. 下一个更大元素 I 【单调栈】
- error:2006D080:BIO routines:BIO_new_file:no such file
- 中间人攻击——ettercap的使用
- frameset的用法
- 公司成立三年即上市 网游速度获资本垂青
- 从Unity导出FBX到网页,实现一个模型多个动作动画
- Linux环境下连连看游戏代码,C++实现连连看游戏核心代码
- UICC 之 USIM 详解全系列——常用命令详解与实例说明
- 协程的原理及协程在高并发服务中的应用