1. Florian Ebeling
  2. VectorBoolean

Commits

Andy Finnell  committed 29b0fbf

reimplementing difference to take care of disjoint and contained contours

  • Participants
  • Parent commits 7bd35be
  • Branches default

Comments (0)

Files changed (1)

File VectorBoolean/FBBezierGraph.m

View file
  • Ignore whitespace
 
 - (void) markCrossingsAsEntryOrExitWithBezierGraphForUnion:(FBBezierGraph *)otherGraph;
 - (void) markCrossingsAsEntryOrExitWithBezierGraphForIntersect:(FBBezierGraph *)otherGraph;
+- (void) markCrossingsAsEntryOrExitWithBezierGraphForDifference:(FBBezierGraph *)otherGraph markInside:(BOOL)markInside;
 
 - (NSArray *) nonintersectingContours;
 - (BOOL) containsContour:(FBBezierContour *)contour;
 
 - (FBBezierGraph *) intersectWithBezierGraph:(FBBezierGraph *)graph
 {
-#if 1
     [self insertCrossingsWithBezierGraph:graph];
     
     [self markCrossingsAsEntryOrExitWithBezierGraphForIntersect:graph];
     [graph removeCrossings];
     
     return result;
-#else
-    BOOL hasCrossings = [self insertCrossingsWithBezierGraph:graph];
-    if ( !hasCrossings ) {
-        // There are no crossings, which means one contains the other, or they're completely disjoint 
-        BOOL subjectContainsClip = [self containsPoint:graph.testPoint];
-        BOOL clipContainsSubject = [graph containsPoint:self.testPoint];
-        
-        // Clean up crossings so the graphs can be reused
-        [self removeCrossings];
-        [graph removeCrossings];
-        
-        if ( subjectContainsClip )
-            return graph; // intersection is the clip graph
-        if ( clipContainsSubject )
-            return self; // intersection is the subject (clip doesn't do anything)
-        
-        // Neither contains the other, which means the intersection is nil
-        return [FBBezierGraph bezierGraph];
-    }
-    
-    [self markCrossingsAsEntryOrExitWithBezierGraph:graph markInside:YES];
-    [graph markCrossingsAsEntryOrExitWithBezierGraph:self markInside:YES];
-    
-    FBBezierGraph *result = [self bezierGraphFromIntersections];
-    [result round];
-    
-    // Clean up crossings so the graphs can be reused
-    [self removeCrossings];
-    [graph removeCrossings];
-    
-    return result;
-#endif
 }
 
 - (void) markCrossingsAsEntryOrExitWithBezierGraphForIntersect:(FBBezierGraph *)otherGraph
 
 - (FBBezierGraph *) differenceWithBezierGraph:(FBBezierGraph *)graph
 {
+#if 1
+    [self insertCrossingsWithBezierGraph:graph];
+    
+    [self markCrossingsAsEntryOrExitWithBezierGraphForDifference:graph markInside:NO];
+    [graph markCrossingsAsEntryOrExitWithBezierGraphForDifference:self markInside:YES];
+    
+    FBBezierGraph *result = [self bezierGraphFromIntersections];
+    [result round];
+    
+    NSArray *ourNonintersectingContours = [self nonintersectingContours];
+    NSArray *theirNonintersectinContours = [graph nonintersectingContours];
+    NSMutableArray *finalNonintersectingContours = [NSMutableArray arrayWithCapacity:[ourNonintersectingContours count] + [theirNonintersectinContours count]];
+    // There are no crossings, which means one contains the other, or they're completely disjoint 
+    for (FBBezierContour *ourContour in ourNonintersectingContours) {
+        BOOL clipContainsSubject = [graph containsContour:ourContour];
+        if ( !clipContainsSubject )
+            [finalNonintersectingContours addObject:ourContour];
+    }
+    for (FBBezierContour *theirContour in theirNonintersectinContours) {
+        BOOL subjectContainsClip = [self containsContour:theirContour];
+        if ( subjectContainsClip )
+            [finalNonintersectingContours addObject:theirContour]; // add it as a hole
+    }
+    
+    // Append the final nonintersecting contours
+    for (FBBezierContour *contour in finalNonintersectingContours)
+        [result addContour:contour];
+    
+    // Clean up crossings so the graphs can be reused
+    [self removeCrossings];
+    [graph removeCrossings];
+    
+    return result;  
+#else
     BOOL hasCrossings = [self insertCrossingsWithBezierGraph:graph];
     if ( !hasCrossings ) {
         // There are no crossings, which means one contains the other, or they're completely disjoint 
     [graph removeCrossings];
     
     return result;
+#endif
 }
 
+- (void) markCrossingsAsEntryOrExitWithBezierGraphForDifference:(FBBezierGraph *)otherGraph markInside:(BOOL)markInside
+{
+    for (FBBezierContour *contour in self.contours) {
+        NSArray *intersectingContours = contour.intersectingContours;
+        for (FBBezierContour *otherContour in intersectingContours) {
+            if ( otherContour.inside == FBContourInsideHole )
+                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:!markInside];
+            else
+                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:markInside];
+        }
+    }
+}
+
+
 - (FBBezierGraph *) xorWithBezierGraph:(FBBezierGraph *)graph
 {
     FBBezierGraph *allParts = [self unionWithBezierGraph:graph];