aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-17 15:49:16 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-17 15:49:16 +0000
commitb3f0921fba9457ba7ea79f220d8c1ec9345bfd3a (patch)
tree88e4c5e6b5f7622e4949073f8de141c2685a503e
parent319baf99636c39f41d93c8808b7be3d198aa27b4 (diff)
shape ops work in progress
Try to fix the 32 bit build by making some math decisions more robust. Rewrite the cubic intersection special case that detects if only end points are shared. Rewrite the angle sort setup that computes whether a cubic bends to the left or right. git-svn-id: http://skia.googlecode.com/svn/trunk@8726 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--experimental/Intersection/as.htm154
-rw-r--r--src/pathops/SkDQuadIntersection.cpp35
-rw-r--r--src/pathops/SkIntersections.cpp4
-rw-r--r--src/pathops/SkIntersections.h9
-rw-r--r--src/pathops/SkOpAngle.cpp45
-rw-r--r--src/pathops/SkPathOpsCubic.h9
-rw-r--r--src/pathops/SkPathOpsDebug.h2
-rw-r--r--tests/PathOpsAngleTest.cpp58
-rw-r--r--tests/PathOpsCubicIntersectionTest.cpp5
-rw-r--r--tests/PathOpsOpTest.cpp30
-rw-r--r--tests/PathOpsQuadIntersectionTest.cpp4
11 files changed, 296 insertions, 59 deletions
diff --git a/experimental/Intersection/as.htm b/experimental/Intersection/as.htm
index 063b92113d..0d0c6551a3 100644
--- a/experimental/Intersection/as.htm
+++ b/experimental/Intersection/as.htm
@@ -3692,11 +3692,161 @@ path.lineTo(0,0);
path.close();
</div>
+<div id="cubicOp67u">
+ RunTestSet [cubicOp67u]
+{{3,5}, {1,6}, {5,0}, {3,1}},
+{{3,1}, {3,5}},
+op union
+{{0,5}, {1,3}, {5,3}, {6,1}},
+{{6,1}, {0,5}},
+debugShowCubicIntersection no self intersect {{3,5}, {1,6}, {5,0}, {3,1}}
+debugShowCubicLineIntersection wtTs[0]=0 {{3,5}, {1,6}, {5,0}, {3,1}} {{3,5}} wtTs[1]=0.5 {{3,3}} wtTs[2]=1 {{3,1}} wnTs[0]=1 {{3,1}, {3,5}} wnTs[1]=0.5 wnTs[2]=0
+debugShowCubicIntersection no intersect {{3,5}, {1,6}, {5,0}, {3,1}} {{0,5}, {1,3}, {5,3}, {6,1}}
+debugShowCubicLineIntersection wtTs[0]=0.5 {{3,5}, {1,6}, {5,0}, {3,1}} {{2.9999999999999991,3.0000000000000004}} wnTs[0]=0.5 {{6,1}, {0,5}}
+debugShowCubicLineIntersection wtTs[0]=0.5 {{0,5}, {1,3}, {5,3}, {6,1}} {{2.9999999999999991,2.9999999999999991}} wnTs[0]=0.5 {{3,1}, {3,5}}
+debugShowLineIntersection wtTs[0]=0.5 {{3,1}, {3,5}} {{3,3}} wnTs[0]=0.5 {{6,1}, {0,5}}
+debugShowCubicIntersection no self intersect {{0,5}, {1,3}, {5,3}, {6,1}}
+debugShowCubicLineIntersection wtTs[0]=0 {{0,5}, {1,3}, {5,3}, {6,1}} {{0,5}} wtTs[1]=0.5 {{3,3}} wtTs[2]=1 {{6,1}} wnTs[0]=1 {{6,1}, {0,5}} wnTs[1]=0.5 wnTs[2]=0
+SkOpSegment::debugShowActiveSpans id=1 (3,5 1,6 5,0 3,1) t=0 (3,5) tEnd=0.5 other=2 otherT=1 otherIndex=4 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=1 (3,5 1,6 5,0 3,1) t=0.5 (3,3) tEnd=1 other=4 otherT=0.5 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=1 (3,5 1,6 5,0 3,1) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (3,1 3,5) t=0 (3,1) tEnd=0.5 other=1 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (3,1 3,5) t=0.5 (3,3) tEnd=1 other=3 otherT=0.5 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (3,1 3,5) t=0.5 (3,3) tEnd=1 other=1 otherT=0.5 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (3,1 3,5) t=0.5 (3,3) tEnd=1 other=4 otherT=0.5 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0 (0,5) tEnd=0.5 other=4 otherT=1 otherIndex=4 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0.5 (3,3) tEnd=1 other=4 otherT=0.5 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0 (6,1) tEnd=0.5 other=3 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=3 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=3 otherT=0.5 otherIndex=2 windSum=? windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=1 otherT=0.5 otherIndex=1 windSum=? windValue=1 oppValue=0
+SkOpSegment::findTop SkOpSegment::debugShowSort contourWinding=0 oppContourWinding=0 sign=1
+SkOpSegment::debugShowSort [0] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=1 tEnd=0.5 sign=1 windValue=1 windSum=? 0->-1 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [1] {{3,1}, {3,5}} tStart=0 tEnd=0.5 sign=-1 windValue=1 windSum=? -1->0 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::findTop swap=1 serpentine=0 containedByEnds=0 monotonic=0
+SkOpSegment::markWinding id=1 (3,5 1,6 5,0 3,1) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=1 (3,5 1,6 5,0 3,1) t=0.5 [2] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=1 (3,5 1,6 5,0 3,1) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markWinding id=1 (3,5 1,6 5,0 3,1) t=0.5 [2] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markWinding id=2 (3,1 3,5) t=0 [0] (3,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::findNextOp SkOpSegment::debugShowSort contourWinding=0 oppContourWinding=0 sign=-1
+SkOpSegment::debugShowSort [1] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 0->1 (max=1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [2] {{3,1}, {3,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 1->0 (max=1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [3] {{6,1}, {0,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=? 0->1 (max=1) done=0 tiny=0 opp=1
+SkOpSegment::debugShowSort [4] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=? 0->-1 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [5] {{3,1}, {3,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=? -1->0 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [0] {{6,1}, {0,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=? 1->0 (max=1) done=0 tiny=0 opp=1
+SkOpSegment::findNextOp firstIndex=[1] sign=-1
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::markWinding id=4 (6,1 0,5) t=0.5 [2] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=4 (6,1 0,5) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=4 (6,1 0,5) t=0.5 [3] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=3 (0,5 1,3 5,3 6,1) t=0 [0] (0,5) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::findNextOp chase.append id=3
+SkOpSegment::activeOp op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDoneBinary id=1 (3,5 1,6 5,0 3,1) t=0 [0] (3,5) tEnd=0.5 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1
+SkOpSegment::markDoneBinary id=2 (3,1 3,5) t=0.5 [2] (3,3) tEnd=0.5 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1
+SkOpSegment::markDoneBinary id=2 (3,1 3,5) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1
+SkOpSegment::markDoneBinary id=2 (3,1 3,5) t=0.5 [3] (3,3) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1
+SkOpSegment::findNextOp chase.append id=2
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::markWinding id=4 (6,1 0,5) t=0 [0] (6,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=3 (0,5 1,3 5,3 6,1) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::markWinding id=3 (0,5 1,3 5,3 6,1) t=0.5 [2] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1
+SkOpSegment::findNextOp chase.append id=3
+SkOpSegment::markDoneBinary id=1 (3,5 1,6 5,0 3,1) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markDoneBinary id=1 (3,5 1,6 5,0 3,1) t=0.5 [2] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::findNextOp from:[1] to:[2] start=2 end=0
+bridgeOp current id=1 from=(3,1) to=(3,3)
+path.moveTo(3,1);
+path.cubicTo(4,0.5, 3.5,1.75, 3,3);
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=2 (3,1 3,5) t=0 [0] (3,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+bridgeOp current id=2 from=(3,3) to=(3,1)
+path.lineTo(3,1);
+path.close();
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0 (0,5) tEnd=0.5 other=4 otherT=1 otherIndex=4 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0.5 (3,3) tEnd=1 other=4 otherT=0.5 otherIndex=2 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0 (6,1) tEnd=0.5 other=3 otherT=1 otherIndex=3 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=3 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=3 otherT=0.5 otherIndex=2 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=1 otherT=0.5 otherIndex=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=3 (0,5 1,3 5,3 6,1) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markDoneBinary id=3 (0,5 1,3 5,3 6,1) t=0.5 [2] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+bridgeOp current id=3 from=(3,3) to=(6,1)
+path.moveTo(3,3);
+path.cubicTo(4.25,2.5, 5.5,2, 6,1);
+SkOpSegment::findNextOp SkOpSegment::debugShowSort contourWinding=1 oppContourWinding=0 sign=1
+SkOpSegment::debugShowSort [1] {{6,1}, {0,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 1->0 (max=1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [2] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 0->1 (max=1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [3] {{3,1}, {3,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 1->0 (max=1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [4] {{0,5}, {1,3}, {5,3}, {6,1}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 0->-1 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [5] {{6,1}, {0,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 -1->0 (max=-1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [6] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=-1 0->-1 (max=-1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [7] {{3,1}, {3,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=-1 -1->0 (max=-1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [0] {{0,5}, {1,3}, {5,3}, {6,1}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 0->1 (max=1) done=1 tiny=0 opp=0
+SkOpSegment::findNextOp firstIndex=[1] sign=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::markDoneBinary id=4 (6,1 0,5) t=0 [0] (6,1) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::findNextOp from:[4] to:[3] start=2 end=0
+bridgeOp current id=4 from=(6,1) to=(3,3)
+path.lineTo(3,3);
+path.close();
+SkOpSegment::debugShowActiveSpans id=3 (0,5 1,3 5,3 6,1) t=0 (0,5) tEnd=0.5 other=4 otherT=1 otherIndex=4 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=2 otherT=0.5 otherIndex=3 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=3 otherT=0.5 otherIndex=2 windSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=4 (6,1 0,5) t=0.5 (3,3) tEnd=1 other=1 otherT=0.5 otherIndex=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::findNextOp simple
+SkOpSegment::markDoneBinary id=3 (0,5 1,3 5,3 6,1) t=0 [0] (0,5) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+bridgeOp current id=3 from=(3,3) to=(0,5)
+path.moveTo(3,3);
+path.cubicTo(1.75,3.5, 0.5,4, 0,5);
+SkOpSegment::findNextOp SkOpSegment::debugShowSort contourWinding=0 oppContourWinding=0 sign=-1
+SkOpSegment::debugShowSort [5] {{6,1}, {0,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 0->1 (max=1) done=0 tiny=0 opp=0
+SkOpSegment::debugShowSort [6] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=-1 0->-1 (max=-1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [7] {{3,1}, {3,5}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=-1 -1->0 (max=-1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [0] {{0,5}, {1,3}, {5,3}, {6,1}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 1->2 (max=2) done=1 tiny=0 opp=0
+SkOpSegment::debugShowSort [1] {{6,1}, {0,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 2->1 (max=2) done=1 tiny=0 opp=0
+SkOpSegment::debugShowSort [2] {{3,5}, {1,6}, {5,0}, {3,1}} tStart=0.5 tEnd=1 sign=-1 windValue=1 windSum=1 0->1 (max=1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [3] {{3,1}, {3,5}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 1->0 (max=1) done=1 tiny=0 opp=1
+SkOpSegment::debugShowSort [4] {{0,5}, {1,3}, {5,3}, {6,1}} tStart=0.5 tEnd=0 sign=1 windValue=1 windSum=1 1->0 (max=1) done=1 tiny=0 opp=0
+SkOpSegment::findNextOp firstIndex=[5] sign=-1
+SkOpSegment::activeOp op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::markDoneBinary id=4 (6,1 0,5) t=0.5 [2] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markDoneBinary id=4 (6,1 0,5) t=0.5 [1] (3,3) tEnd=0.5 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::markDoneBinary id=4 (6,1 0,5) t=0.5 [3] (3,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1
+SkOpSegment::findNextOp from:[4] to:[3] start=2 end=0
+bridgeOp current id=4 from=(0,5) to=(3,3)
+path.lineTo(3,3);
+path.close();
+</div>
+
</div>
<script type="text/javascript">
var testDivs = [
+ cubicOp67u,
testQuad1,
cubicOp62d,
cubicOp61d,
@@ -4008,6 +4158,10 @@ function parse_all(test) {
if (line.length == 0) {
continue;
}
+ var opStart = "SkOpSegment::";
+ if (line.lastIndexOf(opStart, 0) === 0) {
+ line = line.substr(opStart.length);
+ }
var type = line.lastIndexOf("debugShowSort", 0) === 0 ? REC_TYPE_SORT
: line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
: line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
diff --git a/src/pathops/SkDQuadIntersection.cpp b/src/pathops/SkDQuadIntersection.cpp
index db4e2facff..0344680b6d 100644
--- a/src/pathops/SkDQuadIntersection.cpp
+++ b/src/pathops/SkDQuadIntersection.cpp
@@ -72,7 +72,7 @@ static int addValidRoots(const double roots[4], const int count, double valid[4]
return result;
}
-static bool only_end_pts_in_common(const SkDQuad& q1, const SkDQuad& q2, SkIntersections* i) {
+static bool only_end_pts_in_common(const SkDQuad& q1, const SkDQuad& q2) {
// the idea here is to see at minimum do a quick reject by rotating all points
// to either side of the line formed by connecting the endpoints
// if the opposite curves points are on the line or on the other side, the
@@ -96,21 +96,10 @@ static bool only_end_pts_in_common(const SkDQuad& q1, const SkDQuad& q2, SkInter
}
for (int n = 0; n < 3; ++n) {
double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
- if (test * sign > 0 && precisely_zero(test)) {
- SkDebugf("*** very teeny\n");
- }
- if (test * sign > 0) {
+ if (test * sign > 0 && !precisely_zero(test)) {
goto tryNextHalfPlane;
}
}
- for (int i1 = 0; i1 < 3; i1 += 2) {
- for (int i2 = 0; i2 < 3; i2 += 2) {
- if (q1[i1] == q2[i2]) {
- i->insert(i1 >> 1, i2 >> 1, q1[i1]);
- }
- }
- }
- SkASSERT(i->used() < 3);
return true;
tryNextHalfPlane:
;
@@ -365,19 +354,28 @@ static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1
int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
// if the quads share an end point, check to see if they overlap
- if (only_end_pts_in_common(q1, q2, this)) {
+ for (int i1 = 0; i1 < 3; i1 += 2) {
+ for (int i2 = 0; i2 < 3; i2 += 2) {
+ if (q1[i1].approximatelyEqualHalf(q2[i2])) {
+ insert(i1 >> 1, i2 >> 1, q1[i1]);
+ }
+ }
+ }
+ SkASSERT(fUsed < 3);
+ if (only_end_pts_in_common(q1, q2)) {
return fUsed;
}
- if (only_end_pts_in_common(q2, q1, this)) {
- swapPts();
+ if (only_end_pts_in_common(q2, q1)) {
return fUsed;
}
// see if either quad is really a line
if (is_linear(q1, q2, this)) {
return fUsed;
}
- if (is_linear(q2, q1, this)) {
- swapPts();
+ SkIntersections swapped;
+ if (is_linear(q2, q1, &swapped)) {
+ swapped.swapPts();
+ set(swapped);
return fUsed;
}
SkDQuadImplicit i1(q1);
@@ -385,6 +383,7 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
if (i1.match(i2)) {
// FIXME: compute T values
// compute the intersections of the ends to find the coincident span
+ reset();
bool useVertical = fabs(q1[0].fX - q1[2].fX) < fabs(q1[0].fY - q1[2].fY);
double t;
if ((t = SkIntersections::Axial(q1, q2[0], useVertical)) >= 0) {
diff --git a/src/pathops/SkIntersections.cpp b/src/pathops/SkIntersections.cpp
index 205308f646..72f801bb1b 100644
--- a/src/pathops/SkIntersections.cpp
+++ b/src/pathops/SkIntersections.cpp
@@ -136,6 +136,10 @@ void SkIntersections::insertCoincidentPair(double s1, double e1, double s2, doub
}
int SkIntersections::insert(double one, double two, const SkDPoint& pt) {
+ if (fIsCoincident[0] == 3 && between(fT[0][0], one, fT[0][1])) {
+ // For now, don't allow a mix of coincident and non-coincident intersections
+ return -1;
+ }
SkASSERT(fUsed <= 1 || fT[0][0] <= fT[0][1]);
int index;
for (index = 0; index < fUsed; ++index) {
diff --git a/src/pathops/SkIntersections.h b/src/pathops/SkIntersections.h
index c2f05fe936..a677a38b43 100644
--- a/src/pathops/SkIntersections.h
+++ b/src/pathops/SkIntersections.h
@@ -36,6 +36,15 @@ public:
};
TArray operator[](int n) const { return TArray(fT[n]); }
+ void set(const SkIntersections& i) {
+ memcpy(fPt, i.fPt, sizeof(fPt));
+ memcpy(fT, i.fT, sizeof(fT));
+ memcpy(fIsCoincident, i.fIsCoincident, sizeof(fIsCoincident));
+ fUsed = i.fUsed;
+ fSwap = i.fSwap;
+ SkDEBUGCODE(fDepth = i.fDepth);
+ }
+
int cubic(const SkPoint a[4]) {
SkDCubic cubic;
cubic.set(a);
diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp
index 2a9ebebd87..7cdfd8c04b 100644
--- a/src/pathops/SkOpAngle.cpp
+++ b/src/pathops/SkOpAngle.cpp
@@ -7,6 +7,7 @@
#include "SkIntersections.h"
#include "SkOpAngle.h"
#include "SkPathOpsCurve.h"
+#include "TSearch.h"
// FIXME: this is bogus for quads and cubics
// if the quads and cubics' line from end pt to ctrl pt are coincident,
@@ -194,20 +195,54 @@ void SkOpAngle::setSpans() {
fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
} break;
case SkPath::kCubic_Verb: {
- int nextC = 2;
+ // int nextC = 2;
fCurvePart = SkDCubic::SubDivide(fPts, startT, endT);
fTangent1.cubicEndPoints(fCurvePart, 0, 1);
if (dx() == 0 && dy() == 0) {
fTangent1.cubicEndPoints(fCurvePart, 0, 2);
- nextC = 3;
+ // nextC = 3;
if (dx() == 0 && dy() == 0) {
fTangent1.cubicEndPoints(fCurvePart, 0, 3);
}
}
- fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
- if (nextC == 2 && approximately_zero(fSide)) {
- fSide = -fTangent1.pointDistance(fCurvePart[3]);
+ // fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only
+ // if (nextC == 2 && approximately_zero(fSide)) {
+ // fSide = -fTangent1.pointDistance(fCurvePart[3]);
+ // }
+ double testTs[4];
+ // OPTIMIZATION: keep inflections precomputed with cubic segment?
+ int testCount = SkDCubic::FindInflections(fPts, testTs);
+ double limitT = endT;
+ int index;
+ for (index = 0; index < testCount; ++index) {
+ if (!between(startT, testTs[index], limitT)) {
+ testTs[index] = -1;
+ }
+ }
+ testTs[testCount++] = startT;
+ testTs[testCount++] = endT;
+ QSort<double>(testTs, &testTs[testCount - 1]);
+ double bestSide = 0;
+ int testCases = (testCount << 1) - 1;
+ index = 0;
+ while (testTs[index] < 0) {
+ ++index;
+ }
+ index <<= 1;
+ for (; index < testCases; ++index) {
+ int testIndex = index >> 1;
+ double testT = testTs[testIndex];
+ if (index & 1) {
+ testT = (testT + testTs[testIndex + 1]) / 2;
+ }
+ // OPTIMIZE: could avoid call for t == startT, endT
+ SkDPoint pt = dcubic_xy_at_t(fPts, testT);
+ double testSide = fTangent1.pointDistance(pt);
+ if (fabs(bestSide) < fabs(testSide)) {
+ bestSide = testSide;
+ }
}
+ fSide = -bestSide; // compare sign only
} break;
default:
SkASSERT(0);
diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h
index 48280fd32f..37492ddbba 100644
--- a/src/pathops/SkPathOpsCubic.h
+++ b/src/pathops/SkPathOpsCubic.h
@@ -41,6 +41,13 @@ struct SkDCubic {
bool endsAreExtremaInXOrY() const;
static int FindExtrema(double a, double b, double c, double d, double tValue[2]);
int findInflections(double tValues[]) const;
+
+ static int FindInflections(const SkPoint a[4], double tValues[]) {
+ SkDCubic cubic;
+ cubic.set(a);
+ return cubic.findInflections(tValues);
+ }
+
int findMaxCurvature(double tValues[]) const;
bool isLinear(int startIndex, int endIndex) const;
bool monotonicInY() const;
@@ -48,11 +55,13 @@ struct SkDCubic {
static int RootsValidT(const double A, const double B, const double C, double D, double s[3]);
bool serpentine() const;
SkDCubic subDivide(double t1, double t2) const;
+
static SkDCubic SubDivide(const SkPoint a[4], double t1, double t2) {
SkDCubic cubic;
cubic.set(a);
return cubic.subDivide(t1, t2);
}
+
void subDivide(const SkDPoint& a, const SkDPoint& d, double t1, double t2, SkDPoint p[2]) const;
static void SubDivide(const SkPoint pts[4], const SkDPoint& a, const SkDPoint& d, double t1,
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index 065ba4b782..a642af4c01 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -12,7 +12,7 @@
#ifdef SK_RELEASE
#define FORCE_RELEASE 1
#else
-#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
+#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
#endif
#define ONE_OFF_DEBUG 0
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index 650b99666b..6714ca4609 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -23,17 +23,17 @@ struct SortSet {
};
static const SortSet set1[] = {
- {lines[0], 2, 0.54070336, 0.388888889},
- {cubics[0], 4, 0.666669871, 0.405037112},
- {lines[0], 2, 0.54070336, 0.9140625},
- {cubics[0], 4, 0.666669871, 0.875},
+ {cubics[0], 4, 0.66666987081928919, 0.875},
+ {lines[0], 2, 0.574070336, 0.388888889},
+ {cubics[0], 4, 0.66666987081928919, 0.4050371120499307 },
+ {lines[0], 2, 0.574070336, 0.9140625},
};
static const SortSet set2[] = {
+ {cubics[0], 4, 0.666666667, 0.875},
{lines[0], 2, 0.574074074, 0.388888889},
{cubics[0], 4, 0.666666667, 0.405037112},
{lines[0], 2, 0.574074074, 0.9140625},
- {cubics[0], 4, 0.666666667, 0.875},
};
struct SortSetTests {
@@ -42,36 +42,22 @@ struct SortSetTests {
};
static const SortSetTests tests[] = {
- { set1, SK_ARRAY_COUNT(set1) },
- { set2, SK_ARRAY_COUNT(set2) }
+ { set2, SK_ARRAY_COUNT(set2) },
+ { set1, SK_ARRAY_COUNT(set1) }
};
static void setup(const SortSet* set, const size_t idx, SkPoint const ** data,
- SkPoint* reverse, SkOpSegment* seg) {
+ SkOpSegment* seg, int* ts) {
SkPoint start, end;
if (set[idx].ptCount == 2) {
- if (set[idx].tStart < set[idx].tEnd) {
- *data = set[idx].ptData;
- } else {
- reverse[0] = set[idx].ptData[1];
- reverse[1] = set[idx].ptData[0];
- *data = reverse;
- }
+ *data = set[idx].ptData;
seg->addLine(*data, false, false);
SkDLine dLine;
dLine.set(set[idx].ptData);
start = dLine.xyAtT(set[idx].tStart).asSkPoint();
end = dLine.xyAtT(set[idx].tEnd).asSkPoint();
} else if (set[idx].ptCount == 4) {
- if (set[idx].tStart < set[idx].tEnd) {
- *data = set[idx].ptData;
- } else {
- reverse[0] = set[idx].ptData[3];
- reverse[1] = set[idx].ptData[2];
- reverse[2] = set[idx].ptData[1];
- reverse[3] = set[idx].ptData[0];
- *data = reverse;
- }
+ *data = set[idx].ptData;
seg->addCubic(*data, false, false);
SkDCubic dCubic;
dCubic.set(set[idx].ptData);
@@ -82,6 +68,18 @@ static void setup(const SortSet* set, const size_t idx, SkPoint const ** data,
seg->addT(NULL, end, set[idx].tEnd);
seg->addT(NULL, set[idx].ptData[0], 0);
seg->addT(NULL, set[idx].ptData[set[idx].ptCount - 1], 1);
+ int tIndex = 0;
+ do {
+ if (seg->t(tIndex) == set[idx].tStart) {
+ ts[0] = tIndex;
+ }
+ if (seg->t(tIndex) == set[idx].tEnd) {
+ ts[1] = tIndex;
+ }
+ if (seg->t(tIndex) >= 1) {
+ break;
+ }
+ } while (++tIndex);
}
static void PathOpsAngleTest(skiatest::Reporter* reporter) {
@@ -89,19 +87,17 @@ static void PathOpsAngleTest(skiatest::Reporter* reporter) {
const SortSetTests& test = tests[index];
for (size_t idxL = 0; idxL < test.count - 1; ++idxL) {
SkOpSegment lesser, greater;
- SkPoint lesserReverse[4], greaterReverse[4];
+ int lesserTs[2], greaterTs[2];
const SkPoint* lesserData, * greaterData;
const SortSet* set = test.set;
- setup(set, idxL, &lesserData, lesserReverse, &lesser);
+ setup(set, idxL, &lesserData, &lesser, lesserTs);
size_t idxG = idxL + 1;
- setup(set, idxG, &greaterData, greaterReverse, &greater);
+ setup(set, idxG, &greaterData, &greater, greaterTs);
SkOpAngle first, second;
first.set(lesserData, (SkPath::Verb) (set[idxL].ptCount - 1), &lesser,
- 0, 1, lesser.spans());
- first.setSpans();
+ lesserTs[0], lesserTs[1], lesser.spans());
second.set(greaterData, (SkPath::Verb) (set[idxG].ptCount - 1), &greater,
- 0, 1, greater.spans());
- second.setSpans();
+ greaterTs[0], greaterTs[1], greater.spans());
bool compare = first < second;
if (!compare) {
SkDebugf("%s test[%d]: lesser[%d] > greater[%d]\n", __FUNCTION__,
diff --git a/tests/PathOpsCubicIntersectionTest.cpp b/tests/PathOpsCubicIntersectionTest.cpp
index f3db3c0909..6af76c2adb 100644
--- a/tests/PathOpsCubicIntersectionTest.cpp
+++ b/tests/PathOpsCubicIntersectionTest.cpp
@@ -163,6 +163,9 @@ static const SkDCubic testSet[] = {
const size_t testSetCount = SK_ARRAY_COUNT(testSet);
static const SkDCubic newTestSet[] = {
+{{{3, 5}, {1, 6}, {5, 0}, {3, 1}}},
+{{{0, 5}, {1, 3}, {5, 3}, {6, 1}}},
+
{{{0, 1}, {1, 5}, {1, 0}, {1, 0}}},
{{{0, 1}, {0, 1}, {1, 0}, {5, 1}}},
@@ -283,8 +286,8 @@ static void newOneOff(skiatest::Reporter* reporter, int outer, int inner) {
}
static void oneOffTest(skiatest::Reporter* reporter) {
+ oneOff(reporter, 14, 16);
newOneOff(reporter, 0, 1);
- oneOff(reporter, 0, 1);
}
static void oneOffTests(skiatest::Reporter* reporter) {
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 4d7c621c3e..91a36150a0 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -1096,9 +1096,37 @@ static void rectOp1d(skiatest::Reporter* reporter) {
testPathOp(reporter, path, pathB, kDifference_PathOp);
}
-static void (*firstTest)(skiatest::Reporter* ) = rectOp1d;
+static void cubicOp66u(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,6, 4,2, 5,3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,4);
+ pathB.cubicTo(3,5, 1,0, 6,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp);
+}
+
+static void cubicOp67u(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.moveTo(3,5);
+ path.cubicTo(1,6, 5,0, 3,1);
+ path.lineTo(3,5);
+ path.close();
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,3, 5,3, 6,1);
+ pathB.lineTo(0,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp);
+}
+
+static void (*firstTest)(skiatest::Reporter* ) = cubicOp1i;
static struct TestDesc tests[] = {
+ TEST(cubicOp67u),
+ TEST(cubicOp66u),
TEST(rectOp1d),
TEST(cubicOp65d),
TEST(cubicOp64d),
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index 85555631df..4276051c6c 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -252,8 +252,7 @@ static void oneOffTest1(skiatest::Reporter* reporter, size_t outer, size_t inner
}
static void QuadraticIntersection_OneOffTest(skiatest::Reporter* reporter) {
- oneOffTest1(reporter, 0, 1);
- oneOffTest1(reporter, 1, 0);
+ oneOffTest1(reporter, 43, 47);
}
static void oneOffTests(skiatest::Reporter* reporter) {
@@ -465,3 +464,4 @@ static void PathOpsQuadIntersectionTest(skiatest::Reporter* reporter) {
#include "TestClassDef.h"
DEFINE_TESTCLASS_SHORT(PathOpsQuadIntersectionTest)
+DEFINE_TESTCLASS_SHORT(QuadraticIntersection_OneOffTest)