介紹
Douglas-Peukcer算法由D.Douglas和T.Peueker于1973年提出,是線狀要素抽稀的經典算法。用它處理大量冗余的幾何數據點,既可以達到數據量精簡的目的,有可以在很大程度上保留幾何形狀的骨架。
算法思路
將待處理曲線的首末點虛連一條直線,求所有中間點與直線的距離,并找出最大距離值dmax ,用dmax與抽稀閾值tolerance相比較:
若dmax < tolerance,這條曲線上的中間點全部舍去;
若dmax ≥ tolerance,則以該點為界,把曲線分為兩部分,對這兩部分曲線重復上述過程,直至所有的點都被處理完成。
用途
可用于圖表的繪制和地圖繪制線減少軌跡點
Demo效果
遞歸核心代碼
- (NSArray *)reduceWithDouglasPeuker:(NSArray *)points tolerance:(CGFloat)tolerance
{
if (tolerance <= 0 || points.count < 3) {
return points;
}
NSInteger index = 0;
CGFloat dmax = 0.f;
// 遍歷除首尾點以外的點
for (NSInteger i = 1; i < points.count - 1; i ++) {
CGFloat distance = [self getDistanceWithStartPoint:[points.firstObject CGPointValue] endPoint:[points.lastObject CGPointValue] betweenPoint:[points[i] CGPointValue]];
if (distance > dmax)
{
dmax = distance;
index = i;
}
}
// 遞歸
if (dmax >= tolerance) {
NSArray *resultList = [self reduceWithDouglasPeuker:[points subarrayWithRange:NSMakeRange(0, index)] tolerance:tolerance];
return [resultList arrayByAddingObjectsFromArray:[self reduceWithDouglasPeuker:[points subarrayWithRange:NSMakeRange(index, points.count - index)] tolerance:tolerance]];
} else {
return @[points.firstObject, points.lastObject];
}
}
// 鞋帶公式求三角形的高, 也可以用海倫公式
- (CGFloat)getDistanceWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint betweenPoint:(CGPoint)point
{
CGFloat dx = startPoint.x - endPoint.x;
CGFloat dy = startPoint.y - endPoint.y;
CGFloat sxey = startPoint.x * endPoint.y;
CGFloat exsy = endPoint.x * startPoint.y;
// 起止點的長度
CGFloat length = sqrt(dx * dx + dy * dy);
return fabs(dy * point.x - dx * point.y + sxey - exsy) / length;
}