1<html> 2<head> 3<div height="0" hidden="true"> 4 5Skia UnitTests: --match PathOpsOp$ --resourcePath resources\ SK_DEBUG 6<div id="android1"> 7seg=1 {{{-5, 0}, {1075, 0}}} 8seg=2 {{{1075, 0}, {1075, 242}}} 9seg=3 {{{1075, 242}, {-5, 242}}} 10seg=4 {{{-5, 242}, {-5, 0}}} 11op sect 12seg=5 {{{0, 0}, {1080, 0}}} 13seg=6 {{{1080, 0}, {1080, 242}}} 14seg=7 {{{1080, 242}, {0, 242}}} 15seg=8 {{{0, 242}, {0, 0}}} 16debugShowLineIntersection wtTs[0]=0 {{{1075,0}, {1075,242}}} {{1075,0}} wnTs[0]=1 {{{-5,0}, {1075,0}}} 17debugShowLineIntersection wtTs[0]=1 {{{-5,242}, {-5,0}}} {{-5,0}} wnTs[0]=0 {{{-5,0}, {1075,0}}} 18debugShowLineIntersection wtTs[0]=0 {{{1075,242}, {-5,242}}} {{1075,242}} wnTs[0]=1 {{{1075,0}, {1075,242}}} 19debugShowLineIntersection wtTs[0]=0 {{{-5,242}, {-5,0}}} {{-5,242}} wnTs[0]=1 {{{1075,242}, {-5,242}}} 20debugShowLineIntersection wtTs[0]=0 {{{0,0}, {1080,0}}} {{0,0}} wtTs[1]=0.99537037 {{1075,0}} wnTs[0]=0.00462963 {{{-5,0}, {1075,0}}} wnTs[1]=1 21SkOpSegment::addT insert t=0.00462962963 segID=1 spanID=17 22SkOpSegment::addT insert t=0.99537037 segID=5 spanID=18 23debugShowLineIntersection wtTs[0]=1 {{{0,242}, {0,0}}} {{0,0}} wnTs[0]=0.00462963 {{{-5,0}, {1075,0}}} 24debugShowLineIntersection wtTs[0]=0.99537037 {{{0,0}, {1080,0}}} {{1075,0}} wnTs[0]=0 {{{1075,0}, {1075,242}}} 25debugShowLineIntersection wtTs[0]=0.00462962963 {{{1080,242}, {0,242}}} {{1075,242}} wnTs[0]=1 {{{1075,0}, {1075,242}}} 26SkOpSegment::addT insert t=0.00462962963 segID=7 spanID=19 27debugShowLineIntersection wtTs[0]=0.00462962963 {{{1080,242}, {0,242}}} {{1075,242}} wtTs[1]=1 {{0,242}} wnTs[0]=0 {{{1075,242}, {-5,242}}} wnTs[1]=0.99537037 28SkOpSegment::addT insert t=0.99537037 segID=3 spanID=20 29debugShowLineIntersection wtTs[0]=0 {{{0,242}, {0,0}}} {{0,242}} wnTs[0]=0.99537 {{{1075,242}, {-5,242}}} 30debugShowLineIntersection wtTs[0]=0 {{{1080,0}, {1080,242}}} {{1080,0}} wnTs[0]=1 {{{0,0}, {1080,0}}} 31debugShowLineIntersection wtTs[0]=1 {{{0,242}, {0,0}}} {{0,0}} wnTs[0]=0 {{{0,0}, {1080,0}}} 32debugShowLineIntersection wtTs[0]=0 {{{1080,242}, {0,242}}} {{1080,242}} wnTs[0]=1 {{{1080,0}, {1080,242}}} 33debugShowLineIntersection wtTs[0]=0 {{{0,242}, {0,0}}} {{0,242}} wnTs[0]=1 {{{1080,242}, {0,242}}} 34------------------x--x---------------- addExpanded 3500: seg/base=3/5 seg/base=7/19 MarkCoinStart 3601: seg/base=3/20 seg/base=7/14 MarkCoinEnd 3702: seg/base=1/17 seg/base=5/9 MarkCoinStart 3803: seg/base=1/2 seg/base=5/18 MarkCoinEnd 39SkOpSegment::debugShowActiveSpans id=1 (-5,0 -8.8817842e-16,0) t=0 tEnd=0.00462962963 windSum=? windValue=1 40SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? windValue=1 41SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1 42SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=? windValue=1 43SkOpSegment::debugShowActiveSpans id=3 (2.22044605e-14,242 -5,242) t=0.99537037 tEnd=1 windSum=? windValue=1 44SkOpSegment::debugShowActiveSpans id=4 (-5,242 -5,0) t=0 tEnd=1 windSum=? windValue=1 45SkOpSegment::debugShowActiveSpans id=5 (0,0 1075,0) t=0 tEnd=0.99537037 windSum=? windValue=1 46SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1 47SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1 48SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1 49SkOpSegment::debugShowActiveSpans id=7 (1075,242 0,242) t=0.00462962963 tEnd=1 windSum=? windValue=1 50SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=? windValue=1 51------------------x--x---------------- move_multiples 5200: seg/base=3/5 seg/base=7/19 MarkCoinStart 5301: seg/base=3/20 seg/base=7/14 MarkCoinEnd 5402: seg/base=1/17 seg/base=5/9 MarkCoinStart 5503: seg/base=1/2 seg/base=5/18 MarkCoinEnd 56------------------x--x---------------- move_nearby 5700: seg/base=3/5 seg/base=7/19 MarkCoinStart 5801: seg/base=3/20 seg/base=7/14 MarkCoinEnd 5902: seg/base=1/17 seg/base=5/9 MarkCoinStart 6003: seg/base=1/2 seg/base=5/18 MarkCoinEnd 61------------------x--x---------------- correctEnds 6200: seg/base=3/5 seg/base=7/19 MarkCoinStart 6301: seg/base=3/20 seg/base=7/14 MarkCoinEnd 6402: seg/base=1/17 seg/base=5/9 MarkCoinStart 6503: seg/base=1/2 seg/base=5/18 MarkCoinEnd 66------------------x--x---------------- addEndMovedSpans 6700: seg/base=3/5 seg/base=7/19 MarkCoinStart 6801: seg/base=3/20 seg/base=7/14 MarkCoinEnd 6902: seg/base=1/17 seg/base=5/9 MarkCoinStart 7003: seg/base=1/2 seg/base=5/18 MarkCoinEnd 71------------------x--x---------------- expand 7200: seg/base=3/5 seg/base=7/19 MarkCoinStart 7301: seg/base=3/20 seg/base=7/14 MarkCoinEnd 7402: seg/base=1/17 seg/base=5/9 MarkCoinStart 7503: seg/base=1/2 seg/base=5/18 MarkCoinEnd 76------------------x--x---------------- addExpanded 7700: seg/base=3/5 seg/base=7/19 MarkCoinStart 7801: seg/base=3/20 seg/base=7/14 MarkCoinEnd 7902: seg/base=1/17 seg/base=5/9 MarkCoinStart 8003: seg/base=1/2 seg/base=5/18 MarkCoinEnd 81------------------x--x---------------- mark 8200: seg/base=3/5 seg/base=7/19 MarkCoinStart 8301: seg/base=3/20 seg/base=7/14 MarkCoinEnd 8402: seg/base=1/17 seg/base=5/9 MarkCoinStart 8503: seg/base=1/2 seg/base=5/18 MarkCoinEnd 86-------------------------------------- missing_coincidence 87-------------------------------------- expand 88-------------------------------------- expand 89-------------------------------------- apply 90SkOpSegment::markDone id=7 (1080,242 0,242) t=0.00462962963 [19] (1075,242) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0 91SkOpSegment::markDone id=5 (0,0 1080,0) t=0 [9] (0,0) tEnd=0.99537037 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0 92-------------------------------------- findOverlaps 93SkOpSegment::debugShowActiveSpans id=1 (-5,0 -8.8817842e-16,0) t=0 tEnd=0.00462962963 windSum=? windValue=1 94SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1 95SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1 96SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=? oppSum=? windValue=1 oppValue=1 97SkOpSegment::debugShowActiveSpans id=3 (2.22044605e-14,242 -5,242) t=0.99537037 tEnd=1 windSum=? windValue=1 98SkOpSegment::debugShowActiveSpans id=4 (-5,242 -5,0) t=0 tEnd=1 windSum=? windValue=1 99SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1 100SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1 101SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1 102SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=? windValue=1 103-------------------------------------- calc_angles 104SkOpSegment::sortAngles [1] tStart=0.00462962963 [17] 105SkOpAngle::after [1/1] 15/15 tStart=0.00462962963 tEnd=0 < [8/12] 23/23 tStart=1 tEnd=0 < [1/2] 31/31 tStart=0.00462962963 tEnd=1 T 4 106SkOpAngle::afterPart {{{0,0}, {-5,0}}} id=1 107SkOpAngle::afterPart {{{0,0}, {0,242}}} id=8 108SkOpAngle::afterPart {{{0,0}, {1075,0}}} id=1 109SkOpSegment::sortAngles [1] tStart=1 [2] 110SkOpAngle::after [1/3] 15/15 tStart=1 tEnd=0.00462962963 < [2/4] 23/23 tStart=0 tEnd=1 < [5/9] 31/31 tStart=0.99537037 tEnd=1 T 4 111SkOpAngle::afterPart {{{1075,0}, {-8.8817842e-16,0}}} id=1 112SkOpAngle::afterPart {{{1075,0}, {1075,242}}} id=2 113SkOpAngle::afterPart {{{1075,0}, {1080,0}}} id=5 114SkOpSegment::sortAngles [2] tStart=0 [3] 115SkOpSegment::sortAngles [2] tStart=1 [4] 116SkOpAngle::after [2/5] 7/7 tStart=1 tEnd=0 < [3/6] 15/15 tStart=0 tEnd=0.99537037 < [7/10] 31/31 tStart=0.00462962963 tEnd=0 T 4 117SkOpAngle::afterPart {{{1075,242}, {1075,0}}} id=2 118SkOpAngle::afterPart {{{1075,242}, {2.22044605e-14,242}}} id=3 119SkOpAngle::afterPart {{{1075,242}, {1080,242}}} id=7 120SkOpSegment::sortAngles [3] tStart=0 [5] 121SkOpSegment::sortAngles [3] tStart=0.99537037 [20] 122SkOpAngle::after [3/7] 31/31 tStart=0.99537037 tEnd=0 < [8/11] 7/7 tStart=0 tEnd=1 < [3/8] 15/15 tStart=0.99537037 tEnd=1 T 4 123SkOpAngle::afterPart {{{0,242}, {1075,242}}} id=3 124SkOpAngle::afterPart {{{0,242}, {0,0}}} id=8 125SkOpAngle::afterPart {{{0,242}, {-5,242}}} id=3 126SkOpSegment::sortAngles [5] tStart=0.99537037 [18] 127SkOpSegment::sortAngles [7] tStart=0.00462962963 [19] 128SkOpSegment::sortAngles [8] tStart=0 [15] 129SkOpSegment::sortAngles [8] tStart=1 [16] 130coinSpan - id=3 t=0 tEnd=0.99537037 131coinSpan + id=7 t=0.00462962963 tEnd=1 132coinSpan - id=1 t=0.00462962963 tEnd=1 133coinSpan + id=5 t=0 tEnd=0.99537037 134SkOpSpan::sortableTop dir=kTop seg=1 t=0.00231481481 pt=(-2.5,0) 135SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=1 seg=1 {{{-5, 0}, {1075, 0}}} t=0.00231481481 pt=(-2.5,0) slope=(1080,0) 136SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 137SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 138SkOpSegment::markWinding id=4 (-5,242 -5,0) t=0 [7] (-5,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0 139SkOpSegment::markWinding id=3 (1075,242 -5,242) t=0.99537037 [20] (2.22044605e-14,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0 140SkOpSegment::activeOp id=1 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0 141SkOpSegment::markDone id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 142SkOpSegment::markDone id=4 (-5,242 -5,0) t=0 [7] (-5,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 143SkOpSegment::markDone id=3 (1075,242 -5,242) t=0.99537037 [20] (2.22044605e-14,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 144bridgeOp chase.append id=3 windSum=-1 145SkOpSegment::markWinding id=3 (1075,242 -5,242) t=0 [5] (1075,242) tEnd=0.99537037 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1 146SkOpSegment::markAngle last segment=3 span=5 windSum=-1 147SkOpSegment::markWinding id=8 (0,242 0,0) t=0 [15] (0,242) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0 148SkOpSegment::markAngle last segment=8 span=16 149SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1 150SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1 151SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=-1 oppSum=-1 windValue=1 oppValue=1 152SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1 153SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1 154SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1 155SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0 156SkOpSegment::activeOp id=3 t=0.99537037 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1 157SkOpSegment::markWinding id=7 (1080,242 0,242) t=0 [13] (1080,242) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0 158SkOpSegment::markWinding id=6 (1080,0 1080,242) t=0 [11] (1080,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0 159SkOpSegment::markWinding id=5 (0,0 1080,0) t=0.99537037 [18] (1075,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0 160SkOpSegment::markAngle last segment=5 span=18 windSum=-1 161SkOpSegment::markWinding id=2 (1075,0 1075,242) t=0 [3] (1075,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0 162SkOpSegment::markAngle last segment=2 span=3 windSum=-1 163SkOpSegment::findNextOp 164SkOpAngle::dumpOne [3/6] next=7/10 sect=15/15 s=0 [5] e=0.99537037 [20] sgn=-1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 165SkOpAngle::dumpOne [7/10] next=2/5 sect=31/31 s=0.00462962963 [19] e=0 [13] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand 166SkOpAngle::dumpOne [2/5] next=3/6 sect=7/7 s=1 [4] e=0 [3] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 167SkOpSegment::activeOp id=7 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0 168SkOpSegment::markDone id=7 (1080,242 0,242) t=0 [13] (1080,242) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 169SkOpSegment::markDone id=6 (1080,0 1080,242) t=0 [11] (1080,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 170SkOpSegment::markDone id=5 (0,0 1080,0) t=0.99537037 [18] (1075,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0 171SkOpSegment::findNextOp chase.append segment=5 span=18 windSum=-1 172SkOpSegment::activeOp id=2 t=1 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1 173SkOpSegment::findNextOp chase.append segment=2 span=3 windSum=-1 174SkOpSegment::markDone id=3 (1075,242 -5,242) t=0 [5] (1075,242) tEnd=0.99537037 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1 175SkOpSegment::findNextOp from:[3] to:[2] start=90366152 end=90366008 176bridgeOp current id=3 from=(2.22044605e-14,242) to=(1075,242) 177SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0.00462962963 [17] (-8.8817842e-16,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1 178SkOpSegment::markAngle last segment=1 span=17 windSum=-1 179SkOpSegment::findNextOp 180SkOpAngle::dumpOne [2/4] next=5/9 sect=23/23 s=0 [3] e=1 [4] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 181SkOpAngle::dumpOne [5/9] next=1/3 sect=31/31 s=0.99537037 [18] e=1 [10] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done operand 182SkOpAngle::dumpOne [1/3] next=2/4 sect=15/15 s=1 [2] e=0.00462962963 [17] sgn=1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 183SkOpSegment::activeOp id=5 t=0.99537037 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0 184SkOpSegment::activeOp id=1 t=1 tEnd=0.00462962963 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1 185SkOpSegment::findNextOp chase.append segment=1 span=17 windSum=-1 186SkOpSegment::markDone id=2 (1075,0 1075,242) t=0 [3] (1075,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0 187SkOpSegment::findNextOp from:[2] to:[1] start=90365736 end=90368360 188bridgeOp current id=2 from=(1075,242) to=(1075,0) 189path.moveTo(2.22044605e-14,242); 190path.lineTo(1075,242); 191SkOpSegment::findNextOp 192SkOpAngle::dumpOne [1/2] next=1/1 sect=31/31 s=0.00462962963 [17] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 193SkOpAngle::dumpOne [1/1] next=8/12 sect=15/15 s=0.00462962963 [17] e=0 [1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done 194SkOpAngle::dumpOne [8/12] next=1/2 sect=23/23 s=1 [16] e=0 [15] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand 195SkOpSegment::activeOp id=1 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0 196SkOpSegment::activeOp id=8 t=1 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1 197SkOpSegment::markDone id=1 (-5,0 1075,0) t=0.00462962963 [17] (-8.8817842e-16,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1 198SkOpSegment::findNextOp from:[1] to:[8] start=90368192 end=90368048 199bridgeOp current id=1 from=(1075,0) to=(-8.8817842e-16,0) 200path.lineTo(1075,0); 201SkOpSegment::findNextOp 202SkOpAngle::dumpOne [8/11] next=3/8 sect=7/7 s=0 [15] e=1 [16] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand 203SkOpAngle::dumpOne [3/8] next=3/7 sect=15/15 s=0.99537037 [20] e=1 [6] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done 204SkOpAngle::dumpOne [3/7] next=8/11 sect=31/31 s=0.99537037 [20] e=0 [5] sgn=1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 done 205SkOpSegment::activeOp id=3 t=0.99537037 tEnd=1 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0 206SkOpSegment::activeOp id=3 t=0.99537037 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1 207SkOpSegment::markDone id=8 (0,242 0,0) t=0 [15] (0,242) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0 208SkOpSegment::findNextOp from:[8] to:[3] start=90368840 end=90366336 209bridgeOp current id=8 from=(0,0) to=(0,242) 210path.lineTo(-8.8817842e-16,0); 211path.lineTo(0,242); 212path.close(); 213</div> 214 215</div> 216 217<script type="text/javascript"> 218 219 var testDivs = [ 220 android1, 221 ]; 222 223var decimal_places = 3; // make this 3 to show more precision 224 225var tests = []; 226var testLines = []; 227var testTitles = []; 228var testIndex = 0; 229var ctx; 230 231var xmin, xmax, focusXmin, focusXmax; 232var ymin, ymax, focusYmin, focusYmax; 233var scale; 234var mouseX, mouseY; 235var srcLeft, srcTop; 236var screenWidth, screenHeight; 237var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics; 238var curveT = 0; 239 240var pt_labels = 2; 241var collect_bounds = false; 242var control_lines = 0; 243var curve_t = false; 244var debug_xy = 1; 245var focus_enabled = false; 246var focus_on_selection = false; 247var step_limit = 0; 248var draw_active = false; 249var draw_add = false; 250var draw_angle = 0; 251var draw_coincidence = false; 252var draw_deriviatives = 0; 253var draw_direction = false; 254var draw_hints = false; 255var draw_id = false; 256var draw_intersection = 0; 257var draw_intersectT = false; 258var draw_legend = true; 259var draw_log = false; 260var draw_mark = false; 261var draw_midpoint = false; 262var draw_op = 0; 263var draw_sequence = false; 264var draw_sort = 0; 265var draw_top = false; 266var draw_path = 3; 267var draw_computed = 0; 268var retina_scale = !!window.devicePixelRatio; 269 270var activeCount = 0; 271var addCount = 0; 272var angleCount = 0; 273var coinCount = 0; 274var opCount = 0; 275var sectCount = 0; 276var sortCount = 0; 277var topCount = 0; 278var markCount = 0; 279var activeMax = 0; 280var addMax = 0; 281var angleMax = 0; 282var coinMax = 0; 283var sectMax = 0; 284var sectMax2 = 0; 285var sortMax = 0; 286var topMax = 0; 287var markMax = 0; 288var opMax = 0; 289var stepMax = 0; 290var lastIndex = 0; 291var hasPath = false; 292var hasAlignedPath = false; 293var hasComputedPath = false; 294var angleBetween = false; 295var afterIndex = 0; 296 297var firstActiveSpan = -1; 298var logStart = -1; 299var logRange = 0; 300 301var SPAN_ID = 0; 302var SPAN_X1 = SPAN_ID + 1; 303var SPAN_Y1 = SPAN_X1 + 1; 304var SPAN_X2 = SPAN_Y1 + 1; 305var SPAN_Y2 = SPAN_X2 + 1; 306 307var SPAN_L_TX = SPAN_Y2 + 1; 308var SPAN_L_TY = SPAN_L_TX + 1; 309var SPAN_L_OTHER = SPAN_L_TY + 1; 310var SPAN_L_OTHERT = SPAN_L_OTHER + 1; 311var SPAN_L_OTHERI = SPAN_L_OTHERT + 1; 312var SPAN_L_SUM = SPAN_L_OTHERI + 1; 313var SPAN_L_VAL = SPAN_L_SUM + 1; 314var SPAN_L_OPP = SPAN_L_VAL + 1; 315 316var SPAN_X3 = SPAN_Y2 + 1; 317var SPAN_Y3 = SPAN_X3 + 1; 318 319var SPAN_Q_TX = SPAN_Y3 + 1; 320var SPAN_Q_TY = SPAN_Q_TX + 1; 321var SPAN_Q_OTHER = SPAN_Q_TY + 1; 322var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1; 323var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1; 324var SPAN_Q_SUM = SPAN_Q_OTHERI + 1; 325var SPAN_Q_VAL = SPAN_Q_SUM + 1; 326var SPAN_Q_OPP = SPAN_Q_VAL + 1; 327 328var SPAN_K_W = SPAN_Y3 + 1; 329var SPAN_K_TX = SPAN_K_W + 1; 330var SPAN_K_TY = SPAN_K_TX + 1; 331var SPAN_K_OTHER = SPAN_K_TY + 1; 332var SPAN_K_OTHERT = SPAN_K_OTHER + 1; 333var SPAN_K_OTHERI = SPAN_K_OTHERT + 1; 334var SPAN_K_SUM = SPAN_K_OTHERI + 1; 335var SPAN_K_VAL = SPAN_K_SUM + 1; 336var SPAN_K_OPP = SPAN_K_VAL + 1; 337 338var SPAN_X4 = SPAN_Y3 + 1; 339var SPAN_Y4 = SPAN_X4 + 1; 340 341var SPAN_C_TX = SPAN_Y4 + 1; 342var SPAN_C_TY = SPAN_C_TX + 1; 343var SPAN_C_OTHER = SPAN_C_TY + 1; 344var SPAN_C_OTHERT = SPAN_C_OTHER + 1; 345var SPAN_C_OTHERI = SPAN_C_OTHERT + 1; 346var SPAN_C_SUM = SPAN_C_OTHERI + 1; 347var SPAN_C_VAL = SPAN_C_SUM + 1; 348var SPAN_C_OPP = SPAN_C_VAL + 1; 349 350var ACTIVE_LINE_SPAN = 1; 351var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1; 352var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1; 353var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1; 354 355var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1; 356var ADD_LINETO = ADD_MOVETO + 1; 357var ADD_QUADTO = ADD_LINETO + 1; 358var ADD_CONICTO = ADD_QUADTO + 1; 359var ADD_CUBICTO = ADD_CONICTO + 1; 360var ADD_CLOSE = ADD_CUBICTO + 1; 361var ADD_FILL = ADD_CLOSE + 1; 362 363var PATH_LINE = ADD_FILL + 1; 364var PATH_QUAD = PATH_LINE + 1; 365var PATH_CONIC = PATH_QUAD + 1; 366var PATH_CUBIC = PATH_CONIC + 1; 367 368var INTERSECT_LINE = PATH_CUBIC + 1; 369var INTERSECT_LINE_2 = INTERSECT_LINE + 1; 370var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1; 371var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1; 372var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1; 373var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1; 374var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1; 375var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1; 376var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1; 377var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1; 378var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1; 379var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1; 380var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1; 381var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1; 382var INTERSECT_CONIC_QUAD_3 = INTERSECT_CONIC_QUAD_2 + 1; 383var INTERSECT_CONIC_QUAD_4 = INTERSECT_CONIC_QUAD_3 + 1; 384var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_4 + 1; 385var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1; 386var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1; 387var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1; 388var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1; 389var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1; 390var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1; 391var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1; 392var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1; 393var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1; 394var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1; 395var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1; 396var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1; 397var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1; 398var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1; 399var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1; 400var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1; 401var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1; 402var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1; 403// FIXME: add cubic 5- 9 404var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1; 405 406var SORT_UNARY = INTERSECT_CUBIC_NO + 1; 407var SORT_BINARY = SORT_UNARY + 1; 408 409var OP_DIFFERENCE = SORT_BINARY + 1; 410var OP_INTERSECT = OP_DIFFERENCE + 1; 411var OP_UNION = OP_INTERSECT + 1; 412var OP_XOR = OP_UNION + 1; 413 414var MARK_LINE = OP_XOR + 1; 415var MARK_QUAD = MARK_LINE + 1; 416var MARK_CONIC = MARK_QUAD + 1; 417var MARK_CUBIC = MARK_CONIC + 1; 418var MARK_DONE_LINE = MARK_CUBIC + 1; 419var MARK_DONE_QUAD = MARK_DONE_LINE + 1; 420var MARK_DONE_CONIC = MARK_DONE_QUAD + 1; 421var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1; 422var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1; 423var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1; 424var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1; 425var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1; 426var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1; 427var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1; 428var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1; 429var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1; 430var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1; 431var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1; 432var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1; 433var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1; 434var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1; 435var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1; 436var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1; 437var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1; 438var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1; 439 440var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1; 441var COMPUTED_SET_2 = COMPUTED_SET_1 + 1; 442 443var ANGLE_AFTER = COMPUTED_SET_2 + 1; 444var ANGLE_AFTERPART = ANGLE_AFTER + 1; 445 446var ACTIVE_OP = ANGLE_AFTERPART + 1; 447 448var COIN_MAIN_SPAN = ACTIVE_OP + 1; 449var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1; 450 451var FRAG_TYPE_LAST = COIN_OPP_SPAN; 452 453var REC_TYPE_UNKNOWN = -1; 454var REC_TYPE_PATH = 0; 455var REC_TYPE_PATH2 = 1; 456var REC_TYPE_SECT = 2; 457var REC_TYPE_ACTIVE = 3; 458var REC_TYPE_ADD = 4; 459var REC_TYPE_SORT = 5; 460var REC_TYPE_OP = 6; 461var REC_TYPE_MARK = 7; 462var REC_TYPE_COMPUTED = 8; 463var REC_TYPE_COIN = 9; 464var REC_TYPE_ANGLE = 10; 465var REC_TYPE_ACTIVE_OP = 11; 466var REC_TYPE_AFTERPART = 12; 467var REC_TYPE_TOP = 13; 468var REC_TYPE_COINCIDENCE = 14; 469var REC_TYPE_ALIGNED = 15; 470var REC_TYPE_LAST = REC_TYPE_ALIGNED; 471 472function strs_to_nums(strs) { 473 var result = []; 474 for (var idx = 1; idx < strs.length; ++idx) { 475 var str = strs[idx]; 476 var num = parseFloat(str); 477 if (isNaN(num)) { 478 result.push(str); 479 } else { 480 result.push(num); 481 } 482 } 483 return result; 484} 485 486function filter_str_by(id, str, regex, array) { 487 if (regex.test(str)) { 488 var strs = regex.exec(str); 489 var result = strs_to_nums(strs); 490 array.push(id); 491 array.push(result); 492 return true; 493 } 494 return false; 495} 496 497function construct_regexp2(pattern) { 498 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 499 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*"); 500 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)"); 501 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)"); 502 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)"); 503 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)"); 504 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType"); 505 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+"); 506 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)"); 507 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 508 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)"); 509 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 510 escape = escape.replace(/PATH/g, "pathB?"); 511 escape = escape.replace(/IDX/g, "(-?\\d+)"); 512 escape = escape.replace(/NUM/g, "(-?\\d+)"); 513 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)"); 514 return new RegExp(escape, 'i'); 515} 516 517function construct_regexp2c(pattern) { 518 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 519 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*"); 520 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}"); 521 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}"); 522 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}"); 523 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}"); 524 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType"); 525 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+"); 526 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}"); 527 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 528 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)"); 529 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?"); 530 escape = escape.replace(/OPER/g, "[a-z]+"); 531 escape = escape.replace(/PATH/g, "pathB?"); 532 escape = escape.replace(/T_F/g, "([TF])"); 533 escape = escape.replace(/IDX/g, "(-?\\d+)"); 534 escape = escape.replace(/NUM/g, "(-?\\d+)"); 535 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)"); 536 return new RegExp(escape, 'i'); 537} 538 539function match_regexp(str, lineNo, array, id, pattern) { 540 var regex = construct_regexp2(pattern); 541 if (filter_str_by(id, str, regex, array)) { 542 return true; 543 } 544 regex = construct_regexp2c(pattern); 545 return filter_str_by(id, str, regex, array); 546} 547 548function endsWith(str, suffix) { 549 return str.indexOf(suffix, str.length - suffix.length) !== -1; 550} 551 552function parse_all(test) { 553 var lines = test.match(/[^\r\n]+/g); 554 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add 555 var record = []; 556 var recType = REC_TYPE_UNKNOWN; 557 var lastLineNo; 558 var moveX, moveY; 559 for (var lineNo = 0; lineNo < lines.length; ++lineNo) { 560 var line = lines[lineNo]; 561 if (line.length == 0) { 562 continue; 563 } 564 var opStart = "SkOpSegment::"; 565 if (line.lastIndexOf(opStart, 0) === 0) { 566 line = line.substr(opStart.length); 567 } 568 var angleStart = "SkOpAngle::"; 569 if (line.lastIndexOf(angleStart, 0) === 0) { 570 line = line.substr(angleStart.length); 571 } 572 var coinStart = "SkOpCoincidence::"; 573 if (line.lastIndexOf(coinStart, 0) === 0) { 574 line = line.substr(coinStart.length); 575 } 576 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE 577 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE 578 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2 579 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN 580 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART 581 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT 582 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP 583 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED 584 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT 585 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED 586 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT 587 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP 588 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD 589 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD 590 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE 591 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK 592 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED 593 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH 594 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP 595 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH 596 : REC_TYPE_UNKNOWN; 597 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT 598 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) { 599 if (recType != REC_TYPE_UNKNOWN) { 600 records.push(recType); 601 records.push(lastLineNo); 602 records.push(record); 603 } 604 record = []; 605 recType = type; 606 lastLineNo = lineNo; 607 } 608 var found = false; 609 switch (recType) { 610 case REC_TYPE_ACTIVE: 611 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" + 612" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX" 613 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" + 614" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX" 615 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" + 616" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX" 617 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" + 618" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX" 619 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" + 620" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM" 621 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" + 622" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM" 623 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" + 624" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM" 625 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" + 626" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM" 627 ); 628 break; 629 case REC_TYPE_ACTIVE_OP: 630 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" + 631" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX" 632 ); 633 break; 634 case REC_TYPE_ADD: 635 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) { 636 moveX = record[1][0]; 637 moveY = record[1][1]; 638 found = true; 639 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) { 640 record[1].unshift(moveY); 641 record[1].unshift(moveX); 642 moveX = record[1][2]; 643 moveY = record[1][3]; 644 found = true; 645 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) { 646 record[1].unshift(moveY); 647 record[1].unshift(moveX); 648 moveX = record[1][4]; 649 moveY = record[1][5]; 650 found = true; 651 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) { 652 record[1].unshift(moveY); 653 record[1].unshift(moveX); 654 moveX = record[1][4]; 655 moveY = record[1][5]; 656 found = true; 657 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) { 658 record[1].unshift(moveY); 659 record[1].unshift(moveX); 660 moveX = record[1][6]; 661 moveY = record[1][7]; 662 found = true; 663 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) { 664 found = true; 665 } else { 666 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();"); 667 } 668 break; 669 case REC_TYPE_AFTERPART: 670 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL id=IDX") 671 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL id=IDX") 672 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL id=IDX") 673 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL id=IDX") 674 break; 675 case REC_TYPE_ALIGNED: 676 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL" 677 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL" 678 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL" 679 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL" 680 ); 681 break; 682 case REC_TYPE_ANGLE: 683 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " + 684"[IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL < [IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL < [IDX/IDX] NUM/NUM tStart=T_VAL tEnd=T_VAL T_F IDX"); 685 break; 686 case REC_TYPE_COIN: 687 found = true; 688 break; 689 case REC_TYPE_COINCIDENCE: 690 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" + 691" + id=IDX t=T_VAL tEnd=T_VAL" 692 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" + 693" - id=IDX t=T_VAL tEnd=T_VAL" 694 ); 695 break; 696 case REC_TYPE_COMPUTED: 697 found = line == "computed quadratics given" 698 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1" 699 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2" 700 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL," 701 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL," 702 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL," 703 ); 704 break; 705 case REC_TYPE_PATH: 706 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL" 707 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL" 708 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL" 709 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL" 710 ); 711 break; 712 case REC_TYPE_PATH2: 713 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}" 714 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}" 715 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}" 716 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}" 717 ); 718 break; 719 case REC_TYPE_SECT: 720 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" + 721" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 722 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" + 723" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 724 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" + 725" no intersect LINE_VAL LINE_VAL" 726 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" + 727" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 728 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" + 729" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 730 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" + 731" no intersect QUAD_VAL LINE_VAL" 732 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" + 733" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL" 734 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" + 735" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL" 736 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" + 737" no intersect QUAD_VAL QUAD_VAL" 738 739 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" + 740" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 741 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" + 742" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 743 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" + 744" no intersect CONIC_VAL LINE_VAL" 745 746 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" + 747" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL" 748 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" + 749" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL" 750 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_3, "debugShowConicQuadIntersection" + 751" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL" 752 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_4, "debugShowConicQuadIntersection" + 753" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL" 754 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" + 755" no intersect CONIC_VAL QUAD_VAL" 756 757 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" + 758" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL" 759 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" + 760" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL" 761 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" + 762" no intersect CONIC_VAL CONIC_VAL" 763 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" + 764" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL" 765 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" + 766" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL" 767 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" + 768" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL" 769 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" + 770" no intersect CUBIC_VAL LINE_VAL" 771 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" + 772" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL" 773 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" + 774" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL" 775 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" + 776" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL" 777 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" + 778" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL" 779 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" + 780" no intersect CUBIC_VAL QUAD_VAL" 781 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" + 782" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL" 783 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" + 784" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL" 785 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" + 786" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL" 787 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" + 788" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL" 789 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" + 790" no intersect CUBIC_VAL CUBIC_VAL" 791 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" + 792" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL" 793 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" + 794" no self intersect CUBIC_VAL" 795 ); 796 break; 797 case REC_TYPE_SORT: 798 var hasDone = / done/.test(line); 799 var hasUnorderable = / unorderable/.test(line); 800 var hasSmall = / small/.test(line); 801 var hasTiny = / tiny/.test(line); 802 var hasOperand = / operand/.test(line); 803 var hasStop = / stop/.test(line); 804 line.replace(/[ a-z]+$/, ""); 805 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" + 806" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT" 807 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" + 808" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT oppVal=IDX oppSum=OPT" 809 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" + 810" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT" 811 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" + 812" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT oppVal=IDX oppSum=OPT" 813 ); 814 if (found) { 815 record[1].push(hasDone); 816 record[1].push(hasUnorderable); 817 record[1].push(hasSmall); 818 record[1].push(hasTiny); 819 record[1].push(hasOperand); 820 record[1].push(hasStop); 821 } 822 break; 823 case REC_TYPE_TOP: 824 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" + 825" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM" 826 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" + 827" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM" 828 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" + 829" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM" 830 ); 831 break; 832 case REC_TYPE_MARK: 833 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" + 834" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX" 835 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" + 836" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX" 837 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" + 838" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX" 839 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" + 840" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX" 841 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" + 842" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT" 843 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" + 844" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT" 845 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" + 846" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT" 847 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" + 848" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT" 849 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" + 850" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 851 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" + 852" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 853 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" + 854" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 855 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" + 856" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX" 857 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" + 858" last segment=IDX span=IDX" 859 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" + 860" last seg=IDX span=IDX" 861 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" + 862" last segment=IDX span=IDX windSum=OPT" 863 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" + 864" last seg=IDX span=IDX windSum=OPT" 865 ); 866 break; 867 case REC_TYPE_OP: 868 if (line.lastIndexOf("oppSign oppSign=", 0) === 0 869 || line.lastIndexOf("operator<", 0) === 0) { 870 found = true; 871 break; 872 } 873 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff" 874 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect" 875 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect" 876 ) || match_regexp(line, lineNo, record, OP_UNION, "op union" 877 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor" 878 ); 879 break; 880 case REC_TYPE_UNKNOWN: 881 found = true; 882 break; 883 } 884 if (!found) { 885 console.log(line + " [" + lineNo + "] of type " + type + " not found"); 886 } 887 } 888 if (recType != REC_TYPE_UNKNOWN) { 889 records.push(recType); 890 records.push(lastLineNo); 891 records.push(record); 892 } 893 if (records.length >= 1) { 894 tests[testIndex] = records; 895 testLines[testIndex] = lines; 896 } 897} 898 899function init(test) { 900 var canvas = document.getElementById('canvas'); 901 if (!canvas.getContext) return; 902 ctx = canvas.getContext('2d'); 903 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1; 904 var unscaledWidth = window.innerWidth - 20; 905 var unscaledHeight = window.innerHeight - 20; 906 screenWidth = unscaledWidth; 907 screenHeight = unscaledHeight; 908 canvas.width = unscaledWidth * resScale; 909 canvas.height = unscaledHeight * resScale; 910 canvas.style.width = unscaledWidth + 'px'; 911 canvas.style.height = unscaledHeight + 'px'; 912 if (resScale != 1) { 913 ctx.scale(resScale, resScale); 914 } 915 xmin = Infinity; 916 xmax = -Infinity; 917 ymin = Infinity; 918 ymax = -Infinity; 919 hasPath = hasAlignedPath = hasComputedPath = false; 920 firstActiveSpan = -1; 921 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 922 var recType = test[tIndex]; 923 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) { 924 console.log("unknown rec type: " + recType); 925 throw "stop execution"; 926 } 927 var records = test[tIndex + 2]; 928 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 929 var fragType = records[recordIndex]; 930 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) { 931 console.log("unknown in range frag type: " + fragType); 932 throw "stop execution"; 933 } 934 var frags = records[recordIndex + 1]; 935 var first = 0; 936 var last = -1; 937 var first2 = 0; 938 var last2 = 0; 939 switch (recType) { 940 case REC_TYPE_ALIGNED: 941 hasAlignedPath = true; 942 case REC_TYPE_COMPUTED: 943 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) { 944 break; 945 } 946 if (REC_TYPE_COMPUTED == recType) { 947 hasComputedPath = true; 948 } 949 case REC_TYPE_PATH: 950 first = 1; 951 switch (fragType) { 952 case PATH_LINE: 953 last = 5; 954 break; 955 case PATH_CONIC: 956 case PATH_QUAD: 957 last = 7; 958 break; 959 case PATH_CUBIC: 960 last = 9; 961 break; 962 default: 963 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH" 964 : "REC_TYPE_COMPUTED") + " frag type:" + fragType); 965 throw "stop execution"; 966 } 967 if (recType == REC_TYPE_PATH) { 968 hasPath = true; 969 } 970 break; 971 case REC_TYPE_PATH2: 972 first = 1; 973 switch (fragType) { 974 case PATH_LINE: 975 last = 5; 976 break; 977 case PATH_CONIC: 978 case PATH_QUAD: 979 last = 7; 980 break; 981 case PATH_CUBIC: 982 last = 9; 983 break; 984 default: 985 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2" 986 : "REC_TYPE_COMPUTED") + " frag type:" + fragType); 987 throw "stop execution"; 988 } 989 if (recType == REC_TYPE_PATH2) { 990 hasPath = true; 991 } 992 break; 993 case REC_TYPE_ACTIVE: 994 if (firstActiveSpan < 0) { 995 firstActiveSpan = tIndex; 996 } 997 first = 1; 998 switch (fragType) { 999 case ACTIVE_LINE_SPAN: 1000 last = 5; 1001 break; 1002 case ACTIVE_CONIC_SPAN: 1003 case ACTIVE_QUAD_SPAN: 1004 last = 7; 1005 break; 1006 case ACTIVE_CUBIC_SPAN: 1007 last = 9; 1008 break; 1009 default: 1010 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType); 1011 throw "stop execution"; 1012 } 1013 break; 1014 case REC_TYPE_ADD: 1015 switch (fragType) { 1016 case ADD_MOVETO: 1017 break; 1018 case ADD_LINETO: 1019 last = 4; 1020 break; 1021 case ADD_CONICTO: 1022 case ADD_QUADTO: 1023 last = 6; 1024 break; 1025 case ADD_CUBICTO: 1026 last = 8; 1027 break; 1028 case ADD_CLOSE: 1029 case ADD_FILL: 1030 break; 1031 default: 1032 console.log("unknown REC_TYPE_ADD frag type: " + fragType); 1033 throw "stop execution"; 1034 } 1035 break; 1036 case REC_TYPE_AFTERPART: 1037 switch (fragType) { 1038 case PATH_LINE: 1039 last = 4; 1040 break; 1041 case PATH_CONIC: 1042 case PATH_QUAD: 1043 last = 6; 1044 break; 1045 case PATH_CUBIC: 1046 last = 8; 1047 break; 1048 default: 1049 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType); 1050 throw "stop execution"; 1051 } 1052 break; 1053 case REC_TYPE_SECT: 1054 switch (fragType) { 1055 case INTERSECT_LINE: 1056 first = 1; last = 5; first2 = 8; last2 = 12; 1057 break; 1058 case INTERSECT_LINE_2: 1059 first = 1; last = 5; first2 = 11; last2 = 15; 1060 break; 1061 case INTERSECT_LINE_NO: 1062 first = 0; last = 4; first2 = 4; last2 = 8; 1063 break; 1064 case INTERSECT_CONIC_LINE: 1065 first = 1; last = 7; first2 = 11; last2 = 15; 1066 break; 1067 case INTERSECT_QUAD_LINE: 1068 first = 1; last = 7; first2 = 10; last2 = 14; 1069 break; 1070 case INTERSECT_CONIC_LINE_2: 1071 first = 1; last = 7; first2 = 14; last2 = 18; 1072 break; 1073 case INTERSECT_QUAD_LINE_2: 1074 first = 1; last = 7; first2 = 13; last2 = 17; 1075 break; 1076 case INTERSECT_CONIC_LINE_NO: 1077 first = 0; last = 6; first2 = 7; last2 = 11; 1078 break; 1079 case INTERSECT_QUAD_LINE_NO: 1080 first = 0; last = 6; first2 = 6; last2 = 10; 1081 break; 1082 case INTERSECT_CONIC: 1083 first = 1; last = 7; first2 = 11; last2 = 17; 1084 break; 1085 case INTERSECT_QUAD: 1086 first = 1; last = 7; first2 = 10; last2 = 16; 1087 break; 1088 case INTERSECT_CONIC_2: 1089 first = 1; last = 7; first2 = 14; last2 = 20; 1090 break; 1091 case INTERSECT_QUAD_2: 1092 first = 1; last = 7; first2 = 13; last2 = 19; 1093 break; 1094 case INTERSECT_CONIC_NO: 1095 first = 0; last = 6; first2 = 7; last2 = 13; 1096 break; 1097 case INTERSECT_QUAD_NO: 1098 first = 0; last = 6; first2 = 6; last2 = 12; 1099 break; 1100 case INTERSECT_SELF_CUBIC: 1101 first = 1; last = 9; 1102 break; 1103 case INTERSECT_SELF_CUBIC_NO: 1104 first = 0; last = 8; 1105 break; 1106 case INTERSECT_CUBIC_LINE: 1107 first = 1; last = 9; first2 = 12; last2 = 16; 1108 break; 1109 case INTERSECT_CUBIC_LINE_2: 1110 first = 1; last = 9; first2 = 15; last2 = 19; 1111 break; 1112 case INTERSECT_CUBIC_LINE_3: 1113 first = 1; last = 9; first2 = 18; last2 = 22; 1114 break; 1115 case INTERSECT_CUBIC_LINE_NO: 1116 first = 0; last = 8; first2 = 8; last2 = 12; 1117 break; 1118 case INTERSECT_CONIC_QUAD: 1119 first = 1; last = 7; first2 = 11; last2 = 17; 1120 break; 1121 case INTERSECT_CONIC_QUAD_2: 1122 first = 1; last = 7; first2 = 14; last2 = 20; 1123 break; 1124 case INTERSECT_CONIC_QUAD_3: 1125 first = 1; last = 7; first2 = 17; last2 = 23; 1126 break; 1127 case INTERSECT_CONIC_QUAD_4: 1128 first = 1; last = 7; first2 = 20; last2 = 26; 1129 break; 1130 case INTERSECT_CONIC_QUAD_NO: 1131 first = 0; last = 6; first2 = 7; last2 = 13; 1132 break; 1133 case INTERSECT_CUBIC_QUAD: 1134 first = 1; last = 9; first2 = 12; last2 = 18; 1135 break; 1136 case INTERSECT_CUBIC_QUAD_2: 1137 first = 1; last = 9; first2 = 15; last2 = 21; 1138 break; 1139 case INTERSECT_CUBIC_QUAD_3: 1140 first = 1; last = 9; first2 = 18; last2 = 24; 1141 break; 1142 case INTERSECT_CUBIC_QUAD_4: 1143 first = 1; last = 9; first2 = 21; last2 = 27; 1144 break; 1145 case INTERSECT_CUBIC_QUAD_NO: 1146 first = 0; last = 8; first2 = 8; last2 = 14; 1147 break; 1148 case INTERSECT_CUBIC: 1149 first = 1; last = 9; first2 = 12; last2 = 20; 1150 break; 1151 case INTERSECT_CUBIC_2: 1152 first = 1; last = 9; first2 = 15; last2 = 23; 1153 break; 1154 case INTERSECT_CUBIC_3: 1155 first = 1; last = 9; first2 = 18; last2 = 26; 1156 break; 1157 case INTERSECT_CUBIC_4: 1158 first = 1; last = 9; first2 = 21; last2 = 29; 1159 break; 1160 case INTERSECT_CUBIC_NO: 1161 first = 0; last = 8; first2 = 8; last2 = 16; 1162 break; 1163 default: 1164 console.log("unknown REC_TYPE_SECT frag type: " + fragType); 1165 throw "stop execution"; 1166 } 1167 break; 1168 default: 1169 continue; 1170 } 1171 for (var idx = first; idx < last; idx += 2) { 1172 xmin = Math.min(xmin, frags[idx]); 1173 xmax = Math.max(xmax, frags[idx]); 1174 ymin = Math.min(ymin, frags[idx + 1]); 1175 ymax = Math.max(ymax, frags[idx + 1]); 1176 } 1177 for (var idx = first2; idx < last2; idx += 2) { 1178 xmin = Math.min(xmin, frags[idx]); 1179 xmax = Math.max(xmax, frags[idx]); 1180 ymin = Math.min(ymin, frags[idx + 1]); 1181 ymax = Math.max(ymax, frags[idx + 1]); 1182 } 1183 } 1184 } 1185 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity]; 1186 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 1187 var recType = test[tIndex]; 1188 var records = test[tIndex + 2]; 1189 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 1190 var fragType = records[recordIndex]; 1191 var frags = records[recordIndex + 1]; 1192 switch (recType) { 1193 case REC_TYPE_ACTIVE_OP: 1194 if (!draw_op) { 1195 break; 1196 } 1197 { 1198 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 1199 curve_extremes(curve, angleBounds); 1200 } 1201 break; 1202 case REC_TYPE_ANGLE: 1203 if (!draw_angle) { 1204 break; 1205 } 1206 { 1207 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]); 1208 curve_extremes(curve, angleBounds); 1209 curve = curvePartialByID(test, frags[6], frags[10], frags[11]); 1210 curve_extremes(curve, angleBounds); 1211 curve = curvePartialByID(test, frags[12], frags[16], frags[17]); 1212 } 1213 break; 1214 case REC_TYPE_COINCIDENCE: 1215 if (!draw_coincidence) { 1216 break; 1217 } 1218 { 1219 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 1220 curve_extremes(curve, angleBounds); 1221 } 1222 break; 1223 case REC_TYPE_SORT: 1224 if (!draw_sort) { 1225 break; 1226 } 1227 if (fragType == SORT_UNARY || fragType == SORT_BINARY) { 1228 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]); 1229 curve_extremes(curve, angleBounds); 1230 } 1231 break; 1232 case REC_TYPE_TOP: 1233 if (!draw_top) { 1234 break; 1235 } 1236 { 1237 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 1238 curve_extremes(curve, angleBounds); 1239 } 1240 break; 1241 } 1242 } 1243 } 1244 xmin = Math.min(xmin, angleBounds[0]); 1245 ymin = Math.min(ymin, angleBounds[1]); 1246 xmax = Math.max(xmax, angleBounds[2]); 1247 ymax = Math.max(ymax, angleBounds[3]); 1248 setScale(xmin, xmax, ymin, ymax); 1249 if (hasPath == false && hasComputedPath == true && !draw_computed) { 1250 draw_computed = 7; // show quadratics, conics, and cubics 1251 } 1252 if (hasPath == true && hasComputedPath == false && draw_computed) { 1253 draw_computed = 0; 1254 } 1255} 1256 1257function curveByIDMatch(test, id, recMatch) { 1258 var tIndex = -3; 1259 while ((tIndex += 3) < test.length) { 1260 var recType = test[tIndex]; 1261 if (recType == REC_TYPE_OP) { 1262 continue; 1263 } 1264 if (recType != recMatch) { 1265 return []; 1266 } 1267 var records = test[tIndex + 2]; 1268 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 1269 var fragType = records[recordIndex]; 1270 var frags = records[recordIndex + 1]; 1271 if (frags[0] == id) { 1272 switch (fragType) { 1273 case PATH_LINE: 1274 return [frags[1], frags[2], frags[3], frags[4]]; 1275 case PATH_QUAD: 1276 return [frags[1], frags[2], frags[3], frags[4], 1277 frags[5], frags[6]]; 1278 case PATH_CONIC: 1279 return [frags[1], frags[2], frags[3], frags[4], 1280 frags[5], frags[6], frags[7]]; 1281 case PATH_CUBIC: 1282 return [frags[1], frags[2], frags[3], frags[4], 1283 frags[5], frags[6], frags[7], frags[8]]; 1284 } 1285 } 1286 } 1287 } 1288 return []; 1289} 1290 1291function curveByID(test, id) { 1292 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : []; 1293 if (!result.length) { 1294 result = curveByIDMatch(test, id, REC_TYPE_PATH); 1295 } 1296 return result; 1297} 1298 1299function curvePartialByIDMatch(test, id, t0, t1, recMatch) { 1300 var tIndex = -3; 1301 while ((tIndex += 3) < test.length) { 1302 var recType = test[tIndex]; 1303 if (recType == REC_TYPE_OP) { 1304 continue; 1305 } 1306 if (recType != recMatch) { 1307 return []; 1308 } 1309 var records = test[tIndex + 2]; 1310 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 1311 var fragType = records[recordIndex]; 1312 var frags = records[recordIndex + 1]; 1313 if (frags[0] == id) { 1314 switch (fragType) { 1315 case PATH_LINE: 1316 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1); 1317 case PATH_QUAD: 1318 return quadPartial(frags[1], frags[2], frags[3], frags[4], 1319 frags[5], frags[6], t0, t1); 1320 case PATH_CONIC: 1321 return conicPartial(frags[1], frags[2], frags[3], frags[4], 1322 frags[5], frags[6], frags[7], t0, t1); 1323 case PATH_CUBIC: 1324 return cubicPartial(frags[1], frags[2], frags[3], frags[4], 1325 frags[5], frags[6], frags[7], frags[8], t0, t1); 1326 } 1327 } 1328 } 1329 } 1330 return []; 1331} 1332 1333function curvePartialByID(test, id, t0, t1) { 1334 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : []; 1335 if (!result.length) { 1336 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH); 1337 } 1338 return result; 1339} 1340 1341function idByCurveIDMatch(test, frag, type, recMatch) { 1342 var tIndex = 0; 1343 while (tIndex < test.length) { 1344 var recType = test[tIndex]; 1345 if (recType != recMatch) { 1346 ++tIndex; 1347 continue; 1348 } 1349 var records = test[tIndex + 2]; 1350 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 1351 var fragType = records[recordIndex]; 1352 var frags = records[recordIndex + 1]; 1353 if (frag.length != frags.length - 1) { 1354 continue; 1355 } 1356 switch (fragType) { 1357 case PATH_LINE: 1358 if (frag[0] != frags[1] || frag[1] != frags[2] 1359 || frag[2] != frags[3] || frag[3] != frags[4]) { 1360 continue; 1361 } 1362 return frags[0]; 1363 case PATH_QUAD: 1364 if (frag[0] != frags[1] || frag[1] != frags[2] 1365 || frag[2] != frags[3] || frag[3] != frags[4] 1366 || frag[4] != frags[5] || frag[5] != frags[6]) { 1367 continue; 1368 } 1369 return frags[0]; 1370 case PATH_CONIC: 1371 if (frag[0] != frags[1] || frag[1] != frags[2] 1372 || frag[2] != frags[3] || frag[3] != frags[4] 1373 || frag[4] != frags[5] || frag[5] != frags[6] 1374 || frag[6] != frags[7]) { 1375 continue; 1376 } 1377 return frags[0]; 1378 case PATH_CUBIC: 1379 if (frag[0] != frags[1] || frag[1] != frags[2] 1380 || frag[2] != frags[3] || frag[3] != frags[4] 1381 || frag[4] != frags[5] || frag[5] != frags[6] 1382 || frag[6] != frags[7] || frag[7] != frags[8]) { 1383 continue; 1384 } 1385 return frags[0]; 1386 } 1387 } 1388 ++tIndex; 1389 } 1390 return -1; 1391} 1392 1393function idByCurve(test, frag, type) { 1394 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : []; 1395 if (!result.length) { 1396 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH); 1397 } 1398 return result; 1399} 1400 1401function curve_extremes(curve, bounds) { 1402 var length = curve.length == 7 ? 6 : curve.length; 1403 for (var index = 0; index < length; index += 2) { 1404 var x = curve[index]; 1405 var y = curve[index + 1]; 1406 bounds[0] = Math.min(bounds[0], x); 1407 bounds[1] = Math.min(bounds[1], y); 1408 bounds[2] = Math.max(bounds[2], x); 1409 bounds[3] = Math.max(bounds[3], y); 1410 } 1411} 1412 1413function setScale(x0, x1, y0, y1) { 1414 var srcWidth = x1 - x0; 1415 var srcHeight = y1 - y0; 1416 var usableWidth = screenWidth; 1417 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10)); 1418 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10)); 1419 usableWidth -= (xDigits + yDigits) * 10; 1420 usableWidth -= decimal_places * 10; 1421 if (draw_legend) { 1422 usableWidth -= 40; 1423 } 1424 var hscale = usableWidth / srcWidth; 1425 var vscale = screenHeight / srcHeight; 1426 scale = Math.min(hscale, vscale); 1427 var invScale = 1 / scale; 1428 var sxmin = x0 - invScale * 5; 1429 var symin = y0 - invScale * 10; 1430 var sxmax = x1 + invScale * (6 * decimal_places + 10); 1431 var symax = y1 + invScale * 10; 1432 srcWidth = sxmax - sxmin; 1433 srcHeight = symax - symin; 1434 hscale = usableWidth / srcWidth; 1435 vscale = screenHeight / srcHeight; 1436 scale = Math.min(hscale, vscale); 1437 srcLeft = sxmin; 1438 srcTop = symin; 1439} 1440 1441function drawArc(curve, op, from, to) { 1442 var type = PATH_LINE + (curve.length / 2 - 2); 1443 var pt = pointAtT(curve, type, op ? 0.4 : 0.6); 1444 var dy = pt.y - curve[1]; 1445 var dx = pt.x - curve[0]; 1446 var dist = Math.sqrt(dy * dy + dx * dx); 1447 var _dist = dist * scale; 1448 var angle = Math.atan2(dy, dx); 1449 var _px = (curve[0] - srcLeft) * scale; 1450 var _py = (curve[1] - srcTop) * scale; 1451 var divisor = 4; 1452 var endDist; 1453 do { 1454 var ends = []; 1455 for (var index = -1; index <= 1; index += 2) { 1456 var px = Math.cos(index * Math.PI / divisor); 1457 var py = Math.sin(index * Math.PI / divisor); 1458 ends.push(px); 1459 ends.push(py); 1460 } 1461 var endDx = (ends[2] - ends[0]) * scale * dist; 1462 var endDy = (ends[3] - ends[1]) * scale * dist; 1463 endDist = Math.sqrt(endDx * endDx + endDy * endDy); 1464 if (endDist < 100) { 1465 break; 1466 } 1467 divisor *= 2; 1468 } while (true); 1469 if (endDist < 30) { 1470 return; 1471 } 1472 if (op) { 1473 divisor *= 2; 1474 } 1475 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)"; 1476 ctx.beginPath(); 1477 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false); 1478 ctx.stroke(); 1479 var saveAlign = ctx.textAlign; 1480 var saveStyle = ctx.fillStyle; 1481 var saveFont = ctx.font; 1482 ctx.textAlign = "center"; 1483 ctx.fillStyle = "black"; 1484 ctx.font = "normal 24px Arial"; 1485 divisor *= 0.8; 1486 for (var index = -1; index <= 1; index += 2) { 1487 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist; 1488 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist; 1489 var _px = (px - srcLeft) * scale; 1490 var _py = (py - srcTop) * scale; 1491 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8); 1492 } 1493 ctx.textAlign = saveAlign; 1494 ctx.fillStyle = saveStyle; 1495 ctx.font = saveFont; 1496} 1497 1498function drawPoint(px, py, end) { 1499 var length = drawnPts.length == 7 ? 6 : drawnPts.length; 1500 for (var pts = 0; pts < length; pts += 2) { 1501 var x = drawnPts[pts]; 1502 var y = drawnPts[pts + 1]; 1503 if (px == x && py == y) { 1504 return; 1505 } 1506 } 1507 drawnPts.push(px); 1508 drawnPts.push(py); 1509 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places); 1510 var _px = (px - srcLeft) * scale; 1511 var _py = (py - srcTop) * scale; 1512 ctx.beginPath(); 1513 ctx.arc(_px, _py, 3, 0, Math.PI*2, true); 1514 ctx.closePath(); 1515 if (end) { 1516 ctx.fill(); 1517 } else { 1518 ctx.stroke(); 1519 } 1520 if (debug_xy) { 1521 ctx.textAlign = "left"; 1522 ctx.fillText(label, _px + 5, _py); 1523 } 1524} 1525 1526function coordCount(curveType) { 1527 switch (curveType) { 1528 case PATH_LINE: 1529 return 4; 1530 case PATH_QUAD: 1531 return 6; 1532 case PATH_CONIC: 1533 return 6; 1534 case PATH_CUBIC: 1535 return 8; 1536 } 1537 return -1; 1538} 1539 1540function drawPoints(ptArray, curveType, drawControls) { 1541 var count = coordCount(curveType); 1542 for (var idx = 0; idx < count; idx += 2) { 1543 if (!drawControls && idx != 0 && idx != count - 2) { 1544 continue; 1545 } 1546 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2); 1547 } 1548} 1549 1550function drawControlLines(curve, curveType, drawEnd) { 1551 if (curveType == PATH_LINE) { 1552 return; 1553 } 1554 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 1555 drawLine(curve[0], curve[1], curve[2], curve[3]); 1556 drawLine(curve[2], curve[3], curve[4], curve[5]); 1557 if (curveType == PATH_CUBIC) { 1558 drawLine(curve[4], curve[5], curve[6], curve[7]); 1559 if (drawEnd > 1) { 1560 drawLine(curve[6], curve[7], curve[0], curve[1]); 1561 if (drawEnd > 2) { 1562 drawLine(curve[0], curve[1], curve[4], curve[5]); 1563 drawLine(curve[6], curve[7], curve[2], curve[3]); 1564 } 1565 } 1566 } else if (drawEnd > 1) { 1567 drawLine(curve[4], curve[5], curve[0], curve[1]); 1568 } 1569} 1570 1571function pointAtT(curve, curveType, t) { 1572 var xy = {}; 1573 switch (curveType) { 1574 case PATH_LINE: 1575 var a = 1 - t; 1576 var b = t; 1577 xy.x = a * curve[0] + b * curve[2]; 1578 xy.y = a * curve[1] + b * curve[3]; 1579 break; 1580 case PATH_QUAD: 1581 var one_t = 1 - t; 1582 var a = one_t * one_t; 1583 var b = 2 * one_t * t; 1584 var c = t * t; 1585 xy.x = a * curve[0] + b * curve[2] + c * curve[4]; 1586 xy.y = a * curve[1] + b * curve[3] + c * curve[5]; 1587 break; 1588 case PATH_CONIC: 1589 var one_t = 1 - t; 1590 var a = one_t * one_t; 1591 var b = 2 * one_t * t; 1592 var c = t * t; 1593 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4]; 1594 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5]; 1595 var d = a + b * curve[6] + c; 1596 xy.x /= d; 1597 xy.y /= d; 1598 break; 1599 case PATH_CUBIC: 1600 var one_t = 1 - t; 1601 var one_t2 = one_t * one_t; 1602 var a = one_t2 * one_t; 1603 var b = 3 * one_t2 * t; 1604 var t2 = t * t; 1605 var c = 3 * one_t * t2; 1606 var d = t2 * t; 1607 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6]; 1608 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7]; 1609 break; 1610 } 1611 return xy; 1612} 1613 1614function drawPointAtT(curve, curveType) { 1615 var x, y; 1616 var xy = pointAtT(curve, curveType, curveT); 1617 drawPoint(xy.x, xy.y, true); 1618 if (!draw_intersectT) { 1619 return; 1620 } 1621 ctx.fillStyle = "red"; 1622 drawTAtPointUp(xy.x, xy.y, curveT); 1623} 1624 1625function drawTAtPointUp(px, py, t) { 1626 var label = t.toFixed(decimal_places); 1627 var _px = (px - srcLeft)* scale; 1628 var _py = (py - srcTop) * scale; 1629 ctx.fillText(label, _px + 5, _py - 10); 1630} 1631 1632function drawTAtPointDown(px, py, t) { 1633 var label = t.toFixed(decimal_places); 1634 var _px = (px - srcLeft)* scale; 1635 var _py = (py - srcTop) * scale; 1636 ctx.fillText(label, _px + 5, _py + 10); 1637} 1638 1639function alreadyDrawnLine(x1, y1, x2, y2) { 1640 if (collect_bounds) { 1641 if (focus_enabled) { 1642 focusXmin = Math.min(focusXmin, x1, x2); 1643 focusYmin = Math.min(focusYmin, y1, y2); 1644 focusXmax = Math.max(focusXmax, x1, x2); 1645 focusYmax = Math.max(focusYmax, y1, y2); 1646 } 1647 return true; 1648 } 1649 for (var pts = 0; pts < drawnLines.length; pts += 4) { 1650 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1] 1651 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) { 1652 return true; 1653 } 1654 } 1655 drawnLines.push(x1); 1656 drawnLines.push(y1); 1657 drawnLines.push(x2); 1658 drawnLines.push(y2); 1659 return false; 1660} 1661 1662function drawLine(x1, y1, x2, y2) { 1663 if (alreadyDrawnLine(x1, y1, x2, y2)) { 1664 return; 1665 } 1666 ctx.beginPath(); 1667 ctx.moveTo((x1 - srcLeft) * scale, 1668 (y1 - srcTop) * scale); 1669 ctx.lineTo((x2 - srcLeft) * scale, 1670 (y2 - srcTop) * scale); 1671 ctx.stroke(); 1672} 1673 1674function linePartial(x1, y1, x2, y2, t1, t2) { 1675 var dx = x1 - x2; 1676 var dy = y1 - y2; 1677 var array = [ 1678 x1 - t1 * dx, 1679 y1 - t1 * dy, 1680 x1 - t2 * dx, 1681 y1 - t2 * dy 1682 ]; 1683 return array; 1684} 1685 1686function drawLinePartial(x1, y1, x2, y2, t1, t2) { 1687 var a = linePartial(x1, y1, x2, y2, t1, t2); 1688 var ax = a[0]; 1689 var ay = a[1]; 1690 var bx = a[2]; 1691 var by = a[3]; 1692 if (alreadyDrawnLine(ax, ay, bx, by)) { 1693 return; 1694 } 1695 ctx.beginPath(); 1696 ctx.moveTo((ax - srcLeft) * scale, 1697 (ay - srcTop) * scale); 1698 ctx.lineTo((bx - srcLeft) * scale, 1699 (by - srcTop) * scale); 1700 ctx.stroke(); 1701} 1702 1703function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) { 1704 if (collect_bounds) { 1705 if (focus_enabled) { 1706 focusXmin = Math.min(focusXmin, x1, x2, x3); 1707 focusYmin = Math.min(focusYmin, y1, y2, y3); 1708 focusXmax = Math.max(focusXmax, x1, x2, x3); 1709 focusYmax = Math.max(focusYmax, y1, y2, y3); 1710 } 1711 return true; 1712 } 1713 for (var pts = 0; pts < drawnQuads.length; pts += 6) { 1714 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1] 1715 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3] 1716 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) { 1717 return true; 1718 } 1719 } 1720 drawnQuads.push(x1); 1721 drawnQuads.push(y1); 1722 drawnQuads.push(x2); 1723 drawnQuads.push(y2); 1724 drawnQuads.push(x3); 1725 drawnQuads.push(y3); 1726 return false; 1727} 1728 1729function drawQuad(x1, y1, x2, y2, x3, y3) { 1730 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) { 1731 return; 1732 } 1733 ctx.beginPath(); 1734 ctx.moveTo((x1 - srcLeft) * scale, 1735 (y1 - srcTop) * scale); 1736 ctx.quadraticCurveTo((x2 - srcLeft) * scale, 1737 (y2 - srcTop) * scale, 1738 (x3 - srcLeft) * scale, 1739 (y3 - srcTop) * scale); 1740 ctx.stroke(); 1741} 1742 1743function interp(A, B, t) { 1744 return A + (B - A) * t; 1745} 1746 1747function interp_quad_coords(x1, x2, x3, t) 1748{ 1749 var ab = interp(x1, x2, t); 1750 var bc = interp(x2, x3, t); 1751 var abc = interp(ab, bc, t); 1752 return abc; 1753} 1754 1755function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) { 1756 var ax = interp_quad_coords(x1, x2, x3, t1); 1757 var ay = interp_quad_coords(y1, y2, y3, t1); 1758 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2); 1759 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2); 1760 var cx = interp_quad_coords(x1, x2, x3, t2); 1761 var cy = interp_quad_coords(y1, y2, y3, t2); 1762 var bx = 2*dx - (ax + cx)/2; 1763 var by = 2*dy - (ay + cy)/2; 1764 var array = [ 1765 ax, ay, bx, by, cx, cy 1766 ]; 1767 return array; 1768} 1769 1770function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) { 1771 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2); 1772 var ax = a[0]; 1773 var ay = a[1]; 1774 var bx = a[2]; 1775 var by = a[3]; 1776 var cx = a[4]; 1777 var cy = a[5]; 1778 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) { 1779 return; 1780 } 1781 ctx.beginPath(); 1782 ctx.moveTo((ax - srcLeft) * scale, 1783 (ay - srcTop) * scale); 1784 ctx.quadraticCurveTo((bx - srcLeft) * scale, 1785 (by - srcTop) * scale, 1786 (cx - srcLeft) * scale, 1787 (cy - srcTop) * scale); 1788 ctx.stroke(); 1789} 1790 1791function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) { 1792 if (collect_bounds) { 1793 if (focus_enabled) { 1794 focusXmin = Math.min(focusXmin, x1, x2, x3); 1795 focusYmin = Math.min(focusYmin, y1, y2, y3); 1796 focusXmax = Math.max(focusXmax, x1, x2, x3); 1797 focusYmax = Math.max(focusYmax, y1, y2, y3); 1798 } 1799 return true; 1800 } 1801 for (var pts = 0; pts < drawnConics.length; pts += 8) { 1802 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1] 1803 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3] 1804 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5] 1805 && w == drawnCubics[pts + 6]) { 1806 return true; 1807 } 1808 } 1809 drawnConics.push(x1); 1810 drawnConics.push(y1); 1811 drawnConics.push(x2); 1812 drawnConics.push(y2); 1813 drawnConics.push(x3); 1814 drawnConics.push(y3); 1815 drawnCubics.push(w); 1816 return false; 1817} 1818 1819var kMaxConicToQuadPOW2 = 5; 1820 1821function computeQuadPOW2(curve, tol) { 1822 var a = curve[6] - 1; 1823 var k = a / (4 * (2 + a)); 1824 var x = k * (curve[0] - 2 * curve[2] + curve[4]); 1825 var y = k * (curve[1] - 2 * curve[3] + curve[5]); 1826 1827 var error = Math.sqrt(x * x + y * y); 1828 var pow2; 1829 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) { 1830 if (error <= tol) { 1831 break; 1832 } 1833 error *= 0.25; 1834 } 1835 return pow2; 1836} 1837 1838function subdivide_w_value(w) { 1839 return Math.sqrt(0.5 + w * 0.5); 1840} 1841 1842function chop(curve, part1, part2) { 1843 var w = curve[6]; 1844 var scale = 1 / (1 + w); 1845 part1[0] = curve[0]; 1846 part1[1] = curve[1]; 1847 part1[2] = (curve[0] + curve[2] * w) * scale; 1848 part1[3] = (curve[1] + curve[3] * w) * scale; 1849 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5; 1850 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5; 1851 part2[2] = (curve[2] * w + curve[4]) * scale; 1852 part2[3] = (curve[3] * w + curve[5]) * scale; 1853 part2[4] = curve[4]; 1854 part2[5] = curve[5]; 1855 part1[6] = part2[6] = subdivide_w_value(w); 1856} 1857 1858function subdivide(curve, level, pts) { 1859 if (0 == level) { 1860 pts.push(curve[2]); 1861 pts.push(curve[3]); 1862 pts.push(curve[4]); 1863 pts.push(curve[5]); 1864 } else { 1865 var part1 = [], part2 = []; 1866 chop(curve, part1, part2); 1867 --level; 1868 subdivide(part1, level, pts); 1869 subdivide(part2, level, pts); 1870 } 1871} 1872 1873function chopIntoQuadsPOW2(curve, pow2, pts) { 1874 subdivide(curve, pow2, pts); 1875 return 1 << pow2; 1876} 1877 1878function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) { 1879 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) { 1880 return; 1881 } 1882 ctx.beginPath(); 1883 ctx.moveTo((x1 - srcLeft) * scale, 1884 (y1 - srcTop) * scale); 1885 var tol = 1 / scale; 1886 var curve = [x1, y1, x2, y2, x3, y3, w]; 1887 var pow2 = computeQuadPOW2(curve, tol); 1888 var pts = []; 1889 chopIntoQuadsPOW2(curve, pow2, pts); 1890 for (var i = 0; i < pts.length; i += 4) { 1891 ctx.quadraticCurveTo( 1892 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale, 1893 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale); 1894 } 1895 ctx.stroke(); 1896} 1897 1898function conic_eval_numerator(x1, x2, x3, w, t) { 1899 var src2w = x2 * w; 1900 var C = x1; 1901 var A = x3 - 2 * src2w + C; 1902 var B = 2 * (src2w - C); 1903 return (A * t + B) * t + C; 1904} 1905 1906 1907function conic_eval_denominator(w, t) { 1908 var B = 2 * (w - 1); 1909 var C = 1; 1910 var A = -B; 1911 return (A * t + B) * t + C; 1912} 1913 1914function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) { 1915 var ax = conic_eval_numerator(x1, x2, x3, w, t1); 1916 var ay = conic_eval_numerator(y1, y2, y3, w, t1); 1917 var az = conic_eval_denominator(w, t1); 1918 var midT = (t1 + t2) / 2; 1919 var dx = conic_eval_numerator(x1, x2, x3, w, midT); 1920 var dy = conic_eval_numerator(y1, y2, y3, w, midT); 1921 var dz = conic_eval_denominator(w, midT); 1922 var cx = conic_eval_numerator(x1, x2, x3, w, t2); 1923 var cy = conic_eval_numerator(y1, y2, y3, w, t2); 1924 var cz = conic_eval_denominator(w, t2); 1925 var bx = 2 * dx - (ax + cx) / 2; 1926 var by = 2 * dy - (ay + cy) / 2; 1927 var bz = 2 * dz - (az + cz) / 2; 1928 var dt = t2 - t1; 1929 var dt_1 = 1 - dt; 1930 var array = [ 1931 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0 1932 ]; 1933 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 }; 1934 var dMid = { x:dx / dz, y:dy / dz }; 1935 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y }; 1936 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] }; 1937 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y) 1938 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y); 1939 array[6] = partW; 1940 return array; 1941} 1942 1943function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) { 1944 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2); 1945 var ax = a[0]; 1946 var ay = a[1]; 1947 var bx = a[2]; 1948 var by = a[3]; 1949 var cx = a[4]; 1950 var cy = a[5]; 1951 var w_ = a[6]; 1952 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_); 1953} 1954 1955function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) { 1956 if (collect_bounds) { 1957 if (focus_enabled) { 1958 focusXmin = Math.min(focusXmin, x1, x2, x3, x4); 1959 focusYmin = Math.min(focusYmin, y1, y2, y3, y4); 1960 focusXmax = Math.max(focusXmax, x1, x2, x3, x4); 1961 focusYmax = Math.max(focusYmax, y1, y2, y3, y4); 1962 } 1963 return true; 1964 } 1965 for (var pts = 0; pts < drawnCubics.length; pts += 8) { 1966 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1] 1967 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3] 1968 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5] 1969 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) { 1970 return true; 1971 } 1972 } 1973 drawnCubics.push(x1); 1974 drawnCubics.push(y1); 1975 drawnCubics.push(x2); 1976 drawnCubics.push(y2); 1977 drawnCubics.push(x3); 1978 drawnCubics.push(y3); 1979 drawnCubics.push(x4); 1980 drawnCubics.push(y4); 1981 return false; 1982} 1983 1984function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) { 1985 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) { 1986 return; 1987 } 1988 ctx.beginPath(); 1989 ctx.moveTo((x1 - srcLeft) * scale, 1990 (y1 - srcTop) * scale); 1991 ctx.bezierCurveTo((x2 - srcLeft) * scale, 1992 (y2 - srcTop) * scale, 1993 (x3 - srcLeft) * scale, 1994 (y3 - srcTop) * scale, 1995 (x4 - srcLeft) * scale, 1996 (y4 - srcTop) * scale); 1997 ctx.stroke(); 1998} 1999 2000function interp_cubic_coords(x1, x2, x3, x4, t) 2001{ 2002 var ab = interp(x1, x2, t); 2003 var bc = interp(x2, x3, t); 2004 var cd = interp(x3, x4, t); 2005 var abc = interp(ab, bc, t); 2006 var bcd = interp(bc, cd, t); 2007 var abcd = interp(abc, bcd, t); 2008 return abcd; 2009} 2010 2011function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 2012 var ax = interp_cubic_coords(x1, x2, x3, x4, t1); 2013 var ay = interp_cubic_coords(y1, y2, y3, y4, t1); 2014 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3); 2015 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3); 2016 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3); 2017 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3); 2018 var dx = interp_cubic_coords(x1, x2, x3, x4, t2); 2019 var dy = interp_cubic_coords(y1, y2, y3, y4, t2); 2020 var mx = ex * 27 - ax * 8 - dx; 2021 var my = ey * 27 - ay * 8 - dy; 2022 var nx = fx * 27 - ax - dx * 8; 2023 var ny = fy * 27 - ay - dy * 8; 2024 var bx = (mx * 2 - nx) / 18; 2025 var by = (my * 2 - ny) / 18; 2026 var cx = (nx * 2 - mx) / 18; 2027 var cy = (ny * 2 - my) / 18; 2028 var array = [ 2029 ax, ay, bx, by, cx, cy, dx, dy 2030 ]; 2031 return array; 2032} 2033 2034function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 2035 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2); 2036 var ax = a[0]; 2037 var ay = a[1]; 2038 var bx = a[2]; 2039 var by = a[3]; 2040 var cx = a[4]; 2041 var cy = a[5]; 2042 var dx = a[6]; 2043 var dy = a[7]; 2044 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) { 2045 return; 2046 } 2047 ctx.beginPath(); 2048 ctx.moveTo((ax - srcLeft) * scale, 2049 (ay - srcTop) * scale); 2050 ctx.bezierCurveTo((bx - srcLeft) * scale, 2051 (by - srcTop) * scale, 2052 (cx - srcLeft) * scale, 2053 (cy - srcTop) * scale, 2054 (dx - srcLeft) * scale, 2055 (dy - srcTop) * scale); 2056 ctx.stroke(); 2057} 2058 2059function drawCurve(c) { 2060 switch (c.length) { 2061 case 4: 2062 drawLine(c[0], c[1], c[2], c[3]); 2063 break; 2064 case 6: 2065 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]); 2066 break; 2067 case 7: 2068 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]); 2069 break; 2070 case 8: 2071 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); 2072 break; 2073 } 2074} 2075 2076function boundsWidth(pts) { 2077 var min = pts[0]; 2078 var max = pts[0]; 2079 var length = pts.length == 7 ? 6 : pts.length; 2080 for (var idx = 2; idx < length; idx += 2) { 2081 min = Math.min(min, pts[idx]); 2082 max = Math.max(max, pts[idx]); 2083 } 2084 return max - min; 2085} 2086 2087function boundsHeight(pts) { 2088 var min = pts[1]; 2089 var max = pts[1]; 2090 var length = pts.length == 7 ? 6 : pts.length; 2091 for (var idx = 3; idx < length; idx += 2) { 2092 min = Math.min(min, pts[idx]); 2093 max = Math.max(max, pts[idx]); 2094 } 2095 return max - min; 2096} 2097 2098function tangent(pts) { 2099 var dx = pts[2] - pts[0]; 2100 var dy = pts[3] - pts[1]; 2101 if (dx == 0 && dy == 0 && pts.length > 4) { 2102 dx = pts[4] - pts[0]; 2103 dy = pts[5] - pts[1]; 2104 if (dx == 0 && dy == 0 && pts.length == 8) { 2105 dx = pts[6] - pts[0]; 2106 dy = pts[7] - pts[1]; 2107 } 2108 } 2109 return Math.atan2(-dy, dx); 2110} 2111 2112function hodograph(cubic) { 2113 var hodo = []; 2114 hodo[0] = 3 * (cubic[2] - cubic[0]); 2115 hodo[1] = 3 * (cubic[3] - cubic[1]); 2116 hodo[2] = 3 * (cubic[4] - cubic[2]); 2117 hodo[3] = 3 * (cubic[5] - cubic[3]); 2118 hodo[4] = 3 * (cubic[6] - cubic[4]); 2119 hodo[5] = 3 * (cubic[7] - cubic[5]); 2120 return hodo; 2121} 2122 2123function hodograph2(cubic) { 2124 var quad = hodograph(cubic); 2125 var hodo = []; 2126 hodo[0] = 2 * (quad[2] - quad[0]); 2127 hodo[1] = 2 * (quad[3] - quad[1]); 2128 hodo[2] = 2 * (quad[4] - quad[2]); 2129 hodo[3] = 2 * (quad[5] - quad[3]); 2130 return hodo; 2131} 2132 2133function quadraticRootsReal(A, B, C, s) { 2134 if (A == 0) { 2135 if (B == 0) { 2136 s[0] = 0; 2137 return C == 0; 2138 } 2139 s[0] = -C / B; 2140 return 1; 2141 } 2142 /* normal form: x^2 + px + q = 0 */ 2143 var p = B / (2 * A); 2144 var q = C / A; 2145 var p2 = p * p; 2146 if (p2 < q) { 2147 return 0; 2148 } 2149 var sqrt_D = 0; 2150 if (p2 > q) { 2151 sqrt_D = sqrt(p2 - q); 2152 } 2153 s[0] = sqrt_D - p; 2154 s[1] = -sqrt_D - p; 2155 return 1 + s[0] != s[1]; 2156} 2157 2158function add_valid_ts(s, realRoots, t) { 2159 var foundRoots = 0; 2160 for (var index = 0; index < realRoots; ++index) { 2161 var tValue = s[index]; 2162 if (tValue >= 0 && tValue <= 1) { 2163 for (var idx2 = 0; idx2 < foundRoots; ++idx2) { 2164 if (t[idx2] != tValue) { 2165 t[foundRoots++] = tValue; 2166 } 2167 } 2168 } 2169 } 2170 return foundRoots; 2171} 2172 2173function quadraticRootsValidT(a, b, c, t) { 2174 var s = []; 2175 var realRoots = quadraticRootsReal(A, B, C, s); 2176 var foundRoots = add_valid_ts(s, realRoots, t); 2177 return foundRoots != 0; 2178} 2179 2180function find_cubic_inflections(cubic, tValues) { 2181 var Ax = src[2] - src[0]; 2182 var Ay = src[3] - src[1]; 2183 var Bx = src[4] - 2 * src[2] + src[0]; 2184 var By = src[5] - 2 * src[3] + src[1]; 2185 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0]; 2186 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1]; 2187 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx), 2188 Ax * By - Ay * Bx, tValues); 2189} 2190 2191function dxy_at_t(curve, type, t) { 2192 var dxy = {}; 2193 if (type == PATH_LINE) { 2194 dxy.x = curve[2] - curve[0]; 2195 dxy.y = curve[3] - curve[1]; 2196 } else if (type == PATH_QUAD) { 2197 var a = t - 1; 2198 var b = 1 - 2 * t; 2199 var c = t; 2200 dxy.x = a * curve[0] + b * curve[2] + c * curve[4]; 2201 dxy.y = a * curve[1] + b * curve[3] + c * curve[5]; 2202 } else if (type == PATH_CONIC) { 2203 var p20x = curve[4] - curve[0]; 2204 var p20y = curve[5] - curve[1]; 2205 var p10xw = (curve[2] - curve[0]) * curve[6]; 2206 var p10yw = (curve[3] - curve[1]) * curve[6]; 2207 var coeff0x = curve[6] * p20x - p20x; 2208 var coeff0y = curve[6] * p20y - p20y; 2209 var coeff1x = p20x - 2 * p10xw; 2210 var coeff1y = p20y - 2 * p10yw; 2211 dxy.x = t * (t * coeff0x + coeff1x) + p10xw; 2212 dxy.y = t * (t * coeff0y + coeff1y) + p10yw; 2213 } else if (type == PATH_CUBIC) { 2214 var one_t = 1 - t; 2215 var a = curve[0]; 2216 var b = curve[2]; 2217 var c = curve[4]; 2218 var d = curve[6]; 2219 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 2220 a = curve[1]; 2221 b = curve[3]; 2222 c = curve[5]; 2223 d = curve[7]; 2224 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 2225 } 2226 return dxy; 2227} 2228 2229function dpt_at_t(curve, t) { 2230 var type = PATH_LINE + (curve.length / 2 - 2); 2231 return dxy_at_t(curve, type, t); 2232} 2233 2234function drawLabel(num, px, py) { 2235 ctx.beginPath(); 2236 ctx.arc(px, py, 8, 0, Math.PI*2, true); 2237 ctx.closePath(); 2238 ctx.strokeStyle = "rgba(0,0,0, 0.4)"; 2239 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1; 2240 ctx.stroke(); 2241 ctx.fillStyle = "black"; 2242 ctx.font = "normal 10px Arial"; 2243 // ctx.rotate(0.001); 2244 ctx.fillText(num, px - 2, py + 3); 2245 // ctx.rotate(-0.001); 2246} 2247 2248function drawLabelX(ymin, num, loc) { 2249 var px = (loc - srcLeft) * scale; 2250 var py = (ymin - srcTop) * scale - 20; 2251 drawLabel(num, px, py); 2252} 2253 2254function drawLabelY(xmin, num, loc) { 2255 var px = (xmin - srcLeft) * scale - 20; 2256 var py = (loc - srcTop) * scale; 2257 drawLabel(num, px, py); 2258} 2259 2260function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) { 2261 ctx.beginPath(); 2262 ctx.moveTo(hx, hy - 100); 2263 ctx.lineTo(hx, hy); 2264 ctx.strokeStyle = hMinY < 0 ? "green" : "blue"; 2265 ctx.stroke(); 2266 ctx.beginPath(); 2267 ctx.moveTo(hx, hy); 2268 ctx.lineTo(hx, hy + 100); 2269 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue"; 2270 ctx.stroke(); 2271 ctx.beginPath(); 2272 ctx.moveTo(hx - 100, hy); 2273 ctx.lineTo(hx, hy); 2274 ctx.strokeStyle = hMinX < 0 ? "green" : "blue"; 2275 ctx.stroke(); 2276 ctx.beginPath(); 2277 ctx.moveTo(hx, hy); 2278 ctx.lineTo(hx + 100, hy); 2279 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue"; 2280 ctx.stroke(); 2281} 2282 2283function scalexy(x, y, mag) { 2284 var length = Math.sqrt(x * x + y * y); 2285 return mag / length; 2286} 2287 2288function drawArrow(x, y, dx, dy, s) { 2289 var dscale = scalexy(dx, dy, 1 / scale * 100 * s); 2290 dx *= dscale; 2291 dy *= dscale; 2292 ctx.beginPath(); 2293 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale); 2294 x += dx; 2295 y += dy; 2296 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale); 2297 dx /= 10; 2298 dy /= 10; 2299 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale); 2300 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale); 2301 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale); 2302 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale); 2303 ctx.strokeStyle = "rgba(0,75,0, 0.4)"; 2304 ctx.stroke(); 2305} 2306 2307function x_at_t(curve, t) { 2308 var one_t = 1 - t; 2309 if (curve.length == 4) { 2310 return one_t * curve[0] + t * curve[2]; 2311 } 2312 var one_t2 = one_t * one_t; 2313 var t2 = t * t; 2314 if (curve.length == 6) { 2315 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4]; 2316 } 2317 if (curve.length == 7) { 2318 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4]) 2319 / (one_t2 +2 * one_t * t * curve[6] + t2); 2320 } 2321 var a = one_t2 * one_t; 2322 var b = 3 * one_t2 * t; 2323 var c = 3 * one_t * t2; 2324 var d = t2 * t; 2325 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6]; 2326} 2327 2328function y_at_t(curve, t) { 2329 var one_t = 1 - t; 2330 if (curve.length == 4) { 2331 return one_t * curve[1] + t * curve[3]; 2332 } 2333 var one_t2 = one_t * one_t; 2334 var t2 = t * t; 2335 if (curve.length == 6) { 2336 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5]; 2337 } 2338 if (curve.length == 7) { 2339 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5]) 2340 / (one_t2 +2 * one_t * t * curve[6] + t2); 2341 } 2342 var a = one_t2 * one_t; 2343 var b = 3 * one_t2 * t; 2344 var c = 3 * one_t * t2; 2345 var d = t2 * t; 2346 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7]; 2347} 2348 2349function pt_at_t(curve, t) { 2350 var pt = {}; 2351 pt.x = x_at_t(curve, t); 2352 pt.y = y_at_t(curve, t); 2353 return pt; 2354} 2355 2356function drawOrder(curve, t, label) { 2357 var px = x_at_t(curve, t); 2358 var py = y_at_t(curve, t); 2359 var _px = (px - srcLeft) * scale; 2360 var _py = (py - srcTop) * scale; 2361 ctx.beginPath(); 2362 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 2363 ctx.closePath(); 2364 ctx.fillStyle = "white"; 2365 ctx.fill(); 2366 if (label == 'L') { 2367 ctx.strokeStyle = "rgba(255,0,0, 1)"; 2368 ctx.fillStyle = "rgba(255,0,0, 1)"; 2369 } else { 2370 ctx.strokeStyle = "rgba(0,0,255, 1)"; 2371 ctx.fillStyle = "rgba(0,0,255, 1)"; 2372 } 2373 ctx.stroke(); 2374 ctx.font = "normal 16px Arial"; 2375 ctx.textAlign = "center"; 2376 ctx.fillText(label, _px, _py + 5); 2377 ctx.font = "normal 10px Arial"; 2378} 2379 2380function drawVisibleOrder(curve, label) { 2381 var s = pt_at_t(curve, 0); 2382 var e = pt_at_t(curve, 1); 2383 var sOn = ptOnScreen(s); 2384 var eOn = ptOnScreen(e); 2385 var defaultT = 0.85; 2386 if (sOn && eOn) 2387 return drawOrder(curve, defaultT, label); 2388 if (sOn || eOn) { 2389 if (eOn) { 2390 defaultT = 1 - defaultT; 2391 } 2392 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2; 2393 var t = defaultT; 2394 var tries = 16; 2395 do { 2396 var mid = pt_at_t(curve, t); 2397 if (ptOnScreen(mid)) 2398 return drawOrder(curve, t, label); 2399 t += step; 2400 step /= 2; 2401 } while (--tries > 0); 2402 drawOrder(curve, defaultT, label); 2403 } 2404 // scattershot until we find a visible point 2405 var denom = 2; // visit odd number num / denom to hit unique pts 2406 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ... 2407 do { 2408 for (var numer = 1; numer < denom; numer += 2) { 2409 var t = numer / denom + 0.1; 2410 if (t >= 1) { 2411 break; 2412 } 2413 var mid = pt_at_t(curve, t); 2414 if (ptOnScreen(mid)) 2415 return drawOrder(curve, t, label); 2416 } 2417 denom *= 2; 2418 } while (--tries > 0); 2419 drawOrder(curve, defaultT, label); 2420} 2421 2422function set_length(pt, newLen) { 2423 var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y); 2424 var scale = newLen / len; 2425 var newPt = { x: pt.x * scale, y: pt.y * scale }; 2426 return newPt; 2427} 2428 2429function drawDirection(curve, t) { 2430 var d = dpt_at_t(curve, t); 2431 d = set_length(d, 16); 2432 var pt = localToGlobal(pt_at_t(curve, t)); 2433 ctx.beginPath(); 2434 ctx.moveTo(pt.x - d.y, pt.y + d.x); 2435 ctx.lineTo(pt.x + d.x, pt.y + d.y); 2436 ctx.lineTo(pt.x + d.y, pt.y - d.x); 2437 ctx.strokeStyle = "rgba(0,75,0, 0.4)"; 2438 ctx.stroke(); 2439} 2440 2441function drawVisibleDirection(curve) { 2442 var s = pt_at_t(curve, 0); 2443 var e = pt_at_t(curve, 1); 2444 var sOn = ptOnScreen(s); 2445 var eOn = ptOnScreen(e); 2446 var defaultT = 0.65; 2447 if (sOn && eOn) { 2448 return drawDirection(curve, defaultT); 2449 } 2450 if (sOn || eOn) { 2451 if (eOn) { 2452 defaultT = 1 - defaultT; 2453 } 2454 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2; 2455 var t = defaultT; 2456 var tries = 16; 2457 do { 2458 var mid = pt_at_t(curve, t); 2459 if (ptOnScreen(mid)) 2460 return drawDirection(curve, t); 2461 t += step; 2462 step /= 2; 2463 } while (--tries > 0); 2464 drawDirection(curve, defaultT); 2465 } 2466 // scattershot until we find a visible point 2467 var denom = 2; // visit odd number num / denom to hit unique pts 2468 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ... 2469 do { 2470 for (var numer = 1; numer < denom; numer += 2) { 2471 var t = numer / denom + 0.1; 2472 if (t >= 1) { 2473 break; 2474 } 2475 var mid = pt_at_t(curve, t); 2476 if (ptOnScreen(mid)) 2477 return drawDirection(curve, t); 2478 } 2479 denom *= 2; 2480 } while (--tries > 0); 2481 drawDirection(curve, defaultT); 2482} 2483 2484function drawID(curve, t, id) { 2485 var px = x_at_t(curve, t); 2486 var py = y_at_t(curve, t); 2487 var _px = (px - srcLeft) * scale; 2488 var _py = (py - srcTop) * scale; 2489 draw_id_at(id, _px, _py); 2490} 2491 2492function localToGlobal(local) { 2493 var global = {}; 2494 global.x = (local.x - srcLeft) * scale; 2495 global.y = (local.y - srcTop) * scale; 2496 return global; 2497} 2498 2499function ptOnScreen(local) { 2500 var pt = localToGlobal(local); 2501 return 10 <= pt.x && pt.x <= screenWidth - 10 2502 && 10 <= pt.y && pt.y <= screenHeight - 10; 2503} 2504 2505function drawVisibleID(curve, defaultT, id) { 2506 // determine if either or both ends are visible 2507 var s = pt_at_t(curve, 0); 2508 var e = pt_at_t(curve, 1); 2509 var sOn = ptOnScreen(s); 2510 var eOn = ptOnScreen(e); 2511 if (sOn && eOn) 2512 return drawID(curve, defaultT, id); 2513 if (sOn || eOn) { 2514 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2; 2515 var t = defaultT; 2516 var tries = 16; 2517 do { 2518 var mid = pt_at_t(curve, t); 2519 if (ptOnScreen(mid)) 2520 return drawID(curve, t, id); 2521 t += step; 2522 step /= 2; 2523 } while (--tries > 0); 2524 drawID(curve, defaultT, id); 2525 } 2526 // scattershot until we find a visible point 2527 var denom = 2; // visit odd number num / denom to hit unique pts 2528 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ... 2529 do { 2530 for (var numer = 1; numer < denom; numer += 2) { 2531 var t = numer / denom; 2532 var mid = pt_at_t(curve, t); 2533 if (ptOnScreen(mid)) 2534 return drawID(curve, t, id); 2535 } 2536 denom *= 2; 2537 } while (--tries > 0); 2538 drawID(curve, defaultT, id); 2539} 2540 2541function draw_id_at(id, _px, _py) { 2542 ctx.beginPath(); 2543 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 2544 ctx.closePath(); 2545 ctx.fillStyle = "white"; 2546 ctx.fill(); 2547 ctx.strokeStyle = "rgba(127,127,0, 1)"; 2548 ctx.fillStyle = "rgba(127,127,0, 1)"; 2549 ctx.stroke(); 2550 ctx.font = "normal 16px Arial"; 2551 ctx.textAlign = "center"; 2552 ctx.fillText(id, _px, _py + 5); 2553 ctx.font = "normal 10px Arial"; 2554} 2555 2556function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) { 2557 var curve = [x1, y1, x2, y2]; 2558 drawCurvePartialID(id, curve, t1, t2); 2559} 2560 2561function drawLineID(id, x1, y1, x2, y2) { 2562 drawLinePartialID(id, x1, y1, x2, y2, 0, 1); 2563} 2564 2565function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) { 2566 var curve = [x1, y1, x2, y2, x3, y3]; 2567 drawCurvePartialID(id, curve, t1, t2); 2568} 2569 2570function drawQuadID(id, x1, y1, x2, y2, x3, y3) { 2571 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1); 2572} 2573 2574function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) { 2575 var curve = [x1, y1, x2, y2, x3, y3, w]; 2576 drawCurvePartialID(id, curve, t1, t2); 2577} 2578 2579function drawConicID(id, x1, y1, x2, y2, x3, y3, w) { 2580 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1); 2581} 2582 2583function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) { 2584 var curve = [x1, y1, x2, y2, x3, y3, x4, y4]; 2585 drawCurvePartialID(id, curve, t1, t2); 2586} 2587 2588function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) { 2589 drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1); 2590} 2591 2592function drawCurvePartialID(id, curve, t1, t2) { 2593 drawVisibleID(curve, (t1 + t2) / 2, id); 2594} 2595 2596function drawCurveSpecials(test, curve, type) { 2597 if (pt_labels) { 2598 drawPoints(curve, type, pt_labels == 2); 2599 } 2600 if (control_lines != 0) { 2601 drawControlLines(curve, type, control_lines); 2602 } 2603 if (curve_t) { 2604 drawPointAtT(curve, type); 2605 } 2606 if (draw_midpoint) { 2607 var mid = pointAtT(curve, type, 0.5); 2608 drawPoint(mid.x, mid.y, true); 2609 } 2610 if (draw_id) { 2611 var id = idByCurve(test, curve, type); 2612 if (id >= 0) { 2613 drawVisibleID(curve, 0.5, id); 2614 } 2615 } 2616 if (draw_direction) { 2617 drawVisibleDirection(curve); 2618 } 2619 if (type == PATH_LINE) { 2620 return; 2621 } 2622 if (draw_deriviatives > 0) { 2623 var d = dxy_at_t(curve, type, 0); 2624 drawArrow(curve[0], curve[1], d.x, d.y, 1); 2625 if (draw_deriviatives == 2) { 2626 d = dxy_at_t(curve, type, 1); 2627 if (type == PATH_CUBIC) { 2628 drawArrow(curve[6], curve[7], d.x, d.y, 1); 2629 } else { 2630 drawArrow(curve[4], curve[5], d.x, d.y, 1); 2631 } 2632 } 2633 if (draw_midpoint) { 2634 var mid = pointAtT(curve, type, 0.5); 2635 d = dxy_at_t(curve, type, 0.5); 2636 drawArrow(mid.x, mid.y, d.x, d.y, 1); 2637 } 2638 } 2639 if (type != PATH_CUBIC) { 2640 return; 2641 } 2642 if (draw_sequence) { 2643 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]); 2644 for (var i = 0; i < 8; i+= 2) { 2645 drawLabelX(ymin, i >> 1, curve[i]); 2646 } 2647 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]); 2648 for (var i = 1; i < 8; i+= 2) { 2649 drawLabelY(xmin, i >> 1, curve[i]); 2650 } 2651 } 2652} 2653 2654function logCurves(test) { 2655 for (curves in test) { 2656 var curve = test[curves]; 2657 dumpCurve(curve); 2658 } 2659} 2660 2661function curveToString(curve) { 2662 var str = "{{"; 2663 var length = curve.length == 7 ? 6 : curve.length; 2664 if (curve.length == 7) { 2665 str += "{"; 2666 } 2667 for (i = 0; i < length; i += 2) { 2668 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places); 2669 if (i < curve.length - 2) { 2670 str += "}, {"; 2671 } 2672 } 2673 str += "}"; 2674 if (curve.length == 7) { 2675 str += "}, " + curve[6].toFixed(decimal_places); 2676 } 2677 str += "}"; 2678 return str; 2679} 2680 2681function dumpCurve(curve) { 2682 console.log(curveToString(curve)); 2683} 2684 2685function draw(test, lines, title) { 2686 ctx.fillStyle = "rgba(0,0,0, 0.1)"; 2687 ctx.font = "normal 50px Arial"; 2688 ctx.textAlign = "left"; 2689 ctx.fillText(title, 50, 50); 2690 ctx.font = "normal 10px Arial"; 2691 ctx.lineWidth = "1.001"; "0.999"; 2692 var secondPath = test.length; 2693 var closeCount = 0; 2694 logStart = -1; 2695 logRange = 0; 2696 // find last active rec type at this step 2697 var curType = test[0]; 2698 var curStep = 0; 2699 var hasOp = false; 2700 var lastActive = 0; 2701 var lastAdd = 0; 2702 var lastCoin = 0; 2703 var lastSect = 0; 2704 var lastSort = 0; 2705 var lastMark = 0; 2706 var lastTop = 0; 2707 activeCount = 0; 2708 addCount = 0; 2709 angleCount = 0; 2710 opCount = 0; 2711 sectCount = 0; 2712 sortCount = 0; 2713 topCount = 0; 2714 markCount = 0; 2715 activeMax = 0; 2716 addMax = 0; 2717 angleMax = 0; 2718 coinMax = 0; 2719 opMax = 0; 2720 sectMax = 0; 2721 sectMax2 = 0; 2722 sortMax = 0; 2723 topMax = 0; 2724 markMax = 0; 2725 lastIndex = test.length - 3; 2726 for (var tIndex = 0; tIndex < test.length; tIndex += 3) { 2727 var recType = test[tIndex]; 2728 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) { 2729 console.log("unknown rec type: " + recType); 2730 throw "stop execution"; 2731 } 2732 // if (curType == recType && curType != REC_TYPE_ADD) { 2733 // continue; 2734 // } 2735 var inStepRange = step_limit == 0 || curStep < step_limit; 2736 curType = recType; 2737 if (recType == REC_TYPE_OP) { 2738 hasOp = true; 2739 continue; 2740 } 2741 if (recType == REC_TYPE_UNKNOWN) { 2742 // these types do not advance step 2743 continue; 2744 } 2745 var bumpStep = false; 2746 var records = test[tIndex + 2]; 2747 var fragType = records[0]; 2748 if (recType == REC_TYPE_ADD) { 2749 if (records.length != 2) { 2750 console.log("expect only two elements: " + records.length); 2751 throw "stop execution"; 2752 } 2753 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) { 2754 continue; 2755 } 2756 ++addMax; 2757 if (!draw_add || !inStepRange) { 2758 continue; 2759 } 2760 lastAdd = tIndex; 2761 ++addCount; 2762 bumpStep = true; 2763 } 2764 if (recType == REC_TYPE_PATH && hasOp) { 2765 secondPath = tIndex; 2766 } 2767 if (recType == REC_TYPE_PATH2 && hasOp) { 2768 secondPath = tIndex; 2769 } 2770 if (recType == REC_TYPE_ACTIVE) { 2771 ++activeMax; 2772 if (!draw_active || !inStepRange) { 2773 continue; 2774 } 2775 lastActive = tIndex; 2776 ++activeCount; 2777 bumpStep = true; 2778 } 2779 if (recType == REC_TYPE_ACTIVE_OP) { 2780 ++opMax; 2781 if (!draw_op || !inStepRange) { 2782 continue; 2783 } 2784 lastOp = tIndex; 2785 ++opCount; 2786 bumpStep = true; 2787 } 2788 if (recType == REC_TYPE_AFTERPART) { 2789 if (draw_angle != 3 || !inStepRange) { 2790 continue; 2791 } 2792 lastAngle = tIndex; 2793 ++angleCount; 2794 bumpStep = true; 2795 } 2796 if (recType == REC_TYPE_ANGLE) { 2797 ++angleMax; 2798 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) { 2799 continue; 2800 } 2801 lastAngle = tIndex; 2802 ++angleCount; 2803 bumpStep = true; 2804 } 2805 if (recType == REC_TYPE_COINCIDENCE) { 2806 ++coinMax; 2807 if (!draw_coincidence || !inStepRange) { 2808 continue; 2809 } 2810 lastCoin = tIndex; 2811 ++coinCount; 2812 bumpStep = true; 2813 } 2814 if (recType == REC_TYPE_SECT) { 2815 if (records.length != 2) { 2816 console.log("expect only two elements: " + records.length); 2817 throw "stop execution"; 2818 } 2819 ++sectMax; 2820 var sectBump = 1; 2821 switch (fragType) { 2822 case INTERSECT_LINE: 2823 case INTERSECT_QUAD_LINE: 2824 case INTERSECT_QUAD: 2825 case INTERSECT_CONIC_LINE: 2826 case INTERSECT_CONIC_QUAD: 2827 case INTERSECT_CONIC: 2828 case INTERSECT_SELF_CUBIC: 2829 case INTERSECT_CUBIC_LINE: 2830 case INTERSECT_CUBIC_QUAD: 2831 case INTERSECT_CUBIC: 2832 sectBump = 1; 2833 break; 2834 case INTERSECT_LINE_2: 2835 case INTERSECT_QUAD_LINE_2: 2836 case INTERSECT_QUAD_2: 2837 case INTERSECT_CONIC_LINE_2: 2838 case INTERSECT_CONIC_QUAD_2: 2839 case INTERSECT_CONIC_2: 2840 case INTERSECT_CUBIC_LINE_2: 2841 case INTERSECT_CUBIC_QUAD_2: 2842 case INTERSECT_CUBIC_2: 2843 sectBump = 2; 2844 break; 2845 case INTERSECT_LINE_NO: 2846 case INTERSECT_QUAD_LINE_NO: 2847 case INTERSECT_QUAD_NO: 2848 case INTERSECT_CONIC_LINE_NO: 2849 case INTERSECT_CONIC_QUAD_NO: 2850 case INTERSECT_CONIC_NO: 2851 case INTERSECT_SELF_CUBIC_NO: 2852 case INTERSECT_CUBIC_LINE_NO: 2853 case INTERSECT_CUBIC_QUAD_NO: 2854 case INTERSECT_CUBIC_NO: 2855 sectBump = 0; 2856 break; 2857 case INTERSECT_CONIC_QUAD_3: 2858 case INTERSECT_CUBIC_LINE_3: 2859 case INTERSECT_CUBIC_QUAD_3: 2860 case INTERSECT_CUBIC_3: 2861 sectBump = 3; 2862 break; 2863 case INTERSECT_CONIC_QUAD_4: 2864 case INTERSECT_CUBIC_QUAD_4: 2865 case INTERSECT_CUBIC_4: 2866 sectBump = 4; 2867 break; 2868 default: 2869 console.log("missing case " + records.length); 2870 throw "stop execution"; 2871 } 2872 sectMax2 += sectBump; 2873 if (draw_intersection <= 1 || !inStepRange) { 2874 continue; 2875 } 2876 lastSect = tIndex; 2877 sectCount += sectBump; 2878 bumpStep = true; 2879 } 2880 if (recType == REC_TYPE_SORT) { 2881 ++sortMax; 2882 if (!draw_sort || !inStepRange) { 2883 continue; 2884 } 2885 lastSort = tIndex; 2886 ++sortCount; 2887 bumpStep = true; 2888 } 2889 if (recType == REC_TYPE_TOP) { 2890 ++topMax; 2891 if (!draw_top || !inStepRange) { 2892 continue; 2893 } 2894 lastTop = tIndex; 2895 ++topCount; 2896 bumpStep = true; 2897 } 2898 if (recType == REC_TYPE_MARK) { 2899 ++markMax; 2900 if (!draw_mark || !inStepRange) { 2901 continue; 2902 } 2903 lastMark = tIndex; 2904 ++markCount; 2905 bumpStep = true; 2906 } 2907 if (bumpStep) { 2908 lastIndex = tIndex; 2909 logStart = test[tIndex + 1]; 2910 logRange = records.length / 2; 2911 ++curStep; 2912 } 2913 } 2914 stepMax = (draw_add ? addMax : 0) 2915 + (draw_active ? activeMax : 0) 2916 + (draw_angle ? angleMax : 0) 2917 + (draw_coincidence ? coinMax : 0) 2918 + (draw_op ? opMax : 0) 2919 + (draw_sort ? sortMax : 0) 2920 + (draw_top ? topMax : 0) 2921 + (draw_mark ? markMax : 0) 2922 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0); 2923 if (stepMax == 0) { 2924 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax; 2925 } 2926 drawnPts = []; 2927 drawnLines = []; 2928 drawnQuads = []; 2929 drawnConics = []; 2930 drawnCubics = []; 2931 focusXmin = focusYmin = Infinity; 2932 focusXmax = focusYmax = -Infinity; 2933 var pathIndex = 0; 2934 var opLetter = 'S'; 2935 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) { 2936 var recType = test[tIndex]; 2937 var records = test[tIndex + 2]; 2938 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 2939 var fragType = records[recordIndex]; 2940 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) { 2941 console.log("unknown in range frag type: " + fragType); 2942 throw "stop execution"; 2943 } 2944 var frags = records[recordIndex + 1]; 2945 focus_enabled = false; 2946 switch (recType) { 2947 case REC_TYPE_COMPUTED: 2948 if (draw_computed == 0) { 2949 continue; 2950 } 2951 ctx.lineWidth = 1; 2952 ctx.strokeStyle = pathIndex == 0 ? "black" : "red"; 2953 ctx.fillStyle = "blue"; 2954 var drawThis = false; 2955 switch (fragType) { 2956 case PATH_QUAD: 2957 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0 2958 && (draw_computed & 7) == pathIndex)) { 2959 drawQuad(frags[0], frags[1], frags[2], frags[3], 2960 frags[4], frags[5]); 2961 drawThis = true; 2962 } 2963 break; 2964 case PATH_CONIC: 2965 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0 2966 && (draw_computed & 7) == pathIndex)) { 2967 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3], 2968 frags[4], frags[5], frags[6]); 2969 drawThis = true; 2970 } 2971 break; 2972 case PATH_CUBIC: 2973 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0 2974 && (draw_computed & 7) == pathIndex)) { 2975 drawCubic(frags[0], frags[1], frags[2], frags[3], 2976 frags[4], frags[5], frags[6], frags[7]); 2977 drawThis = true; 2978 } 2979 ++pathIndex; 2980 break; 2981 case COMPUTED_SET_1: 2982 pathIndex = 0; 2983 break; 2984 case COMPUTED_SET_2: 2985 pathIndex = 1; 2986 break; 2987 default: 2988 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType); 2989 throw "stop execution"; 2990 } 2991 if (!drawThis || collect_bounds) { 2992 break; 2993 } 2994 drawCurveSpecials(test, frags, fragType); 2995 break; 2996 case REC_TYPE_ALIGNED: 2997 if (draw_path < 4) { 2998 continue; 2999 } 3000 case REC_TYPE_PATH: 3001 case REC_TYPE_PATH2: 3002 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) { 3003 continue; 3004 } 3005 if (!draw_path) { 3006 continue; 3007 } 3008 var firstPath = tIndex < secondPath; 3009 if ((draw_path & (firstPath ? 1 : 2)) == 0) { 3010 continue; 3011 } 3012 ctx.lineWidth = 1; 3013 ctx.strokeStyle = firstPath ? "black" : "red"; 3014 ctx.fillStyle = "blue"; 3015 var frags2 = []; 3016 switch (fragType) { 3017 case PATH_LINE: 3018 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; } 3019 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]); 3020 break; 3021 case PATH_QUAD: 3022 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; } 3023 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3], 3024 frags2[4], frags2[5]); 3025 break; 3026 case PATH_CONIC: 3027 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; } 3028 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3], 3029 frags2[4], frags2[5], frags2[6]); 3030 break; 3031 case PATH_CUBIC: 3032 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; } 3033 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3], 3034 frags2[4], frags2[5], frags2[6], frags2[7]); 3035 break; 3036 default: 3037 console.log("unknown " + recType + " frag type: " + fragType); 3038 throw "stop execution"; 3039 } 3040 if (collect_bounds) { 3041 break; 3042 } 3043 drawCurveSpecials(test, frags2, fragType); 3044 break; 3045 case REC_TYPE_OP: 3046 switch (fragType) { 3047 case OP_INTERSECT: opLetter = 'I'; break; 3048 case OP_DIFFERENCE: opLetter = 'D'; break; 3049 case OP_UNION: opLetter = 'U'; break; 3050 case OP_XOR: opLetter = 'X'; break; 3051 default: 3052 console.log("unknown REC_TYPE_OP frag type: " + fragType); 3053 throw "stop execution"; 3054 } 3055 break; 3056 case REC_TYPE_ACTIVE: 3057 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) { 3058 continue; 3059 } 3060 var x1 = frags[SPAN_X1]; 3061 var y1 = frags[SPAN_Y1]; 3062 var x2 = frags[SPAN_X2]; 3063 var y2 = frags[SPAN_Y2]; 3064 var x3, y3, x3, y4, w; 3065 ctx.lineWidth = 3; 3066 ctx.strokeStyle = "rgba(0,0,255, 0.3)"; 3067 focus_enabled = true; 3068 switch (fragType) { 3069 case ACTIVE_LINE_SPAN: 3070 drawLine(x1, y1, x2, y2); 3071 if (draw_id) { 3072 drawLineID(frags[0], x1, y1, x2, y2); 3073 } 3074 if (pt_labels) { 3075 var curve = [x1, y1, x2, y2]; 3076 ctx.fillStyle = "blue"; 3077 drawPoints(curve, PATH_LINE, pt_labels == 2); 3078 } 3079 break; 3080 case ACTIVE_QUAD_SPAN: 3081 x3 = frags[SPAN_X3]; 3082 y3 = frags[SPAN_Y3]; 3083 drawQuad(x1, y1, x2, y2, x3, y3); 3084 if (draw_id) { 3085 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3); 3086 } 3087 if (pt_labels) { 3088 var curve = [x1, y1, x2, y2, x3, y3]; 3089 ctx.fillStyle = "blue"; 3090 drawPoints(curve, PATH_QUAD, pt_labels == 2); 3091 } 3092 break; 3093 case ACTIVE_CONIC_SPAN: 3094 x3 = frags[SPAN_X3]; 3095 y3 = frags[SPAN_Y3]; 3096 w = frags[SPAN_K_W]; 3097 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w); 3098 if (draw_id) { 3099 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w); 3100 } 3101 if (pt_labels) { 3102 var curve = [x1, y1, x2, y2, x3, y3, w]; 3103 ctx.fillStyle = "blue"; 3104 drawPoints(curve, PATH_CONIC, pt_labels == 2); 3105 } 3106 break; 3107 case ACTIVE_CUBIC_SPAN: 3108 x3 = frags[SPAN_X3]; 3109 y3 = frags[SPAN_Y3]; 3110 x4 = frags[SPAN_X4]; 3111 y4 = frags[SPAN_Y4]; 3112 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4); 3113 if (draw_id) { 3114 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4); 3115 } 3116 if (pt_labels) { 3117 var curve = [x1, y1, x2, y2, x3, y3, x4, y4]; 3118 ctx.fillStyle = "blue"; 3119 drawPoints(curve, PATH_CUBIC, pt_labels == 2); 3120 } 3121 break; 3122 default: 3123 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType); 3124 throw "stop execution"; 3125 } 3126 break; 3127 case REC_TYPE_ACTIVE_OP: 3128 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) { 3129 continue; 3130 } 3131 focus_enabled = true; 3132 ctx.lineWidth = 3; 3133 var activeSpan = frags[7] == "1"; 3134 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)"; 3135 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 3136 drawCurve(curve); 3137 if (draw_op > 1) { 3138 drawArc(curve, false, frags[3], frags[4]); 3139 drawArc(curve, true, frags[5], frags[6]); 3140 } 3141 break; 3142 case REC_TYPE_ADD: 3143 if (!draw_add) { 3144 continue; 3145 } 3146 ctx.lineWidth = 3; 3147 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)" 3148 : closeCount == 1 ? "rgba(0,127,0, 0.3)" 3149 : closeCount == 2 ? "rgba(0,127,127, 0.3)" 3150 : closeCount == 3 ? "rgba(127,127,0, 0.3)" 3151 : "rgba(127,0,127, 0.3)"; 3152 focus_enabled = true; 3153 switch (fragType) { 3154 case ADD_MOVETO: 3155 break; 3156 case ADD_LINETO: 3157 if (step_limit == 0 || tIndex >= lastAdd) { 3158 drawLine(frags[0], frags[1], frags[2], frags[3]); 3159 } 3160 break; 3161 case ADD_QUADTO: 3162 if (step_limit == 0 || tIndex >= lastAdd) { 3163 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]); 3164 } 3165 break; 3166 case ADD_CONICTO: 3167 if (step_limit == 0 || tIndex >= lastAdd) { 3168 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3], 3169 frags[4], frags[5], frags[6]); 3170 } 3171 break; 3172 case ADD_CUBICTO: 3173 if (step_limit == 0 || tIndex >= lastAdd) { 3174 drawCubic(frags[0], frags[1], frags[2], frags[3], 3175 frags[4], frags[5], frags[6], frags[7]); 3176 } 3177 break; 3178 case ADD_CLOSE: 3179 ++closeCount; 3180 break; 3181 case ADD_FILL: 3182 break; 3183 default: 3184 console.log("unknown REC_TYPE_ADD frag type: " + fragType); 3185 throw "stop execution"; 3186 } 3187 break; 3188 case REC_TYPE_ANGLE: 3189 angleBetween = frags[18] == "T"; 3190 afterIndex = 0; 3191 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) { 3192 continue; 3193 } 3194 focus_enabled = true; 3195 ctx.lineWidth = 3; 3196 ctx.strokeStyle = "rgba(127,45,127, 0.3)"; 3197 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]); 3198 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]); 3199 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]); 3200 drawCurve(leftCurve); 3201 drawCurve(rightCurve); 3202 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)"; 3203 drawCurve(midCurve); 3204 if (draw_angle > 1) { 3205 drawVisibleOrder(leftCurve, 'L'); 3206 drawVisibleOrder(rightCurve, 'R'); 3207 } 3208 if (draw_id) { 3209 drawVisibleID(leftCurve, 0.5, frags[0]); 3210 drawVisibleID(midCurve, 0.5, frags[6]); 3211 drawVisibleID(rightCurve, 0.5, frags[12]); 3212 } 3213 break; 3214 case REC_TYPE_AFTERPART: 3215 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) { 3216 continue; 3217 } 3218 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)" 3219 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)" 3220 : "rgba(0,0,255, 1.0)"; 3221 var curve; 3222 var id; 3223 switch (fragType) { 3224 case PATH_LINE: 3225 curve = [ frags[0], frags[1], frags[2], frags[3] ]; 3226 id = frags[4]; 3227 break; 3228 case PATH_QUAD: 3229 curve = [ frags[0], frags[1], frags[2], frags[3], 3230 frags[4], frags[5] ]; 3231 id = frags[6]; 3232 break; 3233 case PATH_CONIC: 3234 curve = [ frags[0], frags[1], frags[2], frags[3], 3235 frags[4], frags[5], frags[6] ]; 3236 id = frags[7]; 3237 break; 3238 case PATH_CUBIC: 3239 curve = [ frags[0], frags[1], frags[2], frags[3], 3240 frags[4], frags[5], frags[6], frags[7] ]; 3241 id = frags[8]; 3242 break; 3243 default: 3244 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType); 3245 throw "stop execution"; 3246 } 3247 drawCurve(curve); 3248 if (draw_id) { 3249 drawVisibleID(curve, 0.5, id); 3250 } 3251 ++afterIndex; 3252 break; 3253 case REC_TYPE_COINCIDENCE: 3254 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) { 3255 continue; 3256 } 3257 focus_enabled = true; 3258 ctx.lineWidth = 3; 3259 ctx.strokeStyle = "rgba(127,45,63, 0.3)"; 3260 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 3261 drawCurve(curve); 3262 break; 3263 case REC_TYPE_SECT: 3264 if (!draw_intersection) { 3265 continue; 3266 } 3267 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) { 3268 continue; 3269 } 3270 // draw_intersection == 1 : show all 3271 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step 3272 // draw_intersection == 3 : step == 0 ? show all : show intersection #step 3273 ctx.lineWidth = 1; 3274 ctx.strokeStyle = "rgba(0,0,255, 0.3)"; 3275 ctx.fillStyle = "blue"; 3276 focus_enabled = true; 3277 var f = []; 3278 var c1s; 3279 var c1l; 3280 var c2s; 3281 var c2l; 3282 switch (fragType) { 3283 case INTERSECT_LINE: 3284 f.push(5, 6, 0, 7); 3285 c1s = 1; c1l = 4; c2s = 8; c2l = 4; 3286 break; 3287 case INTERSECT_LINE_2: 3288 f.push(5, 6, 0, 10); 3289 f.push(8, 9, 7, 15); 3290 c1s = 1; c1l = 4; c2s = 11; c2l = 4; 3291 break; 3292 case INTERSECT_LINE_NO: 3293 c1s = 0; c1l = 4; c2s = 4; c2l = 4; 3294 break; 3295 case INTERSECT_QUAD_LINE: 3296 f.push(7, 8, 0, 9); 3297 c1s = 1; c1l = 6; c2s = 10; c2l = 4; 3298 break; 3299 case INTERSECT_QUAD_LINE_2: 3300 f.push(7, 8, 0, 12); 3301 f.push(10, 11, 9, 17); 3302 c1s = 1; c1l = 6; c2s = 13; c2l = 4; 3303 break; 3304 case INTERSECT_QUAD_LINE_NO: 3305 c1s = 0; c1l = 6; c2s = 6; c2l = 4; 3306 break; 3307 case INTERSECT_QUAD: 3308 f.push(7, 8, 0, 9); 3309 c1s = 1; c1l = 6; c2s = 10; c2l = 6; 3310 break; 3311 case INTERSECT_QUAD_2: 3312 f.push(7, 8, 0, 12); 3313 f.push(10, 11, 9, 19); 3314 c1s = 1; c1l = 6; c2s = 13; c2l = 6; 3315 break; 3316 case INTERSECT_QUAD_NO: 3317 c1s = 0; c1l = 6; c2s = 6; c2l = 6; 3318 break; 3319 case INTERSECT_CONIC_LINE: 3320 f.push(8, 9, 0, 10); 3321 c1s = 1; c1l = 7; c2s = 11; c2l = 4; 3322 break; 3323 case INTERSECT_CONIC_LINE_2: 3324 f.push(8, 9, 0, 12); 3325 f.push(11, 12, 10, 18); 3326 c1s = 1; c1l = 7; c2s = 14; c2l = 4; 3327 break; 3328 case INTERSECT_CONIC_LINE_NO: 3329 c1s = 0; c1l = 7; c2s = 7; c2l = 4; 3330 break; 3331 case INTERSECT_CONIC_QUAD: 3332 f.push(8, 9, 0, 10); 3333 c1s = 1; c1l = 7; c2s = 11; c2l = 6; 3334 break; 3335 case INTERSECT_CONIC_QUAD_2: 3336 f.push(8, 9, 0, 12); 3337 f.push(11, 12, 10, 18); 3338 c1s = 1; c1l = 7; c2s = 14; c2l = 6; 3339 break; 3340 case INTERSECT_CONIC_QUAD_3: 3341 f.push(8, 9, 0, 15); 3342 f.push(11, 12, 10, 21); 3343 f.push(14, 15, 13, 22); 3344 c1s = 1; c1l = 7; c2s = 17; c2l = 6; 3345 break; 3346 case INTERSECT_CONIC_QUAD_4: 3347 f.push(8, 9, 0, 18); 3348 f.push(11, 12, 10, 24); 3349 f.push(14, 15, 13, 25); 3350 f.push(17, 18, 16, 26); 3351 c1s = 1; c1l = 7; c2s = 20; c2l = 6; 3352 break; 3353 case INTERSECT_CONIC_QUAD_NO: 3354 c1s = 0; c1l = 7; c2s = 7; c2l = 6; 3355 break; 3356 case INTERSECT_CONIC: 3357 f.push(8, 9, 0, 10); 3358 c1s = 1; c1l = 7; c2s = 11; c2l = 7; 3359 break; 3360 case INTERSECT_CONIC_2: 3361 f.push(8, 9, 0, 13); 3362 f.push(11, 12, 10, 21); 3363 c1s = 1; c1l = 7; c2s = 14; c2l = 7; 3364 break; 3365 case INTERSECT_CONIC_NO: 3366 c1s = 0; c1l = 7; c2s = 7; c2l = 7; 3367 break; 3368 case INTERSECT_SELF_CUBIC: 3369 f.push(9, 10, 0, 11); 3370 c1s = 1; c1l = 8; c2s = 0; c2l = 0; 3371 break; 3372 case INTERSECT_SELF_CUBIC_NO: 3373 c1s = 0; c1l = 8; c2s = 0; c2l = 0; 3374 break; 3375 case INTERSECT_CUBIC_LINE: 3376 f.push(9, 10, 0, 11); 3377 c1s = 1; c1l = 8; c2s = 12; c2l = 4; 3378 break; 3379 case INTERSECT_CUBIC_LINE_2: 3380 f.push(9, 10, 0, 14); 3381 f.push(12, 13, 11, 19); 3382 c1s = 1; c1l = 8; c2s = 15; c2l = 4; 3383 break; 3384 case INTERSECT_CUBIC_LINE_3: 3385 f.push(9, 10, 0, 17); 3386 f.push(12, 13, 11, 22); 3387 f.push(15, 16, 14, 23); 3388 c1s = 1; c1l = 8; c2s = 18; c2l = 4; 3389 break; 3390 case INTERSECT_CUBIC_QUAD_NO: 3391 c1s = 0; c1l = 8; c2s = 8; c2l = 6; 3392 break; 3393 case INTERSECT_CUBIC_QUAD: 3394 f.push(9, 10, 0, 11); 3395 c1s = 1; c1l = 8; c2s = 12; c2l = 6; 3396 break; 3397 case INTERSECT_CUBIC_QUAD_2: 3398 f.push(9, 10, 0, 14); 3399 f.push(12, 13, 11, 21); 3400 c1s = 1; c1l = 8; c2s = 15; c2l = 6; 3401 break; 3402 case INTERSECT_CUBIC_QUAD_3: 3403 f.push(9, 10, 0, 17); 3404 f.push(12, 13, 11, 24); 3405 f.push(15, 16, 14, 25); 3406 c1s = 1; c1l = 8; c2s = 18; c2l = 6; 3407 break; 3408 case INTERSECT_CUBIC_QUAD_4: 3409 f.push(9, 10, 0, 20); 3410 f.push(12, 13, 11, 27); 3411 f.push(15, 16, 14, 28); 3412 f.push(18, 19, 17, 29); 3413 c1s = 1; c1l = 8; c2s = 21; c2l = 6; 3414 break; 3415 case INTERSECT_CUBIC_LINE_NO: 3416 c1s = 0; c1l = 8; c2s = 8; c2l = 4; 3417 break; 3418 case INTERSECT_CUBIC: 3419 f.push(9, 10, 0, 11); 3420 c1s = 1; c1l = 8; c2s = 12; c2l = 8; 3421 break; 3422 case INTERSECT_CUBIC_2: 3423 f.push(9, 10, 0, 14); 3424 f.push(12, 13, 11, 23); 3425 c1s = 1; c1l = 8; c2s = 15; c2l = 8; 3426 break; 3427 case INTERSECT_CUBIC_3: 3428 f.push(9, 10, 0, 17); 3429 f.push(12, 13, 11, 26); 3430 f.push(15, 16, 14, 27); 3431 c1s = 1; c1l = 8; c2s = 18; c2l = 8; 3432 break; 3433 case INTERSECT_CUBIC_4: 3434 f.push(9, 10, 0, 20); 3435 f.push(12, 13, 11, 29); 3436 f.push(15, 16, 14, 30); 3437 f.push(18, 19, 17, 31); 3438 c1s = 1; c1l = 8; c2s = 21; c2l = 8; 3439 break; 3440 case INTERSECT_CUBIC_NO: 3441 c1s = 0; c1l = 8; c2s = 8; c2l = 8; 3442 break; 3443 default: 3444 console.log("unknown REC_TYPE_SECT frag type: " + fragType); 3445 throw "stop execution"; 3446 } 3447 if (draw_intersection != 1) { 3448 var id = -1; 3449 var curve; 3450 switch (c1l) { 3451 case 4: 3452 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]); 3453 if (draw_id) { 3454 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]]; 3455 id = idByCurve(test, curve, PATH_LINE); 3456 } 3457 break; 3458 case 6: 3459 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3460 frags[c1s + 4], frags[c1s + 5]); 3461 if (draw_id) { 3462 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3463 frags[c1s + 4], frags[c1s + 5]]; 3464 id = idByCurve(test, curve, PATH_QUAD); 3465 } 3466 break; 3467 case 7: 3468 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3469 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]); 3470 if (draw_id) { 3471 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3472 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]]; 3473 id = idByCurve(test, curve, PATH_CONIC); 3474 } 3475 break; 3476 case 8: 3477 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3478 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]); 3479 if (draw_id) { 3480 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3], 3481 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]]; 3482 id = idByCurve(test, curve, PATH_CUBIC); 3483 } 3484 break; 3485 } 3486 if (id >= 0) { 3487 drawVisibleID(curve, 0.5, id); 3488 } 3489 id = -1; 3490 switch (c2l) { 3491 case 0: 3492 break; 3493 case 4: 3494 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]); 3495 if (draw_id) { 3496 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]]; 3497 id = idByCurve(test, curve, PATH_LINE); 3498 } 3499 break; 3500 case 6: 3501 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3502 frags[c2s + 4], frags[c2s + 5]); 3503 if (draw_id) { 3504 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3505 frags[c2s + 4], frags[c2s + 5]]; 3506 id = idByCurve(test, curve, PATH_QUAD); 3507 } 3508 break; 3509 case 7: 3510 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3511 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]); 3512 if (draw_id) { 3513 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3514 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]]; 3515 id = idByCurve(test, curve, PATH_CONIC); 3516 } 3517 break; 3518 case 8: 3519 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3520 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]); 3521 if (draw_id) { 3522 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3], 3523 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]]; 3524 id = idByCurve(test, curve, PATH_CUBIC); 3525 } 3526 break; 3527 } 3528 if (id >= 0) { 3529 drawVisibleID(curve, 0.5, id); 3530 } 3531 } 3532 if (collect_bounds) { 3533 break; 3534 } 3535 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) { 3536 for (var idx = 0; idx < f.length; idx += 4) { 3537 drawPoint(frags[f[idx]], frags[f[idx + 1]], true); 3538 } 3539 } 3540 if (!draw_intersectT) { 3541 break; 3542 } 3543 ctx.fillStyle = "red"; 3544 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) { 3545 for (var idx = 0; idx < f.length; idx += 4) { 3546 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]); 3547 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]); 3548 } 3549 } 3550 break; 3551 case REC_TYPE_SORT: 3552 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) { 3553 continue; 3554 } 3555 ctx.lineWidth = 3; 3556 ctx.strokeStyle = "rgba(127,127,0, 0.5)"; 3557 focus_enabled = true; 3558 switch (fragType) { 3559 case SORT_UNARY: 3560 case SORT_BINARY: 3561 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]); 3562 drawCurve(curve); 3563 break; 3564 default: 3565 console.log("unknown REC_TYPE_SORT frag type: " + fragType); 3566 throw "stop execution"; 3567 } 3568 break; 3569 case REC_TYPE_TOP: 3570 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) { 3571 continue; 3572 } 3573 ctx.lineWidth = 3; 3574 ctx.strokeStyle = "rgba(127,127,0, 0.5)"; 3575 focus_enabled = true; 3576 { 3577 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]); 3578 drawCurve(curve); 3579 var type = PATH_LINE + (curve.length / 2 - 2); 3580 var mid = pointAtT(curve, type, 0.5); 3581 var d = dxy_at_t(curve, type, 0.5); 3582 drawArrow(mid.x, mid.y, d.x, d.y, 0.3); 3583 } 3584 break; 3585 case REC_TYPE_MARK: 3586 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) { 3587 continue; 3588 } 3589 ctx.lineWidth = 3; 3590 ctx.strokeStyle = fragType >= MARK_DONE_LINE ? 3591 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)"; 3592 focus_enabled = true; 3593 switch (fragType) { 3594 case MARK_LINE: 3595 case MARK_DONE_LINE: 3596 case MARK_UNSORTABLE_LINE: 3597 case MARK_SIMPLE_LINE: 3598 case MARK_SIMPLE_DONE_LINE: 3599 case MARK_DONE_UNARY_LINE: 3600 drawLinePartial(frags[1], frags[2], frags[3], frags[4], 3601 frags[5], frags[9]); 3602 if (draw_id) { 3603 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 3604 frags[5], frags[9]); 3605 } 3606 break; 3607 case MARK_QUAD: 3608 case MARK_DONE_QUAD: 3609 case MARK_UNSORTABLE_QUAD: 3610 case MARK_SIMPLE_QUAD: 3611 case MARK_SIMPLE_DONE_QUAD: 3612 case MARK_DONE_UNARY_QUAD: 3613 drawQuadPartial(frags[1], frags[2], frags[3], frags[4], 3614 frags[5], frags[6], frags[7], frags[11]); 3615 if (draw_id) { 3616 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 3617 frags[5], frags[6], frags[7], frags[11]); 3618 } 3619 break; 3620 case MARK_CUBIC: 3621 case MARK_DONE_CUBIC: 3622 case MARK_UNSORTABLE_CUBIC: 3623 case MARK_SIMPLE_CUBIC: 3624 case MARK_SIMPLE_DONE_CUBIC: 3625 case MARK_DONE_UNARY_CUBIC: 3626 drawCubicPartial(frags[1], frags[2], frags[3], frags[4], 3627 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]); 3628 if (draw_id) { 3629 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4], 3630 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]); 3631 } 3632 break; 3633 case MARK_ANGLE_LAST: 3634 // FIXME: ignored for now 3635 break; 3636 default: 3637 console.log("unknown REC_TYPE_MARK frag type: " + fragType); 3638 throw "stop execution"; 3639 } 3640 break; 3641 default: 3642 continue; 3643 } 3644 } 3645 switch (recType) { 3646 case REC_TYPE_SORT: 3647 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) { 3648 break; 3649 } 3650 var angles = []; // use tangent lines to describe arcs 3651 var windFrom = []; 3652 var windTo = []; 3653 var opp = []; 3654 var minXY = Number.MAX_VALUE; 3655 var partial; 3656 focus_enabled = true; 3657 var someUnsortable = false; 3658 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 3659 var fragType = records[recordIndex]; 3660 var frags = records[recordIndex + 1]; 3661 var unsortable = (fragType == SORT_UNARY && frags[14]) || 3662 (fragType == SORT_BINARY && frags[16]); 3663 someUnsortable |= unsortable; 3664 switch (fragType) { 3665 case SORT_UNARY: 3666 case SORT_BINARY: 3667 partial = curvePartialByID(test, frags[0], frags[6], frags[8]); 3668 break; 3669 default: 3670 console.log("unknown REC_TYPE_SORT frag type: " + fragType); 3671 throw "stop execution"; 3672 } 3673 var dx = boundsWidth(partial); 3674 var dy = boundsHeight(partial); 3675 minXY = Math.min(minXY, dx * dx + dy * dy); 3676 if (collect_bounds) { 3677 continue; 3678 } 3679 angles.push(tangent(partial)); 3680 var from = frags[12]; 3681 var to = frags[12]; 3682 var sgn = frags[10]; 3683 if (sgn < 0) { 3684 from -= frags[11]; 3685 } else if (sgn > 0) { 3686 to -= frags[11]; 3687 } 3688 windFrom.push(from + (unsortable ? "!" : "")); 3689 windTo.push(to + (unsortable ? "!" : "")); 3690 opp.push(fragType == SORT_BINARY); 3691 if (draw_sort == 1) { 3692 drawVisibleOrder(partial, frags[12]); 3693 } else { 3694 drawVisibleOrder(partial, (recordIndex / 2) + 1); 3695 } 3696 } 3697 var radius = Math.sqrt(minXY) / 2 * scale; 3698 radius = Math.min(50, radius); 3699 var scaledRadius = radius / scale; 3700 var centerX = partial[0]; 3701 var centerY = partial[1]; 3702 if (collect_bounds) { 3703 if (focus_enabled) { 3704 focusXmin = Math.min(focusXmin, centerX - scaledRadius); 3705 focusYmin = Math.min(focusYmin, centerY - scaledRadius); 3706 focusXmax = Math.max(focusXmax, centerX + scaledRadius); 3707 focusYmax = Math.max(focusYmax, centerY + scaledRadius); 3708 } 3709 break; 3710 } 3711 break; 3712 default: 3713 break; 3714 } 3715 } 3716 if (collect_bounds) { 3717 return; 3718 } 3719 if (draw_log && logStart >= 0) { 3720 ctx.font = "normal 10px Arial"; 3721 ctx.textAlign = "left"; 3722 ctx.beginPath(); 3723 var top = screenHeight - 20 - (logRange + 2) * 10; 3724 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10); 3725 ctx.fillStyle = "white"; 3726 ctx.fill(); 3727 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 3728 if (logStart > 0) { 3729 ctx.fillText(lines[logStart - 1], 50, top + 8); 3730 } 3731 ctx.fillStyle = "black"; 3732 for (var idx = 0; idx < logRange; ++idx) { 3733 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx); 3734 } 3735 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 3736 if (logStart + logRange < lines.length) { 3737 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange); 3738 } 3739 } 3740 if (draw_legend) { 3741 var pos = 0; 3742 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark; 3743 // drawBox(pos++, "yellow", "black", opLetter, true, ''); 3744 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey); 3745 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey); 3746 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey); 3747 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey); 3748 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey); 3749 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey); 3750 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey); 3751 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey); 3752 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey); 3753 drawBox(pos++, "black", "white", 3754 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey); 3755 drawBox(pos++, "rgba(0,63,0, 0.7)", "white", 3756 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed], 3757 draw_computed != 0, computedKey); 3758 drawBox(pos++, "green", "black", step_limit, drawSomething, ''); 3759 drawBox(pos++, "green", "black", stepMax, drawSomething, ''); 3760 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, ''); 3761 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, ''); 3762 if (curve_t) { 3763 drawCurveTControl(); 3764 } 3765 ctx.font = "normal 20px Arial"; 3766 ctx.fillStyle = "rgba(0,0,0, 0.3)"; 3767 ctx.textAlign = "right"; 3768 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5); 3769 } 3770 if (draw_hints) { 3771 ctx.font = "normal 10px Arial"; 3772 ctx.fillStyle = "rgba(0,0,0, 0.5)"; 3773 ctx.textAlign = "right"; 3774 var y = 4; 3775 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10); 3776 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10); 3777 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10); 3778 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10); 3779 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10); 3780 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10); 3781 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10); 3782 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10); 3783 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10); 3784 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10); 3785 } 3786} 3787 3788function drawBox(y, backC, foreC, str, enable, label) { 3789 ctx.beginPath(); 3790 ctx.fillStyle = backC; 3791 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30); 3792 ctx.fill(); 3793 ctx.font = "normal 16px Arial"; 3794 ctx.fillStyle = foreC; 3795 ctx.textAlign = "center"; 3796 ctx.fillText(str, screenWidth - 20, y * 50 + 32); 3797 if (!enable) { 3798 ctx.fillStyle = "rgba(255,255,255, 0.5)"; 3799 ctx.fill(); 3800 } 3801 if (label != '') { 3802 ctx.font = "normal 9px Arial"; 3803 ctx.fillStyle = "black"; 3804 ctx.fillText(label, screenWidth - 47, y * 50 + 40); 3805 } 3806} 3807 3808function drawCurveTControl() { 3809 ctx.lineWidth = 2; 3810 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 3811 ctx.beginPath(); 3812 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80); 3813 ctx.stroke(); 3814 var ty = 40 + curveT * (screenHeight - 80); 3815 ctx.beginPath(); 3816 ctx.moveTo(screenWidth - 80, ty); 3817 ctx.lineTo(screenWidth - 85, ty - 5); 3818 ctx.lineTo(screenWidth - 85, ty + 5); 3819 ctx.lineTo(screenWidth - 80, ty); 3820 ctx.fillStyle = "rgba(0,0,0, 0.6)"; 3821 ctx.fill(); 3822 var num = curveT.toFixed(decimal_places); 3823 ctx.font = "normal 10px Arial"; 3824 ctx.textAlign = "left"; 3825 ctx.fillText(num, screenWidth - 78, ty); 3826} 3827 3828function ptInTControl() { 3829 var e = window.event; 3830 var tgt = e.target || e.srcElement; 3831 var left = tgt.offsetLeft; 3832 var top = tgt.offsetTop; 3833 var x = (e.clientX - left); 3834 var y = (e.clientY - top); 3835 if (x < screenWidth - 80 || x > screenWidth - 50) { 3836 return false; 3837 } 3838 if (y < 40 || y > screenHeight - 80) { 3839 return false; 3840 } 3841 curveT = (y - 40) / (screenHeight - 120); 3842 if (curveT < 0 || curveT > 1) { 3843 throw "stop execution"; 3844 } 3845 return true; 3846} 3847 3848function drawTop() { 3849 if (tests[testIndex] == null) { 3850 var str = testDivs[testIndex].textContent; 3851 parse_all(str); 3852 var title = testDivs[testIndex].id.toString(); 3853 testTitles[testIndex] = title; 3854 } 3855 init(tests[testIndex]); 3856 redraw(); 3857} 3858 3859function redraw() { 3860 if (focus_on_selection) { 3861 collect_bounds = true; 3862 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]); 3863 collect_bounds = false; 3864 if (focusXmin < focusXmax && focusYmin < focusYmax) { 3865 setScale(focusXmin, focusXmax, focusYmin, focusYmax); 3866 } 3867 } 3868 ctx.beginPath(); 3869 ctx.fillStyle = "white"; 3870 ctx.rect(0, 0, screenWidth, screenHeight); 3871 ctx.fill(); 3872 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]); 3873} 3874 3875function dumpCurvePartial(test, id, t0, t1) { 3876 var curve = curveByID(test, id); 3877 var name = ["line", "quad", "cubic"][curve.length / 2 - 2]; 3878 console.log("id=" + id + " " + name + "=" + curveToString(curve) 3879 + " t0=" + t0 + " t1=" + t1 3880 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1))); 3881} 3882 3883function dumpAngleTest(test, id, t0, t1) { 3884 var curve = curveByID(test, id); 3885 console.log(" { {" + curveToString(curve) + "}, " 3886 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //"); 3887} 3888 3889function dumpLogToConsole() { 3890 if (logStart < 0) { 3891 return; 3892 } 3893 var test = tests[testIndex]; 3894 var recType = REC_TYPE_UNKNOWN; 3895 var records; 3896 for (var index = 0; index < test.length; index += 3) { 3897 var lastLineNo = test[index + 1]; 3898 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) { 3899 recType = test[index]; 3900 records = test[index + 2]; 3901 break; 3902 } 3903 } 3904 if (recType == REC_TYPE_UNKNOWN) { 3905 return; 3906 } 3907 var lines = testLines[testIndex]; 3908 for (var idx = 0; idx < logRange; ++idx) { 3909 var line = lines[logStart + idx]; 3910 console.log(line); 3911 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) { 3912 var fragType = records[recordIndex]; 3913 var frags = records[recordIndex + 1]; 3914 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) { 3915 dumpCurvePartial(test, frags[0], frags[4], frags[5]); 3916 dumpCurvePartial(test, frags[6], frags[10], frags[11]); 3917 dumpCurvePartial(test, frags[12], frags[16], frags[17]); 3918 console.log("\nstatic IntersectData intersectDataSet[] = { //"); 3919 dumpAngleTest(test, frags[0], frags[4], frags[5]); 3920 dumpAngleTest(test, frags[6], frags[10], frags[11]); 3921 dumpAngleTest(test, frags[12], frags[16], frags[17]); 3922 console.log("}; //"); 3923 } 3924 } 3925 } 3926} 3927 3928var activeKey = 'a'; 3929var pathKey = 'b'; 3930var pathBackKey = 'B'; 3931var centerKey = 'c'; 3932var coincidenceKey = 'C'; 3933var addKey = 'd'; 3934var deriviativesKey = 'f'; 3935var angleKey = 'g'; 3936var angleBackKey = 'G'; 3937var intersectionKey = 'i'; 3938var intersectionBackKey = 'I'; 3939var sequenceKey = 'j'; 3940var midpointKey = 'k'; 3941var logKey = 'l'; 3942var logToConsoleKey = 'L'; 3943var markKey = 'm'; 3944var sortKey = 'o'; 3945var opKey = 'p'; 3946var opBackKey = 'P'; 3947var computedKey = 'q'; 3948var computedBackKey = 'Q'; 3949var directionKey = 'r'; 3950var stepKey = 's'; 3951var stepBackKey = 'S'; 3952var intersectTKey = 't'; 3953var topKey = 'T'; 3954var curveTKey = 'u'; 3955var controlLinesBackKey = 'V'; 3956var controlLinesKey = 'v'; 3957var ptsKey = 'x'; 3958var xyKey = 'y'; 3959var logCurvesKey = 'z'; 3960var focusKey = '`'; 3961var idKey = '.'; 3962var retinaKey = '\\'; 3963 3964function doKeyPress(evt) { 3965 var char = String.fromCharCode(evt.charCode); 3966 var focusWasOn = false; 3967 switch (char) { 3968 case '0': 3969 case '1': 3970 case '2': 3971 case '3': 3972 case '4': 3973 case '5': 3974 case '6': 3975 case '7': 3976 case '8': 3977 case '9': 3978 decimal_places = char - '0'; 3979 redraw(); 3980 break; 3981 case activeKey: 3982 draw_active ^= true; 3983 redraw(); 3984 break; 3985 case addKey: 3986 draw_add ^= true; 3987 redraw(); 3988 break; 3989 case angleKey: 3990 draw_angle = (draw_angle + 1) % 4; 3991 redraw(); 3992 break; 3993 case angleBackKey: 3994 draw_angle = (draw_angle + 2) % 3; 3995 redraw(); 3996 break; 3997 case centerKey: 3998 setScale(xmin, xmax, ymin, ymax); 3999 redraw(); 4000 break; 4001 case coincidenceKey: 4002 draw_coincidence ^= true; 4003 redraw(); 4004 break; 4005 case controlLinesBackKey: 4006 control_lines = (control_lines + 3) % 4; 4007 redraw(); 4008 break; 4009 case controlLinesKey: 4010 control_lines = (control_lines + 1) % 4; 4011 redraw(); 4012 break; 4013 case computedBackKey: 4014 draw_computed = (draw_computed + 5) % 6; 4015 redraw(); 4016 break; 4017 case computedKey: 4018 draw_computed = (draw_computed + 1) % 6; 4019 redraw(); 4020 break; 4021 case curveTKey: 4022 curve_t ^= true; 4023 if (curve_t) { 4024 draw_legend = true; 4025 } 4026 redraw(); 4027 break; 4028 case deriviativesKey: 4029 draw_deriviatives = (draw_deriviatives + 1) % 3; 4030 redraw(); 4031 break; 4032 case directionKey: 4033 draw_direction ^= true; 4034 redraw(); 4035 break; 4036 case focusKey: 4037 focus_on_selection ^= true; 4038 setScale(xmin, xmax, ymin, ymax); 4039 redraw(); 4040 break; 4041 case idKey: 4042 draw_id ^= true; 4043 redraw(); 4044 break; 4045 case intersectionBackKey: 4046 draw_intersection = (draw_intersection + 3) % 4; 4047 redraw(); 4048 break; 4049 case intersectionKey: 4050 draw_intersection = (draw_intersection + 1) % 4; 4051 redraw(); 4052 break; 4053 case intersectTKey: 4054 draw_intersectT ^= true; 4055 redraw(); 4056 break; 4057 case logCurvesKey: 4058 logCurves(tests[testIndex]); 4059 break; 4060 case logKey: 4061 draw_log ^= true; 4062 redraw(); 4063 break; 4064 case logToConsoleKey: 4065 if (draw_log) { 4066 dumpLogToConsole(); 4067 } 4068 break; 4069 case markKey: 4070 draw_mark ^= true; 4071 redraw(); 4072 break; 4073 case midpointKey: 4074 draw_midpoint ^= true; 4075 redraw(); 4076 break; 4077 case opKey: 4078 draw_op = (draw_op + 1) % 3; 4079 redraw(); 4080 break; 4081 case opBackKey: 4082 draw_op = (draw_op + 2) % 3; 4083 redraw(); 4084 break; 4085 case pathKey: 4086 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0)); 4087 redraw(); 4088 break; 4089 case pathBackKey: 4090 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0)); 4091 redraw(); 4092 break; 4093 case ptsKey: 4094 pt_labels = (pt_labels + 1) % 3; 4095 redraw(); 4096 break; 4097 case retinaKey: 4098 retina_scale ^= true; 4099 drawTop(); 4100 break; 4101 case sequenceKey: 4102 draw_sequence ^= true; 4103 redraw(); 4104 break; 4105 case sortKey: 4106 draw_sort = (draw_sort + 1) % 3; 4107 drawTop(); 4108 break; 4109 case stepKey: 4110 step_limit++; 4111 if (step_limit > stepMax) { 4112 step_limit = stepMax; 4113 } 4114 redraw(); 4115 break; 4116 case stepBackKey: 4117 step_limit--; 4118 if (step_limit < 0) { 4119 step_limit = 0; 4120 } 4121 redraw(); 4122 break; 4123 case topKey: 4124 draw_top ^= true; 4125 redraw(); 4126 break; 4127 case xyKey: 4128 debug_xy = (debug_xy + 1) % 3; 4129 redraw(); 4130 break; 4131 case '-': 4132 focusWasOn = focus_on_selection; 4133 if (focusWasOn) { 4134 focus_on_selection = false; 4135 scale /= 1.2; 4136 } else { 4137 scale /= 2; 4138 calcLeftTop(); 4139 } 4140 redraw(); 4141 focus_on_selection = focusWasOn; 4142 break; 4143 case '=': 4144 case '+': 4145 focusWasOn = focus_on_selection; 4146 if (focusWasOn) { 4147 focus_on_selection = false; 4148 scale *= 1.2; 4149 } else { 4150 scale *= 2; 4151 calcLeftTop(); 4152 } 4153 redraw(); 4154 focus_on_selection = focusWasOn; 4155 break; 4156 case '?': 4157 draw_hints ^= true; 4158 if (draw_hints && !draw_legend) { 4159 draw_legend = true; 4160 } 4161 redraw(); 4162 break; 4163 case '/': 4164 draw_legend ^= true; 4165 redraw(); 4166 break; 4167 } 4168} 4169 4170function doKeyDown(evt) { 4171 var char = evt.keyCode; 4172 var preventDefault = false; 4173 switch (char) { 4174 case 37: // left arrow 4175 if (evt.shiftKey) { 4176 testIndex -= 9; 4177 } 4178 if (--testIndex < 0) 4179 testIndex = tests.length - 1; 4180 drawTop(); 4181 preventDefault = true; 4182 break; 4183 case 39: // right arrow 4184 if (evt.shiftKey) { 4185 testIndex += 9; 4186 } 4187 if (++testIndex >= tests.length) 4188 testIndex = 0; 4189 drawTop(); 4190 preventDefault = true; 4191 break; 4192 } 4193 if (preventDefault) { 4194 evt.preventDefault(); 4195 return false; 4196 } 4197 return true; 4198} 4199 4200(function() { 4201 var hidden = "hidden"; 4202 4203 // Standards: 4204 if (hidden in document) 4205 document.addEventListener("visibilitychange", onchange); 4206 else if ((hidden = "mozHidden") in document) 4207 document.addEventListener("mozvisibilitychange", onchange); 4208 else if ((hidden = "webkitHidden") in document) 4209 document.addEventListener("webkitvisibilitychange", onchange); 4210 else if ((hidden = "msHidden") in document) 4211 document.addEventListener("msvisibilitychange", onchange); 4212 // IE 9 and lower: 4213 else if ('onfocusin' in document) 4214 document.onfocusin = document.onfocusout = onchange; 4215 // All others: 4216 else 4217 window.onpageshow = window.onpagehide 4218 = window.onfocus = window.onblur = onchange; 4219 4220 function onchange (evt) { 4221 var v = 'visible', h = 'hidden', 4222 evtMap = { 4223 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h 4224 }; 4225 4226 evt = evt || window.event; 4227 if (evt.type in evtMap) 4228 document.body.className = evtMap[evt.type]; 4229 else 4230 document.body.className = this[hidden] ? "hidden" : "visible"; 4231 } 4232})(); 4233 4234function calcXY() { 4235 var e = window.event; 4236 var tgt = e.target || e.srcElement; 4237 var left = tgt.offsetLeft; 4238 var top = tgt.offsetTop; 4239 mouseX = (e.clientX - left) / scale + srcLeft; 4240 mouseY = (e.clientY - top) / scale + srcTop; 4241} 4242 4243function calcLeftTop() { 4244 srcLeft = mouseX - screenWidth / 2 / scale; 4245 srcTop = mouseY - screenHeight / 2 / scale; 4246} 4247 4248var disableClick = false; 4249 4250function handleMouseClick() { 4251 if (disableClick) { 4252 return; 4253 } 4254 if (!curve_t || !ptInTControl()) { 4255 calcXY(); 4256 calcLeftTop(); 4257 } 4258 redraw(); 4259// if (!curve_t || !ptInTControl()) { 4260// mouseX = screenWidth / 2 / scale + srcLeft; 4261// mouseY = screenHeight / 2 / scale + srcTop; 4262// } 4263} 4264 4265function handleMouseOver() { 4266 calcXY(); 4267 if (debug_xy != 2) { 4268 return; 4269 } 4270 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places); 4271 ctx.beginPath(); 4272 ctx.rect(300,100,num.length * 6,10); 4273 ctx.fillStyle="white"; 4274 ctx.fill(); 4275 ctx.font = "normal 10px Arial"; 4276 ctx.fillStyle="black"; 4277 ctx.textAlign = "left"; 4278 ctx.fillText(num, 300, 108); 4279} 4280 4281function start() { 4282 for (var i = 0; i < testDivs.length; ++i) { 4283 tests[i] = null; 4284 } 4285 testIndex = 0; 4286 drawTop(); 4287 window.addEventListener('keypress', doKeyPress, true); 4288 window.addEventListener('keydown', doKeyDown, true); 4289 window.onresize = function() { 4290 drawTop(); 4291 } 4292 /* 4293 window.onpagehide = function() { 4294 disableClick = true; 4295 } 4296 */ 4297 window.onpageshow = function () { 4298 disableClick = false; 4299 } 4300} 4301 4302</script> 4303</head> 4304 4305<body onLoad="start();"> 4306<canvas id="canvas" width="750" height="500" 4307 onmousemove="handleMouseOver()" 4308 onclick="handleMouseClick()" 4309 ></canvas > 4310</body> 4311</html> 4312