Commits

Andy Finnell committed 7bd35be

reimplementing intersect to take care of disjoint and contained contours

Comments (0)

Files changed (4)

VectorBoolean/FBBezierGraph.m

 - (FBContourInside) contourInsides:(FBBezierContour *)contour;
 
 - (void) markCrossingsAsEntryOrExitWithBezierGraphForUnion:(FBBezierGraph *)otherGraph;
+- (void) markCrossingsAsEntryOrExitWithBezierGraphForIntersect:(FBBezierGraph *)otherGraph;
+
 - (NSArray *) nonintersectingContours;
 - (BOOL) containsContour:(FBBezierContour *)contour;
 - (FBBezierContour *) containerForContour:(FBBezierContour *)testContour;
 
 - (FBBezierGraph *) unionWithBezierGraph:(FBBezierGraph *)graph
 {
-#if 1
     [self insertCrossingsWithBezierGraph:graph];
     
     [self markCrossingsAsEntryOrExitWithBezierGraphForUnion: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 self; // union is the subject graph
-        if ( clipContainsSubject )
-            return graph; // union is the clip graph
-        
-        // Neither contains the other, which means we should just append them
-        FBBezierGraph *result = [FBBezierGraph bezierGraph];
-        [result addBezierGraph:self];
-        [result addBezierGraph:graph];
-        return result;
-    }
-    
-    [self markCrossingsAsEntryOrExitWithBezierGraph:graph markInside:NO];
-    [graph markCrossingsAsEntryOrExitWithBezierGraph:self markInside:NO];
-    
-    FBBezierGraph *result = [self bezierGraphFromIntersections];
-    [result round];
-    
-    // Clean up crossings so the graphs can be reused
-    [self removeCrossings];
-    [graph removeCrossings];
-    
-    return result;
-#endif
 }
 
 - (void) markCrossingsAsEntryOrExitWithBezierGraphForUnion:(FBBezierGraph *)otherGraph
 
 - (FBBezierGraph *) intersectWithBezierGraph:(FBBezierGraph *)graph
 {
+#if 1
+    [self insertCrossingsWithBezierGraph:graph];
+    
+    [self markCrossingsAsEntryOrExitWithBezierGraphForIntersect:graph];
+    [graph markCrossingsAsEntryOrExitWithBezierGraphForIntersect:self];
+    
+    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];
+    }
+    
+    // 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) markCrossingsAsEntryOrExitWithBezierGraphForIntersect:(FBBezierGraph *)otherGraph
+{
+    for (FBBezierContour *contour in self.contours) {
+        NSArray *intersectingContours = contour.intersectingContours;
+        for (FBBezierContour *otherContour in intersectingContours) {
+            if ( otherContour.inside == FBContourInsideHole )
+                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:NO];
+            else
+                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:YES];
+        }
+    }
 }
 
 - (FBBezierGraph *) differenceWithBezierGraph:(FBBezierGraph *)graph

VectorBoolean/MyDocument.h

 - (IBAction) onConcentricContours:(id)sender;
 - (IBAction) onMoreConcentricContours:(id)sender;
 - (IBAction) onCircleOverlappingHole:(id)sender;
+- (IBAction) onHoleOverlappingHole:(id)sender;
 
 - (IBAction) onShowPoints:(id)sender;
 - (IBAction) onShowIntersections:(id)sender;

VectorBoolean/MyDocument.m

 - (void) addConcentricContours;
 - (void) addMoreConcentricContours;
 - (void) addOverlappingHole;
+- (void) addHoleOverlappingHole;
 
 - (void) addRectangle:(NSRect)rect;
 - (void) addCircleAtPoint:(NSPoint)center withRadius:(CGFloat)radius;
     [_view.canvas addPath:circle withColor:[NSColor redColor]];
 }
 
+- (void) addHoleOverlappingHole
+{
+    NSBezierPath *holeyRectangle1 = [NSBezierPath bezierPath];
+    [self addRectangle:NSMakeRect(50, 50, 350, 300) toPath:holeyRectangle1];
+    [self addCircleAtPoint:NSMakePoint(210, 200) withRadius:125 toPath:holeyRectangle1];    
+    [_view.canvas addPath:holeyRectangle1 withColor:[NSColor blueColor]];
+    
+    
+    NSBezierPath *holeyRectangle2 = [NSBezierPath bezierPath];
+    [self addRectangle:NSMakeRect(225, 65, 160, 160) toPath:holeyRectangle2];
+    [self addCircleAtPoint:NSMakePoint(305, 145) withRadius:65 toPath:holeyRectangle2];    
+    [_view.canvas addPath:holeyRectangle2 withColor:[NSColor redColor]];
+}
+
 - (void) addRectangle:(NSRect)rect
 {
     NSBezierPath *rectangle = [NSBezierPath bezierPath];
     [self onReset:sender];                
 }
 
+- (IBAction) onHoleOverlappingHole:(id)sender
+{
+    _resetAction = @selector(addHoleOverlappingHole);
+    [self onReset:sender];                
+}
+
 - (IBAction) onShowPoints:(id)sender
 {
     _view.canvas.showPoints = !_view.canvas.showPoints;
         [menuItem setState:_resetAction == @selector(addMoreConcentricContours) ? NSOnState : NSOffState];
     } else if ( [anItem action] == @selector(onCircleOverlappingHole:) ) {
         [menuItem setState:_resetAction == @selector(addOverlappingHole) ? NSOnState : NSOffState];
+    } else if ( [anItem action] == @selector(onHoleOverlappingHole:) ) {
+        [menuItem setState:_resetAction == @selector(addHoleOverlappingHole) ? NSOnState : NSOffState];
     } else if ( [anItem action] == @selector(onShowPoints:) ) {
         [menuItem setState:_view.canvas.showPoints ? NSOnState : NSOffState];
     } else if ( [anItem action] == @selector(onShowIntersections:) ) {

VectorBoolean/en.lproj/MainMenu.xib

 									<reference key="NSOnImage" ref="1033313550"/>
 									<reference key="NSMixedImage" ref="310636482"/>
 								</object>
+								<object class="NSMenuItem" id="892473285">
+									<reference key="NSMenu" ref="930598111"/>
+									<string key="NSTitle">Rectangle w/hole Overlapping Rectangle w/hole</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="1033313550"/>
+									<reference key="NSMixedImage" ref="310636482"/>
+								</object>
 							</object>
 						</object>
 					</object>
 					</object>
 					<int key="connectionID">583</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">onHoleOverlappingHole:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="892473285"/>
+					</object>
+					<int key="connectionID">585</int>
+				</object>
 			</object>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<object class="NSArray" key="orderedObjects">
 							<reference ref="21338714"/>
 							<reference ref="33431505"/>
 							<reference ref="94560581"/>
+							<reference ref="892473285"/>
 						</object>
 						<reference key="parent" ref="40719474"/>
 					</object>
 						<reference key="object" ref="94560581"/>
 						<reference key="parent" ref="930598111"/>
 					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">584</int>
+						<reference key="object" ref="892473285"/>
+						<reference key="parent" ref="930598111"/>
+					</object>
 				</object>
 			</object>
 			<object class="NSMutableDictionary" key="flattenedProperties">
 					<string>58.ImportedFromIB2</string>
 					<string>580.IBPluginDependency</string>
 					<string>582.IBPluginDependency</string>
+					<string>584.IBPluginDependency</string>
 					<string>72.IBPluginDependency</string>
 					<string>72.ImportedFromIB2</string>
 					<string>73.IBPluginDependency</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<integer value="1"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<integer value="1"/>
 				<reference key="dict.values" ref="0"/>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">583</int>
+			<int key="maxID">585</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
 							<string>onDiamondInsideRectangle:</string>
 							<string>onDiamondOverlappingRectangle:</string>
 							<string>onDifference:</string>
+							<string>onHoleOverlappingHole:</string>
 							<string>onIntersect:</string>
 							<string>onJoin:</string>
 							<string>onMoreConcentricContours:</string>
 							<string>id</string>
 							<string>id</string>
 							<string>id</string>
+							<string>id</string>
 						</object>
 					</object>
 					<object class="NSMutableDictionary" key="actionInfosByName">
 							<string>onDiamondInsideRectangle:</string>
 							<string>onDiamondOverlappingRectangle:</string>
 							<string>onDifference:</string>
+							<string>onHoleOverlappingHole:</string>
 							<string>onIntersect:</string>
 							<string>onJoin:</string>
 							<string>onMoreConcentricContours:</string>
 								<string key="candidateClassName">id</string>
 							</object>
 							<object class="IBActionInfo">
+								<string key="name">onHoleOverlappingHole:</string>
+								<string key="candidateClassName">id</string>
+							</object>
+							<object class="IBActionInfo">
 								<string key="name">onIntersect:</string>
 								<string key="candidateClassName">id</string>
 							</object>
 							<string>onDiamondInsideRectangle:</string>
 							<string>onDiamondOverlappingRectangle:</string>
 							<string>onDifference:</string>
+							<string>onHoleOverlappingHole:</string>
 							<string>onIntersect:</string>
 							<string>onJoin:</string>
 							<string>onMoreConcentricContours:</string>
 							<string>id</string>
 							<string>id</string>
 							<string>id</string>
+							<string>id</string>
 						</object>
 					</object>
 					<object class="NSMutableDictionary" key="actionInfosByName">
 							<string>onDiamondInsideRectangle:</string>
 							<string>onDiamondOverlappingRectangle:</string>
 							<string>onDifference:</string>
+							<string>onHoleOverlappingHole:</string>
 							<string>onIntersect:</string>
 							<string>onJoin:</string>
 							<string>onMoreConcentricContours:</string>
 								<string key="candidateClassName">id</string>
 							</object>
 							<object class="IBActionInfo">
+								<string key="name">onHoleOverlappingHole:</string>
+								<string key="candidateClassName">id</string>
+							</object>
+							<object class="IBActionInfo">
 								<string key="name">onIntersect:</string>
 								<string key="candidateClassName">id</string>
 							</object>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.