2013-03-22 13 views
5

Es fällt mir schwer herauszufinden, wie man den Schnittpunkt zweier geschlossener NSBezierPath-Objekte in Kakao bestimmt. Ich habe online recherchiert und konnte die Antwort bisher nicht finden.Wie kann man feststellen, ob sich NSBezierPaths in Cocoa schneiden?

Hier ist was ich habe. enter image description here

Ich muss eine Art von einer Methode schreiben, die in all diesen Fällen wahr zurückgeben würde.

Was ich so weit zu denken ist das Rechteck zu glätten von bezierPathByFlatteningPath und anschließend jedes Element nehmen (als Liniensegment) mit elementAtIndex: associatedPoints: in es durch jeden Punkt zu gehen und prüfen, ob die zweite Objekt (Rechteck oder Ellipse) enthält diesen Punkt (containsPoint:).

Aber ich weiß nicht, wie alle durch die Punkte eines Segments gehen ...

Wenn jemand einen Tipp oder eine Idee hat, dass ich es könnte helfen, wirklich zu schätzen würde!

+2

Wenn Sie daran interessiert sind nur in Rechtecke sind, dann CGRectIsEmpty (CGRectIntersection (R1, R2)) kehrt JA ist sie sich nicht schneiden, sonst NO. – verec

+0

Oh sorry ... Ich schätze total vergessen zu erwähnen, dass ich auch Ellipsen habe ... Ich werde meine Frage aktualisieren –

+1

Wenn Sie an einer ungefähren Lösung interessiert sind, die Ihnen falsche Positive liefert (zB: wenn die Antwort NEIN ist, dann schneiden Sie sich definitiv NICHT, wenn die Antwort JA ist, dann schneiden sie die meiste Zeit, aber nicht immer), verwenden Sie die Eclipse-Begrenzungsbox als Rechteck, um die Kreuzung mit einem anderen Rechteck/einer Eclipse-Begrenzungsbox zu berechnen ... – verec

Antwort

3

Wenn Sie 2 Bezierpfad Rechtecke haben und wissen, die jeweils ihren Rahmen, dann können Sie verwenden NSIntersectsRect():

NSRect rect1 = NSMakeRect(20.0, 150.0, 300.0, 100.0); 
NSRect rect2 = NSMakeRect(100.0, 100.0, 100.0, 200.0); 

[[NSColor redColor] set]; 

[NSBezierPath strokeRect:rect1]; 
[NSBezierPath strokeRect:rect2]; 

BOOL intersects = NSIntersectsRect(rect1, rect2); 

NSLog(@"intersects == %@", (intersects ? @"YES" : @"NO")); 

Produziert:

enter image description here

In diesem Fall würde es log intersects == YES .

2

Hier ist eine ziemlich schnelle und saubere Lösung. Es funktioniert auch, um mehrere Pfade vs eins zu testen, was in Ordnung ist, nicht wahr?

Es funktioniert auf CGBezier (iOS und MacOS kompatibel)

• 1 - Erstellen Sie die necessaries Kontexte

Erstellen Sie eine 16-Bit, eine Komponente (kein Alpha) Graphics Port mit der gleichen Größe als die Ansicht.

  • Nicht diesen Kontext bei jedem Test neu erstellen, es ist zeitaufwendig. Erstellen Sie es nur neu, wenn die Größe der Ansicht geändert wird.
  • wir nennen diesen Kontext computeContext

Erstellen eines 16 Bit, eine Komponente (kein Alpha) Graphics Port von 1 Pixel Breite und Höhe.

  • Lassen Sie uns diesen Zusammenhang nennen Testcontext

• 2 - Wenn Sie die Pfade Kreuzung testen müssen:

Wir in arbeiten computeContext für die folgenden Operationen:

  • Löschen der Kontext (Es wird voll schwarz)
  • den Kontext Sie alle testen möchten, auf den Pfad Clip
  • Füllen von Pfaden im Vergleich zu dem Sie mit weißer Farbe
  • (Von jetzt Sie testen möchten, muss nicht im computeContext enthalten sein.) das Bild holen und es in dem Testcontext mit so etwas wie zeichnen:
CGImageRef clippedPathsImage = CGBitmapContextCreateImage(computeContext); 
CGRect  onePixSquare = CGRectMake(0,0,1,1); 
CGContextDrawImage(testContext, onePixSquare, clippedPathsImage); 

(Keine Sorge, Bilderzeugungsfunktion ist schnell Es ist malloc keine Speicher, da die. Bits werden im BitmapContext zugewiesen)

Wir sind fertig!

long* data = CGBitmapContextGetData(testContext); 
BOOL intersects = (*data!=0); 
  • Dies ist viel schneller als eine Zusammensetzung mit Alpha-Zeichnung tun Werte

  • Dies ist viel schneller als in einem großen Bild alle Pixel Testen Die Bildskalierung intern gemacht wird, Hardware beschleunigt. Es ist also keine große Sache.

Wenn Sie aber wollen noch mehr beschleunigen und weniger Präzision leisten können, können Sie eine kleinere computeContext erstellen, für exemple 25% der Ansicht, Größe und machen alle Pfade mit einer Skala Matrix-Transformation.

Die Übertragung im 1-Pixel-Kontext wird dann schneller sein, aber Sie sind nicht sicher, Schnittpunkte zu erkennen, die kleiner als 4 Pixel sind (mit einer 25% -Skala, Logic).

Verwenden Sie keine 8 Bits grau. Ich denke nicht, dass es den Prozess beschleunigt, und Sie verlieren viel Präzision, wenn Sie auf 1 Pixel reduzieren. Genug zum Scheitern.

Vergessen Sie nicht, dass der erste Test, bevor Sie den harten Weg verwenden, ist, Grenzüberschreitungen zu testen!

Das ist alles ein GitHub mit der Bibliothek eröffnete

ist;) https://github.com/moosefactory

hoffe, das hilft, Prost!;)


Hier ist der Code, um einen 16 Bit grauen Kontext zu erstellen. Es kann kürzer sein, aber ich deklariere Variablen, um es klar zu machen. Sie benötigen keine BitmapInfo (letzter Parameter), da es keinen AlphaValue gibt, und wir verwenden kein Float-Format.

-(CGContextRef)createComputeContext 
{ 
    size_t w = (size_t)self.bounds.size.width; 
    size_t h = (size_t)self.bounds.size.height; 
    size_t nComps = 1; 
    size_t bits = 16; 
    size_t bitsPerPix = bits*nComps; 
    size_t bytesPerRow = bitsPerPix*w;  
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); 

    CGContextRef bmContext = CGBitmapContextCreate(NULL, w, h, bits, bytesPerRow, cs, 0); 

    return bmContext; 
} 
+0

Das ist interessant, aber Sie sollten nicht behaupten, dass es hardwarebeschleunigt ist, es sei denn, Sie haben Beweise dafür. Diese Art von CG-Zeichnung - sowohl Pfadrasterung als auch Bildzeichnung in einen Bitmap-Kontext - findet im Allgemeinen auf der CPU statt. –

+0

Hallo Kurt, danke für die Präzision. Ich erwähnte nur GPU-Beschleunigung für die Bildskalierung. Ich weiß, dass alle Bitmap-Operationen von der GPU in CIImage und CALayer behandelt werden. Ich glaube nicht, CoreGraphics ist anders ... Vielleicht braucht es ein wenig Nachforschungen;) Prost. – Moose