拿内蒙古自治区的省界线,做道格拉斯-普克算法和Visvalingam-Whyatt算法的概化测试。
前端用的是leaflet,大概效果如下,黑色的线是原始的省界线数据,红色的线是道格拉斯-普克算法概化成101个节点后的效果,蓝色的线是Visvalingam-Whyatt算法概化成101个节点后的效果,参数由url传递,nodes=101。
通常情况,我们做数据概化,选用的参数也都是概化后的节点数量,而不是距离容差,这样计算效率和渲染效率会更高。
全部代码如下:
Leaflet_map.html:
<!DOCTYPE html>
<html>
<head>
<title>概化算法</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<script src="json.js"></script>
<script src="douglaspeucker.js"></script>
<script src="visvalingam.js"></script>
<style>
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
// 从json.js中获取数据
var polygons = getFeatures();
// 获取要素的坐标
var coordinates = polygons['features'][0]['geometry']['coordinates'][0];
console.log(coordinates);
// 简化
var jianhuaDP = simplifyDouglasPeucker(coordinates,getQueryString('nodes'));
var jianhuaVM = simplifyVisvalingam(coordinates,getQueryString('nodes'));
console.log(jianhuaDP);
console.log(jianhuaVM);
// 简化数据经纬度前后置换
var jianhuaDPPolygon = [];
var jianhuaVMPolygon =[];
for (var i = 0; i < jianhuaDP.length; i++) {
jianhuaDPPolygon.push([jianhuaDP[i][1],jianhuaDP[i][0]])
}
for (var i = 0; i < jianhuaVM.length; i++) {
jianhuaVMPolygon.push([jianhuaVM[i][1],jianhuaVM[i][0]])
}
console.log(jianhuaDPPolygon);
console.log(jianhuaVMPolygon);
// 添加瓦片底图
var map = L.map('map').setView([35.719192,112.273486],3);
L.tileLayer('http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8', {
maxZoom: 24,
}).addTo(map);
// 添加geojson对象,原始的数据
L.geoJSON([polygons],{style: {
weight: 3,
color: '#000000',
fillOpacity: 0
}
}).addTo(map);
// 添加polygon对象,简化后的数据
L.polygon(jianhuaDPPolygon,{
weight: 3,
color: '#c00000',
fillOpacity: 0
}).addTo(map);
L.polygon(jianhuaVMPolygon,{
weight: 3,
color: '#0044cc',
fillOpacity: 0
}).addTo(map);
// 通过网址传参,获取节点个数
function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if(r != null) {
return unescape(r[2]);
}
return null;
}
</script>
</body>
</html>
douglaspeucker.js:
// 道格拉斯-普克简化算法
// 计算距离平方
var sqr = function (x) { return x * x; };
var distSquared = function (p1, p2) {
return sqr(p1[0] - p2[0]) + sqr(p1[1] - p2[1]);
};
// 两点间线段长度
var Line = function(p1, p2) {
this.p1 = p1;
this.p2 = p2;
this.lengthSquared = distSquared(p1, p2);
};
Line.prototype = {
// 计算比例
getRatio: function (point) {
var p1 = this.p1, p2 = this.p2;
var segmentLength = this.lengthSquared;
if (segmentLength === 0) {
return distSquared(point, p1);
}
return ((point[0] - p1[0]) * (p2[0] - p1[0]) +
(point[1] - p1[1]) * (p2[1] - p1[1])) / segmentLength;
},
// 计算长度
distanceToSquared: function (point) {
var p1 = this.p1, p2 = this.p2;
var t = this.getRatio(point);
if (t < 0) { return distSquared(point, p1); }
if (t > 1) { return distSquared(point, p2); }
return distSquared(point, [
p1[0] + t * (p2[0] - p1[0]),
p1[1] + t * (p2[1] - p1[1])
]);
},
// 开平方
distanceTo: function (point) {
return Math.sqrt(this.distanceToSquared(point));
}
};
// 定义全局方法
simplifyDouglasPeucker = function (points, pointsToKeep) {
var start = new Date().getTime();
console.log(start);
var weights = [];
var len = points.length;
console.log(len);
console.log(pointsToKeep);
// 这是一个递归函数
function douglasPeucker (start, end) {
if (end > start + 1) {
var line = new Line(points[start], points[end]);
var maxDist = -1;
var maxDistIndex = 0;
var dist;
// 找到从起点到终点离直线最远的点