CGPathRef пересечение - PullRequest
9 голосов
/ 20 июня 2009

Есть ли способ узнать, пересекаются ли два CGPathRef или нет. В моем случае все CGPath имеют closePath.

Например, у меня два пути. Один путь - это прямоугольник, повернутый на некоторый угол, а другой путь - изогнутый путь. Происхождение двух путей будет часто меняться. В какой-то момент они могут пересекаться. Я хочу знать, когда они пересекаются. Пожалуйста, дайте мне знать, если у вас есть какое-либо решение.

Заранее спасибо

Ответы [ 3 ]

3 голосов
/ 21 июня 2009

Сделайте один путь отсечения, нарисуйте другой путь, затем найдите пиксели, которые пережили процесс отсечения:

// 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% прозрачности в нулевом буфере памяти RGBA с CGBitmapContextCreate и проверьте значения пикселей> 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

Позвольте разрешению растрированных версий быть вашей точностью и выберите точность, соответствующую вашим требованиям к производительности.

0 голосов
/ 22 декабря 2011

В iOS альфа-смесь игнорируется.

Вместо этого вы можете сделать цветовую смесь, которая даст тот же эффект, но не требует альфа:

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 ... полный код для создания пространства RGB на iOS 4, iOS 5, который будет поддерживать вышеуказанные функции:

- (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;
}
0 голосов
/ 20 июня 2009

1) Нет никакого CGPath API для этого. Но вы можете сделать математику, чтобы понять это. Взгляните на эту статью в Википедии о кривых Безье , чтобы увидеть, как реализованы кривые в CGPath.

2) Это будет медленным на iPhone, я ожидаю, но вы могли бы заполнить оба пути в буфер разными цветами (скажем, красным и синим, с альфа = 0,5), а затем перебрать буфер, чтобы найти любой пикселей, которые встречаются на перекрестках. Это будет очень медленно.

...