道格拉斯 普克算法 java_道格拉斯-普克 抽稀算法 附javascript实现

道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点。该算法实现抽稀的过程是:先将一条曲线首尾点虚连一条直线,求其余各点到该直线的距离,取其最大者与规定的临界值相比较,若小于临界值,则将直线两端间各点全部舍去,否则将离该直线距离最大的点保留,并将原线条分成两部分,对每部分线条再实施该抽稀过程,直到结束。抽稀结果点数随选取限差临界值的增大而减少,应用时应根据精度来选取限差临界值,以获得最好的效果。

以下转载自:垂距法与道格拉斯-普克法删除冗余顶点效率的比较

道格拉斯- 普克法可描述为:将一条曲线首末顶点虚连一条直线 ,求出其余各顶点到该直线的距离 ,选其最大者与规定的限差相比较 ,若小于等于限差 ,则将直线两端间各点全部删去;若大于限差 ,则离该直线距离最大的顶点保留 ,并以此为界 ,把曲线分为两部分 ,对这两部分重复使用上述方法 ,直至最终无法作进一步的压缩为止 (见图 3)。

bad5e2e62723482ff11416a70689c6aa.png

道格拉斯 2 普克法有一个十分突出的优点 ,即它是一个整体算法 ,在一般情况下可保留较大弯曲形态上的特征点。经道格拉斯-普克法压缩后得到的图形如图 4所示。由于该算法可准确删除小弯曲上的定点 ,故能从体上有效地保持线要素的形态特征。正是因为道格拉斯-普克法具有这样突出的优点 ,所以已经在线要素地自动制图中得到了较广泛的应用。但道格拉斯- 普克法较垂距法复杂 ,且通常编程实现时需要采用递归方 ,有一定的难度。

7e6f5ca538931813d54832aa20b61ed1.png

转载end

以下是javascript版本的实现

DouglasPeucker

var points = [{

x: 10,

y: 10

}, {

x: 20,

y: 30

}, {

x: 30,

y: 12

}, {

x: 35,

y: 5

}, {

x: 40,

y: 22

}, {

x: 50,

y: 12

}, {

x: 80,

y: 40

}];

var Helper = {

renderPointsTo: function(points, anchor) {

var d;

for (var i = 0, p, a = K(anchor); i < points.length; i++) {

p = points[i];

if (a) {

a.appendChild(K('div', {}, {

position: 'absolute',

left: p.x + 'px',

top: p.y + 'px',

width: '5px',

height: '5px',

backgroundColor: 'green',

fontSize: '1px'

}));

}

}

}

};

Helper.renderPointsTo(points, 'processBefore');

var DouglasPeucker = {

getProcessPoints: function(points, tolerance) {

/// 获取处理后的点

/// 包含点的数组

/// 取样临界值

///

if (!K.isArr(points) || !points.length) { //当points不是数组或没有值时,直接返回一个空数组

return [];

}

if (points.length < 3) return points; //小于3个点时不抽稀,因为1个或2个点无法进行抽稀

var firstPoint = 0,

lastPoint = points.length - 1; //取开始点与结束点的下标

var pointIndexsToKeep = []; //保存需要点下标的数组

pointIndexsToKeep.push(firstPoint);

pointIndexsToKeep.push(lastPoint); //开始与结束不进行处理,直接保留

while (points[firstPoint] == points[lastPoint]) { //处理闭合情况,闭合时,强制断开

lastPoint--;

}

this.reduce(points, firstPoint, lastPoint, tolerance, pointIndexsToKeep); //抽稀

var resultPoints = []; //返回的点数组

pointIndexsToKeep.sort(function(a, b) { //排序,这个可排可不排

return a - b;

});

for (var i = 0; i < pointIndexsToKeep.length; i++) {

resultPoints.push(points[pointIndexsToKeep[i]]);

}

return resultPoints;

},

reduce: function(points, firstPoint, lastPoint, tolerance, pointIndexsToKeep) {

/// 抽稀处理

/// 待抽稀的数组

/// 起点

/// 终点

/// 取样临界值

/// 保留点下标的数组

var maxDis = 0,

idxFarthest = 0; //定义最大长度及最远点的下标

for (var i = firstPoint, dis; i < lastPoint; i++) {

dis = this.perpendicularDistance(points[firstPoint], points[lastPoint], points[i]); //获取当前点到起点与

if (dis > maxDis) { //保存最远距离

maxDis = dis;

idxFarthest = i;

}

}

if (maxDis > tolerance && idxFarthest != 0) { //如果最远距离大于临界值

pointIndexsToKeep.push(idxFarthest);

this.reduce(points, firstPoint, idxFarthest, tolerance, pointIndexsToKeep);

this.reduce(points, idxFarthest, lastPoint, tolerance, pointIndexsToKeep);

}

},

perpendicularDistance: function(beginPoint, endPoint, comparePoint) {

/// 计算给出的comparePoint到beginPoint与endPoint组成的直线的垂直距离

/// 起始点

/// 结束点

/// 比较点

///

//Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle

//Base = v((x1-x2)2+(y1-y2)2) *Base of Triangle*

//Area = .5*Base*H *Solve for height

//Height = Area/.5/Base

var area = Math.abs(0.5 * (beginPoint.x * endPoint.y + endPoint.x * comparePoint.y + comparePoint.x * beginPoint.y -

endPoint.x * beginPoint.y - comparePoint.x * endPoint.y - beginPoint.x * comparePoint.y));

var bottom = Math.sqrt(Math.pow(beginPoint.x - endPoint.x, 2) + Math.pow(beginPoint.y - endPoint.y, 2));

var height = area / bottom * 2;

return height;

}

};

Helper.renderPointsTo(DouglasPeucker.getProcessPoints(points, 14), 'processAfter');

欢迎试用Magix、star与fork

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值