道格拉斯-普克抽稀演算法,是用來對大量冗餘的圖形資料點進行壓縮以提取必要的資料點。
該演算法實現抽稀的過程是:
1)對曲線的首末點虛連一條直線,求曲線上所有點與直線的距離,並找出最大距離值dmax,用dmax與事先給定的閾值D相比:
2)若dmax<D,則將這條曲線上的中間點全部捨去;則該直線段作為曲線的近似,該段曲線處理完畢。
若dmax≥D,保留dmax對應的座標點,並以該點為界,把曲線分為兩部分,對這兩部分重複使用該方法,即重複1),2)步,直到所有dmax均<D,即完成對曲線的抽稀。
顯然,本演算法的抽稀精度也與閾值相關,閾值越大,簡化程度越大,點減少的越多,反之,化簡程度越低,點保留的越多,形狀也越趨於原曲線。
bool SimplifyCurve(CurveVertexes &prevPts, CurveVertexes &nextPts, double tolerance)
{
// Exception
if(!prevPts.size() || tolerance < 0.)
{
return false;
}
nextPts.clear();
// Initialization
int ptSize = prevPts.size();
SimpStack stack(ptSize);
// Loop until two vertex meet with ...
while(stack.m_curOrder >= 0)
{
//Get Top Elemelt;
int lOrder = stack.m_lOrders[stack.m_curOrder];
int rOrder = stack.m_rOrders[stack.m_curOrder];
stack.m_curOrder--;
//
CGeoPoint<double> lPt = prevPts[lOrder];
CGeoPoint<double> rPt = prevPts[rOrder];
// Max proj distance and which point
double maxProjDist = 0.0;
int whichPt = 0;
// Not in the same X or Y direction
if((rPt.m_x - lPt.m_x) != 0 || (rPt.m_y - lPt.m_y) != 0)
{
// Get Max Distance;
int i = lOrder+1;
for(; i < rOrder; i++)
{
double factor = 0.;
CGeoPoint<double> result;
double projDist = CVectOP<double>::Point2Line(prevPts[lOrder], prevPts[rOrder], prevPts[i], factor, result);
if(projDist > maxProjDist )
{
maxProjDist = projDist;
whichPt = i;
}
}
}
else
{
if(rOrder - lOrder > 1)
{
stack.m_curOrder++;
stack.m_lOrders[stack.m_curOrder] = lOrder;
stack.m_rOrders[stack.m_curOrder] = rOrder-1;
}
}
// Based on this point to split this point array
if(maxProjDist > tolerance) //大於給定值接著二分
{
stack.m_isRetain[whichPt] = true;
if(rOrder - lOrder > 1)
{
stack.m_curOrder++;
stack.m_lOrders[stack.m_curOrder] = lOrder;
stack.m_rOrders[stack.m_curOrder] = whichPt;
stack.m_curOrder++;
stack.m_lOrders[stack.m_curOrder] = whichPt;
stack.m_rOrders[stack.m_curOrder] = rOrder;
}
}
else //小於給定值捨去中間點,留下首末點
{
stack.m_isRetain[lOrder] = true;
stack.m_isRetain[rOrder] = true;
}
}
int i = 0;
for(; i < ptSize; i++)
{
if(!stack.m_isRetain[i])
{
continue;
}
nextPts.push_back(prevPts[i]);
}
return true;
}