我想到了一种方法来实现这个功能。虽然不完美,但考虑到这个问题已经被点赞了几次,我认为其他人也会想看看这种技术。我使用的技术是将要测试的所有项绘制到位图上下文中,然后将进度线的新段绘制到另一个位图上下文中。使用按位运算符比较这些上下文中的数据,如果发现任何重叠,则宣布命中。
这种技术的思想是测试新绘制线段的每个部分与之前绘制的所有线段甚至是同一条线段的早期部分相对比。换句话说,这种技术将检测到当一条线穿过另一条线时以及当它穿过自己时。
演示该技术的示例应用程序可在此处找到:LineSample.zip。
命中测试的核心在我的LineView对象中完成。以下是两个关键方法:
- (CGContextRef)newBitmapContext {
CGContextRef bitmapContext =
CGBitmapContextCreate(NULL,
self.bounds.size.width,
self.bounds.size.height,
8,
self.bounds.size.width,
NULL,
kCGImageAlphaOnly);
CGContextSetShouldAntialias(bitmapContext, NO);
return bitmapContext;
}
- (BOOL)line:(Line *)line canExtendToPoint:(CGPoint) newPoint {
if (line.failed) {
return NO;
}
BOOL ok = YES;
CGContextRef segmentContext = [self newBitmapContext];
CGContextSetLineWidth(segmentContext, 2);
CGPoint lastPoint = [[[line nodes] lastObject] point];
CGContextMoveToPoint(segmentContext, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(segmentContext, newPoint.x, newPoint.y);
CGContextStrokePath(segmentContext);
unsigned char *completedData = CGBitmapContextGetData(hitCompletedContext);
unsigned char *progressData = CGBitmapContextGetData(hitProgressContext);
unsigned char *segmentData = CGBitmapContextGetData(segmentContext);
size_t bytesPerRow = CGBitmapContextGetBytesPerRow(segmentContext);
size_t height = CGBitmapContextGetHeight(segmentContext);
size_t len = bytesPerRow * height;
for (int i = 0; i < len; i++) {
if ((completedData[i] | progressData[i]) & segmentData[i]) {
ok = NO;
break;
}
}
CGContextRelease(segmentContext);
if (ok) {
int numberOfSegments = [[line nodes] count] - 1;
if (numberOfSegments > 0) {
CGPoint secondToLastPoint = [[[line nodes] objectAtIndex:numberOfSegments-1] point];
CGContextSetLineWidth(hitProgressContext, 1);
CGContextMoveToPoint(hitProgressContext, secondToLastPoint.x, secondToLastPoint.y);
CGContextAddLineToPoint(hitProgressContext, lastPoint.x, lastPoint.y);
CGContextStrokePath(hitProgressContext);
}
} else {
line.failed = YES;
[linesFailed addObject:line];
}
return ok;
}
我希望听到建议或看到改进。比如说,只检查新段的边界矩形而不是整个视图会更快。