2009-06-20 10 views
9

Gibt es eine Möglichkeit, herauszufinden, ob zwei CGPathRefs geschnitten werden oder nicht. In meinem Fall haben alle CGPaths closePath.CGPathRef Schnittpunkt

Zum Beispiel habe ich zwei Wege. Ein Pfad ist das Rechteck, das mit einem bestimmten Winkel gedreht wird, und der andere Pfad ist ein gekrümmter Pfad. Zwei Pfade Herkunft wird sich häufig ändern. Irgendwann können sie sich schneiden. Ich möchte wissen, wann sie durchschnitten werden. Bitte lassen Sie mich wissen, wenn Sie eine Lösung haben.

Vielen Dank im Voraus

Antwort

0

1) Es gibt keinen CGPath API, dies zu tun. Aber Sie können die Mathematik tun, um es herauszufinden. Werfen Sie einen Blick auf diesen Wikipedia-Artikel unter Bezier curves, um zu sehen, wie die Kurven in CGPath implementiert werden.

2) Dies wird langsam sein auf dem iPhone Ich würde erwarten, aber Sie könnten beide Pfade in einen Puffer in verschiedenen Farben (sagen wir rot und blau, mit Alpha = 0,5) füllen und dann durch den Puffer zu finden alle Pixel, die an Schnittpunkten auftreten. Dies wird extrem langsam sein.

+0

# 2 ist tatsächlich sehr schnell und ist eine ausgezeichnete Lösung für bestimmte Arten von Problemen (wie zum Beispiel nach Überschneidungen des Strichs anstatt der Füllung suchen). –

3

Machen Sie einen Pfad des Beschneidungspfad, den anderen Weg zeichnen, dann für Pixel suchen, die den Abschneidevorgang überlebt:

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

Dies funktioniert, weil Clipping = schneiden.

Vergessen Sie nicht, dass Schnittpunkt von der Definition der Innerlichkeit abhängt, von denen es mehrere gibt. Dieser Code verwendet die Füllnummer für die Auffüllnummer, die gerade ungerade Regel oder etwas anderes. Wenn die Interiorität Sie nachts nicht aufhält, sollte dieser Code in Ordnung sein.

Meine vorherige Antwort umfasste das Zeichnen transparenter Kurven in einen RGBA-Kontext. Diese Lösung ist besser als die alten, weil es

  1. einfacher
  2. verwendet ein Viertel des Speichers ist als ein 8-Bit-Graustufen-Kontext genügt
  3. die Notwendigkeit für haarigen vermeidet, schwer zu debuggen Transparenz Code

Wer könnte mehr verlangen?

Ich denke, Sie könnten nach einer vollständigen Implementierung fragen, bereit zu schneiden und zu pasten, aber das würde den Spaß verderben und eine ansonsten einfache Antwort verschleiern.

ÄLTERE, schwerer zu verstehen und weniger effiziente ANTWORT

Draw beide CGPathRefsseparat bei 50% Transparenz in eine Null gesetzt, CGBitmapContextCreate -ed RGBA Speicherpuffer und überprüfen Sie, ob Pixelwerte> 128. Dies funktioniert auf jeder Plattform, die CoreGraphics unterstützt (dh iOS und OSX).

In Pseudo-Code

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

Lassen Sie die Auflösung der gerasterten Versionen Ihre Genauigkeit und die Präzision wählen Sie Ihre Performance-Anforderungen gerecht zu werden.

+0

Danke für die Lösung. Aber ich bin bei Core Graphics nicht so gut. Wie können wir nach nicht weißen Pixeln suchen? –

+0

Downvoted, weil dies nicht funktioniert - es wird nicht die Farbwerte auf iOS hinzufügen, es ersetzt sie einfach. Ich schaute durch die Dokumente und probierte verschiedene Konfigurationen des Farbraums, um zu sehen, ob es einen Weg gab, es zum Laufen zu bringen, aber kein Erfolg. – Adam

+0

Wenn Sie keinen Weg finden, Ihren Transparenzcode zum Laufen zu bringen, beginnen Sie eine neue Frage. –

-1

Für iOS scheint die Alpha-Mischung ignoriert zu werden.

Stattdessen können Sie eine Farbmischung tun, die die gleiche Wirkung erzielen, aber nicht alpha brauchen:

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

Pixel im Ausgangsbild wird:

  • RGB = 0 , 0,0 = (0.0f) ... kein Pfad
  • RGB = 64,64,64 = (0,25f) ... ein Pfad, kein Schnittpunkt
  • RGB = 128,128,128 = (0,5f) .. Zwei Wege, Kreuzung gefunden

kompletter Code für Zeichnung:

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

kompletter Code für die Ausgabe Überprüfung:

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

Und schließlich ist hier ein leicht modifizierte Code von einem anderen SO beantworten ... vollständigen Code für die Erstellung von ein RGB-Platz auf iOS 4, iOS 5, der die obigen Funktionen unterstützt:

- (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 ignoriert Alpha nicht. Überprüfen Sie Ihren Code - haben Sie versucht, den CGContext mit kCGImageAlphaPremultipliedLast zu erstellen? –

+0

Ich glaube, dass Ihr Transparenzproblem auf die Tatsache zurückzuführen ist, dass Sie eine ARGB-Bitmap erstellt und dennoch eine RGBA-Farbe angegeben haben. In ARGB ist deine semitransparente Farbe ein hübsches Kornblumenblau mit 50% Alpha. Versuchen Sie das eindeutige CGContextSetRGBFillColor und lassen Sie mich wissen, wenn das es behebt. p.s. Ich habe meine Lösung aktualisiert, um diese lästige Transparenz zu vermeiden. –

+0

kCGImageAlphaPremultipliedLast (und alle Varianten) fehlgeschlagen. – Adam