【发布时间】:2009-06-20 15:03:45
【问题描述】:
有没有办法找出两个 CGPathRef 是否相交。在我的例子中,所有的 CGPaths 都有 closePath。
例如,我有两条路径。一条路径是旋转一定角度的矩形,另一条路径是弯曲路径。两条路径的原点会经常变化。在某些时候,它们可能会相交。我想知道它们何时相交。如果您有任何解决方案,请告诉我。
提前致谢
【问题讨论】:
标签: iphone cocoa cocoa-touch core-graphics
有没有办法找出两个 CGPathRef 是否相交。在我的例子中,所有的 CGPaths 都有 closePath。
例如,我有两条路径。一条路径是旋转一定角度的矩形,另一条路径是弯曲路径。两条路径的原点会经常变化。在某些时候,它们可能会相交。我想知道它们何时相交。如果您有任何解决方案,请告诉我。
提前致谢
【问题讨论】:
标签: iphone cocoa cocoa-touch core-graphics
将一条路径设为剪切路径,绘制另一条路径,然后搜索在剪切过程中幸存下来的像素:
// initialise and erase context
CGContextAddPath(context, path1);
CGContextClip(context);
// set fill colour to intersection colour
CGContextAddPath(context, path2);
CGContextFillPath(context);
// search for pixels that match intersection colour
这是可行的,因为裁剪 = 相交。
不要忘记交集取决于内在性的定义,其中有几个。此代码使用缠绕数填充规则,您可能需要奇偶规则或其他规则。如果内在性不能让你彻夜难眠,那么这段代码应该没问题。
我之前的回答涉及将透明曲线绘制到 RGBA 上下文中。此解决方案优于旧解决方案,因为它是
谁能要求更多?
我想你可以要求一个完整的实现,准备好剪切粘贴,但这会破坏乐趣并混淆原本简单的答案。
年龄较大、较难理解且回答效率较低
将CGPathRefs分别以 50% 的透明度绘制到一个归零的CGBitmapContextCreate-ed RGBA 内存缓冲区中,并检查任何大于 128 的像素值。这适用于任何支持 CoreGraphics (即 iOS 和 OSX)。
在伪代码中
// zero memory
CGContextRef context;
context = CGBitmapContextCreate(memory, wide, high, 8, wide*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
CGContextSetRGBFillColor(context, 1, 1, 1, 0.5); // now everything you draw will be at 50%
// draw your path 1 to context
// draw your path 2 to context
// for each pixel in memory buffer
if(*p > 128) return true; // curves intersect
else p+= 4; // keep looking
让光栅化版本的分辨率成为您的精度,并选择适合您性能需求的精度。
【讨论】:
1) 没有任何CGPath API 可以执行此操作。但是,你可以做数学来弄清楚。查看Bezier curves 上的这篇维基百科文章,了解 CGPath 中的曲线是如何实现的。
2) 我希望这在 iPhone 上会很慢,但是您可以将两条路径填充到不同颜色的缓冲区中(例如,红色和蓝色,alpha=0.5),然后遍历缓冲区以找到任何出现在交叉点的像素。这将非常缓慢。
【讨论】:
对于 iOS,alpha 混合似乎被忽略了。
相反,您可以进行颜色混合,这将达到相同的效果,但不需要 alpha:
CGContextSetBlendMode(context, kCGBlendModeColorDodge);
CGFloat semiTransparent[] = { .5,.5,.5,1};
输出图像中的像素为:
完整的绘图代码:
-(void) drawFirst:(CGPathRef) first second:(CGPathRef) second into:(CGContextRef)context
{
/** setup the context for DODGE (everything gets lighter if it overlaps) */
CGContextSetBlendMode(context, kCGBlendModeColorDodge);
CGFloat semiTransparent[] = { .5,.5,.5,1};
CGContextSetStrokeColor(context, semiTransparent);
CGContextSetFillColor(context, semiTransparent);
CGContextAddPath(context, first);
CGContextFillPath(context);
CGContextStrokePath(context);
CGContextAddPath(context, second);
CGContextFillPath(context);
CGContextStrokePath(context);
}
检查输出的完整代码:
[self drawFirst:YOUR_FIRST_PATH second:YOUR_SECOND_PATH into:context];
// Now we can get a pointer to the image data associated with the bitmap
// context.
BOOL result = FALSE;
unsigned char* data = CGBitmapContextGetData (context);
if (data != NULL) {
for( int i=0; i<width; i++ )
for( int k=0; k<width; k++ )
{
//offset locates the pixel in the data from x,y.
//4 for 4 bytes of data per pixel, w is width of one row of data.
int offset = 4*((width*round(k))+round(i));
int alpha = data[offset];
int red = data[offset+1];
int green = data[offset+2];
int blue = data[offset+3];
if( red > 254 )
{
result = TRUE;
break;
}
}
最后,这是来自另一个 SO 答案的稍微修改的代码......用于在 iOS 4、iOS 5 上创建 RGB 空间的完整代码,它将支持上述功能:
- (CGContextRef) createARGBBitmapContextWithFrame:(CGRect) frame
{
/** NB: this requires iOS 4 or above - it uses the auto-allocating behaviour of Apple's method, to reduce a potential memory leak in the original StackOverflow version */
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
// Get image width, height. We'll use the entire image.
size_t pixelsWide = frame.size.width;
size_t pixelsHigh = frame.size.height;
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
// Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return NULL;
}
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (NULL,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst
//kCGImageAlphaFirst
);
if (context == NULL)
{
fprintf (stderr, "Context not created!");
}
// Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );
return context;
}
【讨论】: