Commits

Anonymous committed 8604862

fixing determining of an intersection is an actual crossing

Comments (0)

Files changed (2)

VectorBoolean/FBBezierGraph.m

 
 static const CGFloat FB2PI = 2.0 * M_PI;
 
+static CGFloat NormalizeAngle(CGFloat value)
+{
+    while ( value < 0.0 )
+        value += FB2PI;
+    while ( value >= FB2PI )
+        value -= FB2PI;
+    return value;
+}
+
 static CGFloat PolarAngle(NSPoint point)
 {
     CGFloat value = 0.0;
         else
             value = 0.0;
     }
-    while ( value < 0.0 )
-        value += FB2PI;
-    while ( value > FB2PI )
-        value -= FB2PI;
-    return value;
+    return NormalizeAngle(value);
+}
+
+typedef struct FBAngleRange {
+    CGFloat minimum;
+    CGFloat maximum;
+} FBAngleRange;
+
+static FBAngleRange FBAngleRangeMake(CGFloat minimum, CGFloat maximum)
+{
+    FBAngleRange range = { minimum, maximum };
+    return range;
+}
+
+static BOOL FBAngleRangeContainsAngle(FBAngleRange range, CGFloat angle)
+{
+    if ( range.minimum <= range.maximum )
+        return angle > range.minimum && angle < range.maximum;
+    
+    // The range wraps around 0. See if the angle falls in the first half
+    if ( angle > range.minimum && angle <= FB2PI )
+        return YES;
+    
+    return angle >= 0.0 && angle < range.maximum;
 }
 
 @interface FBBezierGraph ()
 
+- (NSUInteger) numberOfCrossings;
+- (void) removeDuplicateCrossings;
 - (BOOL) doesEdge:(FBContourEdge *)edge1 crossEdge:(FBContourEdge *)edge2 atIntersection:(FBBezierIntersection *)intersection;
 - (BOOL) insertCrossingsWithBezierGraph:(FBBezierGraph *)other;
 - (BOOL) containsPoint:(NSPoint)point;
 
 - (BOOL) insertCrossingsWithBezierGraph:(FBBezierGraph *)other
 {
-    NSMutableArray *crossings = [NSMutableArray arrayWithCapacity:10];
-    
+    // Find all intersections and, if they cross the other graph, create crossings for them
     for (FBBezierContour *ourContour in self.contours) {
         for (FBContourEdge *ourEdge in ourContour.edges) {
             for (FBBezierContour *theirContour in other.contours) {
                         
                         [ourEdge addCrossing:ourCrossing];
                         [theirEdge addCrossing:theirCrossing];
-                        
-                        // Keep track of the crossing
-                        [crossings addObject:ourCrossing];
-                        [crossings addObject:theirCrossing];
                     }
                 }
             }
         }
     }
  
+    [self removeDuplicateCrossings];
+
+    return [self numberOfCrossings];
+}
+
+- (void) removeDuplicateCrossings
+{
     // Find any duplicate crossings. These will happen at the endpoints of edges
-    NSUInteger removeCount = 0;
-    for (FBEdgeCrossing *crossing in crossings) {
-        if ( crossing.isAtStart && crossing.edge.previous.lastCrossing.isAtEnd ) {
-            FBEdgeCrossing *counterpart = crossing.counterpart;
-            [crossing removeFromEdge];
-            [counterpart removeFromEdge];
-            removeCount += 2;
-        }
-        if ( crossing.isAtEnd && crossing.edge.next.firstCrossing.isAtStart ) {
-            FBEdgeCrossing *counterpart = crossing.edge.next.firstCrossing.counterpart;
-            [crossing.edge.next.firstCrossing removeFromEdge];
-            [counterpart removeFromEdge];
-            removeCount += 2;
+    for (FBBezierContour *ourContour in self.contours) {
+        for (FBContourEdge *ourEdge in ourContour.edges) {
+            for (FBEdgeCrossing *crossing in ourEdge.crossings) {
+                if ( crossing.isAtStart && crossing.edge.previous.lastCrossing.isAtEnd ) {
+                    FBEdgeCrossing *counterpart = crossing.counterpart;
+                    [crossing removeFromEdge];
+                    [counterpart removeFromEdge];
+                }
+                if ( crossing.isAtEnd && crossing.edge.next.firstCrossing.isAtStart ) {
+                    FBEdgeCrossing *counterpart = crossing.edge.next.firstCrossing.counterpart;
+                    [crossing.edge.next.firstCrossing removeFromEdge];
+                    [counterpart removeFromEdge];
+                }
+            }
         }
     }
-    return ([crossings count] - removeCount) > 0;
+}
+
+- (NSUInteger) numberOfCrossings
+{
+    NSUInteger count = 0;
+    for (FBBezierContour *ourContour in self.contours)
+        for (FBContourEdge *ourEdge in ourContour.edges)
+            count += [ourEdge.crossings count];
+    return count;
 }
 
 - (BOOL) doesEdge:(FBContourEdge *)edge1 crossEdge:(FBContourEdge *)edge2 atIntersection:(FBBezierIntersection *)intersection
     CGFloat edge2Angles[] = { PolarAngle(edge2Tangents[0]), PolarAngle(edge2Tangents[1]) };
     
     // Count how many times edge2 angles are between edge1 angles
-    CGFloat minAngle = MIN(edge1Angles[0], edge1Angles[1]);
-    CGFloat maxAngle = MAX(edge1Angles[0], edge1Angles[1]);    
-    NSUInteger count = 0;
-    if ( edge2Angles[0] > minAngle && edge2Angles[0] < maxAngle )
-        count++;
-    if ( edge2Angles[1] > minAngle && edge2Angles[1] < maxAngle )
-        count++;
-    return (count % 2) == 1; // if an odd number, then it splits it
+    FBAngleRange range1 = FBAngleRangeMake(edge1Angles[0], edge1Angles[1]);
+    NSUInteger rangeCount1 = 0;
+    if ( FBAngleRangeContainsAngle(range1, edge2Angles[0]) )
+        rangeCount1++;
+    if ( FBAngleRangeContainsAngle(range1, edge2Angles[1]) )
+        rangeCount1++;
+    
+    FBAngleRange range2 = FBAngleRangeMake(edge1Angles[1], edge1Angles[0]);
+    NSUInteger rangeCount2 = 0;
+    if ( FBAngleRangeContainsAngle(range2, edge2Angles[0]) )
+        rangeCount2++;
+    if ( FBAngleRangeContainsAngle(range2, edge2Angles[1]) )
+        rangeCount2++;
+
+    return rangeCount1 == 1 && rangeCount2 == 1;
 }
 
 - (NSRect) bounds

VectorBoolean/MyDocument.m

 {
     self = [super init];
     if (self) {
-        _resetAction = @selector(addDiamondOverlappingRectangle);
+        _resetAction = @selector(addTriangleInsideRectangle);
     }
     return self;
 }