通过筛选用户输入创建更适用于应用程序的简单数据集。创建一个最小线段集来匹配自由形态的点。
原理:
一次分析一个由3个点组成的集合。对于每个集合,它将第一个和第三个点围绕第二个点的原点集中,然后计算第一个和第三个点的向量点积。
点积返回的值视两个矢量之间的角度的余弦。如果这些点在一条直线上。即他们之间的角度接近于180度(允许有小误差),则算法会舍弃中间的点。
180度的余弦是-1。该代码舍弃向量夹角余弦小于-0.75的所有点。增加容差能产生更好的结果。但同时可能会忽略用户有意的方向转变。
如果你的目标是检查三角形、正方形和其他简单的多边形。那么这个容差会很可靠。要生成“更漂亮”的线图,则需要适用一个更严格的容差来保留用户提供的细节。
#define POINT(X) [[self.points objectAtIndex:X] CGPointValue]
//从自由形态的手势创建线段
float dotproduct (CGPoint v1, CGPoint v2)
{
float dot = (v1.x * v2.x) + (v1.y * v2.y);
float a = ABS(sqrt(v1.x * v1.x + v1.y * v1.y));
float b = ABS(sqrt(v2.x * v2.x + v2.y * v2.y));
dot /= (a * b);
return dot;
}
- (void) touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event
{
if (!self.points) return;
if (self.points.count < 3) return;
// Create the filtered array
NSMutableArray *newpoints = [NSMutableArray array];
[newpoints addObject:[self.points objectAtIndex:0]];
CGPoint p1 = POINT(0);
int i = 1;
// Add only those points that are inflections
for ( i;i < (self.points.count - 1); i++)
{
CGPoint p2 = POINT(i);
CGPoint p3 = POINT(i+1);
// Cast vectors around p2 origin
CGPoint v1 = CGPointMake(p1.x - p2.x, p1.y - p2.y);
CGPoint v2 = CGPointMake(p3.x - p2.x, p3.y - p2.y);
float dot = dotproduct(v1, v2);
// Colinear items need to be as close as possible to 180 degrees
if (dot < -0.75f) continue;
p1 = p2;
[newpoints addObject:[self.points objectAtIndex:i]];
}
// Add final point
if ([newpoints lastObject] != [self.points lastObject]) [newpoints addObject:[self.points lastObject]];
// Report initial and final point counts
NSLog(@"%@", [NSString stringWithFormat:@"%d points to %d points", self.points.count, newpoints.count]);
// Update with the filtered points and draw
self.points = newpoints;
[self setNeedsDisplay];
}