2009-06-20 24 views
9

¿Hay alguna manera de averiguar si dos CGPathRefs están cruzados o no? En mi caso, todos los CGPath están teniendo closePath.Intersección CGPathRef

Por ejemplo, estoy teniendo dos caminos. Una ruta es el rectángulo que se gira con un cierto ángulo y la otra es una trayectoria curva. El origen de dos rutas cambiará con frecuencia. En algún momento pueden cruzarse. Quiero saber cuándo están cruzados. Por favor, avíseme si tiene alguna solución.

Gracias de antemano

Respuesta

0

1) No existe ninguna CGPath API para hacer esto. Pero, puedes hacer los cálculos para resolverlo. Eche un vistazo a este artículo de wikipedia en Bezier curves para ver cómo se implementan las curvas en CGPath.

2) Esto va a ser lento en el iPhone, pero podría llenar ambos caminos en un búfer en diferentes colores (por ejemplo, rojo y azul, con alfa = 0.5) y luego recorrer el búfer para encontrar cualquier pixel que ocurra en las intersecciones. Esto será extremadamente lento.

+0

# 2 en realidad es muy rápido y es una excelente solución para ciertos tipos de problemas (como buscar intersecciones del trazo en lugar del llenado). –

3

Hacer un camino del trazado de recorte, dibujar el otro camino, entonces la búsqueda de píxeles que sobrevivieron al proceso de grapado:

// 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 

Esto funciona porque recorte = intersección.

No olvide que la intersección depende de la definición de interioridad, de los cuales hay varios. Este código usa la regla de relleno del número de cuerda, es posible que desee la regla par impar o alguna otra cosa nuevamente. Si la interioridad no te mantiene despierto por la noche, entonces este código debería estar bien.

Mi respuesta anterior implicó dibujar curvas transparentes en un contexto RGBA. Esta solución es superior a la anterior, ya que es

  1. más simple
  2. utiliza una cuarta parte de la memoria como un contexto de 8 bits en escala de grises es suficiente
  3. evita la necesidad de, código peluda difíciles de depurar la transparencia

¿Quién podría pedir más?

Supongo que podría solicitar una implementación completa, lista para cortar, pero eso arruinaría la diversión y ofuscaría una respuesta simple.

MAYORES, más difícil de entender y menos eficiente RESPUESTA

Dibuje tanto CGPathRefsseparado a 50% de transparencia en una, CGBitmapContextCreate búfer de memoria RGBA -ed cero y de verificación de los valores de los píxeles> 128. Esto funciona en cualquier plataforma que admita CoreGraphics (es decir, iOS y OSX).

En pseudocódigo

// 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 

Vamos a la resolución de las versiones rasterizadas sea su precisión y elegir la precisión para satisfacer sus necesidades de rendimiento.

+0

Gracias por la solución. Pero, no soy tan bueno en Core Graphics. ¿Cómo podemos recuperar y verificar píxeles no blancos? –

+0

Downvoted, porque esto no parece funcionar, no agregará los valores de color en iOS, simplemente los reemplaza. Miré a través de los documentos e intenté diferentes configuraciones de espacio de color para ver si había alguna manera de hacerlo funcionar, pero no tuve éxito. – Adam

+0

Si no puede encontrar la manera de que su código de transparencia funcione, comience una nueva pregunta. –

-1

Para iOS, la mezcla alfa parece ser ignorada.

En su lugar, se puede hacer una mezcla de colores, que conseguirá el mismo efecto, pero no necesita alpha:

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

Los píxeles de salida de la imagen serán:

  • RGB = 0 , 0,0 = (0.0f) ... sin ruta
  • RGB = 64,64,64 = (0.25f) ... una ruta, ninguna intersección
  • RGB = 128,128,128 = (0.5f) .. . dos caminos, intersección encontrada

código completo de dibujo:

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

de código completo para el control de la producción:

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

Y, por último, aquí hay un código ligeramente modificada de otro SO responder ... código completo para la creación de un espacio RGB en iOS 4, iOS 5, que admitirá las funciones anteriores:

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

iOS no ignora alfa. Verifique su código: ¿ha intentado crear el CGContext con kCGImageAlphaPremultipliedLast? –

+0

Creo que su problema de transparencia se debió al hecho de que creó un mapa de bits ARGB pero especificó un color RGBA. En ARGB, su color semiTransparente es un azul aciano bonito con un 50% de alfa. Prueba el inequívoco CGContextSetRGBFillColor y avísame si eso lo soluciona. PD. Actualicé mi solución para evitar estas molestas cuestiones de transparencia. –

+0

kCGImageAlphaPremultipliedLast (y todas las variantes) han fallado. – Adam