道格拉斯-普克抽稀算法
目的
用來(lái)對(duì)大量冗余的圖形數(shù)據(jù)點(diǎn)進(jìn)行壓縮以提取必要的數(shù)據(jù)點(diǎn)。
過(guò)程
先將一條曲線首尾點(diǎn)虛連一條直線,求其余各點(diǎn)到該直線的距離,取其最大者與規(guī)定的臨界值相比較,若小于臨界值,則將直線兩端間各點(diǎn)全部舍去,否則將離該直線距離最大的點(diǎn)保留,并將原線條分成兩部分,對(duì)每部分線條再實(shí)施該抽稀過(guò)程,直到結(jié)束。
抽稀結(jié)果點(diǎn)數(shù)隨選取限差臨界值的增大而減少,應(yīng)用時(shí)應(yīng)根據(jù)精度來(lái)選取限差臨界值,以獲得最好的效果。
一個(gè)十分突出的優(yōu)點(diǎn)
一個(gè)十分突出的優(yōu)點(diǎn),即它是一個(gè)整體算法,通過(guò)準(zhǔn)確刪除小彎曲上的定點(diǎn),能夠在整體上有效地保持線要素的形態(tài)特征。
正是因?yàn)榈栏窭?普克法具有這樣突出的優(yōu)點(diǎn),所以已經(jīng)在線要素地自動(dòng)制圖中得到了較廣泛的應(yīng)用。
C++代碼實(shí)現(xiàn)
/*
* 計(jì)算點(diǎn)到直線的距離
*/
double PerpendicularDistance(CPoint Point1, CPoint Point2, CPoint Point)
{
//Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle
//Base = v((x1-x2)2+(x1-x2)2) *Base of Triangle*
//Area = .5*Base*H *Solve for height
//Height = Area/.5/Base
double area = abs(0.5 * (Point1.x * Point2.y + Point2.x * Point.y + Point.x * Point1.y - Point2.x * Point1.y - Point.x * Point2.y - Point1.x * Point.y));
double bottom = sqrt(pow(Point1.x - Point2.x, 2) + pow(Point1.y - Point2.y, 2));
double height = area / bottom * 2;
return height;
}
/*
* 將要保留的點(diǎn)添加到pointIndexsToKeep中
*/
void DouglasPeuckerReduction(vector<CPoint>points, int firstPoint, int lastPoint, double tolerance, list<int> &pointIndexsToKeep)
{
double maxDistance = 0;
int indexFarthest = 0;
for (int index = firstPoint; index < lastPoint; index++)
{
double distance = PerpendicularDistance
(points[firstPoint], points[lastPoint], points[index]);
if (distance > maxDistance)
{
maxDistance = distance;
indexFarthest = index;
}
}
if (maxDistance > tolerance && indexFarthest != 0)
{
//Add the largest point that exceeds the tolerance
pointIndexsToKeep.push_back(indexFarthest);
DouglasPeuckerReduction(points, firstPoint,
indexFarthest, tolerance, pointIndexsToKeep);
DouglasPeuckerReduction(points, indexFarthest,
lastPoint, tolerance, pointIndexsToKeep);
}
}
/*
* 對(duì)一組點(diǎn)進(jìn)行抽稀
*/
vector<CPoint> DouglasPeucker(vector<CPoint> &Points, double Tolerance)
{
if (Points.empty() || (Points.size() < 3))
return Points;
int firstPoint = 0;
int lastPoint = Points.size() - 1;
list<int> pointIndexsToKeep ;
//Add the first and last index to the keepers
pointIndexsToKeep.push_back(firstPoint);
pointIndexsToKeep.push_back(lastPoint);
//The first and the last point cannot be the same
while (Points[firstPoint]==(Points[lastPoint]))
{
lastPoint--;
}
DouglasPeuckerReduction(Points, firstPoint, lastPoint,
Tolerance, pointIndexsToKeep);
vector<CPoint> returnPoints ;
pointIndexsToKeep.sort();
list<int>::iterator theIterator;
for( theIterator = pointIndexsToKeep.begin(); theIterator != pointIndexsToKeep.end(); theIterator++ )
{
returnPoints.push_back(Points[*theIterator]);
}
return returnPoints;
}