blob: 67552a5085524e5b83e930721f00bcfa498c8f22 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
3<div height="0" hidden="true">
caryclarkdac1d172014-06-17 05:15:38 -07004
caryclarked0935a2015-10-22 07:23:52 -07005Skia UnitTests: --match PathOpsSkp$ --resourcePath resources\ SK_DEBUG
6
caryclark26ad22a2015-10-16 09:03:38 -07007<div id="skpwww_gorcraft_ru_1">
8seg=1 {{{{1170, 4559}, {1176, 4559}, {1176, 4565}}}, 0.707106769f}
9seg=2 {{{1176, 4565}, {1176, 4590}}}
10seg=3 {{{{1176, 4590}, {1176, 4595}, {1171, 4595}}}, 0.707106769f}
11seg=4 {{{1171, 4595}, {83, 4595}}}
12seg=5 {{{{83, 4595}, {78.0086746f, 4595}, {78, 4590.00586f}}}, 0.707720578f}
13seg=6 {{{78, 4590.00586f}, {78, 4565}}}
14seg=7 {{{{78, 4565}, {78, 4559}, {84, 4559}}}, 0.707106769f}
15seg=8 {{{84, 4559}, {1170, 4559}}}
caryclark27c8eb82015-07-06 11:38:33 -070016op union
caryclark26ad22a2015-10-16 09:03:38 -070017seg=9 {{{78, 4590}, {78, 4565}}}
18seg=10 {{{{78, 4565}, {78, 4559}, {84, 4559}}}, 0.707106769f}
19seg=11 {{{84, 4559}, {158, 4559}}}
20seg=12 {{{158, 4559}, {158, 4596}}}
21seg=13 {{{158, 4596}, {84, 4596}}}
22seg=14 {{{{84, 4596}, {78, 4596}, {78, 4590}}}, 0.707106769f}
23debugShowConicLineIntersection wtTs[0]=1 {{{{1170,4559}, {1176,4559}, {1176,4565}}}, 0.707106769} {{1176,4565}} wnTs[0]=0 {{{1176,4565}, {1176,4590}}}
24debugShowConicLineIntersection wtTs[0]=0 {{{{1170,4559}, {1176,4559}, {1176,4565}}}, 0.707106769} {{1170,4559}} wnTs[0]=1 {{{84,4559}, {1170,4559}}}
25debugShowConicLineIntersection wtTs[0]=0 {{{{1176,4590}, {1176,4595}, {1171,4595}}}, 0.707106769} {{1176,4590}} wnTs[0]=1 {{{1176,4565}, {1176,4590}}}
26debugShowConicLineIntersection wtTs[0]=1 {{{{1176,4590}, {1176,4595}, {1171,4595}}}, 0.707106769} {{1171,4595}} wnTs[0]=0 {{{1171,4595}, {83,4595}}}
27debugShowConicLineIntersection wtTs[0]=0 {{{{83,4595}, {78.0086746,4595}, {78,4590.00586}}}, 0.707720578} {{83,4595}} wnTs[0]=1 {{{1171,4595}, {83,4595}}}
28debugShowConicLineIntersection wtTs[0]=1 {{{{83,4595}, {78.0086746,4595}, {78,4590.00586}}}, 0.707720578} {{78,4590.00586}} wnTs[0]=0 {{{78,4590.00586}, {78,4565}}}
29debugShowConicLineIntersection wtTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{78,4565}} wnTs[0]=1 {{{78,4590.00586}, {78,4565}}}
30debugShowConicLineIntersection wtTs[0]=1 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{84,4559}} wnTs[0]=0 {{{84,4559}, {1170,4559}}}
31debugShowLineIntersection wtTs[0]=0.972972973 {{{158,4559}, {158,4596}}} {{158,4595}} wnTs[0]=0.931066 {{{1171,4595}, {83,4595}}}
32SkOpSegment::addT insert t=0.931066176 segID=4 spanID=29
33SkOpSegment::addT insert t=0.972972973 segID=12 spanID=30
34debugShowConicLineIntersection no intersect {{{{84,4596}, {78,4596}, {78,4590}}}, 0.707106769} {{{1171,4595}, {83,4595}}}
35debugShowConicLineIntersection no intersect {{{{83,4595}, {78.0086746,4595}, {78,4590.00586}}}, 0.707720578} {{{78,4590}, {78,4565}}}
caryclark26ad22a2015-10-16 09:03:38 -070036debugShowConicIntersection wtTs[0]=0.999339899 {{{{83,4595}, {78.0086746,4595}, {78,4590.00586}}}, 0.707720578} {{78.0000076,4590.01074}} wnTs[0]=0.99876 {{{{84,4596}, {78,4596}, {78,4590}}}, 0.707106769}
37SkOpSegment::addT insert t=0.999339899 segID=5 spanID=31
38SkOpSegment::addT insert t=0.998759893 segID=14 spanID=32
39debugShowLineIntersection wtTs[0]=0 {{{78,4590}, {78,4565}}} {{78,4590}} wtTs[1]=1 {{78,4565}} wnTs[0]=0.00023432 {{{78,4590.00586}, {78,4565}}} wnTs[1]=1
40SkOpSegment::addT insert t=0.000234320081 segID=6 spanID=33
41debugShowConicLineIntersection wtTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{78,4565}} wnTs[0]=1 {{{78,4590.00586}, {78,4565}}}
42debugShowConicLineIntersection wtTs[0]=1 {{{{84,4596}, {78,4596}, {78,4590}}}, 0.707106769} {{78,4590}} wnTs[0]=0.00023432 {{{78,4590.00586}, {78,4565}}}
43debugShowConicLineIntersection wtTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{78,4565}} wnTs[0]=1 {{{78,4590}, {78,4565}}}
caryclark26ad22a2015-10-16 09:03:38 -070044debugShowConicIntersection wtTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{78,4565}} wtTs[1]=1 {{84,4559}} wnTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} wnTs[1]=1
45debugShowConicLineIntersection wtTs[0]=1 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{84,4559}} wnTs[0]=0 {{{84,4559}, {158,4559}}}
46debugShowConicLineIntersection wtTs[0]=1 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{84,4559}} wnTs[0]=0 {{{84,4559}, {1170,4559}}}
47debugShowLineIntersection wtTs[0]=0 {{{84,4559}, {158,4559}}} {{84,4559}} wtTs[1]=1 {{158,4559}} wnTs[0]=0 {{{84,4559}, {1170,4559}}} wnTs[1]=0.0681399632
48SkOpSegment::addT insert t=0.0681399632 segID=8 spanID=34
49debugShowLineIntersection wtTs[0]=0 {{{158,4559}, {158,4596}}} {{158,4559}} wnTs[0]=0.06814 {{{84,4559}, {1170,4559}}}
50debugShowConicLineIntersection wtTs[0]=0 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{78,4565}} wnTs[0]=1 {{{78,4590}, {78,4565}}}
51debugShowConicLineIntersection wtTs[0]=1 {{{{84,4596}, {78,4596}, {78,4590}}}, 0.707106769} {{78,4590}} wnTs[0]=0 {{{78,4590}, {78,4565}}}
52debugShowConicLineIntersection wtTs[0]=1 {{{{78,4565}, {78,4559}, {84,4559}}}, 0.707106769} {{84,4559}} wnTs[0]=0 {{{84,4559}, {158,4559}}}
53debugShowLineIntersection wtTs[0]=0 {{{158,4559}, {158,4596}}} {{158,4559}} wnTs[0]=1 {{{84,4559}, {158,4559}}}
54debugShowLineIntersection wtTs[0]=0 {{{158,4596}, {84,4596}}} {{158,4596}} wnTs[0]=1 {{{158,4559}, {158,4596}}}
55debugShowConicLineIntersection wtTs[0]=0 {{{{84,4596}, {78,4596}, {78,4590}}}, 0.707106769} {{84,4596}} wnTs[0]=1 {{{158,4596}, {84,4596}}}
caryclark26ad22a2015-10-16 09:03:38 -070056SkOpSegment::markDone id=8 (84,4559 1170,4559) t=0 [15] (84,4559) tEnd=0.0681399632 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
57SkOpSegment::markDone id=10 (78,4565 78,4559 84,4559) t=0 [19] (78,4565) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
58SkOpSegment::markDone id=6 (78,4590.00586 78,4565) t=0.000234320081 [33] (78,4590) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
caryclark26ad22a2015-10-16 09:03:38 -070059SkOpSegment::sortAngles [4] tStart=0.931066176 [29]
60SkOpAngle::after [4/1] 31/31 tStart=0.931066176 tEnd=0 < [12/14] 7/7 tStart=0.972972973 tEnd=0 < [4/2] 15/15 tStart=0.931066176 tEnd=1 T 4
61SkOpAngle::afterPart {{{158,4595}, {1171,4595}}} id=4
62SkOpAngle::afterPart {{{158,4595}, {158,4559}}} id=12
63SkOpAngle::afterPart {{{158,4595}, {83,4595}}} id=4
64SkOpAngle::after [4/1] 31/31 tStart=0.931066176 tEnd=0 < [12/15] 23/23 tStart=0.972972973 tEnd=1 < [12/14] 7/7 tStart=0.972972973 tEnd=0 F 4
65SkOpAngle::afterPart {{{158,4595}, {1171,4595}}} id=4
66SkOpAngle::afterPart {{{158,4595}, {158,4596}}} id=12
67SkOpAngle::afterPart {{{158,4595}, {158,4559}}} id=12
68SkOpAngle::after [12/14] 7/7 tStart=0.972972973 tEnd=0 < [12/15] 23/23 tStart=0.972972973 tEnd=1 < [4/2] 15/15 tStart=0.931066176 tEnd=1 F 4
69SkOpAngle::afterPart {{{158,4595}, {158,4559}}} id=12
70SkOpAngle::afterPart {{{158,4595}, {158,4596}}} id=12
71SkOpAngle::afterPart {{{158,4595}, {83,4595}}} id=4
72SkOpAngle::after [4/2] 15/15 tStart=0.931066176 tEnd=1 < [12/15] 23/23 tStart=0.972972973 tEnd=1 < [4/1] 31/31 tStart=0.931066176 tEnd=0 T 4
73SkOpAngle::afterPart {{{158,4595}, {83,4595}}} id=4
74SkOpAngle::afterPart {{{158,4595}, {158,4596}}} id=12
75SkOpAngle::afterPart {{{158,4595}, {1171,4595}}} id=4
76SkOpSegment::sortAngles [5] tStart=0.999339899 [31]
77SkOpAngle::after [5/3] 25/29 tStart=0.999339899 tEnd=0 < [14/16] 25/29 tStart=0.998759893 tEnd=0 < [5/4] 9/9 tStart=0.999339899 tEnd=1 F 12
caryclarked0935a2015-10-22 07:23:52 -070078SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78.0133288,4595}, {83,4595}}}, 0.708050251} id=5
79SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78.0105173,4596}, {84,4596}}}, 0.707726777} id=14
80SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78.0000041,4590.00819}, {78,4590.00586}}}, 1} id=5
caryclark26ad22a2015-10-16 09:03:38 -070081SkOpAngle::after [5/3] 25/29 tStart=0.999339899 tEnd=0 < [14/17] 9/9 tStart=0.998759893 tEnd=1 < [5/4] 9/9 tStart=0.999339899 tEnd=1 T 11
caryclarked0935a2015-10-22 07:23:52 -070082SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78.0133288,4595}, {83,4595}}}, 0.708050251} id=5
caryclark26ad22a2015-10-16 09:03:38 -070083SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78,4590.00526}, {78,4590}}}, 0.999999642} id=14
caryclarked0935a2015-10-22 07:23:52 -070084SkOpAngle::afterPart {{{{78.0000076,4590.01074}, {78.0000041,4590.00819}, {78,4590.00586}}}, 1} id=5
caryclark26ad22a2015-10-16 09:03:38 -070085SkOpSegment::sortAngles [6] tStart=0.000234320081 [33]
86SkOpAngle::after [6/5] 23/23 tStart=0.000234320081 tEnd=0 < [9/9] 7/7 tStart=0 tEnd=1 < [14/18] 21/21 tStart=1 tEnd=0.998759893 T 4
87SkOpAngle::afterPart {{{78,4590}, {78,4590.00586}}} id=6
88SkOpAngle::afterPart {{{78,4590}, {78,4565}}} id=9
89SkOpAngle::afterPart {{{{78,4590}, {78,4590.00526}, {78.0000076,4590.01074}}}, 0.999999642} id=14
90SkOpSegment::sortAngles [7] tStart=0 [13]
91SkOpSegment::sortAngles [7] tStart=1 [14]
92SkOpSegment::sortAngles [8] tStart=0.0681399632 [34]
93SkOpAngle::after [8/8] 31/31 tStart=0.0681399632 tEnd=1 < [11/12] 15/15 tStart=1 tEnd=0 < [12/13] 23/23 tStart=0 tEnd=0.972972973 T 4
94SkOpAngle::afterPart {{{158,4559}, {1170,4559}}} id=8
95SkOpAngle::afterPart {{{158,4559}, {84,4559}}} id=11
96SkOpAngle::afterPart {{{158,4559}, {158,4595}}} id=12
caryclark27c8eb82015-07-06 11:38:33 -070097SkOpSegment::sortAngles [9] tStart=0 [17]
caryclark26ad22a2015-10-16 09:03:38 -070098SkOpSegment::sortAngles [9] tStart=1 [18]
99SkOpSegment::sortAngles [11] tStart=0 [21]
100SkOpSegment::sortAngles [11] tStart=1 [22]
101SkOpSegment::sortAngles [12] tStart=0 [23]
102SkOpSegment::sortAngles [12] tStart=0.972972973 [30]
103SkOpSegment::sortAngles [14] tStart=0.998759893 [32]
104SkOpSegment::sortAngles [14] tStart=1 [28]
105SkOpCoincidence::debugShowCoincidence - id=11 t=0 tEnd=1
106SkOpCoincidence::debugShowCoincidence + id=8 t=0 tEnd=0.0681399632
107SkOpCoincidence::debugShowCoincidence - id=7 t=0 tEnd=1
108SkOpCoincidence::debugShowCoincidence + id=10 t=0 tEnd=1
109SkOpCoincidence::debugShowCoincidence - id=9 t=0 tEnd=1
110SkOpCoincidence::debugShowCoincidence + id=6 t=0.000234320081 tEnd=1
111SkOpSegment::debugShowActiveSpans id=1 (1170,4559 1176,4559 1176,4565 0.707106769f) t=0 (1170,4559) tEnd=1 windSum=? windValue=1
112SkOpSegment::debugShowActiveSpans id=2 (1176,4565 1176,4590) t=0 (1176,4565) tEnd=1 windSum=? windValue=1
113SkOpSegment::debugShowActiveSpans id=3 (1176,4590 1176,4595 1171,4595 0.707106769f) t=0 (1176,4590) tEnd=1 windSum=? windValue=1
114SkOpSegment::debugShowActiveSpans id=4 (1171,4595 83,4595) t=0 (1171,4595) tEnd=0.931066176 windSum=? windValue=1
115SkOpSegment::debugShowActiveSpans id=4 (1171,4595 83,4595) t=0.931066176 (158,4595) tEnd=1 windSum=? windValue=1
116SkOpSegment::debugShowActiveSpans id=5 (83,4595 78.0086746,4595 78,4590.00586 0.707720578f) t=0 (83,4595) tEnd=0.999339899 windSum=? windValue=1
117SkOpSegment::debugShowActiveSpans id=5 (83,4595 78.0086746,4595 78,4590.00586 0.707720578f) t=0.999339899 (78.0000076,4590.01074) tEnd=1 windSum=? windValue=1
118SkOpSegment::debugShowActiveSpans id=6 (78,4590.00586 78,4565) t=0 (78,4590.00586) tEnd=0.000234320081 windSum=? windValue=1
119SkOpSegment::debugShowActiveSpans id=7 (78,4565 78,4559 84,4559 0.707106769f) t=0 (78,4565) tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
120SkOpSegment::debugShowActiveSpans id=8 (84,4559 1170,4559) t=0.0681399632 (158,4559) tEnd=1 windSum=? windValue=1
121SkOpSegment::debugShowActiveSpans id=9 (78,4590 78,4565) t=0 (78,4590) tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
122SkOpSegment::debugShowActiveSpans id=11 (84,4559 158,4559) t=0 (84,4559) tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1
123SkOpSegment::debugShowActiveSpans id=12 (158,4559 158,4596) t=0 (158,4559) tEnd=0.972972973 windSum=? windValue=1
124SkOpSegment::debugShowActiveSpans id=12 (158,4559 158,4596) t=0.972972973 (158,4595) tEnd=1 windSum=? windValue=1
125SkOpSegment::debugShowActiveSpans id=13 (158,4596 84,4596) t=0 (158,4596) tEnd=1 windSum=? windValue=1
126SkOpSegment::debugShowActiveSpans id=14 (84,4596 78,4596 78,4590 0.707106769f) t=0 (84,4596) tEnd=0.998759893 windSum=? windValue=1
127SkOpSegment::debugShowActiveSpans id=14 (84,4596 78,4596 78,4590 0.707106769f) t=0.998759893 (78.0000076,4590.01074) tEnd=1 windSum=? windValue=1
128SkOpSpan::sortableTop dir=kTop seg=1 t=0.5 pt=(1174.24268,4560.75732)
129SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=1 seg=1 {{{{1170, 4559}, {1176, 4559}, {1176, 4565}}}, 0.707106769f} t=0.5 pt=(1174.24268,4560.75732) slope=(2.56066015,2.56066015)
130SkOpSegment::markWinding id=1 (1170,4559 1176,4559 1176,4565) t=0 [1] (1170,4559) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
131SkOpSegment::markWinding id=2 (1176,4565 1176,4590) t=0 [3] (1176,4565) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
132SkOpSegment::markWinding id=3 (1176,4590 1176,4595 1171,4595) t=0 [5] (1176,4590) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
133SkOpSegment::markWinding id=4 (1171,4595 83,4595) t=0 [7] (1171,4595) tEnd=0.931066176 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
134SkOpSegment::markWinding id=1 (1170,4559 1176,4559 1176,4565) t=0 [1] (1170,4559) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
135SkOpSegment::markWinding id=8 (84,4559 1170,4559) t=0.0681399632 [34] (158,4559) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
caryclark27c8eb82015-07-06 11:38:33 -0700136SkOpSegment::activeOp id=1 t=1 tEnd=0 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
137SkOpSegment::findNextOp simple
caryclark26ad22a2015-10-16 09:03:38 -0700138SkOpSegment::markDone id=1 (1170,4559 1176,4559 1176,4565) t=0 [1] (1170,4559) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
139bridgeOp current id=1 from=(1176,4565) to=(1170,4559)
140path.moveTo(1176,4565);
141path.conicTo(1176,4559, 1170,4559, 0.707106769);
142SkOpSegment::markWinding id=11 (84,4559 158,4559) t=0 [21] (84,4559) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
143SkOpSegment::markWinding id=7 (78,4565 78,4559 84,4559) t=0 [13] (78,4565) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
144SkOpSegment::markWinding id=9 (78,4590 78,4565) t=0 [17] (78,4590) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1
145SkOpSegment::markAngle last segment=9 span=17 windSum=-1
146SkOpSegment::markWinding id=12 (158,4559 158,4596) t=0 [23] (158,4559) tEnd=0.972972973 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
147SkOpSegment::markAngle last segment=12 span=30 windSum=?
caryclark27c8eb82015-07-06 11:38:33 -0700148SkOpSegment::findNextOp
caryclark26ad22a2015-10-16 09:03:38 -0700149SkOpAngle::dumpOne [8/8] next=11/12 sect=31/31 s=0.0681399632 [34] e=1 [16] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
150SkOpAngle::dumpOne [11/12] next=12/13 sect=15/15 s=1 [22] e=0 [21] sgn=1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 operand
151SkOpAngle::dumpOne [12/13] next=8/8 sect=23/23 s=0 [23] e=0.972972973 [30] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand
152SkOpSegment::activeOp id=11 t=1 tEnd=0 op=union miFrom=0 miTo=1 suFrom=0 suTo=1 result=1
153SkOpSegment::findNextOp chase.append segment=9 span=17 windSum=-1
154SkOpSegment::activeOp id=12 t=0 tEnd=0.972972973 op=union miFrom=1 miTo=1 suFrom=1 suTo=0 result=0
155SkOpSegment::markDone id=12 (158,4559 158,4596) t=0 [23] (158,4559) tEnd=0.972972973 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
156SkOpSegment::findNextOp chase.append segment=12 span=30 windSum=-2147483647
157SkOpSegment::markDone id=8 (84,4559 1170,4559) t=0.0681399632 [34] (158,4559) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
caryclarked0935a2015-10-22 07:23:52 -0700158SkOpSegment::findNextOp from:[8] to:[11] start=6561036 end=6560932
caryclark26ad22a2015-10-16 09:03:38 -0700159bridgeOp current id=8 from=(1170,4559) to=(158,4559)
caryclark27c8eb82015-07-06 11:38:33 -0700160SkOpSegment::findNextOp simple
caryclark26ad22a2015-10-16 09:03:38 -0700161SkOpSegment::markDone id=11 (84,4559 158,4559) t=0 [21] (84,4559) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1
162bridgeOp current id=11 from=(158,4559) to=(84,4559)
163SkOpSegment::findNextOp simple
164SkOpSegment::markDone id=7 (78,4565 78,4559 84,4559) t=0 [13] (78,4565) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1
165bridgeOp current id=7 from=(84,4559) to=(78,4565)
166path.lineTo(84,4559);
167path.conicTo(78,4559, 78,4565, 0.707106769);
168SkOpSegment::markWinding id=14 (84,4596 78,4596 78,4590) t=0.998759893 [32] (78.0000076,4590.01074) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
169SkOpSegment::markAngle last segment=14 span=32 windSum=-1
170SkOpSegment::markWinding id=6 (78,4590.00586 78,4565) t=0 [11] (78,4590.00586) tEnd=0.000234320081 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
171SkOpSegment::markWinding id=5 (83,4595 78.0086746,4595 78,4590.00586) t=0.999339899 [31] (78.0000076,4590.01074) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
172SkOpSegment::markAngle last segment=5 span=31 windSum=-1
caryclark27c8eb82015-07-06 11:38:33 -0700173SkOpSegment::findNextOp
caryclark26ad22a2015-10-16 09:03:38 -0700174SkOpAngle::dumpOne [9/9] next=14/18 sect=7/7 s=0 [17] e=1 [18] sgn=-1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 operand
175SkOpAngle::dumpOne [14/18] next=6/5 sect=21/21 s=1 [28] e=0.998759893 [32] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
176SkOpAngle::dumpOne [6/5] next=9/9 sect=23/23 s=0.000234320081 [33] e=0 [11] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1
177SkOpSegment::activeOp id=14 t=1 tEnd=0.998759893 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
178SkOpSegment::findNextOp chase.append segment=14 span=32 windSum=-1
179SkOpSegment::activeOp id=6 t=0.000234320081 tEnd=0 op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
180SkOpSegment::markDone id=6 (78,4590.00586 78,4565) t=0 [11] (78,4590.00586) tEnd=0.000234320081 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
181SkOpSegment::markDone id=5 (83,4595 78.0086746,4595 78,4590.00586) t=0.999339899 [31] (78.0000076,4590.01074) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
182SkOpSegment::findNextOp chase.append segment=5 span=31 windSum=-1
183SkOpSegment::markDone id=9 (78,4590 78,4565) t=0 [17] (78,4590) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1
caryclarked0935a2015-10-22 07:23:52 -0700184SkOpSegment::findNextOp from:[9] to:[14] start=6561756 end=6562204
caryclark26ad22a2015-10-16 09:03:38 -0700185bridgeOp current id=9 from=(78,4565) to=(78,4590)
186SkOpSegment::markWinding id=14 (84,4596 78,4596 78,4590) t=0 [27] (84,4596) tEnd=0.998759893 newWindSum=-2 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
187SkOpSegment::markWinding id=13 (158,4596 84,4596) t=0 [25] (158,4596) tEnd=1 newWindSum=-2 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
188SkOpSegment::markWinding id=12 (158,4559 158,4596) t=0.972972973 [30] (158,4595) tEnd=1 newWindSum=-2 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
189SkOpSegment::markAngle last segment=12 span=30 windSum=-2
190SkOpSegment::markWinding id=5 (83,4595 78.0086746,4595 78,4590.00586) t=0 [9] (83,4595) tEnd=0.999339899 newWindSum=-1 newOppSum=-2 oppSum=? windSum=? windValue=1 oppValue=0
191SkOpSegment::markWinding id=4 (1171,4595 83,4595) t=0.931066176 [29] (158,4595) tEnd=1 newWindSum=-1 newOppSum=-2 oppSum=? windSum=? windValue=1 oppValue=0
192SkOpSegment::markAngle last segment=4 span=29 windSum=-1
caryclark27c8eb82015-07-06 11:38:33 -0700193SkOpSegment::findNextOp
caryclark26ad22a2015-10-16 09:03:38 -0700194SkOpAngle::dumpOne [14/17] next=5/4 sect=9/9 s=0.998759893 [32] e=1 [28] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
195SkOpAngle::dumpOne [5/4] next=14/16 sect=9/9 s=0.999339899 [31] e=1 [10] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 done
196SkOpAngle::dumpOne [14/16] next=5/3 sect=25/29 s=0.998759893 [32] e=0 [27] sgn=1 windVal=1 windSum=-2 oppVal=0 oppSum=0 operand
197SkOpAngle::dumpOne [5/3] next=14/17 sect=25/29 s=0.999339899 [31] e=0 [9] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-2
198SkOpSegment::activeOp id=5 t=0.999339899 tEnd=1 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
199SkOpSegment::activeOp id=14 t=0.998759893 tEnd=0 op=union miFrom=1 miTo=1 suFrom=0 suTo=1 result=0
200SkOpSegment::markDone id=14 (84,4596 78,4596 78,4590) t=0 [27] (84,4596) tEnd=0.998759893 newWindSum=-2 newOppSum=0 oppSum=0 windSum=-2 windValue=1 oppValue=0
201SkOpSegment::markDone id=13 (158,4596 84,4596) t=0 [25] (158,4596) tEnd=1 newWindSum=-2 newOppSum=0 oppSum=0 windSum=-2 windValue=1 oppValue=0
202SkOpSegment::markDone id=12 (158,4559 158,4596) t=0.972972973 [30] (158,4595) tEnd=1 newWindSum=-2 newOppSum=0 oppSum=0 windSum=-2 windValue=1 oppValue=0
203SkOpSegment::activeOp id=5 t=0.999339899 tEnd=0 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
204SkOpSegment::markDone id=5 (83,4595 78.0086746,4595 78,4590.00586) t=0 [9] (83,4595) tEnd=0.999339899 newWindSum=-1 newOppSum=-2 oppSum=-2 windSum=-1 windValue=1 oppValue=0
205SkOpSegment::markDone id=4 (1171,4595 83,4595) t=0.931066176 [29] (158,4595) tEnd=1 newWindSum=-1 newOppSum=-2 oppSum=-2 windSum=-1 windValue=1 oppValue=0
206SkOpSegment::findNextOp chase.append segment=4 span=29 windSum=-1
207SkOpSegment::markDone id=14 (84,4596 78,4596 78,4590) t=0.998759893 [32] (78.0000076,4590.01074) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
caryclarked0935a2015-10-22 07:23:52 -0700208SkOpSegment::findNextOp from:[14] to:[5] start=6562100 end=6559532
caryclark26ad22a2015-10-16 09:03:38 -0700209bridgeOp current id=14 from=(78,4590) to=(78.0000076,4590.01074)
210path.lineTo(78,4590);
211path.conicTo(78,4590.00537, 78.0000076,4590.01074, 0.999999642);
212SkOpSegment::debugShowActiveSpans id=2 (1176,4565 1176,4590) t=0 (1176,4565) tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
213SkOpSegment::debugShowActiveSpans id=3 (1176,4590 1176,4595 1171,4595 0.707106769f) t=0 (1176,4590) tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
214SkOpSegment::debugShowActiveSpans id=4 (1171,4595 83,4595) t=0 (1171,4595) tEnd=0.931066176 windSum=-1 oppSum=0 windValue=1 oppValue=0
215SkOpSegment::activeOp id=4 t=0.931066176 tEnd=0 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
216SkOpSegment::findNextOp simple
217SkOpSegment::markDone id=4 (1171,4595 83,4595) t=0 [7] (1171,4595) tEnd=0.931066176 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
218bridgeOp current id=4 from=(158,4595) to=(1171,4595)
219SkOpSegment::findNextOp simple
220SkOpSegment::markDone id=3 (1176,4590 1176,4595 1171,4595) t=0 [5] (1176,4590) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
221bridgeOp current id=3 from=(1171,4595) to=(1176,4590)
222path.moveTo(158,4595);
223path.lineTo(1171,4595);
224path.conicTo(1176,4595, 1176,4590, 0.707106769);
225SkOpSegment::findNextOp simple
226SkOpSegment::markDone id=2 (1176,4565 1176,4590) t=0 [3] (1176,4565) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
227bridgeOp current id=2 from=(1176,4590) to=(1176,4565)
228path.lineTo(1176,4565);
caryclarkdac1d172014-06-17 05:15:38 -0700229</div>
caryclark26ad22a2015-10-16 09:03:38 -0700230
caryclarked0935a2015-10-22 07:23:52 -0700231
232
caryclarkdac1d172014-06-17 05:15:38 -0700233</div>
234
235<script type="text/javascript">
236
237var testDivs = [
caryclark26ad22a2015-10-16 09:03:38 -0700238 skpwww_gorcraft_ru_1,
caryclarkdac1d172014-06-17 05:15:38 -0700239];
240
241var decimal_places = 3; // make this 3 to show more precision
242
243var tests = [];
244var testLines = [];
245var testTitles = [];
246var testIndex = 0;
247var ctx;
248
249var xmin, xmax, focusXmin, focusXmax;
250var ymin, ymax, focusYmin, focusYmax;
251var scale;
252var mouseX, mouseY;
253var srcLeft, srcTop;
254var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700255var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700256var curveT = 0;
257
258var pt_labels = 2;
259var collect_bounds = false;
260var control_lines = 0;
261var curve_t = false;
262var debug_xy = 1;
263var focus_enabled = false;
264var focus_on_selection = false;
265var step_limit = 0;
266var draw_active = false;
267var draw_add = false;
268var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700269var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700270var draw_deriviatives = 0;
271var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700272var draw_id = false;
273var draw_intersection = 0;
274var draw_intersectT = false;
275var draw_legend = true;
276var draw_log = false;
277var draw_mark = false;
278var draw_midpoint = false;
279var draw_op = 0;
280var draw_sequence = false;
281var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700282var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700283var draw_path = 3;
284var draw_computed = 0;
285var retina_scale = !!window.devicePixelRatio;
286
287var activeCount = 0;
288var addCount = 0;
289var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700290var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700291var opCount = 0;
292var sectCount = 0;
293var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700294var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700295var markCount = 0;
296var activeMax = 0;
297var addMax = 0;
298var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700299var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700300var sectMax = 0;
301var sectMax2 = 0;
302var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700303var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700304var markMax = 0;
305var opMax = 0;
306var stepMax = 0;
307var lastIndex = 0;
308var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700309var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700310var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700311var angleBetween = false;
312var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700313
314var firstActiveSpan = -1;
315var logStart = -1;
316var logRange = 0;
317
318var SPAN_ID = 0;
319var SPAN_X1 = SPAN_ID + 1;
320var SPAN_Y1 = SPAN_X1 + 1;
321var SPAN_X2 = SPAN_Y1 + 1;
322var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700323
caryclarkdac1d172014-06-17 05:15:38 -0700324var SPAN_L_T = SPAN_Y2 + 1;
325var SPAN_L_TX = SPAN_L_T + 1;
326var SPAN_L_TY = SPAN_L_TX + 1;
327var SPAN_L_TEND = SPAN_L_TY + 1;
328var SPAN_L_OTHER = SPAN_L_TEND + 1;
329var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
330var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
331var SPAN_L_SUM = SPAN_L_OTHERI + 1;
332var SPAN_L_VAL = SPAN_L_SUM + 1;
333var SPAN_L_OPP = SPAN_L_VAL + 1;
334
335var SPAN_X3 = SPAN_Y2 + 1;
336var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700337
caryclarkdac1d172014-06-17 05:15:38 -0700338var SPAN_Q_T = SPAN_Y3 + 1;
339var SPAN_Q_TX = SPAN_Q_T + 1;
340var SPAN_Q_TY = SPAN_Q_TX + 1;
341var SPAN_Q_TEND = SPAN_Q_TY + 1;
342var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
343var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
344var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
345var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
346var SPAN_Q_VAL = SPAN_Q_SUM + 1;
347var SPAN_Q_OPP = SPAN_Q_VAL + 1;
348
caryclark1049f122015-04-20 08:31:59 -0700349var SPAN_K_W = SPAN_Y3 + 1;
350var SPAN_K_T = SPAN_K_W + 1;
351var SPAN_K_TX = SPAN_K_T + 1;
352var SPAN_K_TY = SPAN_K_TX + 1;
353var SPAN_K_TEND = SPAN_K_TY + 1;
354var SPAN_K_OTHER = SPAN_K_TEND + 1;
355var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
356var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
357var SPAN_K_SUM = SPAN_K_OTHERI + 1;
358var SPAN_K_VAL = SPAN_K_SUM + 1;
359var SPAN_K_OPP = SPAN_K_VAL + 1;
360
caryclarkdac1d172014-06-17 05:15:38 -0700361var SPAN_X4 = SPAN_Y3 + 1;
362var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700363
caryclarkdac1d172014-06-17 05:15:38 -0700364var SPAN_C_T = SPAN_Y4 + 1;
365var SPAN_C_TX = SPAN_C_T + 1;
366var SPAN_C_TY = SPAN_C_TX + 1;
367var SPAN_C_TEND = SPAN_C_TY + 1;
368var SPAN_C_OTHER = SPAN_C_TEND + 1;
369var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
370var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
371var SPAN_C_SUM = SPAN_C_OTHERI + 1;
372var SPAN_C_VAL = SPAN_C_SUM + 1;
373var SPAN_C_OPP = SPAN_C_VAL + 1;
374
375var ACTIVE_LINE_SPAN = 1;
376var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700377var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
378var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700379
380var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
381var ADD_LINETO = ADD_MOVETO + 1;
382var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700383var ADD_CONICTO = ADD_QUADTO + 1;
384var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700385var ADD_CLOSE = ADD_CUBICTO + 1;
386var ADD_FILL = ADD_CLOSE + 1;
387
388var PATH_LINE = ADD_FILL + 1;
389var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700390var PATH_CONIC = PATH_QUAD + 1;
391var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700392
393var INTERSECT_LINE = PATH_CUBIC + 1;
394var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
395var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
396var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
397var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
398var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
399var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
400var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
401var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700402var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
403var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
404var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
405var INTERSECT_CONIC = INTERSECT_CONIC_LINE_NO + 1;
406var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
407var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
408var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700409var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
410var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
411var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
412var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
413var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
414var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
415var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
416var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
417var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
418var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
419var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
420var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
421var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
422var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
423// FIXME: add cubic 5- 9
424var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
425
426var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
427var SORT_BINARY = SORT_UNARY + 1;
428
429var OP_DIFFERENCE = SORT_BINARY + 1;
430var OP_INTERSECT = OP_DIFFERENCE + 1;
431var OP_UNION = OP_INTERSECT + 1;
432var OP_XOR = OP_UNION + 1;
433
434var MARK_LINE = OP_XOR + 1;
435var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700436var MARK_CONIC = MARK_QUAD + 1;
437var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700438var MARK_DONE_LINE = MARK_CUBIC + 1;
439var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700440var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
441var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700442var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
443var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700444var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
445var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700446var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
447var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700448var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
449var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700450var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
451var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700452var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
453var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700454var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
455var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700456var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
457var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700458var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
459
460var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
461var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
462
caryclark624637c2015-05-11 07:21:27 -0700463var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700464var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700465
caryclark54359292015-03-26 07:52:43 -0700466var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700467
caryclark624637c2015-05-11 07:21:27 -0700468var COIN_MAIN_SPAN = ACTIVE_OP + 1;
469var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
470
471var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700472
473var REC_TYPE_UNKNOWN = -1;
474var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700475var REC_TYPE_PATH2 = 1;
476var REC_TYPE_SECT = 2;
477var REC_TYPE_ACTIVE = 3;
478var REC_TYPE_ADD = 4;
479var REC_TYPE_SORT = 5;
480var REC_TYPE_OP = 6;
481var REC_TYPE_MARK = 7;
482var REC_TYPE_COMPUTED = 8;
483var REC_TYPE_COIN = 9;
484var REC_TYPE_ANGLE = 10;
485var REC_TYPE_ACTIVE_OP = 11;
486var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700487var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700488var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700489var REC_TYPE_ALIGNED = 15;
490var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700491
492function strs_to_nums(strs) {
493 var result = [];
494 for (var idx = 1; idx < strs.length; ++idx) {
495 var str = strs[idx];
496 var num = parseFloat(str);
497 if (isNaN(num)) {
498 result.push(str);
499 } else {
500 result.push(num);
501 }
502 }
503 return result;
504}
505
506function filter_str_by(id, str, regex, array) {
507 if (regex.test(str)) {
508 var strs = regex.exec(str);
509 var result = strs_to_nums(strs);
510 array.push(id);
511 array.push(result);
512 return true;
513 }
514 return false;
515}
516
517function construct_regexp2(pattern) {
518 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
519 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
520 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700521 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700522 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
523 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
524 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\\)");
527 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
528 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(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700531 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700532 escape = escape.replace(/NUM/g, "(-?\\d+)");
533 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
534 return new RegExp(escape, 'i');
535}
536
537function construct_regexp2c(pattern) {
538 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
539 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700540 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700541 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700542 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
543 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700544 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700545 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700546 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700547 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 -0700548 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700549 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700550 escape = escape.replace(/OPER/g, "[a-z]+");
551 escape = escape.replace(/PATH/g, "pathB?");
552 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700553 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700554 escape = escape.replace(/NUM/g, "(-?\\d+)");
555 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
556 return new RegExp(escape, 'i');
557}
558
559function match_regexp(str, lineNo, array, id, pattern) {
560 var regex = construct_regexp2(pattern);
561 if (filter_str_by(id, str, regex, array)) {
562 return true;
563 }
564 regex = construct_regexp2c(pattern);
565 return filter_str_by(id, str, regex, array);
566}
567
568function endsWith(str, suffix) {
569 return str.indexOf(suffix, str.length - suffix.length) !== -1;
570}
571
572function parse_all(test) {
573 var lines = test.match(/[^\r\n]+/g);
574 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
575 var record = [];
576 var recType = REC_TYPE_UNKNOWN;
577 var lastLineNo;
578 var moveX, moveY;
579 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
580 var line = lines[lineNo];
581 if (line.length == 0) {
582 continue;
583 }
584 var opStart = "SkOpSegment::";
585 if (line.lastIndexOf(opStart, 0) === 0) {
586 line = line.substr(opStart.length);
587 }
588 var angleStart = "SkOpAngle::";
589 if (line.lastIndexOf(angleStart, 0) === 0) {
590 line = line.substr(angleStart.length);
591 }
caryclark624637c2015-05-11 07:21:27 -0700592 var coinStart = "SkOpCoincidence::";
593 if (line.lastIndexOf(coinStart, 0) === 0) {
594 line = line.substr(coinStart.length);
595 }
caryclark54359292015-03-26 07:52:43 -0700596 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700597 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700598 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclarkdac1d172014-06-17 05:15:38 -0700599 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700600 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700601 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
602 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
603 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
604 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
caryclark26ad22a2015-10-16 09:03:38 -0700605 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700606 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700607 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700608 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
609 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
610 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
611 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
612 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700613 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700614 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
615 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
616 : REC_TYPE_UNKNOWN;
617 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
618 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
619 if (recType != REC_TYPE_UNKNOWN) {
620 records.push(recType);
621 records.push(lastLineNo);
622 records.push(record);
623 }
624 record = [];
625 recType = type;
626 lastLineNo = lineNo;
627 }
628 var found = false;
629 switch (recType) {
630 case REC_TYPE_ACTIVE:
631 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700632" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700633 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700634" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700635 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700636" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700637 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700638" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
639 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
640" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
641 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
642" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
643 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
644" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
645 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
646" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700647 );
648 break;
649 case REC_TYPE_ACTIVE_OP:
650 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
651" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
652 );
653 break;
654 case REC_TYPE_ADD:
655 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
656 moveX = record[1][0];
657 moveY = record[1][1];
658 found = true;
659 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
660 record[1].unshift(moveY);
661 record[1].unshift(moveX);
662 moveX = record[1][2];
663 moveY = record[1][3];
664 found = true;
665 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
666 record[1].unshift(moveY);
667 record[1].unshift(moveX);
668 moveX = record[1][4];
669 moveY = record[1][5];
670 found = true;
caryclark1049f122015-04-20 08:31:59 -0700671 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
672 record[1].unshift(moveY);
673 record[1].unshift(moveX);
674 moveX = record[1][4];
675 moveY = record[1][5];
676 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700677 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
678 record[1].unshift(moveY);
679 record[1].unshift(moveX);
680 moveX = record[1][6];
681 moveY = record[1][7];
682 found = true;
683 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
684 found = true;
685 } else {
686 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
687 }
688 break;
caryclark54359292015-03-26 07:52:43 -0700689 case REC_TYPE_AFTERPART:
690 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL")
691 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL")
caryclark1049f122015-04-20 08:31:59 -0700692 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL")
caryclark54359292015-03-26 07:52:43 -0700693 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL")
694 break;
caryclark26ad22a2015-10-16 09:03:38 -0700695 case REC_TYPE_ALIGNED:
696 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
697 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
698 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
699 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
700 );
701 break;
caryclarkdac1d172014-06-17 05:15:38 -0700702 case REC_TYPE_ANGLE:
703 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700704"[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");
705 break;
706 case REC_TYPE_COIN:
707 found = true;
708 break;
caryclark624637c2015-05-11 07:21:27 -0700709 case REC_TYPE_COINCIDENCE:
710 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
711" + id=IDX t=T_VAL tEnd=T_VAL"
712 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
713" - id=IDX t=T_VAL tEnd=T_VAL"
714 );
715 break;
caryclarkdac1d172014-06-17 05:15:38 -0700716 case REC_TYPE_COMPUTED:
717 found = line == "computed quadratics given"
718 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
719 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
720 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700721 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700722 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
723 );
724 break;
725 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700726 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
727 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700728 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700729 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
730 );
731 break;
732 case REC_TYPE_PATH2:
733 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
734 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700735 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700736 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700737 );
738 break;
739 case REC_TYPE_SECT:
740 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
741" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
742 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
743" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
744 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
745" no intersect LINE_VAL LINE_VAL"
746 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
747" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
748 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
749" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
750 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
751" no intersect QUAD_VAL LINE_VAL"
752 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
753" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
754 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
755" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
756 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
757" no intersect QUAD_VAL QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700758 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
759" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
760 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
761" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
762 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
763" no intersect CONIC_VAL LINE_VAL"
764 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
765" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
766 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
767" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
768 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
769" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700770 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
771" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
772 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
773" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
774 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
775" 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"
776 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
777" no intersect CUBIC_VAL LINE_VAL"
778 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
779" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
780 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
781" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
782 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
783" 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"
784 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
785" 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"
786 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
787" no intersect CUBIC_VAL QUAD_VAL"
788 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
789" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
790 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
791" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
792 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
793" 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"
794 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
795" 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"
796 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
797" no intersect CUBIC_VAL CUBIC_VAL"
798 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
799" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
800 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
801" no self intersect CUBIC_VAL"
802 );
803 break;
804 case REC_TYPE_SORT:
805 var hasDone = / done/.test(line);
806 var hasUnorderable = / unorderable/.test(line);
807 var hasSmall = / small/.test(line);
808 var hasTiny = / tiny/.test(line);
809 var hasOperand = / operand/.test(line);
810 var hasStop = / stop/.test(line);
811 line.replace(/[ a-z]+$/, "");
812 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
813" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
814 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
815" [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"
816 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
817" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
818 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
819" [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"
820 );
821 if (found) {
822 record[1].push(hasDone);
823 record[1].push(hasUnorderable);
824 record[1].push(hasSmall);
825 record[1].push(hasTiny);
826 record[1].push(hasOperand);
827 record[1].push(hasStop);
828 }
829 break;
caryclark03b03ca2015-04-23 09:13:37 -0700830 case REC_TYPE_TOP:
831 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
832" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
833 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
834" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
835 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
836" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
837 );
838 break;
caryclarkdac1d172014-06-17 05:15:38 -0700839 case REC_TYPE_MARK:
840 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700841" 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 -0700842 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700843" 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 -0700844 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
845" 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 -0700846 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700847" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
848 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
849" 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"
850 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
851" 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 -0700852 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
853" 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 -0700854 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
855" 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 -0700856 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
857" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
858 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
859" 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 -0700860 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
861" 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 -0700862 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
863" 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 -0700864 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700865" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700866 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
867" last segment=IDX span=IDX windSum=OPT");
caryclarkdac1d172014-06-17 05:15:38 -0700868 break;
869 case REC_TYPE_OP:
870 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
871 || line.lastIndexOf("operator<", 0) === 0) {
872 found = true;
873 break;
874 }
caryclark54359292015-03-26 07:52:43 -0700875 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700876 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700877 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700878 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
879 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
880 );
881 break;
882 case REC_TYPE_UNKNOWN:
883 found = true;
884 break;
885 }
886 if (!found) {
887 console.log(line + " [" + lineNo + "] of type " + type + " not found");
888 }
889 }
890 if (recType != REC_TYPE_UNKNOWN) {
891 records.push(recType);
892 records.push(lastLineNo);
893 records.push(record);
894 }
895 if (records.length >= 1) {
896 tests[testIndex] = records;
897 testLines[testIndex] = lines;
898 }
899}
900
901function init(test) {
902 var canvas = document.getElementById('canvas');
903 if (!canvas.getContext) return;
904 ctx = canvas.getContext('2d');
905 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
906 var unscaledWidth = window.innerWidth - 20;
907 var unscaledHeight = window.innerHeight - 20;
908 screenWidth = unscaledWidth;
909 screenHeight = unscaledHeight;
910 canvas.width = unscaledWidth * resScale;
911 canvas.height = unscaledHeight * resScale;
912 canvas.style.width = unscaledWidth + 'px';
913 canvas.style.height = unscaledHeight + 'px';
914 if (resScale != 1) {
915 ctx.scale(resScale, resScale);
916 }
917 xmin = Infinity;
918 xmax = -Infinity;
919 ymin = Infinity;
920 ymax = -Infinity;
caryclark26ad22a2015-10-16 09:03:38 -0700921 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700922 firstActiveSpan = -1;
923 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
924 var recType = test[tIndex];
925 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
926 console.log("unknown rec type: " + recType);
927 throw "stop execution";
928 }
929 var records = test[tIndex + 2];
930 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
931 var fragType = records[recordIndex];
932 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
933 console.log("unknown in range frag type: " + fragType);
934 throw "stop execution";
935 }
936 var frags = records[recordIndex + 1];
937 var first = 0;
938 var last = -1;
939 var first2 = 0;
940 var last2 = 0;
941 switch (recType) {
caryclark26ad22a2015-10-16 09:03:38 -0700942 case REC_TYPE_ALIGNED:
943 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -0700944 case REC_TYPE_COMPUTED:
945 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
946 break;
947 }
caryclark26ad22a2015-10-16 09:03:38 -0700948 if (REC_TYPE_COMPUTED == recType) {
949 hasComputedPath = true;
950 }
caryclarkdac1d172014-06-17 05:15:38 -0700951 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700952 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700953 switch (fragType) {
954 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700955 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700956 break;
caryclark1049f122015-04-20 08:31:59 -0700957 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700958 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700959 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700960 break;
961 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700962 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700963 break;
964 default:
965 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
966 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
967 throw "stop execution";
968 }
969 if (recType == REC_TYPE_PATH) {
970 hasPath = true;
971 }
972 break;
caryclark54359292015-03-26 07:52:43 -0700973 case REC_TYPE_PATH2:
974 first = 1;
975 switch (fragType) {
976 case PATH_LINE:
977 last = 5;
978 break;
caryclark1049f122015-04-20 08:31:59 -0700979 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700980 case PATH_QUAD:
981 last = 7;
982 break;
983 case PATH_CUBIC:
984 last = 9;
985 break;
986 default:
987 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
988 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
989 throw "stop execution";
990 }
991 if (recType == REC_TYPE_PATH2) {
992 hasPath = true;
993 }
994 break;
caryclarkdac1d172014-06-17 05:15:38 -0700995 case REC_TYPE_ACTIVE:
996 if (firstActiveSpan < 0) {
997 firstActiveSpan = tIndex;
998 }
999 first = 1;
1000 switch (fragType) {
1001 case ACTIVE_LINE_SPAN:
1002 last = 5;
1003 break;
caryclark1049f122015-04-20 08:31:59 -07001004 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -07001005 case ACTIVE_QUAD_SPAN:
1006 last = 7;
1007 break;
1008 case ACTIVE_CUBIC_SPAN:
1009 last = 9;
1010 break;
1011 default:
1012 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
1013 throw "stop execution";
1014 }
1015 break;
1016 case REC_TYPE_ADD:
1017 switch (fragType) {
1018 case ADD_MOVETO:
1019 break;
1020 case ADD_LINETO:
1021 last = 4;
1022 break;
caryclark1049f122015-04-20 08:31:59 -07001023 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -07001024 case ADD_QUADTO:
1025 last = 6;
1026 break;
1027 case ADD_CUBICTO:
1028 last = 8;
1029 break;
1030 case ADD_CLOSE:
1031 case ADD_FILL:
1032 break;
1033 default:
1034 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
1035 throw "stop execution";
1036 }
1037 break;
caryclark54359292015-03-26 07:52:43 -07001038 case REC_TYPE_AFTERPART:
1039 switch (fragType) {
1040 case PATH_LINE:
1041 last = 4;
1042 break;
caryclark1049f122015-04-20 08:31:59 -07001043 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001044 case PATH_QUAD:
1045 last = 6;
1046 break;
1047 case PATH_CUBIC:
1048 last = 8;
1049 break;
1050 default:
1051 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
1052 throw "stop execution";
1053 }
1054 break;
caryclarkdac1d172014-06-17 05:15:38 -07001055 case REC_TYPE_SECT:
1056 switch (fragType) {
1057 case INTERSECT_LINE:
1058 first = 1; last = 5; first2 = 8; last2 = 12;
1059 break;
1060 case INTERSECT_LINE_2:
1061 first = 1; last = 5; first2 = 11; last2 = 15;
1062 break;
1063 case INTERSECT_LINE_NO:
1064 first = 0; last = 4; first2 = 4; last2 = 8;
1065 break;
caryclark1049f122015-04-20 08:31:59 -07001066 case INTERSECT_CONIC_LINE:
1067 first = 1; last = 7; first2 = 11; last2 = 15;
1068 break;
caryclarkdac1d172014-06-17 05:15:38 -07001069 case INTERSECT_QUAD_LINE:
1070 first = 1; last = 7; first2 = 10; last2 = 14;
1071 break;
caryclark1049f122015-04-20 08:31:59 -07001072 case INTERSECT_CONIC_LINE_2:
1073 first = 1; last = 7; first2 = 14; last2 = 18;
1074 break;
caryclarkdac1d172014-06-17 05:15:38 -07001075 case INTERSECT_QUAD_LINE_2:
1076 first = 1; last = 7; first2 = 13; last2 = 17;
1077 break;
caryclark1049f122015-04-20 08:31:59 -07001078 case INTERSECT_CONIC_LINE_NO:
1079 first = 0; last = 6; first2 = 7; last2 = 11;
1080 break;
caryclarkdac1d172014-06-17 05:15:38 -07001081 case INTERSECT_QUAD_LINE_NO:
1082 first = 0; last = 6; first2 = 6; last2 = 10;
1083 break;
caryclark1049f122015-04-20 08:31:59 -07001084 case INTERSECT_CONIC:
1085 first = 1; last = 7; first2 = 11; last2 = 17;
1086 break;
caryclarkdac1d172014-06-17 05:15:38 -07001087 case INTERSECT_QUAD:
1088 first = 1; last = 7; first2 = 10; last2 = 16;
1089 break;
caryclark1049f122015-04-20 08:31:59 -07001090 case INTERSECT_CONIC_2:
1091 first = 1; last = 7; first2 = 14; last2 = 20;
1092 break;
caryclarkdac1d172014-06-17 05:15:38 -07001093 case INTERSECT_QUAD_2:
1094 first = 1; last = 7; first2 = 13; last2 = 19;
1095 break;
caryclark1049f122015-04-20 08:31:59 -07001096 case INTERSECT_CONIC_NO:
1097 first = 0; last = 6; first2 = 7; last2 = 13;
1098 break;
caryclarkdac1d172014-06-17 05:15:38 -07001099 case INTERSECT_QUAD_NO:
1100 first = 0; last = 6; first2 = 6; last2 = 12;
1101 break;
1102 case INTERSECT_SELF_CUBIC:
1103 first = 1; last = 9;
1104 break;
1105 case INTERSECT_SELF_CUBIC_NO:
1106 first = 0; last = 8;
1107 break;
1108 case INTERSECT_CUBIC_LINE:
1109 first = 1; last = 9; first2 = 12; last2 = 16;
1110 break;
1111 case INTERSECT_CUBIC_LINE_2:
1112 first = 1; last = 9; first2 = 15; last2 = 19;
1113 break;
1114 case INTERSECT_CUBIC_LINE_3:
1115 first = 1; last = 9; first2 = 18; last2 = 22;
1116 break;
1117 case INTERSECT_CUBIC_LINE_NO:
1118 first = 0; last = 8; first2 = 8; last2 = 12;
1119 break;
1120 case INTERSECT_CUBIC_QUAD:
1121 first = 1; last = 9; first2 = 12; last2 = 18;
1122 break;
1123 case INTERSECT_CUBIC_QUAD_2:
1124 first = 1; last = 9; first2 = 15; last2 = 21;
1125 break;
1126 case INTERSECT_CUBIC_QUAD_3:
1127 first = 1; last = 9; first2 = 18; last2 = 24;
1128 break;
1129 case INTERSECT_CUBIC_QUAD_4:
1130 first = 1; last = 9; first2 = 21; last2 = 27;
1131 break;
1132 case INTERSECT_CUBIC_QUAD_NO:
1133 first = 0; last = 8; first2 = 8; last2 = 14;
1134 break;
1135 case INTERSECT_CUBIC:
1136 first = 1; last = 9; first2 = 12; last2 = 20;
1137 break;
1138 case INTERSECT_CUBIC_2:
1139 first = 1; last = 9; first2 = 15; last2 = 23;
1140 break;
1141 case INTERSECT_CUBIC_3:
1142 first = 1; last = 9; first2 = 18; last2 = 26;
1143 break;
1144 case INTERSECT_CUBIC_4:
1145 first = 1; last = 9; first2 = 21; last2 = 29;
1146 break;
1147 case INTERSECT_CUBIC_NO:
1148 first = 0; last = 8; first2 = 8; last2 = 16;
1149 break;
1150 default:
1151 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1152 throw "stop execution";
1153 }
1154 break;
1155 default:
1156 continue;
1157 }
1158 for (var idx = first; idx < last; idx += 2) {
1159 xmin = Math.min(xmin, frags[idx]);
1160 xmax = Math.max(xmax, frags[idx]);
1161 ymin = Math.min(ymin, frags[idx + 1]);
1162 ymax = Math.max(ymax, frags[idx + 1]);
1163 }
1164 for (var idx = first2; idx < last2; idx += 2) {
1165 xmin = Math.min(xmin, frags[idx]);
1166 xmax = Math.max(xmax, frags[idx]);
1167 ymin = Math.min(ymin, frags[idx + 1]);
1168 ymax = Math.max(ymax, frags[idx + 1]);
1169 }
1170 }
1171 }
1172 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1173 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1174 var recType = test[tIndex];
1175 var records = test[tIndex + 2];
1176 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1177 var fragType = records[recordIndex];
1178 var frags = records[recordIndex + 1];
1179 switch (recType) {
1180 case REC_TYPE_ACTIVE_OP:
1181 if (!draw_op) {
1182 break;
1183 }
1184 {
1185 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1186 curve_extremes(curve, angleBounds);
1187 }
1188 break;
1189 case REC_TYPE_ANGLE:
1190 if (!draw_angle) {
1191 break;
1192 }
caryclark54359292015-03-26 07:52:43 -07001193 {
caryclarkdac1d172014-06-17 05:15:38 -07001194 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1195 curve_extremes(curve, angleBounds);
1196 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1197 curve_extremes(curve, angleBounds);
1198 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1199 }
1200 break;
caryclark624637c2015-05-11 07:21:27 -07001201 case REC_TYPE_COINCIDENCE:
1202 if (!draw_coincidence) {
1203 break;
1204 }
1205 {
1206 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1207 curve_extremes(curve, angleBounds);
1208 }
1209 break;
caryclarkdac1d172014-06-17 05:15:38 -07001210 case REC_TYPE_SORT:
1211 if (!draw_sort) {
1212 break;
1213 }
1214 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1215 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1216 curve_extremes(curve, angleBounds);
1217 }
1218 break;
caryclark03b03ca2015-04-23 09:13:37 -07001219 case REC_TYPE_TOP:
1220 if (!draw_top) {
1221 break;
1222 }
1223 {
1224 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1225 curve_extremes(curve, angleBounds);
1226 }
1227 break;
caryclarkdac1d172014-06-17 05:15:38 -07001228 }
1229 }
1230 }
1231 xmin = Math.min(xmin, angleBounds[0]);
1232 ymin = Math.min(ymin, angleBounds[1]);
1233 xmax = Math.max(xmax, angleBounds[2]);
1234 ymax = Math.max(ymax, angleBounds[3]);
1235 setScale(xmin, xmax, ymin, ymax);
1236 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001237 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001238 }
1239 if (hasPath == true && hasComputedPath == false && draw_computed) {
1240 draw_computed = 0;
1241 }
1242}
1243
caryclark26ad22a2015-10-16 09:03:38 -07001244function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001245 var tIndex = -3;
1246 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001247 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001248 if (recType == REC_TYPE_OP) {
1249 continue;
1250 }
caryclark26ad22a2015-10-16 09:03:38 -07001251 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001252 return [];
1253 }
1254 var records = test[tIndex + 2];
1255 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1256 var fragType = records[recordIndex];
1257 var frags = records[recordIndex + 1];
1258 if (frags[0] == id) {
1259 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001260 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001261 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001262 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001263 return [frags[1], frags[2], frags[3], frags[4],
1264 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001265 case PATH_CONIC:
1266 return [frags[1], frags[2], frags[3], frags[4],
1267 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001268 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001269 return [frags[1], frags[2], frags[3], frags[4],
1270 frags[5], frags[6], frags[7], frags[8]];
1271 }
1272 }
1273 }
caryclarkdac1d172014-06-17 05:15:38 -07001274 }
1275 return [];
1276}
1277
caryclark26ad22a2015-10-16 09:03:38 -07001278function curveByID(test, id) {
1279 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
1280 if (!result.length) {
1281 result = curveByIDMatch(test, id, REC_TYPE_PATH);
1282 }
1283 return result;
1284}
1285
1286function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001287 var tIndex = -3;
1288 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001289 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001290 if (recType == REC_TYPE_OP) {
1291 continue;
1292 }
caryclark26ad22a2015-10-16 09:03:38 -07001293 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001294 return [];
1295 }
1296 var records = test[tIndex + 2];
1297 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1298 var fragType = records[recordIndex];
1299 var frags = records[recordIndex + 1];
1300 if (frags[0] == id) {
1301 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001302 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001303 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001304 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001305 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1306 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001307 case PATH_CONIC:
1308 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1309 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001310 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001311 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1312 frags[5], frags[6], frags[7], frags[8], t0, t1);
1313 }
1314 }
1315 }
caryclarkdac1d172014-06-17 05:15:38 -07001316 }
1317 return [];
1318}
1319
caryclark26ad22a2015-10-16 09:03:38 -07001320function curvePartialByID(test, id, t0, t1) {
1321 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
1322 if (!result.length) {
1323 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
1324 }
1325 return result;
1326}
1327
1328function idByCurveIDMatch(test, frag, type, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001329 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001330 while (tIndex < test.length) {
1331 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001332 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001333 ++tIndex;
1334 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001335 }
1336 var records = test[tIndex + 2];
1337 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1338 var fragType = records[recordIndex];
1339 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001340 if (frag.length != frags.length - 1) {
1341 continue;
1342 }
caryclarkdac1d172014-06-17 05:15:38 -07001343 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001344 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001345 if (frag[0] != frags[1] || frag[1] != frags[2]
1346 || frag[2] != frags[3] || frag[3] != frags[4]) {
1347 continue;
1348 }
1349 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001350 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001351 if (frag[0] != frags[1] || frag[1] != frags[2]
1352 || frag[2] != frags[3] || frag[3] != frags[4]
1353 || frag[4] != frags[5] || frag[5] != frags[6]) {
1354 continue;
1355 }
1356 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001357 case PATH_CONIC:
1358 if (frag[0] != frags[1] || frag[1] != frags[2]
1359 || frag[2] != frags[3] || frag[3] != frags[4]
1360 || frag[4] != frags[5] || frag[5] != frags[6]
1361 || frag[6] != frags[7]) {
1362 continue;
1363 }
1364 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001365 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001366 if (frag[0] != frags[1] || frag[1] != frags[2]
1367 || frag[2] != frags[3] || frag[3] != frags[4]
1368 || frag[4] != frags[5] || frag[5] != frags[6]
1369 || frag[6] != frags[7] || frag[7] != frags[8]) {
1370 continue;
1371 }
1372 return frags[0];
1373 }
1374 }
1375 ++tIndex;
1376 }
1377 return -1;
1378}
1379
caryclark26ad22a2015-10-16 09:03:38 -07001380function idByCurve(test, frag, type) {
1381 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
1382 if (!result.length) {
1383 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
1384 }
1385 return result;
1386}
1387
caryclarkdac1d172014-06-17 05:15:38 -07001388function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001389 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001390 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001391 var x = curve[index];
1392 var y = curve[index + 1];
1393 bounds[0] = Math.min(bounds[0], x);
1394 bounds[1] = Math.min(bounds[1], y);
1395 bounds[2] = Math.max(bounds[2], x);
1396 bounds[3] = Math.max(bounds[3], y);
1397 }
1398}
1399
1400function setScale(x0, x1, y0, y1) {
1401 var srcWidth = x1 - x0;
1402 var srcHeight = y1 - y0;
1403 var usableWidth = screenWidth;
1404 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1405 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1406 usableWidth -= (xDigits + yDigits) * 10;
1407 usableWidth -= decimal_places * 10;
1408 if (draw_legend) {
1409 usableWidth -= 40;
1410 }
1411 var hscale = usableWidth / srcWidth;
1412 var vscale = screenHeight / srcHeight;
1413 scale = Math.min(hscale, vscale);
1414 var invScale = 1 / scale;
1415 var sxmin = x0 - invScale * 5;
1416 var symin = y0 - invScale * 10;
1417 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1418 var symax = y1 + invScale * 10;
1419 srcWidth = sxmax - sxmin;
1420 srcHeight = symax - symin;
1421 hscale = usableWidth / srcWidth;
1422 vscale = screenHeight / srcHeight;
1423 scale = Math.min(hscale, vscale);
1424 srcLeft = sxmin;
1425 srcTop = symin;
1426}
1427
1428function drawArc(curve, op, from, to) {
1429 var type = PATH_LINE + (curve.length / 2 - 2);
1430 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1431 var dy = pt.y - curve[1];
1432 var dx = pt.x - curve[0];
1433 var dist = Math.sqrt(dy * dy + dx * dx);
1434 var _dist = dist * scale;
1435 var angle = Math.atan2(dy, dx);
1436 var _px = (curve[0] - srcLeft) * scale;
1437 var _py = (curve[1] - srcTop) * scale;
1438 var divisor = 4;
1439 var endDist;
1440 do {
1441 var ends = [];
1442 for (var index = -1; index <= 1; index += 2) {
1443 var px = Math.cos(index * Math.PI / divisor);
1444 var py = Math.sin(index * Math.PI / divisor);
1445 ends.push(px);
1446 ends.push(py);
1447 }
1448 var endDx = (ends[2] - ends[0]) * scale * dist;
1449 var endDy = (ends[3] - ends[1]) * scale * dist;
1450 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1451 if (endDist < 100) {
1452 break;
1453 }
1454 divisor *= 2;
1455 } while (true);
1456 if (endDist < 30) {
1457 return;
1458 }
1459 if (op) {
1460 divisor *= 2;
1461 }
1462 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1463 ctx.beginPath();
1464 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1465 ctx.stroke();
1466 var saveAlign = ctx.textAlign;
1467 var saveStyle = ctx.fillStyle;
1468 var saveFont = ctx.font;
1469 ctx.textAlign = "center";
1470 ctx.fillStyle = "black";
1471 ctx.font = "normal 24px Arial";
1472 divisor *= 0.8;
1473 for (var index = -1; index <= 1; index += 2) {
1474 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1475 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1476 var _px = (px - srcLeft) * scale;
1477 var _py = (py - srcTop) * scale;
1478 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1479 }
1480 ctx.textAlign = saveAlign;
1481 ctx.fillStyle = saveStyle;
1482 ctx.font = saveFont;
1483}
1484
1485function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001486 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1487 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001488 var x = drawnPts[pts];
1489 var y = drawnPts[pts + 1];
1490 if (px == x && py == y) {
1491 return;
1492 }
1493 }
1494 drawnPts.push(px);
1495 drawnPts.push(py);
1496 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1497 var _px = (px - srcLeft) * scale;
1498 var _py = (py - srcTop) * scale;
1499 ctx.beginPath();
1500 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1501 ctx.closePath();
1502 if (end) {
1503 ctx.fill();
1504 } else {
1505 ctx.stroke();
1506 }
1507 if (debug_xy) {
1508 ctx.textAlign = "left";
1509 ctx.fillText(label, _px + 5, _py);
1510 }
1511}
1512
caryclark1049f122015-04-20 08:31:59 -07001513function coordCount(curveType) {
1514 switch (curveType) {
1515 case PATH_LINE:
1516 return 4;
1517 case PATH_QUAD:
1518 return 6;
1519 case PATH_CONIC:
1520 return 6;
1521 case PATH_CUBIC:
1522 return 8;
1523 }
1524 return -1;
1525}
1526
caryclarkdac1d172014-06-17 05:15:38 -07001527function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001528 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001529 for (var idx = 0; idx < count; idx += 2) {
1530 if (!drawControls && idx != 0 && idx != count - 2) {
1531 continue;
1532 }
1533 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1534 }
1535}
1536
1537function drawControlLines(curve, curveType, drawEnd) {
1538 if (curveType == PATH_LINE) {
1539 return;
1540 }
1541 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1542 drawLine(curve[0], curve[1], curve[2], curve[3]);
1543 drawLine(curve[2], curve[3], curve[4], curve[5]);
1544 if (curveType == PATH_CUBIC) {
1545 drawLine(curve[4], curve[5], curve[6], curve[7]);
1546 if (drawEnd > 1) {
1547 drawLine(curve[6], curve[7], curve[0], curve[1]);
1548 if (drawEnd > 2) {
1549 drawLine(curve[0], curve[1], curve[4], curve[5]);
1550 drawLine(curve[6], curve[7], curve[2], curve[3]);
1551 }
1552 }
1553 } else if (drawEnd > 1) {
1554 drawLine(curve[4], curve[5], curve[0], curve[1]);
1555 }
1556}
1557
1558function pointAtT(curve, curveType, t) {
1559 var xy = {};
1560 switch (curveType) {
1561 case PATH_LINE:
1562 var a = 1 - t;
1563 var b = t;
1564 xy.x = a * curve[0] + b * curve[2];
1565 xy.y = a * curve[1] + b * curve[3];
1566 break;
1567 case PATH_QUAD:
1568 var one_t = 1 - t;
1569 var a = one_t * one_t;
1570 var b = 2 * one_t * t;
1571 var c = t * t;
1572 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1573 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1574 break;
caryclark1049f122015-04-20 08:31:59 -07001575 case PATH_CONIC:
1576 var one_t = 1 - t;
1577 var a = one_t * one_t;
1578 var b = 2 * one_t * t;
1579 var c = t * t;
1580 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1581 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1582 var d = a + b * curve[6] + c;
1583 xy.x /= d;
1584 xy.y /= d;
1585 break;
caryclarkdac1d172014-06-17 05:15:38 -07001586 case PATH_CUBIC:
1587 var one_t = 1 - t;
1588 var one_t2 = one_t * one_t;
1589 var a = one_t2 * one_t;
1590 var b = 3 * one_t2 * t;
1591 var t2 = t * t;
1592 var c = 3 * one_t * t2;
1593 var d = t2 * t;
1594 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1595 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1596 break;
1597 }
1598 return xy;
1599}
1600
1601function drawPointAtT(curve, curveType) {
1602 var x, y;
1603 var xy = pointAtT(curve, curveType, curveT);
1604 drawPoint(xy.x, xy.y, true);
1605 if (!draw_intersectT) {
1606 return;
1607 }
1608 ctx.fillStyle = "red";
1609 drawTAtPointUp(xy.x, xy.y, curveT);
1610}
1611
1612function drawTAtPointUp(px, py, t) {
1613 var label = t.toFixed(decimal_places);
1614 var _px = (px - srcLeft)* scale;
1615 var _py = (py - srcTop) * scale;
1616 ctx.fillText(label, _px + 5, _py - 10);
1617}
1618
1619function drawTAtPointDown(px, py, t) {
1620 var label = t.toFixed(decimal_places);
1621 var _px = (px - srcLeft)* scale;
1622 var _py = (py - srcTop) * scale;
1623 ctx.fillText(label, _px + 5, _py + 10);
1624}
1625
1626function alreadyDrawnLine(x1, y1, x2, y2) {
1627 if (collect_bounds) {
1628 if (focus_enabled) {
1629 focusXmin = Math.min(focusXmin, x1, x2);
1630 focusYmin = Math.min(focusYmin, y1, y2);
1631 focusXmax = Math.max(focusXmax, x1, x2);
1632 focusYmax = Math.max(focusYmax, y1, y2);
1633 }
1634 return true;
1635 }
1636 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1637 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1638 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1639 return true;
1640 }
1641 }
1642 drawnLines.push(x1);
1643 drawnLines.push(y1);
1644 drawnLines.push(x2);
1645 drawnLines.push(y2);
1646 return false;
1647}
1648
1649function drawLine(x1, y1, x2, y2) {
1650 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1651 return;
1652 }
1653 ctx.beginPath();
1654 ctx.moveTo((x1 - srcLeft) * scale,
1655 (y1 - srcTop) * scale);
1656 ctx.lineTo((x2 - srcLeft) * scale,
1657 (y2 - srcTop) * scale);
1658 ctx.stroke();
1659}
1660
1661function linePartial(x1, y1, x2, y2, t1, t2) {
1662 var dx = x1 - x2;
1663 var dy = y1 - y2;
1664 var array = [
1665 x1 - t1 * dx,
1666 y1 - t1 * dy,
1667 x1 - t2 * dx,
1668 y1 - t2 * dy
1669 ];
1670 return array;
1671}
1672
1673function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1674 var a = linePartial(x1, y1, x2, y2, t1, t2);
1675 var ax = a[0];
1676 var ay = a[1];
1677 var bx = a[2];
1678 var by = a[3];
1679 if (alreadyDrawnLine(ax, ay, bx, by)) {
1680 return;
1681 }
1682 ctx.beginPath();
1683 ctx.moveTo((ax - srcLeft) * scale,
1684 (ay - srcTop) * scale);
1685 ctx.lineTo((bx - srcLeft) * scale,
1686 (by - srcTop) * scale);
1687 ctx.stroke();
1688}
1689
1690function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1691 if (collect_bounds) {
1692 if (focus_enabled) {
1693 focusXmin = Math.min(focusXmin, x1, x2, x3);
1694 focusYmin = Math.min(focusYmin, y1, y2, y3);
1695 focusXmax = Math.max(focusXmax, x1, x2, x3);
1696 focusYmax = Math.max(focusYmax, y1, y2, y3);
1697 }
1698 return true;
1699 }
1700 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1701 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1702 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1703 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1704 return true;
1705 }
1706 }
1707 drawnQuads.push(x1);
1708 drawnQuads.push(y1);
1709 drawnQuads.push(x2);
1710 drawnQuads.push(y2);
1711 drawnQuads.push(x3);
1712 drawnQuads.push(y3);
1713 return false;
1714}
1715
1716function drawQuad(x1, y1, x2, y2, x3, y3) {
1717 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1718 return;
1719 }
1720 ctx.beginPath();
1721 ctx.moveTo((x1 - srcLeft) * scale,
1722 (y1 - srcTop) * scale);
1723 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1724 (y2 - srcTop) * scale,
1725 (x3 - srcLeft) * scale,
1726 (y3 - srcTop) * scale);
1727 ctx.stroke();
1728}
1729
1730function interp(A, B, t) {
1731 return A + (B - A) * t;
1732}
1733
1734function interp_quad_coords(x1, x2, x3, t)
1735{
1736 var ab = interp(x1, x2, t);
1737 var bc = interp(x2, x3, t);
1738 var abc = interp(ab, bc, t);
1739 return abc;
1740}
1741
1742function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1743 var ax = interp_quad_coords(x1, x2, x3, t1);
1744 var ay = interp_quad_coords(y1, y2, y3, t1);
1745 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1746 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1747 var cx = interp_quad_coords(x1, x2, x3, t2);
1748 var cy = interp_quad_coords(y1, y2, y3, t2);
1749 var bx = 2*dx - (ax + cx)/2;
1750 var by = 2*dy - (ay + cy)/2;
1751 var array = [
1752 ax, ay, bx, by, cx, cy
1753 ];
1754 return array;
1755}
1756
1757function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1758 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1759 var ax = a[0];
1760 var ay = a[1];
1761 var bx = a[2];
1762 var by = a[3];
1763 var cx = a[4];
1764 var cy = a[5];
1765 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1766 return;
1767 }
1768 ctx.beginPath();
1769 ctx.moveTo((ax - srcLeft) * scale,
1770 (ay - srcTop) * scale);
1771 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1772 (by - srcTop) * scale,
1773 (cx - srcLeft) * scale,
1774 (cy - srcTop) * scale);
1775 ctx.stroke();
1776}
1777
caryclark1049f122015-04-20 08:31:59 -07001778function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1779 if (collect_bounds) {
1780 if (focus_enabled) {
1781 focusXmin = Math.min(focusXmin, x1, x2, x3);
1782 focusYmin = Math.min(focusYmin, y1, y2, y3);
1783 focusXmax = Math.max(focusXmax, x1, x2, x3);
1784 focusYmax = Math.max(focusYmax, y1, y2, y3);
1785 }
1786 return true;
1787 }
1788 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1789 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
1790 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1791 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1792 && w == drawnCubics[pts + 6]) {
1793 return true;
1794 }
1795 }
1796 drawnConics.push(x1);
1797 drawnConics.push(y1);
1798 drawnConics.push(x2);
1799 drawnConics.push(y2);
1800 drawnConics.push(x3);
1801 drawnConics.push(y3);
1802 drawnCubics.push(w);
1803 return false;
1804}
1805
1806var kMaxConicToQuadPOW2 = 5;
1807
1808function computeQuadPOW2(curve, tol) {
1809 var a = curve[6] - 1;
1810 var k = a / (4 * (2 + a));
1811 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1812 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1813
1814 var error = Math.sqrt(x * x + y * y);
1815 var pow2;
1816 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1817 if (error <= tol) {
1818 break;
1819 }
1820 error *= 0.25;
1821 }
1822 return pow2;
1823}
1824
1825function subdivide_w_value(w) {
1826 return Math.sqrt(0.5 + w * 0.5);
1827}
1828
1829function chop(curve, part1, part2) {
1830 var w = curve[6];
1831 var scale = 1 / (1 + w);
1832 part1[0] = curve[0];
1833 part1[1] = curve[1];
1834 part1[2] = (curve[0] + curve[2] * w) * scale;
1835 part1[3] = (curve[1] + curve[3] * w) * scale;
1836 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1837 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1838 part2[2] = (curve[2] * w + curve[4]) * scale;
1839 part2[3] = (curve[3] * w + curve[5]) * scale;
1840 part2[4] = curve[4];
1841 part2[5] = curve[5];
1842 part1[6] = part2[6] = subdivide_w_value(w);
1843}
1844
1845function subdivide(curve, level, pts) {
1846 if (0 == level) {
1847 pts.push(curve[2]);
1848 pts.push(curve[3]);
1849 pts.push(curve[4]);
1850 pts.push(curve[5]);
1851 } else {
1852 var part1 = [], part2 = [];
1853 chop(curve, part1, part2);
1854 --level;
1855 subdivide(part1, level, pts);
1856 subdivide(part2, level, pts);
1857 }
1858}
1859
1860function chopIntoQuadsPOW2(curve, pow2, pts) {
1861 subdivide(curve, pow2, pts);
1862 return 1 << pow2;
1863}
1864
1865function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1866 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1867 return;
1868 }
1869 ctx.beginPath();
1870 ctx.moveTo((x1 - srcLeft) * scale,
1871 (y1 - srcTop) * scale);
1872 var tol = 1 / scale;
1873 var curve = [x1, y1, x2, y2, x3, y3, w];
1874 var pow2 = computeQuadPOW2(curve, tol);
1875 var pts = [];
1876 chopIntoQuadsPOW2(curve, pow2, pts);
1877 for (var i = 0; i < pts.length; i += 4) {
1878 ctx.quadraticCurveTo(
1879 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1880 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1881 }
1882 ctx.stroke();
1883}
1884
1885function conic_eval_numerator(x1, x2, x3, w, t) {
1886 var src2w = x2 * w;
1887 var C = x1;
1888 var A = x3 - 2 * src2w + C;
1889 var B = 2 * (src2w - C);
1890 return (A * t + B) * t + C;
1891}
1892
1893
1894function conic_eval_denominator(w, t) {
1895 var B = 2 * (w - 1);
1896 var C = 1;
1897 var A = -B;
1898 return (A * t + B) * t + C;
1899}
1900
1901function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1902 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1903 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1904 var az = conic_eval_denominator(w, t1);
1905 var midT = (t1 + t2) / 2;
1906 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1907 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1908 var dz = conic_eval_denominator(w, midT);
1909 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1910 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1911 var cz = conic_eval_denominator(w, t2);
1912 var bx = 2 * dx - (ax + cx) / 2;
1913 var by = 2 * dy - (ay + cy) / 2;
1914 var bz = 2 * dz - (az + cz) / 2;
1915 var dt = t2 - t1;
1916 var dt_1 = 1 - dt;
caryclark1049f122015-04-20 08:31:59 -07001917 var array = [
caryclarked0935a2015-10-22 07:23:52 -07001918 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07001919 ];
caryclarked0935a2015-10-22 07:23:52 -07001920 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
1921 var dMid = { x:dx / dz, y:dy / dz };
1922 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
1923 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
1924 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
1925 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
1926 array[6] = partW;
caryclark1049f122015-04-20 08:31:59 -07001927 return array;
1928}
1929
1930function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1931 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1932 var ax = a[0];
1933 var ay = a[1];
1934 var bx = a[2];
1935 var by = a[3];
1936 var cx = a[4];
1937 var cy = a[5];
1938 var w_ = a[6];
1939 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1940}
1941
caryclarkdac1d172014-06-17 05:15:38 -07001942function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1943 if (collect_bounds) {
1944 if (focus_enabled) {
1945 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1946 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1947 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1948 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1949 }
1950 return true;
1951 }
1952 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1953 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
1954 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1955 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1956 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1957 return true;
1958 }
1959 }
1960 drawnCubics.push(x1);
1961 drawnCubics.push(y1);
1962 drawnCubics.push(x2);
1963 drawnCubics.push(y2);
1964 drawnCubics.push(x3);
1965 drawnCubics.push(y3);
1966 drawnCubics.push(x4);
1967 drawnCubics.push(y4);
1968 return false;
1969}
1970
1971function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1972 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1973 return;
1974 }
1975 ctx.beginPath();
1976 ctx.moveTo((x1 - srcLeft) * scale,
1977 (y1 - srcTop) * scale);
1978 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1979 (y2 - srcTop) * scale,
1980 (x3 - srcLeft) * scale,
1981 (y3 - srcTop) * scale,
1982 (x4 - srcLeft) * scale,
1983 (y4 - srcTop) * scale);
1984 ctx.stroke();
1985}
1986
1987function interp_cubic_coords(x1, x2, x3, x4, t)
1988{
1989 var ab = interp(x1, x2, t);
1990 var bc = interp(x2, x3, t);
1991 var cd = interp(x3, x4, t);
1992 var abc = interp(ab, bc, t);
1993 var bcd = interp(bc, cd, t);
1994 var abcd = interp(abc, bcd, t);
1995 return abcd;
1996}
1997
1998function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1999 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
2000 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
2001 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
2002 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
2003 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
2004 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
2005 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
2006 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
2007 var mx = ex * 27 - ax * 8 - dx;
2008 var my = ey * 27 - ay * 8 - dy;
2009 var nx = fx * 27 - ax - dx * 8;
2010 var ny = fy * 27 - ay - dy * 8;
2011 var bx = (mx * 2 - nx) / 18;
2012 var by = (my * 2 - ny) / 18;
2013 var cx = (nx * 2 - mx) / 18;
2014 var cy = (ny * 2 - my) / 18;
2015 var array = [
2016 ax, ay, bx, by, cx, cy, dx, dy
2017 ];
2018 return array;
2019}
2020
2021function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2022 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2023 var ax = a[0];
2024 var ay = a[1];
2025 var bx = a[2];
2026 var by = a[3];
2027 var cx = a[4];
2028 var cy = a[5];
2029 var dx = a[6];
2030 var dy = a[7];
2031 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
2032 return;
2033 }
2034 ctx.beginPath();
2035 ctx.moveTo((ax - srcLeft) * scale,
2036 (ay - srcTop) * scale);
2037 ctx.bezierCurveTo((bx - srcLeft) * scale,
2038 (by - srcTop) * scale,
2039 (cx - srcLeft) * scale,
2040 (cy - srcTop) * scale,
2041 (dx - srcLeft) * scale,
2042 (dy - srcTop) * scale);
2043 ctx.stroke();
2044}
2045
2046function drawCurve(c) {
2047 switch (c.length) {
2048 case 4:
2049 drawLine(c[0], c[1], c[2], c[3]);
2050 break;
2051 case 6:
2052 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
2053 break;
caryclark1049f122015-04-20 08:31:59 -07002054 case 7:
2055 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
2056 break;
caryclarkdac1d172014-06-17 05:15:38 -07002057 case 8:
2058 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
2059 break;
2060 }
2061}
2062
2063function boundsWidth(pts) {
2064 var min = pts[0];
2065 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07002066 var length = pts.length == 7 ? 6 : pts.length;
2067 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002068 min = Math.min(min, pts[idx]);
2069 max = Math.max(max, pts[idx]);
2070 }
2071 return max - min;
2072}
2073
2074function boundsHeight(pts) {
2075 var min = pts[1];
2076 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07002077 var length = pts.length == 7 ? 6 : pts.length;
2078 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002079 min = Math.min(min, pts[idx]);
2080 max = Math.max(max, pts[idx]);
2081 }
2082 return max - min;
2083}
2084
2085function tangent(pts) {
2086 var dx = pts[2] - pts[0];
2087 var dy = pts[3] - pts[1];
2088 if (dx == 0 && dy == 0 && pts.length > 4) {
2089 dx = pts[4] - pts[0];
2090 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002091 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002092 dx = pts[6] - pts[0];
2093 dy = pts[7] - pts[1];
2094 }
2095 }
2096 return Math.atan2(-dy, dx);
2097}
2098
2099function hodograph(cubic) {
2100 var hodo = [];
2101 hodo[0] = 3 * (cubic[2] - cubic[0]);
2102 hodo[1] = 3 * (cubic[3] - cubic[1]);
2103 hodo[2] = 3 * (cubic[4] - cubic[2]);
2104 hodo[3] = 3 * (cubic[5] - cubic[3]);
2105 hodo[4] = 3 * (cubic[6] - cubic[4]);
2106 hodo[5] = 3 * (cubic[7] - cubic[5]);
2107 return hodo;
2108}
2109
2110function hodograph2(cubic) {
2111 var quad = hodograph(cubic);
2112 var hodo = [];
2113 hodo[0] = 2 * (quad[2] - quad[0]);
2114 hodo[1] = 2 * (quad[3] - quad[1]);
2115 hodo[2] = 2 * (quad[4] - quad[2]);
2116 hodo[3] = 2 * (quad[5] - quad[3]);
2117 return hodo;
2118}
2119
2120function quadraticRootsReal(A, B, C, s) {
2121 if (A == 0) {
2122 if (B == 0) {
2123 s[0] = 0;
2124 return C == 0;
2125 }
2126 s[0] = -C / B;
2127 return 1;
2128 }
2129 /* normal form: x^2 + px + q = 0 */
2130 var p = B / (2 * A);
2131 var q = C / A;
2132 var p2 = p * p;
2133 if (p2 < q) {
2134 return 0;
2135 }
2136 var sqrt_D = 0;
2137 if (p2 > q) {
2138 sqrt_D = sqrt(p2 - q);
2139 }
2140 s[0] = sqrt_D - p;
2141 s[1] = -sqrt_D - p;
2142 return 1 + s[0] != s[1];
2143}
2144
2145function add_valid_ts(s, realRoots, t) {
2146 var foundRoots = 0;
2147 for (var index = 0; index < realRoots; ++index) {
2148 var tValue = s[index];
2149 if (tValue >= 0 && tValue <= 1) {
2150 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2151 if (t[idx2] != tValue) {
2152 t[foundRoots++] = tValue;
2153 }
2154 }
2155 }
2156 }
2157 return foundRoots;
2158}
2159
2160function quadraticRootsValidT(a, b, c, t) {
2161 var s = [];
2162 var realRoots = quadraticRootsReal(A, B, C, s);
2163 var foundRoots = add_valid_ts(s, realRoots, t);
2164 return foundRoots != 0;
2165}
2166
2167function find_cubic_inflections(cubic, tValues) {
2168 var Ax = src[2] - src[0];
2169 var Ay = src[3] - src[1];
2170 var Bx = src[4] - 2 * src[2] + src[0];
2171 var By = src[5] - 2 * src[3] + src[1];
2172 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2173 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2174 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2175 Ax * By - Ay * Bx, tValues);
2176}
2177
2178function dxy_at_t(curve, type, t) {
2179 var dxy = {};
2180 if (type == PATH_QUAD) {
2181 var a = t - 1;
2182 var b = 1 - 2 * t;
2183 var c = t;
2184 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2185 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002186 } else if (type == PATH_CONIC) {
2187 var p20x = curve[4] - curve[0];
2188 var p20y = curve[5] - curve[1];
2189 var p10xw = (curve[2] - curve[0]) * curve[6];
2190 var p10yw = (curve[3] - curve[1]) * curve[6];
2191 var coeff0x = curve[6] * p20x - p20x;
2192 var coeff0y = curve[6] * p20y - p20y;
2193 var coeff1x = p20x - 2 * p10xw;
2194 var coeff1y = p20y - 2 * p10yw;
2195 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2196 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002197 } else if (type == PATH_CUBIC) {
2198 var one_t = 1 - t;
2199 var a = curve[0];
2200 var b = curve[2];
2201 var c = curve[4];
2202 var d = curve[6];
2203 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2204 a = curve[1];
2205 b = curve[3];
2206 c = curve[5];
2207 d = curve[7];
2208 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2209 }
2210 return dxy;
2211}
2212
2213function drawLabel(num, px, py) {
2214 ctx.beginPath();
2215 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2216 ctx.closePath();
2217 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2218 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2219 ctx.stroke();
2220 ctx.fillStyle = "black";
2221 ctx.font = "normal 10px Arial";
2222 // ctx.rotate(0.001);
2223 ctx.fillText(num, px - 2, py + 3);
2224 // ctx.rotate(-0.001);
2225}
2226
2227function drawLabelX(ymin, num, loc) {
2228 var px = (loc - srcLeft) * scale;
2229 var py = (ymin - srcTop) * scale - 20;
2230 drawLabel(num, px, py);
2231}
2232
2233function drawLabelY(xmin, num, loc) {
2234 var px = (xmin - srcLeft) * scale - 20;
2235 var py = (loc - srcTop) * scale;
2236 drawLabel(num, px, py);
2237}
2238
2239function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2240 ctx.beginPath();
2241 ctx.moveTo(hx, hy - 100);
2242 ctx.lineTo(hx, hy);
2243 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2244 ctx.stroke();
2245 ctx.beginPath();
2246 ctx.moveTo(hx, hy);
2247 ctx.lineTo(hx, hy + 100);
2248 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2249 ctx.stroke();
2250 ctx.beginPath();
2251 ctx.moveTo(hx - 100, hy);
2252 ctx.lineTo(hx, hy);
2253 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2254 ctx.stroke();
2255 ctx.beginPath();
2256 ctx.moveTo(hx, hy);
2257 ctx.lineTo(hx + 100, hy);
2258 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2259 ctx.stroke();
2260}
2261
2262function scalexy(x, y, mag) {
2263 var length = Math.sqrt(x * x + y * y);
2264 return mag / length;
2265}
2266
caryclark03b03ca2015-04-23 09:13:37 -07002267function drawArrow(x, y, dx, dy, s) {
2268 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002269 dx *= dscale;
2270 dy *= dscale;
2271 ctx.beginPath();
2272 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2273 x += dx;
2274 y += dy;
2275 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2276 dx /= 10;
2277 dy /= 10;
2278 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2279 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2280 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2281 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2282 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2283 ctx.stroke();
2284}
2285
2286function x_at_t(curve, t) {
2287 var one_t = 1 - t;
2288 if (curve.length == 4) {
2289 return one_t * curve[0] + t * curve[2];
2290 }
2291 var one_t2 = one_t * one_t;
2292 var t2 = t * t;
2293 if (curve.length == 6) {
2294 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2295 }
caryclark1049f122015-04-20 08:31:59 -07002296 if (curve.length == 7) {
2297 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2298 / (one_t2 +2 * one_t * t * curve[6] + t2);
2299 }
caryclarkdac1d172014-06-17 05:15:38 -07002300 var a = one_t2 * one_t;
2301 var b = 3 * one_t2 * t;
2302 var c = 3 * one_t * t2;
2303 var d = t2 * t;
2304 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2305}
2306
2307function y_at_t(curve, t) {
2308 var one_t = 1 - t;
2309 if (curve.length == 4) {
2310 return one_t * curve[1] + t * curve[3];
2311 }
2312 var one_t2 = one_t * one_t;
2313 var t2 = t * t;
2314 if (curve.length == 6) {
2315 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2316 }
caryclark1049f122015-04-20 08:31:59 -07002317 if (curve.length == 7) {
2318 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
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[1] + b * curve[3] + c * curve[5] + d * curve[7];
2326}
2327
2328function drawOrder(curve, label) {
2329 var px = x_at_t(curve, 0.75);
2330 var py = y_at_t(curve, 0.75);
2331 var _px = (px - srcLeft) * scale;
2332 var _py = (py - srcTop) * scale;
2333 ctx.beginPath();
2334 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2335 ctx.closePath();
2336 ctx.fillStyle = "white";
2337 ctx.fill();
2338 if (label == 'L') {
2339 ctx.strokeStyle = "rgba(255,0,0, 1)";
2340 ctx.fillStyle = "rgba(255,0,0, 1)";
2341 } else {
2342 ctx.strokeStyle = "rgba(0,0,255, 1)";
2343 ctx.fillStyle = "rgba(0,0,255, 1)";
2344 }
2345 ctx.stroke();
2346 ctx.font = "normal 16px Arial";
2347 ctx.textAlign = "center";
2348 ctx.fillText(label, _px, _py + 5);
2349 ctx.font = "normal 10px Arial";
2350}
2351
2352function drawID(curve, id) {
2353 var px = x_at_t(curve, 0.5);
2354 var py = y_at_t(curve, 0.5);
2355 var _px = (px - srcLeft) * scale;
2356 var _py = (py - srcTop) * scale;
2357 draw_id_at(id, _px, _py);
2358}
2359
2360function draw_id_at(id, _px, _py) {
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 ctx.strokeStyle = "rgba(127,127,0, 1)";
2367 ctx.fillStyle = "rgba(127,127,0, 1)";
2368 ctx.stroke();
2369 ctx.font = "normal 16px Arial";
2370 ctx.textAlign = "center";
2371 ctx.fillText(id, _px, _py + 5);
2372 ctx.font = "normal 10px Arial";
2373}
2374
2375function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2376 var curve = [x1, y1, x2, y2];
2377 drawCurvePartialID(id, curve, t1, t2);
2378}
2379
2380function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2381 var curve = [x1, y1, x2, y2, x3, y3];
2382 drawCurvePartialID(id, curve, t1, t2);
2383}
2384
caryclark1049f122015-04-20 08:31:59 -07002385function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2386 var curve = [x1, y1, x2, y2, x3, y3, w];
2387 drawCurvePartialID(id, curve, t1, t2);
2388}
2389
caryclarkdac1d172014-06-17 05:15:38 -07002390function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2391 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2392 drawCurvePartialID(id, curve, t1, t2);
2393}
2394
2395function drawCurvePartialID(id, curve, t1, t2) {
2396 var px = x_at_t(curve, (t1 + t2) / 2);
2397 var py = y_at_t(curve, (t1 + t2) / 2);
2398 var _px = (px - srcLeft) * scale;
2399 var _py = (py - srcTop) * scale;
2400 draw_id_at(id, _px, _py);
2401}
2402
2403function drawCurveSpecials(test, curve, type) {
2404 if (pt_labels) {
2405 drawPoints(curve, type, pt_labels == 2);
2406 }
2407 if (control_lines != 0) {
2408 drawControlLines(curve, type, control_lines);
2409 }
2410 if (curve_t) {
2411 drawPointAtT(curve, type);
2412 }
2413 if (draw_midpoint) {
2414 var mid = pointAtT(curve, type, 0.5);
2415 drawPoint(mid.x, mid.y, true);
2416 }
2417 if (draw_id) {
2418 var id = idByCurve(test, curve, type);
2419 if (id >= 0) {
2420 drawID(curve, id);
2421 }
2422 }
2423 if (type == PATH_LINE) {
2424 return;
2425 }
2426 if (draw_deriviatives > 0) {
2427 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002428 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002429 if (draw_deriviatives == 2) {
2430 d = dxy_at_t(curve, type, 1);
2431 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002432 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002433 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002434 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002435 }
2436 }
2437 if (draw_midpoint) {
2438 var mid = pointAtT(curve, type, 0.5);
2439 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002440 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002441 }
2442 }
2443 if (type != PATH_CUBIC) {
2444 return;
2445 }
caryclarkdac1d172014-06-17 05:15:38 -07002446 if (draw_sequence) {
2447 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2448 for (var i = 0; i < 8; i+= 2) {
2449 drawLabelX(ymin, i >> 1, curve[i]);
2450 }
2451 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2452 for (var i = 1; i < 8; i+= 2) {
2453 drawLabelY(xmin, i >> 1, curve[i]);
2454 }
2455 }
2456}
2457
2458function logCurves(test) {
2459 for (curves in test) {
2460 var curve = test[curves];
2461 dumpCurve(curve);
2462 }
2463}
2464
2465function curveToString(curve) {
2466 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002467 var length = curve.length == 7 ? 6 : curve.length;
2468 if (curve.length == 7) {
2469 str += "{";
2470 }
2471 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002472 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2473 if (i < curve.length - 2) {
2474 str += "}, {";
2475 }
2476 }
caryclark1049f122015-04-20 08:31:59 -07002477 str += "}";
2478 if (curve.length == 7) {
2479 str += "}, " + curve[6].toFixed(decimal_places);
2480 }
2481 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002482 return str;
2483}
2484
2485function dumpCurve(curve) {
2486 console.log(curveToString(curve));
2487}
2488
2489function draw(test, lines, title) {
2490 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2491 ctx.font = "normal 50px Arial";
2492 ctx.textAlign = "left";
2493 ctx.fillText(title, 50, 50);
2494 ctx.font = "normal 10px Arial";
2495 ctx.lineWidth = "1.001"; "0.999";
2496 var secondPath = test.length;
2497 var closeCount = 0;
2498 logStart = -1;
2499 logRange = 0;
2500 // find last active rec type at this step
2501 var curType = test[0];
2502 var curStep = 0;
2503 var hasOp = false;
2504 var lastActive = 0;
2505 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002506 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002507 var lastSect = 0;
2508 var lastSort = 0;
2509 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002510 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002511 activeCount = 0;
2512 addCount = 0;
2513 angleCount = 0;
2514 opCount = 0;
2515 sectCount = 0;
2516 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002517 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002518 markCount = 0;
2519 activeMax = 0;
2520 addMax = 0;
2521 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002522 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002523 opMax = 0;
2524 sectMax = 0;
2525 sectMax2 = 0;
2526 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002527 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002528 markMax = 0;
2529 lastIndex = test.length - 3;
2530 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2531 var recType = test[tIndex];
2532 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2533 console.log("unknown rec type: " + recType);
2534 throw "stop execution";
2535 }
2536 // if (curType == recType && curType != REC_TYPE_ADD) {
2537 // continue;
2538 // }
2539 var inStepRange = step_limit == 0 || curStep < step_limit;
2540 curType = recType;
2541 if (recType == REC_TYPE_OP) {
2542 hasOp = true;
2543 continue;
2544 }
2545 if (recType == REC_TYPE_UNKNOWN) {
2546 // these types do not advance step
2547 continue;
2548 }
2549 var bumpStep = false;
2550 var records = test[tIndex + 2];
2551 var fragType = records[0];
2552 if (recType == REC_TYPE_ADD) {
2553 if (records.length != 2) {
2554 console.log("expect only two elements: " + records.length);
2555 throw "stop execution";
2556 }
2557 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2558 continue;
2559 }
2560 ++addMax;
2561 if (!draw_add || !inStepRange) {
2562 continue;
2563 }
2564 lastAdd = tIndex;
2565 ++addCount;
2566 bumpStep = true;
2567 }
2568 if (recType == REC_TYPE_PATH && hasOp) {
2569 secondPath = tIndex;
2570 }
caryclark54359292015-03-26 07:52:43 -07002571 if (recType == REC_TYPE_PATH2 && hasOp) {
2572 secondPath = tIndex;
2573 }
caryclarkdac1d172014-06-17 05:15:38 -07002574 if (recType == REC_TYPE_ACTIVE) {
2575 ++activeMax;
2576 if (!draw_active || !inStepRange) {
2577 continue;
2578 }
2579 lastActive = tIndex;
2580 ++activeCount;
2581 bumpStep = true;
2582 }
2583 if (recType == REC_TYPE_ACTIVE_OP) {
2584 ++opMax;
2585 if (!draw_op || !inStepRange) {
2586 continue;
2587 }
2588 lastOp = tIndex;
2589 ++opCount;
2590 bumpStep = true;
2591 }
caryclark54359292015-03-26 07:52:43 -07002592 if (recType == REC_TYPE_AFTERPART) {
2593 if (draw_angle != 3 || !inStepRange) {
2594 continue;
2595 }
2596 lastAngle = tIndex;
2597 ++angleCount;
2598 bumpStep = true;
2599 }
caryclarkdac1d172014-06-17 05:15:38 -07002600 if (recType == REC_TYPE_ANGLE) {
2601 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002602 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002603 continue;
2604 }
2605 lastAngle = tIndex;
2606 ++angleCount;
2607 bumpStep = true;
2608 }
caryclark624637c2015-05-11 07:21:27 -07002609 if (recType == REC_TYPE_COINCIDENCE) {
2610 ++coinMax;
2611 if (!draw_coincidence || !inStepRange) {
2612 continue;
2613 }
2614 lastCoin = tIndex;
2615 ++coinCount;
2616 bumpStep = true;
2617 }
caryclarkdac1d172014-06-17 05:15:38 -07002618 if (recType == REC_TYPE_SECT) {
2619 if (records.length != 2) {
2620 console.log("expect only two elements: " + records.length);
2621 throw "stop execution";
2622 }
2623 ++sectMax;
2624 var sectBump = 1;
2625 switch (fragType) {
2626 case INTERSECT_LINE:
2627 case INTERSECT_QUAD_LINE:
2628 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002629 case INTERSECT_CONIC_LINE:
2630 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002631 case INTERSECT_SELF_CUBIC:
2632 case INTERSECT_CUBIC_LINE:
2633 case INTERSECT_CUBIC_QUAD:
2634 case INTERSECT_CUBIC:
2635 sectBump = 1;
2636 break;
2637 case INTERSECT_LINE_2:
2638 case INTERSECT_QUAD_LINE_2:
2639 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002640 case INTERSECT_CONIC_LINE_2:
2641 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002642 case INTERSECT_CUBIC_LINE_2:
2643 case INTERSECT_CUBIC_QUAD_2:
2644 case INTERSECT_CUBIC_2:
2645 sectBump = 2;
2646 break;
2647 case INTERSECT_LINE_NO:
2648 case INTERSECT_QUAD_LINE_NO:
2649 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002650 case INTERSECT_CONIC_LINE_NO:
2651 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002652 case INTERSECT_SELF_CUBIC_NO:
2653 case INTERSECT_CUBIC_LINE_NO:
2654 case INTERSECT_CUBIC_QUAD_NO:
2655 case INTERSECT_CUBIC_NO:
2656 sectBump = 0;
2657 break;
2658 case INTERSECT_CUBIC_LINE_3:
2659 case INTERSECT_CUBIC_QUAD_3:
2660 case INTERSECT_CUBIC_3:
2661 sectBump = 3;
2662 break;
2663 case INTERSECT_CUBIC_QUAD_4:
2664 case INTERSECT_CUBIC_4:
2665 sectBump = 4;
2666 break;
2667 default:
2668 console.log("missing case " + records.length);
2669 throw "stop execution";
2670 }
2671 sectMax2 += sectBump;
2672 if (draw_intersection <= 1 || !inStepRange) {
2673 continue;
2674 }
2675 lastSect = tIndex;
2676 sectCount += sectBump;
2677 bumpStep = true;
2678 }
2679 if (recType == REC_TYPE_SORT) {
2680 ++sortMax;
2681 if (!draw_sort || !inStepRange) {
2682 continue;
2683 }
2684 lastSort = tIndex;
2685 ++sortCount;
2686 bumpStep = true;
2687 }
caryclark03b03ca2015-04-23 09:13:37 -07002688 if (recType == REC_TYPE_TOP) {
2689 ++topMax;
2690 if (!draw_top || !inStepRange) {
2691 continue;
2692 }
2693 lastTop = tIndex;
2694 ++topCount;
2695 bumpStep = true;
2696 }
caryclarkdac1d172014-06-17 05:15:38 -07002697 if (recType == REC_TYPE_MARK) {
2698 ++markMax;
2699 if (!draw_mark || !inStepRange) {
2700 continue;
2701 }
2702 lastMark = tIndex;
2703 ++markCount;
2704 bumpStep = true;
2705 }
2706 if (bumpStep) {
2707 lastIndex = tIndex;
2708 logStart = test[tIndex + 1];
2709 logRange = records.length / 2;
2710 ++curStep;
2711 }
2712 }
2713 stepMax = (draw_add ? addMax : 0)
2714 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002715 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002716 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002717 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002718 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002719 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002720 + (draw_mark ? markMax : 0)
2721 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2722 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002723 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002724 }
2725 drawnPts = [];
2726 drawnLines = [];
2727 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002728 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002729 drawnCubics = [];
2730 focusXmin = focusYmin = Infinity;
2731 focusXmax = focusYmax = -Infinity;
2732 var pathIndex = 0;
2733 var opLetter = 'S';
2734 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2735 var recType = test[tIndex];
2736 var records = test[tIndex + 2];
2737 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2738 var fragType = records[recordIndex];
2739 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2740 console.log("unknown in range frag type: " + fragType);
2741 throw "stop execution";
2742 }
2743 var frags = records[recordIndex + 1];
2744 focus_enabled = false;
2745 switch (recType) {
2746 case REC_TYPE_COMPUTED:
2747 if (draw_computed == 0) {
2748 continue;
2749 }
2750 ctx.lineWidth = 1;
2751 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2752 ctx.fillStyle = "blue";
2753 var drawThis = false;
2754 switch (fragType) {
2755 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002756 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2757 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002758 drawQuad(frags[0], frags[1], frags[2], frags[3],
2759 frags[4], frags[5]);
2760 drawThis = true;
2761 }
2762 break;
caryclark1049f122015-04-20 08:31:59 -07002763 case PATH_CONIC:
2764 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2765 && (draw_computed & 7) == pathIndex)) {
2766 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2767 frags[4], frags[5], frags[6]);
2768 drawThis = true;
2769 }
2770 break;
caryclarkdac1d172014-06-17 05:15:38 -07002771 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002772 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2773 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002774 drawCubic(frags[0], frags[1], frags[2], frags[3],
2775 frags[4], frags[5], frags[6], frags[7]);
2776 drawThis = true;
2777 }
2778 ++pathIndex;
2779 break;
2780 case COMPUTED_SET_1:
2781 pathIndex = 0;
2782 break;
2783 case COMPUTED_SET_2:
2784 pathIndex = 1;
2785 break;
2786 default:
2787 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2788 throw "stop execution";
2789 }
2790 if (!drawThis || collect_bounds) {
2791 break;
2792 }
2793 drawCurveSpecials(test, frags, fragType);
2794 break;
caryclark26ad22a2015-10-16 09:03:38 -07002795 case REC_TYPE_ALIGNED:
2796 if (draw_path < 4) {
2797 continue;
2798 }
caryclarkdac1d172014-06-17 05:15:38 -07002799 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002800 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07002801 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
2802 continue;
2803 }
caryclarkdac1d172014-06-17 05:15:38 -07002804 if (!draw_path) {
2805 continue;
2806 }
2807 var firstPath = tIndex < secondPath;
2808 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2809 continue;
2810 }
2811 ctx.lineWidth = 1;
2812 ctx.strokeStyle = firstPath ? "black" : "red";
2813 ctx.fillStyle = "blue";
caryclark54359292015-03-26 07:52:43 -07002814 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002815 switch (fragType) {
2816 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002817 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2818 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002819 break;
2820 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002821 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2822 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2823 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002824 break;
caryclark1049f122015-04-20 08:31:59 -07002825 case PATH_CONIC:
2826 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2827 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2828 frags2[4], frags2[5], frags2[6]);
2829 break;
caryclarkdac1d172014-06-17 05:15:38 -07002830 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002831 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2832 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2833 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07002834 break;
2835 default:
caryclark26ad22a2015-10-16 09:03:38 -07002836 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002837 throw "stop execution";
2838 }
2839 if (collect_bounds) {
2840 break;
2841 }
caryclark54359292015-03-26 07:52:43 -07002842 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002843 break;
2844 case REC_TYPE_OP:
2845 switch (fragType) {
2846 case OP_INTERSECT: opLetter = 'I'; break;
2847 case OP_DIFFERENCE: opLetter = 'D'; break;
2848 case OP_UNION: opLetter = 'U'; break;
2849 case OP_XOR: opLetter = 'X'; break;
2850 default:
2851 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2852 throw "stop execution";
2853 }
2854 break;
2855 case REC_TYPE_ACTIVE:
2856 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2857 continue;
2858 }
2859 var x1 = frags[SPAN_X1];
2860 var y1 = frags[SPAN_Y1];
2861 var x2 = frags[SPAN_X2];
2862 var y2 = frags[SPAN_Y2];
caryclark1049f122015-04-20 08:31:59 -07002863 var x3, y3, x3, y4, t1, t2, w;
caryclarkdac1d172014-06-17 05:15:38 -07002864 ctx.lineWidth = 3;
2865 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2866 focus_enabled = true;
2867 switch (fragType) {
2868 case ACTIVE_LINE_SPAN:
2869 t1 = frags[SPAN_L_T];
2870 t2 = frags[SPAN_L_TEND];
2871 drawLinePartial(x1, y1, x2, y2, t1, t2);
2872 if (draw_id) {
2873 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
2874 }
2875 break;
2876 case ACTIVE_QUAD_SPAN:
2877 x3 = frags[SPAN_X3];
2878 y3 = frags[SPAN_Y3];
2879 t1 = frags[SPAN_Q_T];
2880 t2 = frags[SPAN_Q_TEND];
2881 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
2882 if (draw_id) {
2883 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
2884 }
2885 break;
caryclark1049f122015-04-20 08:31:59 -07002886 case ACTIVE_CONIC_SPAN:
2887 x3 = frags[SPAN_X3];
2888 y3 = frags[SPAN_Y3];
2889 t1 = frags[SPAN_K_T];
2890 t2 = frags[SPAN_K_TEND];
2891 w = frags[SPAN_K_W];
2892 drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
2893 if (draw_id) {
2894 drawConicPartialID(frags[0], x1, y1, x2, y2, x3, y3, w, t1, t2);
2895 }
2896 break;
caryclarkdac1d172014-06-17 05:15:38 -07002897 case ACTIVE_CUBIC_SPAN:
2898 x3 = frags[SPAN_X3];
2899 y3 = frags[SPAN_Y3];
2900 x4 = frags[SPAN_X4];
2901 y4 = frags[SPAN_Y4];
2902 t1 = frags[SPAN_C_T];
2903 t2 = frags[SPAN_C_TEND];
2904 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2905 if (draw_id) {
2906 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2907 }
2908 break;
2909 default:
2910 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2911 throw "stop execution";
2912 }
2913 break;
2914 case REC_TYPE_ACTIVE_OP:
2915 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2916 continue;
2917 }
2918 focus_enabled = true;
2919 ctx.lineWidth = 3;
2920 var activeSpan = frags[7] == "1";
2921 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2922 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2923 drawCurve(curve);
2924 if (draw_op > 1) {
2925 drawArc(curve, false, frags[3], frags[4]);
2926 drawArc(curve, true, frags[5], frags[6]);
2927 }
2928 break;
2929 case REC_TYPE_ADD:
2930 if (!draw_add) {
2931 continue;
2932 }
2933 ctx.lineWidth = 3;
2934 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2935 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2936 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2937 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2938 : "rgba(127,0,127, 0.3)";
2939 focus_enabled = true;
2940 switch (fragType) {
2941 case ADD_MOVETO:
2942 break;
2943 case ADD_LINETO:
2944 if (step_limit == 0 || tIndex >= lastAdd) {
2945 drawLine(frags[0], frags[1], frags[2], frags[3]);
2946 }
2947 break;
2948 case ADD_QUADTO:
2949 if (step_limit == 0 || tIndex >= lastAdd) {
2950 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2951 }
2952 break;
caryclark1049f122015-04-20 08:31:59 -07002953 case ADD_CONICTO:
2954 if (step_limit == 0 || tIndex >= lastAdd) {
2955 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2956 frags[4], frags[5], frags[6]);
2957 }
2958 break;
caryclarkdac1d172014-06-17 05:15:38 -07002959 case ADD_CUBICTO:
2960 if (step_limit == 0 || tIndex >= lastAdd) {
2961 drawCubic(frags[0], frags[1], frags[2], frags[3],
2962 frags[4], frags[5], frags[6], frags[7]);
2963 }
2964 break;
2965 case ADD_CLOSE:
2966 ++closeCount;
2967 break;
2968 case ADD_FILL:
2969 break;
2970 default:
2971 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2972 throw "stop execution";
2973 }
2974 break;
2975 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07002976 angleBetween = frags[18] == "T";
2977 afterIndex = 0;
2978 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07002979 continue;
2980 }
2981 focus_enabled = true;
2982 ctx.lineWidth = 3;
2983 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07002984 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2985 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2986 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07002987 drawCurve(leftCurve);
2988 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07002989 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07002990 drawCurve(midCurve);
2991 if (draw_angle > 1) {
2992 drawOrder(leftCurve, 'L');
2993 drawOrder(rightCurve, 'R');
2994 }
2995 break;
caryclark54359292015-03-26 07:52:43 -07002996 case REC_TYPE_AFTERPART:
2997 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
2998 continue;
2999 }
3000 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
3001 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
3002 : "rgba(0,0,255, 1.0)";
3003 switch (fragType) {
3004 case PATH_LINE:
3005 drawLine(frags[0], frags[1], frags[2], frags[3]);
3006 break;
3007 case PATH_QUAD:
3008 drawQuad(frags[0], frags[1], frags[2], frags[3],
3009 frags[4], frags[5]);
3010 break;
caryclark1049f122015-04-20 08:31:59 -07003011 case PATH_CONIC:
3012 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
3013 frags[4], frags[5], frags[6]);
3014 break;
caryclark54359292015-03-26 07:52:43 -07003015 case PATH_CUBIC:
3016 drawCubic(frags[0], frags[1], frags[2], frags[3],
caryclark1049f122015-04-20 08:31:59 -07003017 frags[4], frags[5], frags[6], frags[7]);
caryclark54359292015-03-26 07:52:43 -07003018 break;
3019 default:
3020 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
3021 throw "stop execution";
3022 }
3023 ++afterIndex;
3024 break;
caryclark624637c2015-05-11 07:21:27 -07003025 case REC_TYPE_COINCIDENCE:
3026 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
3027 continue;
3028 }
3029 focus_enabled = true;
3030 ctx.lineWidth = 3;
3031 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
3032 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3033 drawCurve(curve);
3034 break;
caryclarkdac1d172014-06-17 05:15:38 -07003035 case REC_TYPE_SECT:
3036 if (!draw_intersection) {
3037 continue;
3038 }
3039 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
3040 continue;
3041 }
3042 // draw_intersection == 1 : show all
3043 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
3044 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
3045 ctx.lineWidth = 1;
3046 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3047 ctx.fillStyle = "blue";
3048 focus_enabled = true;
3049 var f = [];
3050 var c1s;
3051 var c1l;
3052 var c2s;
3053 var c2l;
3054 switch (fragType) {
3055 case INTERSECT_LINE:
3056 f.push(5, 6, 0, 7);
3057 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
3058 break;
3059 case INTERSECT_LINE_2:
3060 f.push(5, 6, 0, 10);
3061 f.push(8, 9, 7, 15);
3062 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
3063 break;
3064 case INTERSECT_LINE_NO:
3065 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
3066 break;
3067 case INTERSECT_QUAD_LINE:
3068 f.push(7, 8, 0, 9);
3069 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
3070 break;
3071 case INTERSECT_QUAD_LINE_2:
3072 f.push(7, 8, 0, 12);
3073 f.push(10, 11, 9, 17);
3074 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
3075 break;
3076 case INTERSECT_QUAD_LINE_NO:
3077 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
3078 break;
3079 case INTERSECT_QUAD:
3080 f.push(7, 8, 0, 9);
3081 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
3082 break;
3083 case INTERSECT_QUAD_2:
3084 f.push(7, 8, 0, 12);
3085 f.push(10, 11, 9, 19);
3086 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
3087 break;
3088 case INTERSECT_QUAD_NO:
3089 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
3090 break;
caryclark1049f122015-04-20 08:31:59 -07003091 case INTERSECT_CONIC_LINE:
3092 f.push(8, 9, 0, 10);
3093 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
3094 break;
3095 case INTERSECT_CONIC_LINE_2:
3096 f.push(8, 9, 0, 12);
3097 f.push(11, 12, 10, 18);
3098 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3099 break;
3100 case INTERSECT_CONIC_LINE_NO:
3101 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3102 break;
3103 case INTERSECT_CONIC:
3104 f.push(8, 9, 0, 10);
3105 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3106 break;
3107 case INTERSECT_CONIC_2:
3108 f.push(8, 9, 0, 13);
3109 f.push(11, 12, 10, 21);
3110 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3111 break;
3112 case INTERSECT_CONIC_NO:
3113 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3114 break;
caryclarkdac1d172014-06-17 05:15:38 -07003115 case INTERSECT_SELF_CUBIC:
3116 f.push(9, 10, 0, 11);
3117 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3118 break;
3119 case INTERSECT_SELF_CUBIC_NO:
3120 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3121 break;
3122 case INTERSECT_CUBIC_LINE:
3123 f.push(9, 10, 0, 11);
3124 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3125 break;
3126 case INTERSECT_CUBIC_LINE_2:
3127 f.push(9, 10, 0, 14);
3128 f.push(12, 13, 11, 19);
3129 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3130 break;
3131 case INTERSECT_CUBIC_LINE_3:
3132 f.push(9, 10, 0, 17);
3133 f.push(12, 13, 11, 22);
3134 f.push(15, 16, 14, 23);
3135 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3136 break;
3137 case INTERSECT_CUBIC_QUAD_NO:
3138 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3139 break;
3140 case INTERSECT_CUBIC_QUAD:
3141 f.push(9, 10, 0, 11);
3142 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3143 break;
3144 case INTERSECT_CUBIC_QUAD_2:
3145 f.push(9, 10, 0, 14);
3146 f.push(12, 13, 11, 21);
3147 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3148 break;
3149 case INTERSECT_CUBIC_QUAD_3:
3150 f.push(9, 10, 0, 17);
3151 f.push(12, 13, 11, 24);
3152 f.push(15, 16, 14, 25);
3153 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3154 break;
3155 case INTERSECT_CUBIC_QUAD_4:
3156 f.push(9, 10, 0, 20);
3157 f.push(12, 13, 11, 27);
3158 f.push(15, 16, 14, 28);
3159 f.push(18, 19, 17, 29);
3160 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3161 break;
3162 case INTERSECT_CUBIC_LINE_NO:
3163 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3164 break;
3165 case INTERSECT_CUBIC:
3166 f.push(9, 10, 0, 11);
3167 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3168 break;
3169 case INTERSECT_CUBIC_2:
3170 f.push(9, 10, 0, 14);
3171 f.push(12, 13, 11, 23);
3172 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3173 break;
3174 case INTERSECT_CUBIC_3:
3175 f.push(9, 10, 0, 17);
3176 f.push(12, 13, 11, 26);
3177 f.push(15, 16, 14, 27);
3178 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3179 break;
3180 case INTERSECT_CUBIC_4:
3181 f.push(9, 10, 0, 20);
3182 f.push(12, 13, 11, 29);
3183 f.push(15, 16, 14, 30);
3184 f.push(18, 19, 17, 31);
3185 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3186 break;
3187 case INTERSECT_CUBIC_NO:
3188 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3189 break;
3190 default:
3191 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3192 throw "stop execution";
3193 }
3194 if (draw_intersection != 1) {
3195 var id = -1;
3196 var curve;
3197 switch (c1l) {
3198 case 4:
3199 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3200 if (draw_id) {
3201 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3202 id = idByCurve(test, curve, PATH_LINE);
3203 }
3204 break;
3205 case 6:
3206 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3207 frags[c1s + 4], frags[c1s + 5]);
3208 if (draw_id) {
3209 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3210 frags[c1s + 4], frags[c1s + 5]];
3211 id = idByCurve(test, curve, PATH_QUAD);
3212 }
3213 break;
caryclark1049f122015-04-20 08:31:59 -07003214 case 7:
3215 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3216 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3217 if (draw_id) {
3218 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3219 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3220 id = idByCurve(test, curve, PATH_CONIC);
3221 }
3222 break;
caryclarkdac1d172014-06-17 05:15:38 -07003223 case 8:
3224 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3225 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3226 if (draw_id) {
3227 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3228 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3229 id = idByCurve(test, curve, PATH_CUBIC);
3230 }
3231 break;
3232 }
3233 if (id >= 0) {
3234 drawID(curve, id);
3235 }
3236 id = -1;
3237 switch (c2l) {
3238 case 0:
3239 break;
3240 case 4:
3241 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3242 if (draw_id) {
3243 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3244 id = idByCurve(test, curve, PATH_LINE);
3245 }
3246 break;
3247 case 6:
3248 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3249 frags[c2s + 4], frags[c2s + 5]);
3250 if (draw_id) {
3251 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3252 frags[c2s + 4], frags[c2s + 5]];
3253 id = idByCurve(test, curve, PATH_QUAD);
3254 }
3255 break;
caryclark1049f122015-04-20 08:31:59 -07003256 case 7:
3257 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3258 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3259 if (draw_id) {
3260 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3261 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3262 id = idByCurve(test, curve, PATH_CONIC);
3263 }
3264 break;
caryclarkdac1d172014-06-17 05:15:38 -07003265 case 8:
3266 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3267 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3268 if (draw_id) {
3269 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3270 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3271 id = idByCurve(test, curve, PATH_CUBIC);
3272 }
3273 break;
3274 }
3275 if (id >= 0) {
3276 drawID(curve, id);
3277 }
3278 }
3279 if (collect_bounds) {
3280 break;
3281 }
caryclark54359292015-03-26 07:52:43 -07003282 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3283 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003284 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3285 }
3286 }
3287 if (!draw_intersectT) {
3288 break;
3289 }
3290 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003291 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3292 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003293 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3294 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3295 }
3296 }
3297 break;
3298 case REC_TYPE_SORT:
3299 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3300 continue;
3301 }
3302 ctx.lineWidth = 3;
3303 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3304 focus_enabled = true;
3305 switch (fragType) {
3306 case SORT_UNARY:
3307 case SORT_BINARY:
3308 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3309 drawCurve(curve);
3310 break;
3311 default:
3312 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3313 throw "stop execution";
3314 }
3315 break;
caryclark03b03ca2015-04-23 09:13:37 -07003316 case REC_TYPE_TOP:
3317 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3318 continue;
3319 }
3320 ctx.lineWidth = 3;
3321 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3322 focus_enabled = true;
3323 {
3324 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3325 drawCurve(curve);
3326 var type = PATH_LINE + (curve.length / 2 - 2);
3327 var mid = pointAtT(curve, type, 0.5);
3328 var d = dxy_at_t(curve, type, 0.5);
3329 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3330 }
3331 break;
caryclarkdac1d172014-06-17 05:15:38 -07003332 case REC_TYPE_MARK:
3333 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3334 continue;
3335 }
3336 ctx.lineWidth = 3;
3337 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3338 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3339 focus_enabled = true;
3340 switch (fragType) {
3341 case MARK_LINE:
3342 case MARK_DONE_LINE:
3343 case MARK_UNSORTABLE_LINE:
3344 case MARK_SIMPLE_LINE:
3345 case MARK_SIMPLE_DONE_LINE:
3346 case MARK_DONE_UNARY_LINE:
3347 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3348 frags[5], frags[9]);
3349 if (draw_id) {
3350 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3351 frags[5], frags[9]);
3352 }
3353 break;
3354 case MARK_QUAD:
3355 case MARK_DONE_QUAD:
3356 case MARK_UNSORTABLE_QUAD:
3357 case MARK_SIMPLE_QUAD:
3358 case MARK_SIMPLE_DONE_QUAD:
3359 case MARK_DONE_UNARY_QUAD:
3360 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3361 frags[5], frags[6], frags[7], frags[11]);
3362 if (draw_id) {
3363 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3364 frags[5], frags[6], frags[7], frags[11]);
3365 }
3366 break;
3367 case MARK_CUBIC:
3368 case MARK_DONE_CUBIC:
3369 case MARK_UNSORTABLE_CUBIC:
3370 case MARK_SIMPLE_CUBIC:
3371 case MARK_SIMPLE_DONE_CUBIC:
3372 case MARK_DONE_UNARY_CUBIC:
3373 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3374 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3375 if (draw_id) {
3376 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3377 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3378 }
3379 break;
3380 case MARK_ANGLE_LAST:
3381 // FIXME: ignored for now
3382 break;
3383 default:
3384 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3385 throw "stop execution";
3386 }
3387 break;
3388 default:
3389 continue;
3390 }
3391 }
3392 switch (recType) {
3393 case REC_TYPE_SORT:
3394 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3395 break;
3396 }
3397 var angles = []; // use tangent lines to describe arcs
3398 var windFrom = [];
3399 var windTo = [];
3400 var opp = [];
3401 var minXY = Number.MAX_VALUE;
3402 var partial;
3403 focus_enabled = true;
3404 var someUnsortable = false;
3405 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3406 var fragType = records[recordIndex];
3407 var frags = records[recordIndex + 1];
3408 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3409 (fragType == SORT_BINARY && frags[16]);
3410 someUnsortable |= unsortable;
3411 switch (fragType) {
3412 case SORT_UNARY:
3413 case SORT_BINARY:
3414 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3415 break;
3416 default:
3417 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3418 throw "stop execution";
3419 }
3420 var dx = boundsWidth(partial);
3421 var dy = boundsHeight(partial);
3422 minXY = Math.min(minXY, dx * dx + dy * dy);
3423 if (collect_bounds) {
3424 continue;
3425 }
3426 angles.push(tangent(partial));
3427 var from = frags[12];
3428 var to = frags[12];
3429 var sgn = frags[10];
3430 if (sgn < 0) {
3431 from -= frags[11];
3432 } else if (sgn > 0) {
3433 to -= frags[11];
3434 }
3435 windFrom.push(from + (unsortable ? "!" : ""));
3436 windTo.push(to + (unsortable ? "!" : ""));
3437 opp.push(fragType == SORT_BINARY);
3438 if (draw_sort == 1) {
3439 drawOrder(partial, frags[12]);
3440 } else {
3441 drawOrder(partial, (recordIndex / 2) + 1);
3442 }
3443 }
3444 var radius = Math.sqrt(minXY) / 2 * scale;
3445 radius = Math.min(50, radius);
3446 var scaledRadius = radius / scale;
3447 var centerX = partial[0];
3448 var centerY = partial[1];
3449 if (collect_bounds) {
3450 if (focus_enabled) {
3451 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3452 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3453 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3454 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3455 }
3456 break;
3457 }
3458 break;
3459 default:
3460 break;
3461 }
3462 }
3463 if (collect_bounds) {
3464 return;
3465 }
3466 if (draw_log && logStart >= 0) {
3467 ctx.font = "normal 10px Arial";
3468 ctx.textAlign = "left";
3469 ctx.beginPath();
3470 var top = screenHeight - 20 - (logRange + 2) * 10;
3471 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3472 ctx.fillStyle = "white";
3473 ctx.fill();
3474 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3475 if (logStart > 0) {
3476 ctx.fillText(lines[logStart - 1], 50, top + 8);
3477 }
3478 ctx.fillStyle = "black";
3479 for (var idx = 0; idx < logRange; ++idx) {
3480 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3481 }
3482 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3483 if (logStart + logRange < lines.length) {
3484 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3485 }
3486 }
3487 if (draw_legend) {
3488 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003489 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003490 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3491 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3492 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3493 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3494 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003495 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003496 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3497 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003498 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003499 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
3500 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003501 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003502 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3503 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3504 draw_computed != 0, computedKey);
3505 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3506 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3507 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3508 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3509 if (curve_t) {
3510 drawCurveTControl();
3511 }
3512 ctx.font = "normal 20px Arial";
3513 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3514 ctx.textAlign = "right";
3515 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3516 }
3517 if (draw_hints) {
3518 ctx.font = "normal 10px Arial";
3519 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3520 ctx.textAlign = "right";
3521 var y = 4;
3522 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3523 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3524 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3525 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003526 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3527 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3528 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3529 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3530 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3531 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3532 }
3533}
3534
3535function drawBox(y, backC, foreC, str, enable, label) {
3536 ctx.beginPath();
3537 ctx.fillStyle = backC;
3538 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3539 ctx.fill();
3540 ctx.font = "normal 16px Arial";
3541 ctx.fillStyle = foreC;
3542 ctx.textAlign = "center";
3543 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3544 if (!enable) {
3545 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3546 ctx.fill();
3547 }
3548 if (label != '') {
3549 ctx.font = "normal 9px Arial";
3550 ctx.fillStyle = "black";
3551 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3552 }
3553}
3554
3555function drawCurveTControl() {
3556 ctx.lineWidth = 2;
3557 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3558 ctx.beginPath();
3559 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3560 ctx.stroke();
3561 var ty = 40 + curveT * (screenHeight - 80);
3562 ctx.beginPath();
3563 ctx.moveTo(screenWidth - 80, ty);
3564 ctx.lineTo(screenWidth - 85, ty - 5);
3565 ctx.lineTo(screenWidth - 85, ty + 5);
3566 ctx.lineTo(screenWidth - 80, ty);
3567 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3568 ctx.fill();
3569 var num = curveT.toFixed(decimal_places);
3570 ctx.font = "normal 10px Arial";
3571 ctx.textAlign = "left";
3572 ctx.fillText(num, screenWidth - 78, ty);
3573}
3574
3575function ptInTControl() {
3576 var e = window.event;
3577 var tgt = e.target || e.srcElement;
3578 var left = tgt.offsetLeft;
3579 var top = tgt.offsetTop;
3580 var x = (e.clientX - left);
3581 var y = (e.clientY - top);
3582 if (x < screenWidth - 80 || x > screenWidth - 50) {
3583 return false;
3584 }
3585 if (y < 40 || y > screenHeight - 80) {
3586 return false;
3587 }
3588 curveT = (y - 40) / (screenHeight - 120);
3589 if (curveT < 0 || curveT > 1) {
3590 throw "stop execution";
3591 }
3592 return true;
3593}
3594
3595function drawTop() {
3596 if (tests[testIndex] == null) {
3597 var str = testDivs[testIndex].textContent;
3598 parse_all(str);
3599 var title = testDivs[testIndex].id.toString();
3600 testTitles[testIndex] = title;
3601 }
3602 init(tests[testIndex]);
3603 redraw();
3604}
3605
3606function redraw() {
3607 if (focus_on_selection) {
3608 collect_bounds = true;
3609 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3610 collect_bounds = false;
3611 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3612 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3613 }
3614 }
3615 ctx.beginPath();
3616 ctx.fillStyle = "white";
3617 ctx.rect(0, 0, screenWidth, screenHeight);
3618 ctx.fill();
3619 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3620}
3621
3622function dumpCurvePartial(test, id, t0, t1) {
3623 var curve = curveByID(test, id);
3624 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3625 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3626 + " t0=" + t0 + " t1=" + t1
3627 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3628}
3629
3630function dumpAngleTest(test, id, t0, t1) {
3631 var curve = curveByID(test, id);
3632 console.log(" { {" + curveToString(curve) + "}, "
3633 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3634}
3635
3636function dumpLogToConsole() {
3637 if (logStart < 0) {
3638 return;
3639 }
3640 var test = tests[testIndex];
3641 var recType = REC_TYPE_UNKNOWN;
3642 var records;
3643 for (var index = 0; index < test.length; index += 3) {
3644 var lastLineNo = test[index + 1];
3645 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3646 recType = test[index];
3647 records = test[index + 2];
3648 break;
3649 }
3650 }
3651 if (recType == REC_TYPE_UNKNOWN) {
3652 return;
3653 }
3654 var lines = testLines[testIndex];
3655 for (var idx = 0; idx < logRange; ++idx) {
3656 var line = lines[logStart + idx];
3657 console.log(line);
3658 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3659 var fragType = records[recordIndex];
3660 var frags = records[recordIndex + 1];
3661 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003662 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3663 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3664 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3665 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3666 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3667 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3668 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3669 console.log("}; //");
3670 }
3671 }
3672 }
3673}
3674
3675var activeKey = 'a';
3676var pathKey = 'b';
3677var pathBackKey = 'B';
3678var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003679var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003680var addKey = 'd';
3681var deriviativesKey = 'f';
3682var angleKey = 'g';
3683var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003684var intersectionKey = 'i';
3685var intersectionBackKey = 'I';
3686var sequenceKey = 'j';
3687var midpointKey = 'k';
3688var logKey = 'l';
3689var logToConsoleKey = 'L';
3690var markKey = 'm';
3691var sortKey = 'o';
3692var opKey = 'p';
3693var opBackKey = 'P';
3694var computedKey = 'q';
3695var computedBackKey = 'Q';
3696var stepKey = 's';
3697var stepBackKey = 'S';
3698var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003699var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003700var curveTKey = 'u';
3701var controlLinesBackKey = 'V';
3702var controlLinesKey = 'v';
3703var ptsKey = 'x';
3704var xyKey = 'y';
3705var logCurvesKey = 'z';
3706var focusKey = '`';
3707var idKey = '.';
3708var retinaKey = '\\';
3709
3710function doKeyPress(evt) {
3711 var char = String.fromCharCode(evt.charCode);
3712 var focusWasOn = false;
3713 switch (char) {
3714 case '0':
3715 case '1':
3716 case '2':
3717 case '3':
3718 case '4':
3719 case '5':
3720 case '6':
3721 case '7':
3722 case '8':
3723 case '9':
3724 decimal_places = char - '0';
3725 redraw();
3726 break;
3727 case activeKey:
3728 draw_active ^= true;
3729 redraw();
3730 break;
3731 case addKey:
3732 draw_add ^= true;
3733 redraw();
3734 break;
3735 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003736 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003737 redraw();
3738 break;
3739 case angleBackKey:
3740 draw_angle = (draw_angle + 2) % 3;
3741 redraw();
3742 break;
3743 case centerKey:
3744 setScale(xmin, xmax, ymin, ymax);
3745 redraw();
3746 break;
caryclark624637c2015-05-11 07:21:27 -07003747 case coincidenceKey:
3748 draw_coincidence ^= true;
3749 redraw();
3750 break;
caryclarkdac1d172014-06-17 05:15:38 -07003751 case controlLinesBackKey:
3752 control_lines = (control_lines + 3) % 4;
3753 redraw();
3754 break;
3755 case controlLinesKey:
3756 control_lines = (control_lines + 1) % 4;
3757 redraw();
3758 break;
3759 case computedBackKey:
3760 draw_computed = (draw_computed + 5) % 6;
3761 redraw();
3762 break;
3763 case computedKey:
3764 draw_computed = (draw_computed + 1) % 6;
3765 redraw();
3766 break;
3767 case curveTKey:
3768 curve_t ^= true;
3769 if (curve_t) {
3770 draw_legend = true;
3771 }
3772 redraw();
3773 break;
3774 case deriviativesKey:
3775 draw_deriviatives = (draw_deriviatives + 1) % 3;
3776 redraw();
3777 break;
3778 case focusKey:
3779 focus_on_selection ^= true;
3780 setScale(xmin, xmax, ymin, ymax);
3781 redraw();
3782 break;
caryclarkdac1d172014-06-17 05:15:38 -07003783 case idKey:
3784 draw_id ^= true;
3785 redraw();
3786 break;
3787 case intersectionBackKey:
3788 draw_intersection = (draw_intersection + 3) % 4;
3789 redraw();
3790 break;
3791 case intersectionKey:
3792 draw_intersection = (draw_intersection + 1) % 4;
3793 redraw();
3794 break;
3795 case intersectTKey:
3796 draw_intersectT ^= true;
3797 redraw();
3798 break;
3799 case logCurvesKey:
3800 logCurves(tests[testIndex]);
3801 break;
3802 case logKey:
3803 draw_log ^= true;
3804 redraw();
3805 break;
3806 case logToConsoleKey:
3807 if (draw_log) {
3808 dumpLogToConsole();
3809 }
3810 break;
3811 case markKey:
3812 draw_mark ^= true;
3813 redraw();
3814 break;
3815 case midpointKey:
3816 draw_midpoint ^= true;
3817 redraw();
3818 break;
3819 case opKey:
3820 draw_op = (draw_op + 1) % 3;
3821 redraw();
3822 break;
3823 case opBackKey:
3824 draw_op = (draw_op + 2) % 3;
3825 redraw();
3826 break;
3827 case pathKey:
caryclark26ad22a2015-10-16 09:03:38 -07003828 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclarkdac1d172014-06-17 05:15:38 -07003829 redraw();
3830 break;
3831 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07003832 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclarkdac1d172014-06-17 05:15:38 -07003833 redraw();
3834 break;
3835 case ptsKey:
3836 pt_labels = (pt_labels + 1) % 3;
3837 redraw();
3838 break;
3839 case retinaKey:
3840 retina_scale ^= true;
3841 drawTop();
3842 break;
3843 case sequenceKey:
3844 draw_sequence ^= true;
3845 redraw();
3846 break;
3847 case sortKey:
3848 draw_sort = (draw_sort + 1) % 3;
3849 drawTop();
3850 break;
3851 case stepKey:
3852 step_limit++;
3853 if (step_limit > stepMax) {
3854 step_limit = stepMax;
3855 }
3856 redraw();
3857 break;
3858 case stepBackKey:
3859 step_limit--;
3860 if (step_limit < 0) {
3861 step_limit = 0;
3862 }
3863 redraw();
3864 break;
caryclark03b03ca2015-04-23 09:13:37 -07003865 case topKey:
3866 draw_top ^= true;
3867 redraw();
3868 break;
caryclarkdac1d172014-06-17 05:15:38 -07003869 case xyKey:
3870 debug_xy = (debug_xy + 1) % 3;
3871 redraw();
3872 break;
3873 case '-':
3874 focusWasOn = focus_on_selection;
3875 if (focusWasOn) {
3876 focus_on_selection = false;
3877 scale /= 1.2;
3878 } else {
3879 scale /= 2;
3880 calcLeftTop();
3881 }
3882 redraw();
3883 focus_on_selection = focusWasOn;
3884 break;
3885 case '=':
3886 case '+':
3887 focusWasOn = focus_on_selection;
3888 if (focusWasOn) {
3889 focus_on_selection = false;
3890 scale *= 1.2;
3891 } else {
3892 scale *= 2;
3893 calcLeftTop();
3894 }
3895 redraw();
3896 focus_on_selection = focusWasOn;
3897 break;
3898 case '?':
3899 draw_hints ^= true;
3900 if (draw_hints && !draw_legend) {
3901 draw_legend = true;
3902 }
3903 redraw();
3904 break;
3905 case '/':
3906 draw_legend ^= true;
3907 redraw();
3908 break;
3909 }
3910}
3911
3912function doKeyDown(evt) {
3913 var char = evt.keyCode;
3914 var preventDefault = false;
3915 switch (char) {
3916 case 37: // left arrow
3917 if (evt.shiftKey) {
3918 testIndex -= 9;
3919 }
3920 if (--testIndex < 0)
3921 testIndex = tests.length - 1;
3922 drawTop();
3923 preventDefault = true;
3924 break;
3925 case 39: // right arrow
3926 if (evt.shiftKey) {
3927 testIndex += 9;
3928 }
3929 if (++testIndex >= tests.length)
3930 testIndex = 0;
3931 drawTop();
3932 preventDefault = true;
3933 break;
3934 }
3935 if (preventDefault) {
3936 evt.preventDefault();
3937 return false;
3938 }
3939 return true;
3940}
3941
3942(function() {
3943 var hidden = "hidden";
3944
3945 // Standards:
3946 if (hidden in document)
3947 document.addEventListener("visibilitychange", onchange);
3948 else if ((hidden = "mozHidden") in document)
3949 document.addEventListener("mozvisibilitychange", onchange);
3950 else if ((hidden = "webkitHidden") in document)
3951 document.addEventListener("webkitvisibilitychange", onchange);
3952 else if ((hidden = "msHidden") in document)
3953 document.addEventListener("msvisibilitychange", onchange);
3954 // IE 9 and lower:
3955 else if ('onfocusin' in document)
3956 document.onfocusin = document.onfocusout = onchange;
3957 // All others:
3958 else
3959 window.onpageshow = window.onpagehide
3960 = window.onfocus = window.onblur = onchange;
3961
3962 function onchange (evt) {
3963 var v = 'visible', h = 'hidden',
3964 evtMap = {
3965 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3966 };
3967
3968 evt = evt || window.event;
3969 if (evt.type in evtMap)
3970 document.body.className = evtMap[evt.type];
3971 else
3972 document.body.className = this[hidden] ? "hidden" : "visible";
3973 }
3974})();
3975
3976function calcXY() {
3977 var e = window.event;
3978 var tgt = e.target || e.srcElement;
3979 var left = tgt.offsetLeft;
3980 var top = tgt.offsetTop;
3981 mouseX = (e.clientX - left) / scale + srcLeft;
3982 mouseY = (e.clientY - top) / scale + srcTop;
3983}
3984
3985function calcLeftTop() {
3986 srcLeft = mouseX - screenWidth / 2 / scale;
3987 srcTop = mouseY - screenHeight / 2 / scale;
3988}
3989
3990var disableClick = false;
3991
3992function handleMouseClick() {
3993 if (disableClick) {
3994 return;
3995 }
3996 if (!curve_t || !ptInTControl()) {
3997 calcXY();
3998 calcLeftTop();
3999 }
4000 redraw();
4001// if (!curve_t || !ptInTControl()) {
4002// mouseX = screenWidth / 2 / scale + srcLeft;
4003// mouseY = screenHeight / 2 / scale + srcTop;
4004// }
4005}
4006
4007function handleMouseOver() {
4008 calcXY();
4009 if (debug_xy != 2) {
4010 return;
4011 }
4012 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
4013 ctx.beginPath();
4014 ctx.rect(300,100,num.length * 6,10);
4015 ctx.fillStyle="white";
4016 ctx.fill();
4017 ctx.font = "normal 10px Arial";
4018 ctx.fillStyle="black";
4019 ctx.textAlign = "left";
4020 ctx.fillText(num, 300, 108);
4021}
4022
4023function start() {
4024 for (var i = 0; i < testDivs.length; ++i) {
4025 tests[i] = null;
4026 }
4027 testIndex = 0;
4028 drawTop();
4029 window.addEventListener('keypress', doKeyPress, true);
4030 window.addEventListener('keydown', doKeyDown, true);
4031 window.onresize = function() {
4032 drawTop();
4033 }
4034 /*
4035 window.onpagehide = function() {
4036 disableClick = true;
4037 }
4038 */
4039 window.onpageshow = function () {
4040 disableClick = false;
4041 }
4042}
4043
4044</script>
4045</head>
4046
4047<body onLoad="start();">
4048<canvas id="canvas" width="750" height="500"
4049 onmousemove="handleMouseOver()"
4050 onclick="handleMouseClick()"
4051 ></canvas >
4052</body>
4053</html>