blob: fafd2811ca27679dd53c33e4c2b7378854a8eb0f [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
Cary Clark59d5a0e2017-01-23 14:38:52 +00003<div height="0" hidden="true">
Ben Wagner29380bd2017-10-09 14:43:00 -04004
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
caryclarkdac1d172014-06-17 05:15:38 -0700215</div>
216
217<script type="text/javascript">
218
caryclark55888e42016-07-18 10:01:36 -0700219 var testDivs = [
Cary Clark73e597d2017-04-18 12:08:58 -0400220 android1,
caryclark30b9fdd2016-08-31 14:36:29 -0700221 ];
caryclarkdac1d172014-06-17 05:15:38 -0700222
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;
caryclark1049f122015-04-20 08:31:59 -0700237var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700238var 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;
caryclark624637c2015-05-11 07:21:27 -0700251var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700252var draw_deriviatives = 0;
Cary Clarkff114282016-12-14 11:56:16 -0500253var draw_direction = false;
caryclarkdac1d172014-06-17 05:15:38 -0700254var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700255var 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;
caryclark03b03ca2015-04-23 09:13:37 -0700265var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700266var draw_path = 3;
267var draw_computed = 0;
268var retina_scale = !!window.devicePixelRatio;
269
270var activeCount = 0;
271var addCount = 0;
272var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700273var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700274var opCount = 0;
275var sectCount = 0;
276var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700277var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700278var markCount = 0;
279var activeMax = 0;
280var addMax = 0;
281var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700282var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700283var sectMax = 0;
284var sectMax2 = 0;
285var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700286var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700287var markMax = 0;
288var opMax = 0;
289var stepMax = 0;
290var lastIndex = 0;
291var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700292var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700293var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700294var angleBetween = false;
295var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700296
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;
caryclark1049f122015-04-20 08:31:59 -0700306
caryclark55888e42016-07-18 10:01:36 -0700307var SPAN_L_TX = SPAN_Y2 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700308var SPAN_L_TY = SPAN_L_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700309var SPAN_L_OTHER = SPAN_L_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700310var 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;
caryclark1049f122015-04-20 08:31:59 -0700318
caryclark55888e42016-07-18 10:01:36 -0700319var SPAN_Q_TX = SPAN_Y3 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700320var SPAN_Q_TY = SPAN_Q_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700321var SPAN_Q_OTHER = SPAN_Q_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700322var 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
caryclark1049f122015-04-20 08:31:59 -0700328var SPAN_K_W = SPAN_Y3 + 1;
caryclark55888e42016-07-18 10:01:36 -0700329var SPAN_K_TX = SPAN_K_W + 1;
caryclark1049f122015-04-20 08:31:59 -0700330var SPAN_K_TY = SPAN_K_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700331var SPAN_K_OTHER = SPAN_K_TY + 1;
caryclark1049f122015-04-20 08:31:59 -0700332var 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
caryclarkdac1d172014-06-17 05:15:38 -0700338var SPAN_X4 = SPAN_Y3 + 1;
339var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700340
caryclark55888e42016-07-18 10:01:36 -0700341var SPAN_C_TX = SPAN_Y4 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700342var SPAN_C_TY = SPAN_C_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700343var SPAN_C_OTHER = SPAN_C_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700344var 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;
caryclark1049f122015-04-20 08:31:59 -0700352var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
353var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700354
355var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
356var ADD_LINETO = ADD_MOVETO + 1;
357var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700358var ADD_CONICTO = ADD_QUADTO + 1;
359var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700360var ADD_CLOSE = ADD_CUBICTO + 1;
361var ADD_FILL = ADD_CLOSE + 1;
362
363var PATH_LINE = ADD_FILL + 1;
364var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700365var PATH_CONIC = PATH_QUAD + 1;
366var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700367
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;
caryclark1049f122015-04-20 08:31:59 -0700377var 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;
caryclark55888e42016-07-18 10:01:36 -0700380var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1;
381var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1;
caryclark6c3b9cd2016-09-26 05:36:58 -0700382var 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;
caryclark55888e42016-07-18 10:01:36 -0700385var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1;
caryclark1049f122015-04-20 08:31:59 -0700386var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
387var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
388var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700389var 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;
caryclark1049f122015-04-20 08:31:59 -0700416var MARK_CONIC = MARK_QUAD + 1;
417var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700418var MARK_DONE_LINE = MARK_CUBIC + 1;
419var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700420var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
421var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700422var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
423var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700424var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
425var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700426var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
427var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700428var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
429var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700430var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
431var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700432var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
433var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700434var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
435var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700436var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
437var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700438var 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
caryclark624637c2015-05-11 07:21:27 -0700443var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700444var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700445
caryclark54359292015-03-26 07:52:43 -0700446var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700447
caryclark624637c2015-05-11 07:21:27 -0700448var COIN_MAIN_SPAN = ACTIVE_OP + 1;
449var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
450
451var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700452
453var REC_TYPE_UNKNOWN = -1;
454var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700455var 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;
caryclark03b03ca2015-04-23 09:13:37 -0700467var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700468var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700469var REC_TYPE_ALIGNED = 15;
470var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700471
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\\)");
caryclark1049f122015-04-20 08:31:59 -0700501 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700502 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");
caryclark54359292015-03-26 07:52:43 -0700505 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700506 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+)?)");
caryclark1049f122015-04-20 08:31:59 -0700509 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700510 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700511 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700512 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 \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700520 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700521 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700522 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\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700524 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700525 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700526 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700527 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700528 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700529 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700530 escape = escape.replace(/OPER/g, "[a-z]+");
531 escape = escape.replace(/PATH/g, "pathB?");
532 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700533 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700534 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 }
caryclark624637c2015-05-11 07:21:27 -0700572 var coinStart = "SkOpCoincidence::";
573 if (line.lastIndexOf(coinStart, 0) === 0) {
574 line = line.substr(coinStart.length);
575 }
caryclark54359292015-03-26 07:52:43 -0700576 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700577 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700578 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclark55888e42016-07-18 10:01:36 -0700579 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700580 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700581 : 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
caryclark26ad22a2015-10-16 09:03:38 -0700585 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700586 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700587 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700588 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
589 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
Cary Clark59d5a0e2017-01-23 14:38:52 +0000590 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
caryclarkdac1d172014-06-17 05:15:38 -0700591 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
592 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700593 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700594 : 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" +
caryclark55888e42016-07-18 10:01:36 -0700612" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700613 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700614" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700615 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700616" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700617 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700618" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark624637c2015-05-11 07:21:27 -0700619 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700620" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700621 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700622" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700623 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700624" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700625 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700626" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700627 );
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;
caryclark1049f122015-04-20 08:31:59 -0700651 } 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;
caryclarkdac1d172014-06-17 05:15:38 -0700657 } 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;
caryclark54359292015-03-26 07:52:43 -0700669 case REC_TYPE_AFTERPART:
Cary Clarkff114282016-12-14 11:56:16 -0500670 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")
caryclark54359292015-03-26 07:52:43 -0700674 break;
caryclark26ad22a2015-10-16 09:03:38 -0700675 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;
caryclarkdac1d172014-06-17 05:15:38 -0700682 case REC_TYPE_ANGLE:
Cary Clark59d5a0e2017-01-23 14:38:52 +0000683 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700684"[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;
caryclark624637c2015-05-11 07:21:27 -0700689 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;
caryclarkdac1d172014-06-17 05:15:38 -0700696 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,"
caryclark1049f122015-04-20 08:31:59 -0700701 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700702 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
703 );
704 break;
705 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700706 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
707 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700708 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700709 ) || 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}"
caryclark1049f122015-04-20 08:31:59 -0700715 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700716 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700717 );
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"
caryclark55888e42016-07-18 10:01:36 -0700738
caryclark1049f122015-04-20 08:31:59 -0700739 ) || 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"
caryclark55888e42016-07-18 10:01:36 -0700745
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"
caryclark6c3b9cd2016-09-26 05:36:58 -0700750 ) || 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"
caryclark55888e42016-07-18 10:01:36 -0700754 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
755" no intersect CONIC_VAL QUAD_VAL"
756
caryclark1049f122015-04-20 08:31:59 -0700757 ) || 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"
caryclarkdac1d172014-06-17 05:15:38 -0700763 ) || 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;
caryclark03b03ca2015-04-23 09:13:37 -0700823 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;
caryclarkdac1d172014-06-17 05:15:38 -0700832 case REC_TYPE_MARK:
833 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700834" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700835 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700836" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700837 ) || 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"
caryclarkdac1d172014-06-17 05:15:38 -0700839 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700840" 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"
caryclark1049f122015-04-20 08:31:59 -0700845 ) || 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"
caryclark54359292015-03-26 07:52:43 -0700847 ) || 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"
caryclarkdac1d172014-06-17 05:15:38 -0700849 ) || 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"
caryclark1049f122015-04-20 08:31:59 -0700853 ) || 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"
caryclarkdac1d172014-06-17 05:15:38 -0700855 ) || 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"
caryclarkdac1d172014-06-17 05:15:38 -0700857 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700858" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700859 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark55888e42016-07-18 10:01:36 -0700860" 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 );
caryclarkdac1d172014-06-17 05:15:38 -0700866 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 }
caryclark54359292015-03-26 07:52:43 -0700873 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700874 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700875 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700876 ) || 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;
caryclark26ad22a2015-10-16 09:03:38 -0700919 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700920 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) {
caryclark26ad22a2015-10-16 09:03:38 -0700940 case REC_TYPE_ALIGNED:
941 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -0700942 case REC_TYPE_COMPUTED:
943 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
944 break;
945 }
caryclark26ad22a2015-10-16 09:03:38 -0700946 if (REC_TYPE_COMPUTED == recType) {
947 hasComputedPath = true;
948 }
caryclarkdac1d172014-06-17 05:15:38 -0700949 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700950 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700951 switch (fragType) {
952 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700953 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700954 break;
caryclark1049f122015-04-20 08:31:59 -0700955 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700956 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700957 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700958 break;
959 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700960 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700961 break;
962 default:
caryclark55888e42016-07-18 10:01:36 -0700963 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
caryclarkdac1d172014-06-17 05:15:38 -0700964 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
965 throw "stop execution";
966 }
967 if (recType == REC_TYPE_PATH) {
968 hasPath = true;
969 }
970 break;
caryclark54359292015-03-26 07:52:43 -0700971 case REC_TYPE_PATH2:
972 first = 1;
973 switch (fragType) {
974 case PATH_LINE:
975 last = 5;
976 break;
caryclark1049f122015-04-20 08:31:59 -0700977 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700978 case PATH_QUAD:
979 last = 7;
980 break;
981 case PATH_CUBIC:
982 last = 9;
983 break;
984 default:
caryclark55888e42016-07-18 10:01:36 -0700985 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
caryclark54359292015-03-26 07:52:43 -0700986 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
987 throw "stop execution";
988 }
989 if (recType == REC_TYPE_PATH2) {
990 hasPath = true;
991 }
992 break;
caryclarkdac1d172014-06-17 05:15:38 -0700993 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;
caryclark1049f122015-04-20 08:31:59 -07001002 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -07001003 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;
caryclark1049f122015-04-20 08:31:59 -07001021 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -07001022 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;
caryclark54359292015-03-26 07:52:43 -07001036 case REC_TYPE_AFTERPART:
1037 switch (fragType) {
1038 case PATH_LINE:
1039 last = 4;
1040 break;
caryclark1049f122015-04-20 08:31:59 -07001041 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001042 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;
caryclarkdac1d172014-06-17 05:15:38 -07001053 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;
caryclark1049f122015-04-20 08:31:59 -07001064 case INTERSECT_CONIC_LINE:
1065 first = 1; last = 7; first2 = 11; last2 = 15;
1066 break;
caryclarkdac1d172014-06-17 05:15:38 -07001067 case INTERSECT_QUAD_LINE:
1068 first = 1; last = 7; first2 = 10; last2 = 14;
1069 break;
caryclark1049f122015-04-20 08:31:59 -07001070 case INTERSECT_CONIC_LINE_2:
1071 first = 1; last = 7; first2 = 14; last2 = 18;
1072 break;
caryclarkdac1d172014-06-17 05:15:38 -07001073 case INTERSECT_QUAD_LINE_2:
1074 first = 1; last = 7; first2 = 13; last2 = 17;
1075 break;
caryclark1049f122015-04-20 08:31:59 -07001076 case INTERSECT_CONIC_LINE_NO:
1077 first = 0; last = 6; first2 = 7; last2 = 11;
1078 break;
caryclarkdac1d172014-06-17 05:15:38 -07001079 case INTERSECT_QUAD_LINE_NO:
1080 first = 0; last = 6; first2 = 6; last2 = 10;
1081 break;
caryclark1049f122015-04-20 08:31:59 -07001082 case INTERSECT_CONIC:
1083 first = 1; last = 7; first2 = 11; last2 = 17;
1084 break;
caryclarkdac1d172014-06-17 05:15:38 -07001085 case INTERSECT_QUAD:
1086 first = 1; last = 7; first2 = 10; last2 = 16;
1087 break;
caryclark1049f122015-04-20 08:31:59 -07001088 case INTERSECT_CONIC_2:
1089 first = 1; last = 7; first2 = 14; last2 = 20;
1090 break;
caryclarkdac1d172014-06-17 05:15:38 -07001091 case INTERSECT_QUAD_2:
1092 first = 1; last = 7; first2 = 13; last2 = 19;
1093 break;
caryclark1049f122015-04-20 08:31:59 -07001094 case INTERSECT_CONIC_NO:
1095 first = 0; last = 6; first2 = 7; last2 = 13;
1096 break;
caryclarkdac1d172014-06-17 05:15:38 -07001097 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;
caryclark55888e42016-07-18 10:01:36 -07001118 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;
caryclark6c3b9cd2016-09-26 05:36:58 -07001124 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;
caryclark55888e42016-07-18 10:01:36 -07001130 case INTERSECT_CONIC_QUAD_NO:
1131 first = 0; last = 6; first2 = 7; last2 = 13;
1132 break;
caryclarkdac1d172014-06-17 05:15:38 -07001133 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 }
caryclark54359292015-03-26 07:52:43 -07001206 {
caryclarkdac1d172014-06-17 05:15:38 -07001207 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;
caryclark624637c2015-05-11 07:21:27 -07001214 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;
caryclarkdac1d172014-06-17 05:15:38 -07001223 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;
caryclark03b03ca2015-04-23 09:13:37 -07001232 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;
caryclarkdac1d172014-06-17 05:15:38 -07001241 }
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) {
caryclark1049f122015-04-20 08:31:59 -07001250 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001251 }
1252 if (hasPath == true && hasComputedPath == false && draw_computed) {
1253 draw_computed = 0;
1254 }
1255}
1256
caryclark26ad22a2015-10-16 09:03:38 -07001257function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001258 var tIndex = -3;
1259 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001260 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001261 if (recType == REC_TYPE_OP) {
1262 continue;
1263 }
caryclark26ad22a2015-10-16 09:03:38 -07001264 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001265 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) {
caryclark54359292015-03-26 07:52:43 -07001273 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001274 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001275 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001276 return [frags[1], frags[2], frags[3], frags[4],
1277 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001278 case PATH_CONIC:
1279 return [frags[1], frags[2], frags[3], frags[4],
1280 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001281 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001282 return [frags[1], frags[2], frags[3], frags[4],
1283 frags[5], frags[6], frags[7], frags[8]];
1284 }
1285 }
1286 }
caryclarkdac1d172014-06-17 05:15:38 -07001287 }
1288 return [];
1289}
1290
caryclark26ad22a2015-10-16 09:03:38 -07001291function 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) {
caryclark54359292015-03-26 07:52:43 -07001300 var tIndex = -3;
1301 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001302 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001303 if (recType == REC_TYPE_OP) {
1304 continue;
1305 }
caryclark26ad22a2015-10-16 09:03:38 -07001306 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001307 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) {
caryclark54359292015-03-26 07:52:43 -07001315 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001316 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001317 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001318 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1319 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001320 case PATH_CONIC:
1321 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1322 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001323 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001324 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1325 frags[5], frags[6], frags[7], frags[8], t0, t1);
1326 }
1327 }
1328 }
caryclarkdac1d172014-06-17 05:15:38 -07001329 }
1330 return [];
1331}
1332
caryclark26ad22a2015-10-16 09:03:38 -07001333function 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) {
caryclark54359292015-03-26 07:52:43 -07001342 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001343 while (tIndex < test.length) {
1344 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001345 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001346 ++tIndex;
1347 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001348 }
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];
caryclark54359292015-03-26 07:52:43 -07001353 if (frag.length != frags.length - 1) {
1354 continue;
1355 }
caryclarkdac1d172014-06-17 05:15:38 -07001356 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001357 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001358 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];
caryclark54359292015-03-26 07:52:43 -07001363 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001364 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];
caryclark1049f122015-04-20 08:31:59 -07001370 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];
caryclark54359292015-03-26 07:52:43 -07001378 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001379 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
caryclark26ad22a2015-10-16 09:03:38 -07001393function 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
caryclarkdac1d172014-06-17 05:15:38 -07001401function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001402 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001403 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001404 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) {
caryclark1049f122015-04-20 08:31:59 -07001499 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1500 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001501 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
caryclark1049f122015-04-20 08:31:59 -07001526function 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
caryclarkdac1d172014-06-17 05:15:38 -07001540function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001541 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001542 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;
caryclark1049f122015-04-20 08:31:59 -07001588 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;
caryclarkdac1d172014-06-17 05:15:38 -07001599 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}
caryclark55888e42016-07-18 10:01:36 -07001613
caryclarkdac1d172014-06-17 05:15:38 -07001614function 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
caryclark1049f122015-04-20 08:31:59 -07001791function 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]
caryclark55888e42016-07-18 10:01:36 -07001803 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1804 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclark1049f122015-04-20 08:31:59 -07001805 && 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;
caryclark1049f122015-04-20 08:31:59 -07001930 var array = [
caryclarked0935a2015-10-22 07:23:52 -07001931 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07001932 ];
caryclarked0935a2015-10-22 07:23:52 -07001933 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;
caryclark1049f122015-04-20 08:31:59 -07001940 return array;
1941}
caryclark55888e42016-07-18 10:01:36 -07001942
caryclark1049f122015-04-20 08:31:59 -07001943function 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
caryclarkdac1d172014-06-17 05:15:38 -07001955function 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]
caryclark55888e42016-07-18 10:01:36 -07001967 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1968 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclarkdac1d172014-06-17 05:15:38 -07001969 && 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}
caryclark55888e42016-07-18 10:01:36 -07002033
caryclarkdac1d172014-06-17 05:15:38 -07002034function 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;
caryclark1049f122015-04-20 08:31:59 -07002067 case 7:
2068 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
2069 break;
caryclarkdac1d172014-06-17 05:15:38 -07002070 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];
caryclark1049f122015-04-20 08:31:59 -07002079 var length = pts.length == 7 ? 6 : pts.length;
2080 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002081 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];
caryclark1049f122015-04-20 08:31:59 -07002090 var length = pts.length == 7 ? 6 : pts.length;
2091 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002092 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];
caryclark1049f122015-04-20 08:31:59 -07002104 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002105 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 = {};
Cary Clarkff114282016-12-14 11:56:16 -05002193 if (type == PATH_LINE) {
2194 dxy.x = curve[2] - curve[0];
2195 dxy.y = curve[3] - curve[1];
2196 } else if (type == PATH_QUAD) {
caryclarkdac1d172014-06-17 05:15:38 -07002197 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];
caryclark1049f122015-04-20 08:31:59 -07002202 } 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;
caryclarkdac1d172014-06-17 05:15:38 -07002213 } 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
Ben Wagner29380bd2017-10-09 14:43:00 -04002229function dpt_at_t(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002230 var type = PATH_LINE + (curve.length / 2 - 2);
Ben Wagner29380bd2017-10-09 14:43:00 -04002231 return dxy_at_t(curve, type, t);
Cary Clarkff114282016-12-14 11:56:16 -05002232}
2233
caryclarkdac1d172014-06-17 05:15:38 -07002234function 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
caryclark03b03ca2015-04-23 09:13:37 -07002288function drawArrow(x, y, dx, dy, s) {
2289 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002290 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 }
caryclark1049f122015-04-20 08:31:59 -07002317 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 }
caryclarkdac1d172014-06-17 05:15:38 -07002321 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 }
caryclark1049f122015-04-20 08:31:59 -07002338 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 }
caryclarkdac1d172014-06-17 05:15:38 -07002342 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
Ben Wagner29380bd2017-10-09 14:43:00 -04002349function 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;
Cary Clarkff114282016-12-14 11:56:16 -05002354}
2355
2356function drawOrder(curve, t, label) {
2357 var px = x_at_t(curve, t);
2358 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002359 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
Ben Wagner29380bd2017-10-09 14:43:00 -04002380function 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);
Cary Clarkff114282016-12-14 11:56:16 -05002420}
2421
Ben Wagner29380bd2017-10-09 14:43:00 -04002422function 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;
Cary Clarkff114282016-12-14 11:56:16 -05002427}
2428
Ben Wagner29380bd2017-10-09 14:43:00 -04002429function drawDirection(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002430 var d = dpt_at_t(curve, t);
2431 d = set_length(d, 16);
Ben Wagner29380bd2017-10-09 14:43:00 -04002432 var pt = localToGlobal(pt_at_t(curve, t));
Cary Clarkff114282016-12-14 11:56:16 -05002433 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
Ben Wagner29380bd2017-10-09 14:43:00 -04002441function 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);
Cary Clarkff114282016-12-14 11:56:16 -05002482}
2483
2484function drawID(curve, t, id) {
2485 var px = x_at_t(curve, t);
2486 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002487 var _px = (px - srcLeft) * scale;
2488 var _py = (py - srcTop) * scale;
2489 draw_id_at(id, _px, _py);
2490}
2491
Ben Wagner29380bd2017-10-09 14:43:00 -04002492function localToGlobal(local) {
2493 var global = {};
2494 global.x = (local.x - srcLeft) * scale;
2495 global.y = (local.y - srcTop) * scale;
2496 return global;
Cary Clarkff114282016-12-14 11:56:16 -05002497}
2498
Ben Wagner29380bd2017-10-09 14:43:00 -04002499function ptOnScreen(local) {
2500 var pt = localToGlobal(local);
2501 return 10 <= pt.x && pt.x <= screenWidth - 10
2502 && 10 <= pt.y && pt.y <= screenHeight - 10;
Cary Clarkff114282016-12-14 11:56:16 -05002503}
2504
Ben Wagner29380bd2017-10-09 14:43:00 -04002505function 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);
Cary Clarkff114282016-12-14 11:56:16 -05002539}
2540
caryclarkdac1d172014-06-17 05:15:38 -07002541function 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
caryclark55888e42016-07-18 10:01:36 -07002561function drawLineID(id, x1, y1, x2, y2) {
2562 drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
2563}
2564
caryclarkdac1d172014-06-17 05:15:38 -07002565function 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
caryclark55888e42016-07-18 10:01:36 -07002570function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
2571 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
2572}
2573
caryclark1049f122015-04-20 08:31:59 -07002574function 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
caryclark55888e42016-07-18 10:01:36 -07002579function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
2580 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
2581}
2582
caryclarkdac1d172014-06-17 05:15:38 -07002583function 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
caryclark55888e42016-07-18 10:01:36 -07002588function 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
caryclarkdac1d172014-06-17 05:15:38 -07002592function drawCurvePartialID(id, curve, t1, t2) {
Cary Clarkff114282016-12-14 11:56:16 -05002593 drawVisibleID(curve, (t1 + t2) / 2, id);
caryclarkdac1d172014-06-17 05:15:38 -07002594}
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) {
Cary Clarkff114282016-12-14 11:56:16 -05002613 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07002614 }
2615 }
Ben Wagner29380bd2017-10-09 14:43:00 -04002616 if (draw_direction) {
2617 drawVisibleDirection(curve);
Cary Clarkff114282016-12-14 11:56:16 -05002618 }
caryclarkdac1d172014-06-17 05:15:38 -07002619 if (type == PATH_LINE) {
2620 return;
2621 }
2622 if (draw_deriviatives > 0) {
2623 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002624 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002625 if (draw_deriviatives == 2) {
2626 d = dxy_at_t(curve, type, 1);
2627 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002628 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002629 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002630 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002631 }
2632 }
2633 if (draw_midpoint) {
2634 var mid = pointAtT(curve, type, 0.5);
2635 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002636 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002637 }
2638 }
2639 if (type != PATH_CUBIC) {
2640 return;
2641 }
caryclarkdac1d172014-06-17 05:15:38 -07002642 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 = "{{";
caryclark1049f122015-04-20 08:31:59 -07002663 var length = curve.length == 7 ? 6 : curve.length;
2664 if (curve.length == 7) {
2665 str += "{";
2666 }
2667 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002668 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2669 if (i < curve.length - 2) {
2670 str += "}, {";
2671 }
2672 }
caryclark1049f122015-04-20 08:31:59 -07002673 str += "}";
2674 if (curve.length == 7) {
2675 str += "}, " + curve[6].toFixed(decimal_places);
2676 }
2677 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002678 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;
caryclark624637c2015-05-11 07:21:27 -07002702 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002703 var lastSect = 0;
2704 var lastSort = 0;
2705 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002706 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002707 activeCount = 0;
2708 addCount = 0;
2709 angleCount = 0;
2710 opCount = 0;
2711 sectCount = 0;
2712 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002713 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002714 markCount = 0;
2715 activeMax = 0;
2716 addMax = 0;
2717 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002718 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002719 opMax = 0;
2720 sectMax = 0;
2721 sectMax2 = 0;
2722 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002723 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002724 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 }
caryclark54359292015-03-26 07:52:43 -07002767 if (recType == REC_TYPE_PATH2 && hasOp) {
2768 secondPath = tIndex;
2769 }
caryclarkdac1d172014-06-17 05:15:38 -07002770 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 }
caryclark54359292015-03-26 07:52:43 -07002788 if (recType == REC_TYPE_AFTERPART) {
2789 if (draw_angle != 3 || !inStepRange) {
2790 continue;
2791 }
2792 lastAngle = tIndex;
2793 ++angleCount;
2794 bumpStep = true;
2795 }
caryclarkdac1d172014-06-17 05:15:38 -07002796 if (recType == REC_TYPE_ANGLE) {
2797 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002798 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002799 continue;
2800 }
2801 lastAngle = tIndex;
2802 ++angleCount;
2803 bumpStep = true;
2804 }
caryclark624637c2015-05-11 07:21:27 -07002805 if (recType == REC_TYPE_COINCIDENCE) {
2806 ++coinMax;
2807 if (!draw_coincidence || !inStepRange) {
2808 continue;
2809 }
2810 lastCoin = tIndex;
2811 ++coinCount;
2812 bumpStep = true;
2813 }
caryclarkdac1d172014-06-17 05:15:38 -07002814 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:
caryclark1049f122015-04-20 08:31:59 -07002825 case INTERSECT_CONIC_LINE:
caryclark55888e42016-07-18 10:01:36 -07002826 case INTERSECT_CONIC_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002827 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002828 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:
caryclark1049f122015-04-20 08:31:59 -07002837 case INTERSECT_CONIC_LINE_2:
caryclark55888e42016-07-18 10:01:36 -07002838 case INTERSECT_CONIC_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002839 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002840 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:
caryclark1049f122015-04-20 08:31:59 -07002848 case INTERSECT_CONIC_LINE_NO:
caryclark55888e42016-07-18 10:01:36 -07002849 case INTERSECT_CONIC_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002850 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002851 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;
caryclark6c3b9cd2016-09-26 05:36:58 -07002857 case INTERSECT_CONIC_QUAD_3:
caryclarkdac1d172014-06-17 05:15:38 -07002858 case INTERSECT_CUBIC_LINE_3:
2859 case INTERSECT_CUBIC_QUAD_3:
2860 case INTERSECT_CUBIC_3:
2861 sectBump = 3;
2862 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002863 case INTERSECT_CONIC_QUAD_4:
caryclarkdac1d172014-06-17 05:15:38 -07002864 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 }
caryclark03b03ca2015-04-23 09:13:37 -07002889 if (recType == REC_TYPE_TOP) {
2890 ++topMax;
2891 if (!draw_top || !inStepRange) {
2892 continue;
2893 }
2894 lastTop = tIndex;
2895 ++topCount;
2896 bumpStep = true;
2897 }
caryclarkdac1d172014-06-17 05:15:38 -07002898 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)
reed0dc4dd62015-03-24 13:55:33 -07002916 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002917 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002918 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002919 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002920 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002921 + (draw_mark ? markMax : 0)
2922 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2923 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002924 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002925 }
2926 drawnPts = [];
2927 drawnLines = [];
2928 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002929 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002930 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:
caryclark1049f122015-04-20 08:31:59 -07002957 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2958 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002959 drawQuad(frags[0], frags[1], frags[2], frags[3],
2960 frags[4], frags[5]);
2961 drawThis = true;
2962 }
2963 break;
caryclark1049f122015-04-20 08:31:59 -07002964 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;
caryclarkdac1d172014-06-17 05:15:38 -07002972 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002973 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2974 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002975 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;
caryclark26ad22a2015-10-16 09:03:38 -07002996 case REC_TYPE_ALIGNED:
2997 if (draw_path < 4) {
2998 continue;
2999 }
caryclarkdac1d172014-06-17 05:15:38 -07003000 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07003001 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07003002 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
3003 continue;
3004 }
caryclarkdac1d172014-06-17 05:15:38 -07003005 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";
caryclark55888e42016-07-18 10:01:36 -07003015 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07003016 switch (fragType) {
3017 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07003018 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
3019 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07003020 break;
3021 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07003022 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]);
caryclarkdac1d172014-06-17 05:15:38 -07003025 break;
caryclark1049f122015-04-20 08:31:59 -07003026 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;
caryclarkdac1d172014-06-17 05:15:38 -07003031 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07003032 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]);
caryclarkdac1d172014-06-17 05:15:38 -07003035 break;
3036 default:
caryclark26ad22a2015-10-16 09:03:38 -07003037 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003038 throw "stop execution";
3039 }
3040 if (collect_bounds) {
3041 break;
3042 }
caryclark54359292015-03-26 07:52:43 -07003043 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003044 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];
caryclark55888e42016-07-18 10:01:36 -07003064 var x3, y3, x3, y4, w;
caryclarkdac1d172014-06-17 05:15:38 -07003065 ctx.lineWidth = 3;
3066 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3067 focus_enabled = true;
3068 switch (fragType) {
3069 case ACTIVE_LINE_SPAN:
caryclark55888e42016-07-18 10:01:36 -07003070 drawLine(x1, y1, x2, y2);
caryclarkdac1d172014-06-17 05:15:38 -07003071 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003072 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);
caryclarkdac1d172014-06-17 05:15:38 -07003078 }
3079 break;
3080 case ACTIVE_QUAD_SPAN:
3081 x3 = frags[SPAN_X3];
3082 y3 = frags[SPAN_Y3];
caryclark55888e42016-07-18 10:01:36 -07003083 drawQuad(x1, y1, x2, y2, x3, y3);
caryclarkdac1d172014-06-17 05:15:38 -07003084 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003085 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);
caryclarkdac1d172014-06-17 05:15:38 -07003091 }
3092 break;
caryclark1049f122015-04-20 08:31:59 -07003093 case ACTIVE_CONIC_SPAN:
3094 x3 = frags[SPAN_X3];
3095 y3 = frags[SPAN_Y3];
caryclark1049f122015-04-20 08:31:59 -07003096 w = frags[SPAN_K_W];
caryclark55888e42016-07-18 10:01:36 -07003097 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
caryclark1049f122015-04-20 08:31:59 -07003098 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003099 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);
caryclark1049f122015-04-20 08:31:59 -07003105 }
3106 break;
caryclarkdac1d172014-06-17 05:15:38 -07003107 case ACTIVE_CUBIC_SPAN:
3108 x3 = frags[SPAN_X3];
3109 y3 = frags[SPAN_Y3];
3110 x4 = frags[SPAN_X4];
3111 y4 = frags[SPAN_Y4];
caryclark55888e42016-07-18 10:01:36 -07003112 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
caryclarkdac1d172014-06-17 05:15:38 -07003113 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003114 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);
caryclarkdac1d172014-06-17 05:15:38 -07003120 }
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;
caryclark1049f122015-04-20 08:31:59 -07003166 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;
caryclarkdac1d172014-06-17 05:15:38 -07003172 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:
caryclark54359292015-03-26 07:52:43 -07003189 angleBetween = frags[18] == "T";
3190 afterIndex = 0;
3191 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07003192 continue;
3193 }
3194 focus_enabled = true;
3195 ctx.lineWidth = 3;
3196 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07003197 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]);
caryclarkdac1d172014-06-17 05:15:38 -07003200 drawCurve(leftCurve);
3201 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07003202 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07003203 drawCurve(midCurve);
3204 if (draw_angle > 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003205 drawVisibleOrder(leftCurve, 'L');
3206 drawVisibleOrder(rightCurve, 'R');
3207 }
Ben Wagner29380bd2017-10-09 14:43:00 -04003208 if (draw_id) {
3209 drawVisibleID(leftCurve, 0.5, frags[0]);
3210 drawVisibleID(midCurve, 0.5, frags[6]);
3211 drawVisibleID(rightCurve, 0.5, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003212 }
3213 break;
caryclark54359292015-03-26 07:52:43 -07003214 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)"
Cary Clarkff114282016-12-14 11:56:16 -05003220 : "rgba(0,0,255, 1.0)";
3221 var curve;
3222 var id;
caryclark54359292015-03-26 07:52:43 -07003223 switch (fragType) {
3224 case PATH_LINE:
Cary Clarkff114282016-12-14 11:56:16 -05003225 curve = [ frags[0], frags[1], frags[2], frags[3] ];
3226 id = frags[4];
caryclark54359292015-03-26 07:52:43 -07003227 break;
3228 case PATH_QUAD:
Cary Clarkff114282016-12-14 11:56:16 -05003229 curve = [ frags[0], frags[1], frags[2], frags[3],
3230 frags[4], frags[5] ];
3231 id = frags[6];
caryclark54359292015-03-26 07:52:43 -07003232 break;
caryclark1049f122015-04-20 08:31:59 -07003233 case PATH_CONIC:
Cary Clarkff114282016-12-14 11:56:16 -05003234 curve = [ frags[0], frags[1], frags[2], frags[3],
3235 frags[4], frags[5], frags[6] ];
3236 id = frags[7];
caryclark1049f122015-04-20 08:31:59 -07003237 break;
caryclark54359292015-03-26 07:52:43 -07003238 case PATH_CUBIC:
Cary Clarkff114282016-12-14 11:56:16 -05003239 curve = [ frags[0], frags[1], frags[2], frags[3],
3240 frags[4], frags[5], frags[6], frags[7] ];
3241 id = frags[8];
caryclark54359292015-03-26 07:52:43 -07003242 break;
3243 default:
3244 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
3245 throw "stop execution";
3246 }
Cary Clarkff114282016-12-14 11:56:16 -05003247 drawCurve(curve);
Ben Wagner29380bd2017-10-09 14:43:00 -04003248 if (draw_id) {
3249 drawVisibleID(curve, 0.5, id);
Cary Clarkff114282016-12-14 11:56:16 -05003250 }
caryclark54359292015-03-26 07:52:43 -07003251 ++afterIndex;
3252 break;
caryclark624637c2015-05-11 07:21:27 -07003253 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;
caryclarkdac1d172014-06-17 05:15:38 -07003263 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;
caryclark1049f122015-04-20 08:31:59 -07003319 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;
caryclark55888e42016-07-18 10:01:36 -07003331 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;
caryclark6c3b9cd2016-09-26 05:36:58 -07003340 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;
caryclark55888e42016-07-18 10:01:36 -07003353 case INTERSECT_CONIC_QUAD_NO:
3354 c1s = 0; c1l = 7; c2s = 7; c2l = 6;
3355 break;
caryclark1049f122015-04-20 08:31:59 -07003356 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;
caryclarkdac1d172014-06-17 05:15:38 -07003368 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) {
caryclark55888e42016-07-18 10:01:36 -07003451 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003452 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;
caryclark1049f122015-04-20 08:31:59 -07003467 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;
caryclarkdac1d172014-06-17 05:15:38 -07003476 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) {
Cary Clarkff114282016-12-14 11:56:16 -05003487 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003488 }
3489 id = -1;
3490 switch (c2l) {
3491 case 0:
3492 break;
caryclark55888e42016-07-18 10:01:36 -07003493 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003494 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;
caryclark1049f122015-04-20 08:31:59 -07003509 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;
caryclarkdac1d172014-06-17 05:15:38 -07003518 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) {
Cary Clarkff114282016-12-14 11:56:16 -05003529 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003530 }
3531 }
3532 if (collect_bounds) {
3533 break;
3534 }
caryclark54359292015-03-26 07:52:43 -07003535 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3536 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003537 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3538 }
3539 }
3540 if (!draw_intersectT) {
3541 break;
3542 }
3543 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003544 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3545 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003546 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;
caryclark03b03ca2015-04-23 09:13:37 -07003569 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;
caryclarkdac1d172014-06-17 05:15:38 -07003585 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) {
Cary Clarkff114282016-12-14 11:56:16 -05003692 drawVisibleOrder(partial, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003693 } else {
Cary Clarkff114282016-12-14 11:56:16 -05003694 drawVisibleOrder(partial, (recordIndex / 2) + 1);
caryclarkdac1d172014-06-17 05:15:38 -07003695 }
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;
caryclark624637c2015-05-11 07:21:27 -07003742 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003743 // 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);
caryclark624637c2015-05-11 07:21:27 -07003748 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003749 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);
caryclark03b03ca2015-04-23 09:13:37 -07003751 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003752 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
caryclark55888e42016-07-18 10:01:36 -07003753 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003754 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003755 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);
caryclarkdac1d172014-06-17 05:15:38 -07003779 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;
caryclark55888e42016-07-18 10:01:36 -07003830 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003831 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);
caryclark55888e42016-07-18 10:01:36 -07003885 console.log(" { {" + curveToString(curve) + "}, "
caryclarkdac1d172014-06-17 05:15:38 -07003886 + 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) {
caryclarkdac1d172014-06-17 05:15:38 -07003915 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';
caryclark624637c2015-05-11 07:21:27 -07003932var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003933var addKey = 'd';
3934var deriviativesKey = 'f';
3935var angleKey = 'g';
3936var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003937var 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';
Cary Clarkff114282016-12-14 11:56:16 -05003949var directionKey = 'r';
caryclarkdac1d172014-06-17 05:15:38 -07003950var stepKey = 's';
3951var stepBackKey = 'S';
3952var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003953var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003954var 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;
caryclark55888e42016-07-18 10:01:36 -07003983 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003984 break;
3985 case addKey:
3986 draw_add ^= true;
caryclark55888e42016-07-18 10:01:36 -07003987 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07003988 break;
3989 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003990 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003991 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);
caryclark55888e42016-07-18 10:01:36 -07003999 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004000 break;
caryclark624637c2015-05-11 07:21:27 -07004001 case coincidenceKey:
4002 draw_coincidence ^= true;
4003 redraw();
4004 break;
caryclarkdac1d172014-06-17 05:15:38 -07004005 case controlLinesBackKey:
4006 control_lines = (control_lines + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004007 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004008 break;
4009 case controlLinesKey:
4010 control_lines = (control_lines + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004011 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004012 break;
4013 case computedBackKey:
4014 draw_computed = (draw_computed + 5) % 6;
caryclark55888e42016-07-18 10:01:36 -07004015 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004016 break;
4017 case computedKey:
4018 draw_computed = (draw_computed + 1) % 6;
caryclark55888e42016-07-18 10:01:36 -07004019 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004020 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;
Cary Clarkff114282016-12-14 11:56:16 -05004032 case directionKey:
4033 draw_direction ^= true;
4034 redraw();
4035 break;
caryclarkdac1d172014-06-17 05:15:38 -07004036 case focusKey:
4037 focus_on_selection ^= true;
4038 setScale(xmin, xmax, ymin, ymax);
4039 redraw();
4040 break;
caryclarkdac1d172014-06-17 05:15:38 -07004041 case idKey:
4042 draw_id ^= true;
4043 redraw();
4044 break;
4045 case intersectionBackKey:
4046 draw_intersection = (draw_intersection + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004047 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004048 break;
4049 case intersectionKey:
4050 draw_intersection = (draw_intersection + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004051 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004052 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:
caryclark26ad22a2015-10-16 09:03:38 -07004086 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004087 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004088 break;
4089 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07004090 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004091 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004092 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;
caryclark03b03ca2015-04-23 09:13:37 -07004123 case topKey:
4124 draw_top ^= true;
4125 redraw();
4126 break;
caryclarkdac1d172014-06-17 05:15:38 -07004127 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
caryclark55888e42016-07-18 10:01:36 -07004217 window.onpageshow = window.onpagehide
caryclarkdac1d172014-06-17 05:15:38 -07004218 = window.onfocus = window.onblur = onchange;
4219
4220 function onchange (evt) {
4221 var v = 'visible', h = 'hidden',
caryclark55888e42016-07-18 10:01:36 -07004222 evtMap = {
4223 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
caryclarkdac1d172014-06-17 05:15:38 -07004224 };
4225
4226 evt = evt || window.event;
4227 if (evt.type in evtMap)
4228 document.body.className = evtMap[evt.type];
caryclark55888e42016-07-18 10:01:36 -07004229 else
caryclarkdac1d172014-06-17 05:15:38 -07004230 document.body.className = this[hidden] ? "hidden" : "visible";
4231 }
4232})();
4233
4234function calcXY() {
4235 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07004236 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07004237 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>