【问题标题】:CGPathRef intersectionCGPathRef 交点
【发布时间】:2009-06-20 15:03:45
【问题描述】:

有没有办法找出两个 CGPathRef 是否相交。在我的例子中,所有的 CGPaths 都有 closePath。

例如,我有两条路径。一条路径是旋转一定角度的矩形,另一条路径是弯曲路径。两条路径的原点会经常变化。在某些时候,它们可能会相交。我想知道它们何时相交。如果您有任何解决方案,请告诉我。

提前致谢

【问题讨论】:

    标签: iphone cocoa cocoa-touch core-graphics


    【解决方案1】:

    将一条路径设为剪切路径,绘制另一条路径,然后搜索在剪切过程中幸存下来的像素:

    // 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 上下文中。此解决方案优于旧解决方案,因为它是

    1. 更简单
    2. 使用四分之一的内存作为 8 位灰度上下文就足够了
    3. 无需繁琐、难以调试的透明代码

    谁能要求更多?

    我想你可以要求一个完整的实现,准备好剪切粘贴,但这会破坏乐趣并混淆原本简单的答案。

    年龄较大、较难理解且回答效率较低

    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
    

    让光栅化版本的分辨率成为您的精度,并选择适合您性能需求的精度。

    【讨论】:

    • 感谢您的解决方案。但是,我不擅长核心图形。我们如何检索和检查非白色像素。
    • 否决,因为这似乎不起作用 - 它不会在 iOS 上添加颜色值,它只是替换它们。我查看了文档并尝试了不同的色彩空间配置,看看是否有办法让它工作,但没有成功
    • 如果您找不到让透明度代码发挥作用的方法,请提出一个新问题。
    • 如果你的代码可以回答这个问题,那就太好了。现在,这是一个理论上的答案,在实践中似乎不起作用(问题被标记为 iPhone,而您的答案是“如果 .. iPhone ... 可能必须这样做”。我的经验:试过了,没用) .我不希望其他人走上我走的同一条死胡同。
    • 这不是一个剪切和粘贴的答案,您需要做一些工作。任何人都可以看到 iOS 可以绘制透明路径,所以你的代码肯定有 bug。开始“为什么这段代码不绘制透明的 CGPathRefs?”问题。我在答案中添加了更多细节,但我认为您的 CGContext 配置错误,或者您没有单独绘制路径或任何其他数量的问题。一旦你让它工作,请随意发布你的代码,这将是一个更好的答案。
    【解决方案2】:

    1) 没有任何CGPath API 可以执行此操作。但是,你可以做数学来弄清楚。查看Bezier curves 上的这篇维基百科文章,了解 CGPath 中的曲线是如何实现的。

    2) 我希望这在 iPhone 上会很慢,但是您可以将两条路径填充到不同颜色的缓冲区中(例如,红色和蓝色,alpha=0.5),然后遍历缓冲区以找到任何出现在交叉点的像素。这将非常缓慢。

    【讨论】:

    • #2 实际上非常快,对于某些类型的问题(例如寻找笔划的交叉点而不是填充)是一个很好的解决方案。
    【解决方案3】:

    对于 iOS,alpha 混合似乎被忽略了。

    相反,您可以进行颜色混合,这将达到相同的效果,但不需要 alpha:

    CGContextSetBlendMode(context, kCGBlendModeColorDodge);
    CGFloat semiTransparent[] = { .5,.5,.5,1};
    

    输出图像中的像素为:

    • RGB = 0,0,0 = (0.0f) ... 无路径
    • RGB = 64,64,64 = (0.25f) ... 一条路径,没有交叉点
    • RGB = 128,128,128 = (0.5f) ... 两条路径,找到交点

    完整的绘图代码:

    -(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;
    }
    

    【讨论】:

    • iOS 不会忽略 alpha。检查您的代码 - 您是否尝试过使用 kCGImageAlphaPremultipliedLast 创建 CGContext?
    • 我认为您的透明度问题是由于您创建了 ARGB 位图但指定了 RGBA 颜色。在 ARGB 中,您的半透明颜色是具有 50% alpha 的漂亮矢车菊蓝色。尝试明确的 CGContextSetRGBFillColor 并让我知道是否可以解决它。 p.s.我已经更新了我的解决方案以避免这种令人烦恼的透明度问题。
    • kCGImageAlphaPremultipliedLast(和所有变体)失败。
    • 方法称为“ARGB”,但其中没有任何内容指定 alpha 通道的去向 - AFAICS 从阅读 Apple 的文档,位图没有明确的 alpha 通道,Apple 根据内部处理它传入颜色参考。 Apple 的文档将该颜色参考数组定义为 RGBA。还是我在这里错过了什么?
    • alpha 排在第一位是因为 kCGImageAlphaPremultipliedFirst,记录在 CGImage.h 中。位图可以有一个 alpha 通道,CGColorRef 确实定义了顺序,但是您使用的是最有可能取决于位图布局的裸组件数组(cut'n'paste mixup?)。不知道为什么 kCGImageAlphaPremultipliedLast 会失败,它自 2009 年以来一直为我工作。RGBA 并没有什么特别之处,只是它与 OpenGLES 1 纹理完美匹配。
    猜你喜欢
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多