2009-06-20 3 views
9

Existe-t-il un moyen de savoir si deux CGPathRefs sont intersectés ou non. Dans mon cas, tous les CGPaths ont closePath.intersection CGPathRef

Par exemple, j'ai deux chemins. Un chemin est le rectangle qui est tourné avec un certain angle et l'autre chemin est un chemin courbe. L'origine de deux chemins changera fréquemment. À un moment donné, ils peuvent se croiser. Je veux savoir quand ils sont entrecoupés. S'il vous plaît laissez-moi savoir si vous avez une solution.

Merci à l'avance

Répondre

0

1) Il n'y a pas API CGPath pour le faire. Mais, vous pouvez faire le calcul pour le comprendre. Jetez un oeil à cet article wikipedia sur Bezier curves pour voir comment les courbes dans CGPath sont implémentées. 2) Cela va être lent sur l'iPhone, mais vous pouvez remplir les deux chemins dans un tampon de couleurs différentes (disons, rouge et bleu, avec alpha = 0.5), puis parcourir le tampon pour trouver tous les pixels qui se produisent aux intersections. Ce sera extrêmement lent.

+0

# 2 est en fait très rapide, et est une excellente solution pour certains types de problèmes (comme la recherche d'intersections de la course plutôt que le remplissage). –

3

Faire un chemin le chemin de détourage, dessiner l'autre chemin, puis recherchez les pixels qui ont survécu au processus de découpage:

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

Cela fonctionne parce que écrêtage = intersection.

Ne pas oublier cette intersection dépend de la définition de l'intériorité, dont il existe plusieurs. Ce code utilise la règle de remplissage des numéros d'enroulement, vous pourriez vouloir à nouveau la règle paire impaire ou quelque chose d'autre. Si l'intériorité ne vous empêche pas de dormir la nuit, alors ce code devrait être bon.

Ma réponse précédente implique dessiner des courbes transparentes à un contexte RGBA. Cette solution est supérieure à l'ancien parce qu'il est

  1. plus simple
  2. utilise un quart de la mémoire en tant que contexte de nuances de gris 8bit suffit
  3. REND la nécessité de velu, difficiles à déboguer le code de transparence

Qui pourrait demander plus?

Je suppose que vous pourriez demander une implémentation complète, prête à couper et à coller, mais cela gâcherait le plaisir et obscurcirait une réponse autrement simple.

ANCIENS, DUR POUR COMPRENDRE ET MOINS PERFORMANT RÉPONSE

Dessiner les deux CGPathRefsséparément à 50% la transparence dans une mise à zéro, CGBitmapContextCreate -ed mémoire tampon RGBA et vérifier toutes les valeurs de pixel> 128. Cette works sur n'importe quelle plate-forme prenant en charge CoreGraphics (c.-à-d. iOS et OSX).

En pseudocode

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

Que la résolution des versions tramée soit votre précision et choisissez la précision en fonction de vos besoins de performance.

+0

Merci pour la solution. Mais, je ne suis pas très bon à Core Graphics. Comment pouvons-nous récupérer et vérifier les pixels non blancs. –

+0

Downvoted, car cela ne semble pas fonctionner - il ne sera pas AJOUTER les valeurs de couleur sur iOS, il suffit de les remplacer. J'ai regardé à travers les docs et j'ai essayé différentes configurations de colorspace pour voir s'il y avait un moyen de le faire fonctionner, mais pas de succès – Adam

+0

Si vous ne trouvez pas un moyen de faire fonctionner votre code de transparence, lancez une nouvelle question. –

-1

Pour iOS, le mélange alpha semble être ignoré.

Au lieu de cela, vous pouvez faire un mélange de couleurs, ce qui permettra d'atteindre le même effet, mais n'a pas besoin alpha:

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

pixels en sortie image sera:

  • RVB = 0 , 0,0 = (0,0f) ... aucun chemin
  • RVB = 64,64,64 = (0,25f) ... un chemin, aucune intersection
  • RVB = 128,128,128 = (0,5f). deux chemins, intersection trouvée

Code complet pour le dessin:

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

Code complet pour le contrôle de sortie:

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

Et enfin, voici un code légèrement modifié d'une autre SO répondre ... code complet pour la création un espace RVB sur iOS 4, iOS 5, qui prendra en charge les fonctions ci-dessus:

- (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 n'ignore pas alpha. Vérifiez votre code - avez-vous essayé de créer le CGContext avec kCGImageAlphaPremultipliedLast? –

+0

Je pense que votre problème de transparence était dû au fait que vous avez créé un bitmap ARGB mais spécifié une couleur RGBA. En ARGB, votre couleur semi-transparente est un joli bleu de bleuet avec 50% d'alpha. Essayez le CGContextSetRGBFillColor univoque et faites-moi savoir si cela le corrige. p.s. J'ai mis à jour ma solution pour éviter ce problème de transparence. –

+0

kCGImageAlphaPremultipliedLast (et toutes les variantes) a échoué. – Adam