blob: f1288f0fe8454ae1ddc7b2844a0f525e435c9cc3 [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
caryclarkaec25102015-04-29 08:28:30 -07005<div id="loops59i">
6SkDCubic::ComplexBreak
7{{{1, 2}, {7.3333330154418945, 1.6666666269302368}, {-7.5, 2}, {0, 6}}},
8inflectionsTs[0]=0.22755391 {{{5.6899562470344014, 1.5351137489099846}, {-0.59395324579271769, 2.2875990427916371}}},
9inflectionsTs[1]=0.134608255 {{{-1.7562572007939035, 2.2074401507711405}, {6.7824037520473279, 1.6104549548102116}}},
10maxCurvature[0]=0.184583395 {{{2.612965320628251, 1.8574526830515183}, {2.6213210132912339, 1.9473982945574213}}},
11maxCurvature[1]=0.764880287 {{{-0.3599143419711428, -3.5772335093952985}, {-3.9435828934112642, 11.072562225478482}}},
12maxCurvature[2]=0.500240448 {{{11.93379531543474, -0.87734455447864557}, {-11.814505983496176, 5.6289081865421942}}},
13seg=1 {{{0, 6}, {0.293506175f, 4.82597542f}, {1.04645705f, 3.96781874f}, {1.58881736f, 3.34967732f}}}
14seg=2 {{{1.58881736f, 3.34967732f}, {2.89432383f, 1.86175978f}, {2.97965813f, 1.76450205f}, {-7.5f, 2}}}
15seg=3 {{{-7.5f, 2}, {0, 6}}}
16op sect
17seg=4 {{{1, 2}, {2.16902828f, 1.93847215f}, {2.61688614f, 1.89965844f}, {2.61714315f, 1.90242553f}}}
18seg=5 {{{2.61714315f, 1.90242553f}, {2.61827874f, 1.91464937f}, {-6.11562443f, 2.7383337f}, {0, 6}}}
19seg=6 {{{0, 6}, {1, 2}}}
20debugShowCubicIntersection wtTs[0]=1 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{1.58881736,3.34967732}} wnTs[0]=0 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}}
21debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
22debugShowCubicLineIntersection wtTs[0]=1 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{-7.5,2}} wnTs[0]=0 {{{-7.5,2}, {0,6}}}
23debugShowCubicIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
24debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
25debugShowCubicIntersection wtTs[0]=0.538493706 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.17718506,1.99055469}} wnTs[0]=0.0521913 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}}
26SkOpSegment::addT insert t=0.538493706 segID=2 spanID=13
27SkOpSegment::addT insert t=0.0521913275 segID=4 spanID=14
28debugShowCubicIntersection wtTs[0]=0.481912781 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.58025348,2.04903817}} wnTs[0]=0.222514 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
29SkOpSegment::addT insert t=0.481912781 segID=2 spanID=15
30SkOpSegment::addT insert t=0.222514468 segID=5 spanID=16
31debugShowCubicLineIntersection no intersect {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{{0,6}, {1,2}}}
32debugShowCubicLineIntersection wtTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
33debugShowLineIntersection wtTs[0]=1 {{{-7.5,2}, {0,6}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
34debugShowCubicIntersection wtTs[0]=1 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{2.61714315,1.90242553}} wnTs[0]=0 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
35debugShowCubicLineIntersection wtTs[0]=0 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{1,2}} wnTs[0]=1 {{{0,6}, {1,2}}}
36debugShowCubicLineIntersection wtTs[0]=0.293280033 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0.959100008,2.16359997}} wtTs[1]=1 {{0,6}} wnTs[0]=0.9591 {{{0,6}, {1,2}}} wnTs[1]=0
37SkOpSegment::addT insert t=0.293280033 segID=5 spanID=17
38SkOpSegment::addT insert t=0.959100004 segID=6 spanID=18
39SkOpSegment::sortAngles [1] tStart=0 [1]
40SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [5/13] 13/5 tStart=1 tEnd=0.293280033 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 7
41SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
42SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
43SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
44SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [3/6] 13/13 tStart=1 tEnd=0 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 5
45SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
46SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
47SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
48SkOpAngle::after [6/14] 5/5 tStart=0 tEnd=0.959100004 < [3/6] 13/13 tStart=1 tEnd=0 < [5/13] 13/5 tStart=1 tEnd=0.293280033 F 7
49SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
50SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
51SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
52SkOpAngle::after [5/13] 13/5 tStart=1 tEnd=0.293280033 < [3/6] 13/13 tStart=1 tEnd=0 < [1/1] 5/5 tStart=0 tEnd=1 T 7
53SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
54SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
55SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
56SkOpSegment::sortAngles [2] tStart=0.481912781 [15]
57SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/9] 1/1 tStart=0.222514468 tEnd=0 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 T 4
58SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
59SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
60SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
61SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [5/9] 1/1 tStart=0.222514468 tEnd=0 F 4
62SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
63SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
64SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
65SkOpAngle::after [5/9] 1/1 tStart=0.222514468 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 F 4
66SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
67SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
68SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
69SkOpAngle::after [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/2] 29/25 tStart=0.481912781 tEnd=0 T 4
70SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
71SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
72SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
73SkOpSegment::sortAngles [2] tStart=0.538493706 [13]
74SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/7] 17/17 tStart=0.0521913275 tEnd=0 < [2/5] 13/17 tStart=0.538493706 tEnd=1 F 11
75SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
76SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.12006187,1.99363948}, {1.06101314,1.99678878}, {1,2}}} id=4
77SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
78SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/8] 1/1 tStart=0.0521913275 tEnd=1 < [2/5] 13/17 tStart=0.538493706 tEnd=1 T 4
79SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
80SkOpAngle::afterPart {{{1.17718506,1.99055469}, {2.21455765,1.93453399}, {2.61689955,1.89980286}, {2.61714315,1.90242553}}} id=4
81SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
82SkOpSegment::sortAngles [3] tStart=1 [6]
83SkOpSegment::sortAngles [4] tStart=0.0521913275 [14]
84SkOpSegment::sortAngles [5] tStart=0.222514468 [16]
85SkOpSegment::sortAngles [5] tStart=0.293280033 [17]
86SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/15] 21/21 tStart=0.959100004 tEnd=0 < [5/12] 17/21 tStart=0.293280033 tEnd=1 F 11
87SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
88SkOpAngle::afterPart {{{0.959100008,2.16359997}, {0,6}}} id=6
89SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
90SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/16] 5/5 tStart=0.959100004 tEnd=1 < [5/12] 17/21 tStart=0.293280033 tEnd=1 T 4
91SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
92SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1,2}}} id=6
93SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
94SkOpSegment::sortAngles [5] tStart=1 [10]
95SkOpSegment::sortAngles [6] tStart=0 [11]
96SkOpSegment::sortAngles [6] tStart=0.959100004 [18]
97SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
98SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
99SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=? windValue=1 oppValue=0
100SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
101SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=? windValue=1 oppValue=0
102SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=? windValue=1 oppValue=0
103SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
104SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=? windValue=1 oppValue=0
105SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
106SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
107SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
108SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
caryclark08bc8482015-04-24 09:08:57 -0700109-SkOpSegment::findTop- baseAngle
caryclarkaec25102015-04-29 08:28:30 -0700110SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
111SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
112SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
113SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
caryclark08bc8482015-04-24 09:08:57 -0700114-SkOpSegment::findTop- firstAngle
caryclarkaec25102015-04-29 08:28:30 -0700115SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
116SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
117SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
118SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
119SkDCubic::clockwise pt1dist=0.00263265113 pt2dist=-0.00745519926
120SkOpSegment::findTop id=4 s=1 e=0.0521913275 (+) cw=1 swap=0 inflections=1 monotonic=0
121SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
122SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
123SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
124SkOpSegment::activeOp id=4 t=1 tEnd=0.0521913275 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
125SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
126bridgeOp chase.append id=4 windSum=1
127SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
128SkOpSegment::markWinding id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
129SkOpSegment::markAngle last segment=3 span=6
130SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
131SkOpSegment::markWinding id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
132SkOpSegment::markAngle last segment=6 span=18 windSum=1
133SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
134SkOpSegment::markAngle last segment=2 span=15 windSum=1
135SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
136SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
137SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=1 windValue=1 oppValue=0
138SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=1 windValue=1 oppValue=0
139SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=1 windValue=1 oppValue=0
140SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=1 windValue=1 oppValue=0
141SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=1 windValue=1 oppValue=0
142SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
143SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
144SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
145SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=1 windValue=1 oppValue=0
146SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
caryclark03b03ca2015-04-23 09:13:37 -0700147SkOpSegment::findNextOp simple
caryclarkaec25102015-04-29 08:28:30 -0700148SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
149bridgeOp current id=2 from=(1.17718506,1.99055469) to=(-7.5,2)
150path.moveTo(1.17718506,1.99055469);
151path.cubicTo(-0.0773608461,1.85350549, -2.66357183,1.89131618, -7.5,2);
152SkOpSegment::markWinding id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
153SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
154SkOpSegment::markAngle last segment=2 span=15 windSum=1
155SkOpSegment::markWinding id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
156SkOpSegment::markAngle last segment=6 span=18 windSum=1
157SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
158SkOpSegment::markAngle last segment=5 span=17 windSum=2
caryclark03b03ca2015-04-23 09:13:37 -0700159SkOpSegment::findNextOp
caryclarkaec25102015-04-29 08:28:30 -0700160SkOpAngle::dumpOne [3/6] next=1/1 sect=13/13 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
161SkOpAngle::dumpOne [1/1] next=6/14 sect=5/5 s=0 [1] e=1 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1
162SkOpAngle::dumpOne [6/14] next=5/13 sect=5/5 s=0 [11] e=0.959100004 [18] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
163SkOpAngle::dumpOne [5/13] next=3/6 sect=13/5 s=1 [10] e=0.293280033 [17] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
164SkOpSegment::activeOp id=1 t=0 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
165SkOpSegment::findNextOp chase.append segment=2 span=15 windSum=1
166SkOpSegment::activeOp id=6 t=0 tEnd=0.959100004 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
167SkOpSegment::markDone id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
168SkOpSegment::findNextOp chase.append segment=6 span=18 windSum=1
169SkOpSegment::activeOp id=5 t=1 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
170SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
171SkOpSegment::findNextOp chase.append segment=5 span=17 windSum=2
172SkOpSegment::markDone id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
173SkOpSegment::findNextOp from:[3] to:[1] start=43971536 end=43971632
174bridgeOp current id=3 from=(-7.5,2) to=(0,6)
175SkOpSegment::findNextOp simple
176SkOpSegment::markDone id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
177bridgeOp current id=1 from=(0,6) to=(1.58881736,3.34967732)
178path.lineTo(0,6);
179path.cubicTo(0.293506175,4.82597542, 1.04645705,3.96781874, 1.58881736,3.34967732);
180SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
181SkOpSegment::markAngle last segment=5 span=17 windSum=2
182SkOpSegment::findNextOp
183SkOpAngle::dumpOne [2/2] next=5/9 sect=29/25 s=0.481912781 [15] e=0 [3] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
184SkOpAngle::dumpOne [5/9] next=2/3 sect=1/1 s=0.222514468 [16] e=0 [9] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
185SkOpAngle::dumpOne [2/3] next=5/10 sect=13/13 s=0.481912781 [15] e=0.538493706 [13] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
186SkOpAngle::dumpOne [5/10] next=2/2 sect=17/17 s=0.222514468 [16] e=0.293280033 [17] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
187SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
188SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
189SkOpSegment::activeOp id=2 t=0.481912781 tEnd=0.538493706 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
190SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
191SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
192SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
193SkOpSegment::findNextOp from:[2] to:[5] start=2579180 end=2579276
194bridgeOp current id=2 from=(1.58881736,3.34967732) to=(1.58025348,2.04903817)
195path.cubicTo(2.2179575,2.63263083, 2.56372523,2.23855114, 1.58025348,2.04903817);
196SkOpSegment::findNextOp
197SkOpAngle::dumpOne [5/11] next=6/16 sect=1/1 s=0.293280033 [17] e=0.222514468 [16] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
198SkOpAngle::dumpOne [6/16] next=5/12 sect=5/5 s=0.959100004 [18] e=1 [12] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
199SkOpAngle::dumpOne [5/12] next=6/15 sect=17/21 s=0.293280033 [17] e=1 [10] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
200SkOpAngle::dumpOne [6/15] next=5/11 sect=21/21 s=0.959100004 [18] e=0 [11] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
201SkOpSegment::activeOp id=6 t=0.959100004 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
202SkOpSegment::activeOp id=5 t=0.293280033 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
203SkOpSegment::activeOp id=6 t=0.959100004 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
204SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
205SkOpSegment::findNextOp from:[5] to:[6] start=2579372 end=2578764
206bridgeOp current id=5 from=(1.58025348,2.04903817) to=(0.959100008,2.16359997)
207path.cubicTo(1.38787913,2.08115721, 1.17804205,2.11915231, 0.959100008,2.16359997);
208SkOpSegment::findNextOp simple
209SkOpSegment::markDone id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
210bridgeOp current id=6 from=(0.959100008,2.16359997) to=(1,2)
211SkOpSegment::findNextOp
212SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
213SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done stop
214SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
215SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 done stop
216SkOpSegment::activeOp id=2 t=0.538493706 tEnd=0.481912781 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
217SkOpSegment::activeOp id=4 t=0.0521913275 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
218SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
219SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
220SkOpSegment::findNextOp from:[4] to:[2] start=2578892 end=2577740
221bridgeOp current id=4 from=(1,2) to=(1.17718506,1.99055469)
222path.lineTo(1,2);
223path.cubicTo(1.0610131,1.99678874, 1.12006187,1.99363947, 1.17718506,1.99055469);
caryclark03b03ca2015-04-23 09:13:37 -0700224path.close();
caryclarkdac1d172014-06-17 05:15:38 -0700225</div>
caryclark54359292015-03-26 07:52:43 -0700226
caryclarkdac1d172014-06-17 05:15:38 -0700227</div>
228
229<script type="text/javascript">
230
231var testDivs = [
caryclarkaec25102015-04-29 08:28:30 -0700232 loops59i,
caryclarkdac1d172014-06-17 05:15:38 -0700233];
234
235var decimal_places = 3; // make this 3 to show more precision
236
237var tests = [];
238var testLines = [];
239var testTitles = [];
240var testIndex = 0;
241var ctx;
242
243var xmin, xmax, focusXmin, focusXmax;
244var ymin, ymax, focusYmin, focusYmax;
245var scale;
246var mouseX, mouseY;
247var srcLeft, srcTop;
248var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700249var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700250var curveT = 0;
251
252var pt_labels = 2;
253var collect_bounds = false;
254var control_lines = 0;
255var curve_t = false;
256var debug_xy = 1;
257var focus_enabled = false;
258var focus_on_selection = false;
259var step_limit = 0;
260var draw_active = false;
261var draw_add = false;
262var draw_angle = 0;
263var draw_deriviatives = 0;
264var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700265var draw_id = false;
266var draw_intersection = 0;
267var draw_intersectT = false;
268var draw_legend = true;
269var draw_log = false;
270var draw_mark = false;
271var draw_midpoint = false;
272var draw_op = 0;
273var draw_sequence = false;
274var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700275var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700276var draw_path = 3;
277var draw_computed = 0;
278var retina_scale = !!window.devicePixelRatio;
279
280var activeCount = 0;
281var addCount = 0;
282var angleCount = 0;
283var opCount = 0;
284var sectCount = 0;
285var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700286var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700287var markCount = 0;
288var activeMax = 0;
289var addMax = 0;
290var angleMax = 0;
291var sectMax = 0;
292var sectMax2 = 0;
293var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700294var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700295var markMax = 0;
296var opMax = 0;
297var stepMax = 0;
298var lastIndex = 0;
299var hasPath = false;
300var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700301var angleBetween = false;
302var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700303
304var firstActiveSpan = -1;
305var logStart = -1;
306var logRange = 0;
307
308var SPAN_ID = 0;
309var SPAN_X1 = SPAN_ID + 1;
310var SPAN_Y1 = SPAN_X1 + 1;
311var SPAN_X2 = SPAN_Y1 + 1;
312var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700313
caryclarkdac1d172014-06-17 05:15:38 -0700314var SPAN_L_T = SPAN_Y2 + 1;
315var SPAN_L_TX = SPAN_L_T + 1;
316var SPAN_L_TY = SPAN_L_TX + 1;
317var SPAN_L_TEND = SPAN_L_TY + 1;
318var SPAN_L_OTHER = SPAN_L_TEND + 1;
319var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
320var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
321var SPAN_L_SUM = SPAN_L_OTHERI + 1;
322var SPAN_L_VAL = SPAN_L_SUM + 1;
323var SPAN_L_OPP = SPAN_L_VAL + 1;
324
325var SPAN_X3 = SPAN_Y2 + 1;
326var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700327
caryclarkdac1d172014-06-17 05:15:38 -0700328var SPAN_Q_T = SPAN_Y3 + 1;
329var SPAN_Q_TX = SPAN_Q_T + 1;
330var SPAN_Q_TY = SPAN_Q_TX + 1;
331var SPAN_Q_TEND = SPAN_Q_TY + 1;
332var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
333var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
334var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
335var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
336var SPAN_Q_VAL = SPAN_Q_SUM + 1;
337var SPAN_Q_OPP = SPAN_Q_VAL + 1;
338
caryclark1049f122015-04-20 08:31:59 -0700339var SPAN_K_W = SPAN_Y3 + 1;
340var SPAN_K_T = SPAN_K_W + 1;
341var SPAN_K_TX = SPAN_K_T + 1;
342var SPAN_K_TY = SPAN_K_TX + 1;
343var SPAN_K_TEND = SPAN_K_TY + 1;
344var SPAN_K_OTHER = SPAN_K_TEND + 1;
345var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
346var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
347var SPAN_K_SUM = SPAN_K_OTHERI + 1;
348var SPAN_K_VAL = SPAN_K_SUM + 1;
349var SPAN_K_OPP = SPAN_K_VAL + 1;
350
caryclarkdac1d172014-06-17 05:15:38 -0700351var SPAN_X4 = SPAN_Y3 + 1;
352var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700353
caryclarkdac1d172014-06-17 05:15:38 -0700354var SPAN_C_T = SPAN_Y4 + 1;
355var SPAN_C_TX = SPAN_C_T + 1;
356var SPAN_C_TY = SPAN_C_TX + 1;
357var SPAN_C_TEND = SPAN_C_TY + 1;
358var SPAN_C_OTHER = SPAN_C_TEND + 1;
359var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
360var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
361var SPAN_C_SUM = SPAN_C_OTHERI + 1;
362var SPAN_C_VAL = SPAN_C_SUM + 1;
363var SPAN_C_OPP = SPAN_C_VAL + 1;
364
365var ACTIVE_LINE_SPAN = 1;
366var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700367var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
368var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700369
370var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
371var ADD_LINETO = ADD_MOVETO + 1;
372var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700373var ADD_CONICTO = ADD_QUADTO + 1;
374var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700375var ADD_CLOSE = ADD_CUBICTO + 1;
376var ADD_FILL = ADD_CLOSE + 1;
377
378var PATH_LINE = ADD_FILL + 1;
379var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700380var PATH_CONIC = PATH_QUAD + 1;
381var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700382
383var INTERSECT_LINE = PATH_CUBIC + 1;
384var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
385var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
386var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
387var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
388var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
389var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
390var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
391var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700392var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
393var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
394var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
395var INTERSECT_CONIC = INTERSECT_CONIC_LINE_NO + 1;
396var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
397var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
398var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700399var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
400var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
401var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
402var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
403var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
404var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
405var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
406var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
407var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
408var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
409var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
410var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
411var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
412var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
413// FIXME: add cubic 5- 9
414var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
415
416var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
417var SORT_BINARY = SORT_UNARY + 1;
418
419var OP_DIFFERENCE = SORT_BINARY + 1;
420var OP_INTERSECT = OP_DIFFERENCE + 1;
421var OP_UNION = OP_INTERSECT + 1;
422var OP_XOR = OP_UNION + 1;
423
424var MARK_LINE = OP_XOR + 1;
425var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700426var MARK_CONIC = MARK_QUAD + 1;
427var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700428var MARK_DONE_LINE = MARK_CUBIC + 1;
429var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700430var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
431var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700432var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
433var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700434var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
435var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700436var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
437var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700438var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
439var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700440var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
441var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700442var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
443var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700444var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
445var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700446var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
447var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700448var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
449
450var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
451var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
452
453var ANGLE_AFTER = COMPUTED_SET_2;
caryclark54359292015-03-26 07:52:43 -0700454var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700455
caryclark54359292015-03-26 07:52:43 -0700456var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700457
458var FRAG_TYPE_LAST = ACTIVE_OP;
459
460var REC_TYPE_UNKNOWN = -1;
461var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700462var REC_TYPE_PATH2 = 1;
463var REC_TYPE_SECT = 2;
464var REC_TYPE_ACTIVE = 3;
465var REC_TYPE_ADD = 4;
466var REC_TYPE_SORT = 5;
467var REC_TYPE_OP = 6;
468var REC_TYPE_MARK = 7;
469var REC_TYPE_COMPUTED = 8;
470var REC_TYPE_COIN = 9;
471var REC_TYPE_ANGLE = 10;
472var REC_TYPE_ACTIVE_OP = 11;
473var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700474var REC_TYPE_TOP = 13;
475var REC_TYPE_LAST = REC_TYPE_TOP;
caryclarkdac1d172014-06-17 05:15:38 -0700476
477function strs_to_nums(strs) {
478 var result = [];
479 for (var idx = 1; idx < strs.length; ++idx) {
480 var str = strs[idx];
481 var num = parseFloat(str);
482 if (isNaN(num)) {
483 result.push(str);
484 } else {
485 result.push(num);
486 }
487 }
488 return result;
489}
490
491function filter_str_by(id, str, regex, array) {
492 if (regex.test(str)) {
493 var strs = regex.exec(str);
494 var result = strs_to_nums(strs);
495 array.push(id);
496 array.push(result);
497 return true;
498 }
499 return false;
500}
501
502function construct_regexp2(pattern) {
503 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
504 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
505 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700506 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700507 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
508 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
509 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700510 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700511 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
512 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
513 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700514 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700515 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700516 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700517 escape = escape.replace(/NUM/g, "(-?\\d+)");
518 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
519 return new RegExp(escape, 'i');
520}
521
522function construct_regexp2c(pattern) {
523 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
524 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700525 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700526 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700527 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
528 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700529 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700530 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700531 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700532 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 -0700533 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700534 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700535 escape = escape.replace(/OPER/g, "[a-z]+");
536 escape = escape.replace(/PATH/g, "pathB?");
537 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700538 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700539 escape = escape.replace(/NUM/g, "(-?\\d+)");
540 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
541 return new RegExp(escape, 'i');
542}
543
544function match_regexp(str, lineNo, array, id, pattern) {
545 var regex = construct_regexp2(pattern);
546 if (filter_str_by(id, str, regex, array)) {
547 return true;
548 }
549 regex = construct_regexp2c(pattern);
550 return filter_str_by(id, str, regex, array);
551}
552
553function endsWith(str, suffix) {
554 return str.indexOf(suffix, str.length - suffix.length) !== -1;
555}
556
557function parse_all(test) {
558 var lines = test.match(/[^\r\n]+/g);
559 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
560 var record = [];
561 var recType = REC_TYPE_UNKNOWN;
562 var lastLineNo;
563 var moveX, moveY;
564 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
565 var line = lines[lineNo];
566 if (line.length == 0) {
567 continue;
568 }
569 var opStart = "SkOpSegment::";
570 if (line.lastIndexOf(opStart, 0) === 0) {
571 line = line.substr(opStart.length);
572 }
573 var angleStart = "SkOpAngle::";
574 if (line.lastIndexOf(angleStart, 0) === 0) {
575 line = line.substr(angleStart.length);
576 }
caryclark54359292015-03-26 07:52:43 -0700577 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
578 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclarkdac1d172014-06-17 05:15:38 -0700579 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700580 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700581 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
582 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
583 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
584 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
585 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700586 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700587 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
588 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
589 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
590 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
591 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700592 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700593 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
594 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
595 : REC_TYPE_UNKNOWN;
596 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
597 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
598 if (recType != REC_TYPE_UNKNOWN) {
599 records.push(recType);
600 records.push(lastLineNo);
601 records.push(record);
602 }
603 record = [];
604 recType = type;
605 lastLineNo = lineNo;
606 }
607 var found = false;
608 switch (recType) {
609 case REC_TYPE_ACTIVE:
610 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark54359292015-03-26 07:52:43 -0700611" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700612 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark54359292015-03-26 07:52:43 -0700613" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
caryclark1049f122015-04-20 08:31:59 -0700614 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
615" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700616 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark54359292015-03-26 07:52:43 -0700617" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700618 );
619 break;
620 case REC_TYPE_ACTIVE_OP:
621 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
622" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
623 );
624 break;
625 case REC_TYPE_ADD:
626 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
627 moveX = record[1][0];
628 moveY = record[1][1];
629 found = true;
630 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
631 record[1].unshift(moveY);
632 record[1].unshift(moveX);
633 moveX = record[1][2];
634 moveY = record[1][3];
635 found = true;
636 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
637 record[1].unshift(moveY);
638 record[1].unshift(moveX);
639 moveX = record[1][4];
640 moveY = record[1][5];
641 found = true;
caryclark1049f122015-04-20 08:31:59 -0700642 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
643 record[1].unshift(moveY);
644 record[1].unshift(moveX);
645 moveX = record[1][4];
646 moveY = record[1][5];
647 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700648 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
649 record[1].unshift(moveY);
650 record[1].unshift(moveX);
651 moveX = record[1][6];
652 moveY = record[1][7];
653 found = true;
654 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
655 found = true;
656 } else {
657 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
658 }
659 break;
caryclark54359292015-03-26 07:52:43 -0700660 case REC_TYPE_AFTERPART:
661 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL")
662 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL")
caryclark1049f122015-04-20 08:31:59 -0700663 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL")
caryclark54359292015-03-26 07:52:43 -0700664 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL")
665 break;
caryclarkdac1d172014-06-17 05:15:38 -0700666 case REC_TYPE_ANGLE:
667 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700668"[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");
669 break;
670 case REC_TYPE_COIN:
671 found = true;
672 break;
673 case REC_TYPE_COMPUTED:
674 found = line == "computed quadratics given"
675 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
676 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
677 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700678 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700679 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
680 );
681 break;
682 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700683 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
684 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700685 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700686 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
687 );
688 break;
689 case REC_TYPE_PATH2:
690 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
691 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700692 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700693 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700694 );
695 break;
696 case REC_TYPE_SECT:
697 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
698" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
699 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
700" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
701 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
702" no intersect LINE_VAL LINE_VAL"
703 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
704" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
705 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
706" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
707 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
708" no intersect QUAD_VAL LINE_VAL"
709 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
710" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
711 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
712" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
713 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
714" no intersect QUAD_VAL QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700715 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
716" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
717 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
718" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
719 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
720" no intersect CONIC_VAL LINE_VAL"
721 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
722" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
723 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
724" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
725 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
726" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700727 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
728" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
729 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
730" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
731 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
732" 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"
733 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
734" no intersect CUBIC_VAL LINE_VAL"
735 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
736" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
737 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
738" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
739 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
740" 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"
741 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
742" 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"
743 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
744" no intersect CUBIC_VAL QUAD_VAL"
745 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
746" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
747 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
748" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
749 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
750" 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"
751 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
752" 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"
753 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
754" no intersect CUBIC_VAL CUBIC_VAL"
755 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
756" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
757 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
758" no self intersect CUBIC_VAL"
759 );
760 break;
761 case REC_TYPE_SORT:
762 var hasDone = / done/.test(line);
763 var hasUnorderable = / unorderable/.test(line);
764 var hasSmall = / small/.test(line);
765 var hasTiny = / tiny/.test(line);
766 var hasOperand = / operand/.test(line);
767 var hasStop = / stop/.test(line);
768 line.replace(/[ a-z]+$/, "");
769 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
770" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
771 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
772" [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"
773 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
774" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
775 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
776" [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"
777 );
778 if (found) {
779 record[1].push(hasDone);
780 record[1].push(hasUnorderable);
781 record[1].push(hasSmall);
782 record[1].push(hasTiny);
783 record[1].push(hasOperand);
784 record[1].push(hasStop);
785 }
786 break;
caryclark03b03ca2015-04-23 09:13:37 -0700787 case REC_TYPE_TOP:
788 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
789" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
790 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
791" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
792 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
793" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
794 );
795 break;
caryclarkdac1d172014-06-17 05:15:38 -0700796 case REC_TYPE_MARK:
797 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700798" 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 -0700799 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700800" 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 -0700801 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
802" 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 -0700803 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700804" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
805 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
806" 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"
807 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
808" 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 -0700809 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
810" 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 -0700811 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
812" 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 -0700813 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
814" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
815 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
816" 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 -0700817 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
818" 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 -0700819 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
820" 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 -0700821 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700822" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700823 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
824" last segment=IDX span=IDX windSum=OPT");
caryclarkdac1d172014-06-17 05:15:38 -0700825 break;
826 case REC_TYPE_OP:
827 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
828 || line.lastIndexOf("operator<", 0) === 0) {
829 found = true;
830 break;
831 }
caryclark54359292015-03-26 07:52:43 -0700832 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700833 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700834 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700835 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
836 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
837 );
838 break;
839 case REC_TYPE_UNKNOWN:
840 found = true;
841 break;
842 }
843 if (!found) {
844 console.log(line + " [" + lineNo + "] of type " + type + " not found");
845 }
846 }
847 if (recType != REC_TYPE_UNKNOWN) {
848 records.push(recType);
849 records.push(lastLineNo);
850 records.push(record);
851 }
852 if (records.length >= 1) {
853 tests[testIndex] = records;
854 testLines[testIndex] = lines;
855 }
856}
857
858function init(test) {
859 var canvas = document.getElementById('canvas');
860 if (!canvas.getContext) return;
861 ctx = canvas.getContext('2d');
862 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
863 var unscaledWidth = window.innerWidth - 20;
864 var unscaledHeight = window.innerHeight - 20;
865 screenWidth = unscaledWidth;
866 screenHeight = unscaledHeight;
867 canvas.width = unscaledWidth * resScale;
868 canvas.height = unscaledHeight * resScale;
869 canvas.style.width = unscaledWidth + 'px';
870 canvas.style.height = unscaledHeight + 'px';
871 if (resScale != 1) {
872 ctx.scale(resScale, resScale);
873 }
874 xmin = Infinity;
875 xmax = -Infinity;
876 ymin = Infinity;
877 ymax = -Infinity;
878 hasPath = hasComputedPath = false;
879 firstActiveSpan = -1;
880 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
881 var recType = test[tIndex];
882 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
883 console.log("unknown rec type: " + recType);
884 throw "stop execution";
885 }
886 var records = test[tIndex + 2];
887 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
888 var fragType = records[recordIndex];
889 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
890 console.log("unknown in range frag type: " + fragType);
891 throw "stop execution";
892 }
893 var frags = records[recordIndex + 1];
894 var first = 0;
895 var last = -1;
896 var first2 = 0;
897 var last2 = 0;
898 switch (recType) {
899 case REC_TYPE_COMPUTED:
900 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
901 break;
902 }
903 hasComputedPath = true;
904 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700905 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700906 switch (fragType) {
907 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700908 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700909 break;
caryclark1049f122015-04-20 08:31:59 -0700910 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700911 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700912 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700913 break;
914 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700915 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700916 break;
917 default:
918 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
919 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
920 throw "stop execution";
921 }
922 if (recType == REC_TYPE_PATH) {
923 hasPath = true;
924 }
925 break;
caryclark54359292015-03-26 07:52:43 -0700926 case REC_TYPE_PATH2:
927 first = 1;
928 switch (fragType) {
929 case PATH_LINE:
930 last = 5;
931 break;
caryclark1049f122015-04-20 08:31:59 -0700932 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700933 case PATH_QUAD:
934 last = 7;
935 break;
936 case PATH_CUBIC:
937 last = 9;
938 break;
939 default:
940 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
941 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
942 throw "stop execution";
943 }
944 if (recType == REC_TYPE_PATH2) {
945 hasPath = true;
946 }
947 break;
caryclarkdac1d172014-06-17 05:15:38 -0700948 case REC_TYPE_ACTIVE:
949 if (firstActiveSpan < 0) {
950 firstActiveSpan = tIndex;
951 }
952 first = 1;
953 switch (fragType) {
954 case ACTIVE_LINE_SPAN:
955 last = 5;
956 break;
caryclark1049f122015-04-20 08:31:59 -0700957 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700958 case ACTIVE_QUAD_SPAN:
959 last = 7;
960 break;
961 case ACTIVE_CUBIC_SPAN:
962 last = 9;
963 break;
964 default:
965 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
966 throw "stop execution";
967 }
968 break;
969 case REC_TYPE_ADD:
970 switch (fragType) {
971 case ADD_MOVETO:
972 break;
973 case ADD_LINETO:
974 last = 4;
975 break;
caryclark1049f122015-04-20 08:31:59 -0700976 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700977 case ADD_QUADTO:
978 last = 6;
979 break;
980 case ADD_CUBICTO:
981 last = 8;
982 break;
983 case ADD_CLOSE:
984 case ADD_FILL:
985 break;
986 default:
987 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
988 throw "stop execution";
989 }
990 break;
caryclark54359292015-03-26 07:52:43 -0700991 case REC_TYPE_AFTERPART:
992 switch (fragType) {
993 case PATH_LINE:
994 last = 4;
995 break;
caryclark1049f122015-04-20 08:31:59 -0700996 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700997 case PATH_QUAD:
998 last = 6;
999 break;
1000 case PATH_CUBIC:
1001 last = 8;
1002 break;
1003 default:
1004 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
1005 throw "stop execution";
1006 }
1007 break;
caryclarkdac1d172014-06-17 05:15:38 -07001008 case REC_TYPE_SECT:
1009 switch (fragType) {
1010 case INTERSECT_LINE:
1011 first = 1; last = 5; first2 = 8; last2 = 12;
1012 break;
1013 case INTERSECT_LINE_2:
1014 first = 1; last = 5; first2 = 11; last2 = 15;
1015 break;
1016 case INTERSECT_LINE_NO:
1017 first = 0; last = 4; first2 = 4; last2 = 8;
1018 break;
caryclark1049f122015-04-20 08:31:59 -07001019 case INTERSECT_CONIC_LINE:
1020 first = 1; last = 7; first2 = 11; last2 = 15;
1021 break;
caryclarkdac1d172014-06-17 05:15:38 -07001022 case INTERSECT_QUAD_LINE:
1023 first = 1; last = 7; first2 = 10; last2 = 14;
1024 break;
caryclark1049f122015-04-20 08:31:59 -07001025 case INTERSECT_CONIC_LINE_2:
1026 first = 1; last = 7; first2 = 14; last2 = 18;
1027 break;
caryclarkdac1d172014-06-17 05:15:38 -07001028 case INTERSECT_QUAD_LINE_2:
1029 first = 1; last = 7; first2 = 13; last2 = 17;
1030 break;
caryclark1049f122015-04-20 08:31:59 -07001031 case INTERSECT_CONIC_LINE_NO:
1032 first = 0; last = 6; first2 = 7; last2 = 11;
1033 break;
caryclarkdac1d172014-06-17 05:15:38 -07001034 case INTERSECT_QUAD_LINE_NO:
1035 first = 0; last = 6; first2 = 6; last2 = 10;
1036 break;
caryclark1049f122015-04-20 08:31:59 -07001037 case INTERSECT_CONIC:
1038 first = 1; last = 7; first2 = 11; last2 = 17;
1039 break;
caryclarkdac1d172014-06-17 05:15:38 -07001040 case INTERSECT_QUAD:
1041 first = 1; last = 7; first2 = 10; last2 = 16;
1042 break;
caryclark1049f122015-04-20 08:31:59 -07001043 case INTERSECT_CONIC_2:
1044 first = 1; last = 7; first2 = 14; last2 = 20;
1045 break;
caryclarkdac1d172014-06-17 05:15:38 -07001046 case INTERSECT_QUAD_2:
1047 first = 1; last = 7; first2 = 13; last2 = 19;
1048 break;
caryclark1049f122015-04-20 08:31:59 -07001049 case INTERSECT_CONIC_NO:
1050 first = 0; last = 6; first2 = 7; last2 = 13;
1051 break;
caryclarkdac1d172014-06-17 05:15:38 -07001052 case INTERSECT_QUAD_NO:
1053 first = 0; last = 6; first2 = 6; last2 = 12;
1054 break;
1055 case INTERSECT_SELF_CUBIC:
1056 first = 1; last = 9;
1057 break;
1058 case INTERSECT_SELF_CUBIC_NO:
1059 first = 0; last = 8;
1060 break;
1061 case INTERSECT_CUBIC_LINE:
1062 first = 1; last = 9; first2 = 12; last2 = 16;
1063 break;
1064 case INTERSECT_CUBIC_LINE_2:
1065 first = 1; last = 9; first2 = 15; last2 = 19;
1066 break;
1067 case INTERSECT_CUBIC_LINE_3:
1068 first = 1; last = 9; first2 = 18; last2 = 22;
1069 break;
1070 case INTERSECT_CUBIC_LINE_NO:
1071 first = 0; last = 8; first2 = 8; last2 = 12;
1072 break;
1073 case INTERSECT_CUBIC_QUAD:
1074 first = 1; last = 9; first2 = 12; last2 = 18;
1075 break;
1076 case INTERSECT_CUBIC_QUAD_2:
1077 first = 1; last = 9; first2 = 15; last2 = 21;
1078 break;
1079 case INTERSECT_CUBIC_QUAD_3:
1080 first = 1; last = 9; first2 = 18; last2 = 24;
1081 break;
1082 case INTERSECT_CUBIC_QUAD_4:
1083 first = 1; last = 9; first2 = 21; last2 = 27;
1084 break;
1085 case INTERSECT_CUBIC_QUAD_NO:
1086 first = 0; last = 8; first2 = 8; last2 = 14;
1087 break;
1088 case INTERSECT_CUBIC:
1089 first = 1; last = 9; first2 = 12; last2 = 20;
1090 break;
1091 case INTERSECT_CUBIC_2:
1092 first = 1; last = 9; first2 = 15; last2 = 23;
1093 break;
1094 case INTERSECT_CUBIC_3:
1095 first = 1; last = 9; first2 = 18; last2 = 26;
1096 break;
1097 case INTERSECT_CUBIC_4:
1098 first = 1; last = 9; first2 = 21; last2 = 29;
1099 break;
1100 case INTERSECT_CUBIC_NO:
1101 first = 0; last = 8; first2 = 8; last2 = 16;
1102 break;
1103 default:
1104 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1105 throw "stop execution";
1106 }
1107 break;
1108 default:
1109 continue;
1110 }
1111 for (var idx = first; idx < last; idx += 2) {
1112 xmin = Math.min(xmin, frags[idx]);
1113 xmax = Math.max(xmax, frags[idx]);
1114 ymin = Math.min(ymin, frags[idx + 1]);
1115 ymax = Math.max(ymax, frags[idx + 1]);
1116 }
1117 for (var idx = first2; idx < last2; idx += 2) {
1118 xmin = Math.min(xmin, frags[idx]);
1119 xmax = Math.max(xmax, frags[idx]);
1120 ymin = Math.min(ymin, frags[idx + 1]);
1121 ymax = Math.max(ymax, frags[idx + 1]);
1122 }
1123 }
1124 }
1125 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1126 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1127 var recType = test[tIndex];
1128 var records = test[tIndex + 2];
1129 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1130 var fragType = records[recordIndex];
1131 var frags = records[recordIndex + 1];
1132 switch (recType) {
1133 case REC_TYPE_ACTIVE_OP:
1134 if (!draw_op) {
1135 break;
1136 }
1137 {
1138 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1139 curve_extremes(curve, angleBounds);
1140 }
1141 break;
1142 case REC_TYPE_ANGLE:
1143 if (!draw_angle) {
1144 break;
1145 }
caryclark54359292015-03-26 07:52:43 -07001146 {
caryclarkdac1d172014-06-17 05:15:38 -07001147 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1148 curve_extremes(curve, angleBounds);
1149 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1150 curve_extremes(curve, angleBounds);
1151 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1152 }
1153 break;
1154 case REC_TYPE_SORT:
1155 if (!draw_sort) {
1156 break;
1157 }
1158 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1159 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1160 curve_extremes(curve, angleBounds);
1161 }
1162 break;
caryclark03b03ca2015-04-23 09:13:37 -07001163 case REC_TYPE_TOP:
1164 if (!draw_top) {
1165 break;
1166 }
1167 {
1168 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1169 curve_extremes(curve, angleBounds);
1170 }
1171 break;
caryclarkdac1d172014-06-17 05:15:38 -07001172 }
1173 }
1174 }
1175 xmin = Math.min(xmin, angleBounds[0]);
1176 ymin = Math.min(ymin, angleBounds[1]);
1177 xmax = Math.max(xmax, angleBounds[2]);
1178 ymax = Math.max(ymax, angleBounds[3]);
1179 setScale(xmin, xmax, ymin, ymax);
1180 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001181 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001182 }
1183 if (hasPath == true && hasComputedPath == false && draw_computed) {
1184 draw_computed = 0;
1185 }
1186}
1187
1188function curveByID(test, id) {
caryclark54359292015-03-26 07:52:43 -07001189 var tIndex = -3;
1190 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001191 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001192 if (recType == REC_TYPE_OP) {
1193 continue;
1194 }
1195 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001196 return [];
1197 }
1198 var records = test[tIndex + 2];
1199 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1200 var fragType = records[recordIndex];
1201 var frags = records[recordIndex + 1];
1202 if (frags[0] == id) {
1203 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001204 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001205 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001206 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001207 return [frags[1], frags[2], frags[3], frags[4],
1208 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001209 case PATH_CONIC:
1210 return [frags[1], frags[2], frags[3], frags[4],
1211 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001212 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001213 return [frags[1], frags[2], frags[3], frags[4],
1214 frags[5], frags[6], frags[7], frags[8]];
1215 }
1216 }
1217 }
caryclarkdac1d172014-06-17 05:15:38 -07001218 }
1219 return [];
1220}
1221
1222function curvePartialByID(test, id, t0, t1) {
caryclark54359292015-03-26 07:52:43 -07001223 var tIndex = -3;
1224 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001225 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001226 if (recType == REC_TYPE_OP) {
1227 continue;
1228 }
1229 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001230 return [];
1231 }
1232 var records = test[tIndex + 2];
1233 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1234 var fragType = records[recordIndex];
1235 var frags = records[recordIndex + 1];
1236 if (frags[0] == id) {
1237 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001238 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001239 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001240 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001241 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1242 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001243 case PATH_CONIC:
1244 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1245 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001246 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001247 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1248 frags[5], frags[6], frags[7], frags[8], t0, t1);
1249 }
1250 }
1251 }
caryclarkdac1d172014-06-17 05:15:38 -07001252 }
1253 return [];
1254}
1255
1256function idByCurve(test, frag, type) {
caryclark54359292015-03-26 07:52:43 -07001257 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001258 while (tIndex < test.length) {
1259 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001260 if (recType != REC_TYPE_PATH) {
1261 ++tIndex;
1262 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001263 }
1264 var records = test[tIndex + 2];
1265 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1266 var fragType = records[recordIndex];
1267 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001268 if (frag.length != frags.length - 1) {
1269 continue;
1270 }
caryclarkdac1d172014-06-17 05:15:38 -07001271 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001272 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001273 if (frag[0] != frags[1] || frag[1] != frags[2]
1274 || frag[2] != frags[3] || frag[3] != frags[4]) {
1275 continue;
1276 }
1277 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001278 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001279 if (frag[0] != frags[1] || frag[1] != frags[2]
1280 || frag[2] != frags[3] || frag[3] != frags[4]
1281 || frag[4] != frags[5] || frag[5] != frags[6]) {
1282 continue;
1283 }
1284 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001285 case PATH_CONIC:
1286 if (frag[0] != frags[1] || frag[1] != frags[2]
1287 || frag[2] != frags[3] || frag[3] != frags[4]
1288 || frag[4] != frags[5] || frag[5] != frags[6]
1289 || frag[6] != frags[7]) {
1290 continue;
1291 }
1292 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001293 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001294 if (frag[0] != frags[1] || frag[1] != frags[2]
1295 || frag[2] != frags[3] || frag[3] != frags[4]
1296 || frag[4] != frags[5] || frag[5] != frags[6]
1297 || frag[6] != frags[7] || frag[7] != frags[8]) {
1298 continue;
1299 }
1300 return frags[0];
1301 }
1302 }
1303 ++tIndex;
1304 }
1305 return -1;
1306}
1307
1308function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001309 var length = curve.length == 7 ? 6 : curve.length;
caryclarkdac1d172014-06-17 05:15:38 -07001310 for (var index = 0; index < curve.length; index += 2) {
1311 var x = curve[index];
1312 var y = curve[index + 1];
1313 bounds[0] = Math.min(bounds[0], x);
1314 bounds[1] = Math.min(bounds[1], y);
1315 bounds[2] = Math.max(bounds[2], x);
1316 bounds[3] = Math.max(bounds[3], y);
1317 }
1318}
1319
1320function setScale(x0, x1, y0, y1) {
1321 var srcWidth = x1 - x0;
1322 var srcHeight = y1 - y0;
1323 var usableWidth = screenWidth;
1324 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1325 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1326 usableWidth -= (xDigits + yDigits) * 10;
1327 usableWidth -= decimal_places * 10;
1328 if (draw_legend) {
1329 usableWidth -= 40;
1330 }
1331 var hscale = usableWidth / srcWidth;
1332 var vscale = screenHeight / srcHeight;
1333 scale = Math.min(hscale, vscale);
1334 var invScale = 1 / scale;
1335 var sxmin = x0 - invScale * 5;
1336 var symin = y0 - invScale * 10;
1337 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1338 var symax = y1 + invScale * 10;
1339 srcWidth = sxmax - sxmin;
1340 srcHeight = symax - symin;
1341 hscale = usableWidth / srcWidth;
1342 vscale = screenHeight / srcHeight;
1343 scale = Math.min(hscale, vscale);
1344 srcLeft = sxmin;
1345 srcTop = symin;
1346}
1347
1348function drawArc(curve, op, from, to) {
1349 var type = PATH_LINE + (curve.length / 2 - 2);
1350 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1351 var dy = pt.y - curve[1];
1352 var dx = pt.x - curve[0];
1353 var dist = Math.sqrt(dy * dy + dx * dx);
1354 var _dist = dist * scale;
1355 var angle = Math.atan2(dy, dx);
1356 var _px = (curve[0] - srcLeft) * scale;
1357 var _py = (curve[1] - srcTop) * scale;
1358 var divisor = 4;
1359 var endDist;
1360 do {
1361 var ends = [];
1362 for (var index = -1; index <= 1; index += 2) {
1363 var px = Math.cos(index * Math.PI / divisor);
1364 var py = Math.sin(index * Math.PI / divisor);
1365 ends.push(px);
1366 ends.push(py);
1367 }
1368 var endDx = (ends[2] - ends[0]) * scale * dist;
1369 var endDy = (ends[3] - ends[1]) * scale * dist;
1370 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1371 if (endDist < 100) {
1372 break;
1373 }
1374 divisor *= 2;
1375 } while (true);
1376 if (endDist < 30) {
1377 return;
1378 }
1379 if (op) {
1380 divisor *= 2;
1381 }
1382 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1383 ctx.beginPath();
1384 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1385 ctx.stroke();
1386 var saveAlign = ctx.textAlign;
1387 var saveStyle = ctx.fillStyle;
1388 var saveFont = ctx.font;
1389 ctx.textAlign = "center";
1390 ctx.fillStyle = "black";
1391 ctx.font = "normal 24px Arial";
1392 divisor *= 0.8;
1393 for (var index = -1; index <= 1; index += 2) {
1394 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1395 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1396 var _px = (px - srcLeft) * scale;
1397 var _py = (py - srcTop) * scale;
1398 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1399 }
1400 ctx.textAlign = saveAlign;
1401 ctx.fillStyle = saveStyle;
1402 ctx.font = saveFont;
1403}
1404
1405function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001406 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1407 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001408 var x = drawnPts[pts];
1409 var y = drawnPts[pts + 1];
1410 if (px == x && py == y) {
1411 return;
1412 }
1413 }
1414 drawnPts.push(px);
1415 drawnPts.push(py);
1416 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1417 var _px = (px - srcLeft) * scale;
1418 var _py = (py - srcTop) * scale;
1419 ctx.beginPath();
1420 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1421 ctx.closePath();
1422 if (end) {
1423 ctx.fill();
1424 } else {
1425 ctx.stroke();
1426 }
1427 if (debug_xy) {
1428 ctx.textAlign = "left";
1429 ctx.fillText(label, _px + 5, _py);
1430 }
1431}
1432
caryclark1049f122015-04-20 08:31:59 -07001433function coordCount(curveType) {
1434 switch (curveType) {
1435 case PATH_LINE:
1436 return 4;
1437 case PATH_QUAD:
1438 return 6;
1439 case PATH_CONIC:
1440 return 6;
1441 case PATH_CUBIC:
1442 return 8;
1443 }
1444 return -1;
1445}
1446
caryclarkdac1d172014-06-17 05:15:38 -07001447function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001448 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001449 for (var idx = 0; idx < count; idx += 2) {
1450 if (!drawControls && idx != 0 && idx != count - 2) {
1451 continue;
1452 }
1453 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1454 }
1455}
1456
1457function drawControlLines(curve, curveType, drawEnd) {
1458 if (curveType == PATH_LINE) {
1459 return;
1460 }
1461 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1462 drawLine(curve[0], curve[1], curve[2], curve[3]);
1463 drawLine(curve[2], curve[3], curve[4], curve[5]);
1464 if (curveType == PATH_CUBIC) {
1465 drawLine(curve[4], curve[5], curve[6], curve[7]);
1466 if (drawEnd > 1) {
1467 drawLine(curve[6], curve[7], curve[0], curve[1]);
1468 if (drawEnd > 2) {
1469 drawLine(curve[0], curve[1], curve[4], curve[5]);
1470 drawLine(curve[6], curve[7], curve[2], curve[3]);
1471 }
1472 }
1473 } else if (drawEnd > 1) {
1474 drawLine(curve[4], curve[5], curve[0], curve[1]);
1475 }
1476}
1477
1478function pointAtT(curve, curveType, t) {
1479 var xy = {};
1480 switch (curveType) {
1481 case PATH_LINE:
1482 var a = 1 - t;
1483 var b = t;
1484 xy.x = a * curve[0] + b * curve[2];
1485 xy.y = a * curve[1] + b * curve[3];
1486 break;
1487 case PATH_QUAD:
1488 var one_t = 1 - t;
1489 var a = one_t * one_t;
1490 var b = 2 * one_t * t;
1491 var c = t * t;
1492 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1493 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1494 break;
caryclark1049f122015-04-20 08:31:59 -07001495 case PATH_CONIC:
1496 var one_t = 1 - t;
1497 var a = one_t * one_t;
1498 var b = 2 * one_t * t;
1499 var c = t * t;
1500 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1501 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1502 var d = a + b * curve[6] + c;
1503 xy.x /= d;
1504 xy.y /= d;
1505 break;
caryclarkdac1d172014-06-17 05:15:38 -07001506 case PATH_CUBIC:
1507 var one_t = 1 - t;
1508 var one_t2 = one_t * one_t;
1509 var a = one_t2 * one_t;
1510 var b = 3 * one_t2 * t;
1511 var t2 = t * t;
1512 var c = 3 * one_t * t2;
1513 var d = t2 * t;
1514 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1515 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1516 break;
1517 }
1518 return xy;
1519}
1520
1521function drawPointAtT(curve, curveType) {
1522 var x, y;
1523 var xy = pointAtT(curve, curveType, curveT);
1524 drawPoint(xy.x, xy.y, true);
1525 if (!draw_intersectT) {
1526 return;
1527 }
1528 ctx.fillStyle = "red";
1529 drawTAtPointUp(xy.x, xy.y, curveT);
1530}
1531
1532function drawTAtPointUp(px, py, t) {
1533 var label = t.toFixed(decimal_places);
1534 var _px = (px - srcLeft)* scale;
1535 var _py = (py - srcTop) * scale;
1536 ctx.fillText(label, _px + 5, _py - 10);
1537}
1538
1539function drawTAtPointDown(px, py, t) {
1540 var label = t.toFixed(decimal_places);
1541 var _px = (px - srcLeft)* scale;
1542 var _py = (py - srcTop) * scale;
1543 ctx.fillText(label, _px + 5, _py + 10);
1544}
1545
1546function alreadyDrawnLine(x1, y1, x2, y2) {
1547 if (collect_bounds) {
1548 if (focus_enabled) {
1549 focusXmin = Math.min(focusXmin, x1, x2);
1550 focusYmin = Math.min(focusYmin, y1, y2);
1551 focusXmax = Math.max(focusXmax, x1, x2);
1552 focusYmax = Math.max(focusYmax, y1, y2);
1553 }
1554 return true;
1555 }
1556 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1557 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1558 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1559 return true;
1560 }
1561 }
1562 drawnLines.push(x1);
1563 drawnLines.push(y1);
1564 drawnLines.push(x2);
1565 drawnLines.push(y2);
1566 return false;
1567}
1568
1569function drawLine(x1, y1, x2, y2) {
1570 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1571 return;
1572 }
1573 ctx.beginPath();
1574 ctx.moveTo((x1 - srcLeft) * scale,
1575 (y1 - srcTop) * scale);
1576 ctx.lineTo((x2 - srcLeft) * scale,
1577 (y2 - srcTop) * scale);
1578 ctx.stroke();
1579}
1580
1581function linePartial(x1, y1, x2, y2, t1, t2) {
1582 var dx = x1 - x2;
1583 var dy = y1 - y2;
1584 var array = [
1585 x1 - t1 * dx,
1586 y1 - t1 * dy,
1587 x1 - t2 * dx,
1588 y1 - t2 * dy
1589 ];
1590 return array;
1591}
1592
1593function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1594 var a = linePartial(x1, y1, x2, y2, t1, t2);
1595 var ax = a[0];
1596 var ay = a[1];
1597 var bx = a[2];
1598 var by = a[3];
1599 if (alreadyDrawnLine(ax, ay, bx, by)) {
1600 return;
1601 }
1602 ctx.beginPath();
1603 ctx.moveTo((ax - srcLeft) * scale,
1604 (ay - srcTop) * scale);
1605 ctx.lineTo((bx - srcLeft) * scale,
1606 (by - srcTop) * scale);
1607 ctx.stroke();
1608}
1609
1610function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1611 if (collect_bounds) {
1612 if (focus_enabled) {
1613 focusXmin = Math.min(focusXmin, x1, x2, x3);
1614 focusYmin = Math.min(focusYmin, y1, y2, y3);
1615 focusXmax = Math.max(focusXmax, x1, x2, x3);
1616 focusYmax = Math.max(focusYmax, y1, y2, y3);
1617 }
1618 return true;
1619 }
1620 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1621 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1622 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1623 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1624 return true;
1625 }
1626 }
1627 drawnQuads.push(x1);
1628 drawnQuads.push(y1);
1629 drawnQuads.push(x2);
1630 drawnQuads.push(y2);
1631 drawnQuads.push(x3);
1632 drawnQuads.push(y3);
1633 return false;
1634}
1635
1636function drawQuad(x1, y1, x2, y2, x3, y3) {
1637 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1638 return;
1639 }
1640 ctx.beginPath();
1641 ctx.moveTo((x1 - srcLeft) * scale,
1642 (y1 - srcTop) * scale);
1643 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1644 (y2 - srcTop) * scale,
1645 (x3 - srcLeft) * scale,
1646 (y3 - srcTop) * scale);
1647 ctx.stroke();
1648}
1649
1650function interp(A, B, t) {
1651 return A + (B - A) * t;
1652}
1653
1654function interp_quad_coords(x1, x2, x3, t)
1655{
1656 var ab = interp(x1, x2, t);
1657 var bc = interp(x2, x3, t);
1658 var abc = interp(ab, bc, t);
1659 return abc;
1660}
1661
1662function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1663 var ax = interp_quad_coords(x1, x2, x3, t1);
1664 var ay = interp_quad_coords(y1, y2, y3, t1);
1665 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1666 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1667 var cx = interp_quad_coords(x1, x2, x3, t2);
1668 var cy = interp_quad_coords(y1, y2, y3, t2);
1669 var bx = 2*dx - (ax + cx)/2;
1670 var by = 2*dy - (ay + cy)/2;
1671 var array = [
1672 ax, ay, bx, by, cx, cy
1673 ];
1674 return array;
1675}
1676
1677function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1678 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1679 var ax = a[0];
1680 var ay = a[1];
1681 var bx = a[2];
1682 var by = a[3];
1683 var cx = a[4];
1684 var cy = a[5];
1685 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1686 return;
1687 }
1688 ctx.beginPath();
1689 ctx.moveTo((ax - srcLeft) * scale,
1690 (ay - srcTop) * scale);
1691 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1692 (by - srcTop) * scale,
1693 (cx - srcLeft) * scale,
1694 (cy - srcTop) * scale);
1695 ctx.stroke();
1696}
1697
caryclark1049f122015-04-20 08:31:59 -07001698function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1699 if (collect_bounds) {
1700 if (focus_enabled) {
1701 focusXmin = Math.min(focusXmin, x1, x2, x3);
1702 focusYmin = Math.min(focusYmin, y1, y2, y3);
1703 focusXmax = Math.max(focusXmax, x1, x2, x3);
1704 focusYmax = Math.max(focusYmax, y1, y2, y3);
1705 }
1706 return true;
1707 }
1708 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1709 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
1710 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1711 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1712 && w == drawnCubics[pts + 6]) {
1713 return true;
1714 }
1715 }
1716 drawnConics.push(x1);
1717 drawnConics.push(y1);
1718 drawnConics.push(x2);
1719 drawnConics.push(y2);
1720 drawnConics.push(x3);
1721 drawnConics.push(y3);
1722 drawnCubics.push(w);
1723 return false;
1724}
1725
1726var kMaxConicToQuadPOW2 = 5;
1727
1728function computeQuadPOW2(curve, tol) {
1729 var a = curve[6] - 1;
1730 var k = a / (4 * (2 + a));
1731 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1732 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1733
1734 var error = Math.sqrt(x * x + y * y);
1735 var pow2;
1736 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1737 if (error <= tol) {
1738 break;
1739 }
1740 error *= 0.25;
1741 }
1742 return pow2;
1743}
1744
1745function subdivide_w_value(w) {
1746 return Math.sqrt(0.5 + w * 0.5);
1747}
1748
1749function chop(curve, part1, part2) {
1750 var w = curve[6];
1751 var scale = 1 / (1 + w);
1752 part1[0] = curve[0];
1753 part1[1] = curve[1];
1754 part1[2] = (curve[0] + curve[2] * w) * scale;
1755 part1[3] = (curve[1] + curve[3] * w) * scale;
1756 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1757 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1758 part2[2] = (curve[2] * w + curve[4]) * scale;
1759 part2[3] = (curve[3] * w + curve[5]) * scale;
1760 part2[4] = curve[4];
1761 part2[5] = curve[5];
1762 part1[6] = part2[6] = subdivide_w_value(w);
1763}
1764
1765function subdivide(curve, level, pts) {
1766 if (0 == level) {
1767 pts.push(curve[2]);
1768 pts.push(curve[3]);
1769 pts.push(curve[4]);
1770 pts.push(curve[5]);
1771 } else {
1772 var part1 = [], part2 = [];
1773 chop(curve, part1, part2);
1774 --level;
1775 subdivide(part1, level, pts);
1776 subdivide(part2, level, pts);
1777 }
1778}
1779
1780function chopIntoQuadsPOW2(curve, pow2, pts) {
1781 subdivide(curve, pow2, pts);
1782 return 1 << pow2;
1783}
1784
1785function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1786 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1787 return;
1788 }
1789 ctx.beginPath();
1790 ctx.moveTo((x1 - srcLeft) * scale,
1791 (y1 - srcTop) * scale);
1792 var tol = 1 / scale;
1793 var curve = [x1, y1, x2, y2, x3, y3, w];
1794 var pow2 = computeQuadPOW2(curve, tol);
1795 var pts = [];
1796 chopIntoQuadsPOW2(curve, pow2, pts);
1797 for (var i = 0; i < pts.length; i += 4) {
1798 ctx.quadraticCurveTo(
1799 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1800 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1801 }
1802 ctx.stroke();
1803}
1804
1805function conic_eval_numerator(x1, x2, x3, w, t) {
1806 var src2w = x2 * w;
1807 var C = x1;
1808 var A = x3 - 2 * src2w + C;
1809 var B = 2 * (src2w - C);
1810 return (A * t + B) * t + C;
1811}
1812
1813
1814function conic_eval_denominator(w, t) {
1815 var B = 2 * (w - 1);
1816 var C = 1;
1817 var A = -B;
1818 return (A * t + B) * t + C;
1819}
1820
1821function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1822 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1823 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1824 var az = conic_eval_denominator(w, t1);
1825 var midT = (t1 + t2) / 2;
1826 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1827 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1828 var dz = conic_eval_denominator(w, midT);
1829 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1830 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1831 var cz = conic_eval_denominator(w, t2);
1832 var bx = 2 * dx - (ax + cx) / 2;
1833 var by = 2 * dy - (ay + cy) / 2;
1834 var bz = 2 * dz - (az + cz) / 2;
1835 var dt = t2 - t1;
1836 var dt_1 = 1 - dt;
1837 var partW = (1 + dt * (w - 1)) / Math.sqrt(dt * dt + 2 * dt * dt_1 * w + dt_1 * dt_1);
1838 var array = [
1839 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, partW
1840 ];
1841 return array;
1842}
1843
1844function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1845 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1846 var ax = a[0];
1847 var ay = a[1];
1848 var bx = a[2];
1849 var by = a[3];
1850 var cx = a[4];
1851 var cy = a[5];
1852 var w_ = a[6];
1853 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1854}
1855
caryclarkdac1d172014-06-17 05:15:38 -07001856function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1857 if (collect_bounds) {
1858 if (focus_enabled) {
1859 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1860 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1861 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1862 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1863 }
1864 return true;
1865 }
1866 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1867 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
1868 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1869 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1870 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1871 return true;
1872 }
1873 }
1874 drawnCubics.push(x1);
1875 drawnCubics.push(y1);
1876 drawnCubics.push(x2);
1877 drawnCubics.push(y2);
1878 drawnCubics.push(x3);
1879 drawnCubics.push(y3);
1880 drawnCubics.push(x4);
1881 drawnCubics.push(y4);
1882 return false;
1883}
1884
1885function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1886 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1887 return;
1888 }
1889 ctx.beginPath();
1890 ctx.moveTo((x1 - srcLeft) * scale,
1891 (y1 - srcTop) * scale);
1892 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1893 (y2 - srcTop) * scale,
1894 (x3 - srcLeft) * scale,
1895 (y3 - srcTop) * scale,
1896 (x4 - srcLeft) * scale,
1897 (y4 - srcTop) * scale);
1898 ctx.stroke();
1899}
1900
1901function interp_cubic_coords(x1, x2, x3, x4, t)
1902{
1903 var ab = interp(x1, x2, t);
1904 var bc = interp(x2, x3, t);
1905 var cd = interp(x3, x4, t);
1906 var abc = interp(ab, bc, t);
1907 var bcd = interp(bc, cd, t);
1908 var abcd = interp(abc, bcd, t);
1909 return abcd;
1910}
1911
1912function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1913 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1914 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1915 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1916 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1917 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1918 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1919 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1920 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1921 var mx = ex * 27 - ax * 8 - dx;
1922 var my = ey * 27 - ay * 8 - dy;
1923 var nx = fx * 27 - ax - dx * 8;
1924 var ny = fy * 27 - ay - dy * 8;
1925 var bx = (mx * 2 - nx) / 18;
1926 var by = (my * 2 - ny) / 18;
1927 var cx = (nx * 2 - mx) / 18;
1928 var cy = (ny * 2 - my) / 18;
1929 var array = [
1930 ax, ay, bx, by, cx, cy, dx, dy
1931 ];
1932 return array;
1933}
1934
1935function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1936 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
1937 var ax = a[0];
1938 var ay = a[1];
1939 var bx = a[2];
1940 var by = a[3];
1941 var cx = a[4];
1942 var cy = a[5];
1943 var dx = a[6];
1944 var dy = a[7];
1945 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
1946 return;
1947 }
1948 ctx.beginPath();
1949 ctx.moveTo((ax - srcLeft) * scale,
1950 (ay - srcTop) * scale);
1951 ctx.bezierCurveTo((bx - srcLeft) * scale,
1952 (by - srcTop) * scale,
1953 (cx - srcLeft) * scale,
1954 (cy - srcTop) * scale,
1955 (dx - srcLeft) * scale,
1956 (dy - srcTop) * scale);
1957 ctx.stroke();
1958}
1959
1960function drawCurve(c) {
1961 switch (c.length) {
1962 case 4:
1963 drawLine(c[0], c[1], c[2], c[3]);
1964 break;
1965 case 6:
1966 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1967 break;
caryclark1049f122015-04-20 08:31:59 -07001968 case 7:
1969 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
1970 break;
caryclarkdac1d172014-06-17 05:15:38 -07001971 case 8:
1972 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1973 break;
1974 }
1975}
1976
1977function boundsWidth(pts) {
1978 var min = pts[0];
1979 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07001980 var length = pts.length == 7 ? 6 : pts.length;
1981 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001982 min = Math.min(min, pts[idx]);
1983 max = Math.max(max, pts[idx]);
1984 }
1985 return max - min;
1986}
1987
1988function boundsHeight(pts) {
1989 var min = pts[1];
1990 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07001991 var length = pts.length == 7 ? 6 : pts.length;
1992 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001993 min = Math.min(min, pts[idx]);
1994 max = Math.max(max, pts[idx]);
1995 }
1996 return max - min;
1997}
1998
1999function tangent(pts) {
2000 var dx = pts[2] - pts[0];
2001 var dy = pts[3] - pts[1];
2002 if (dx == 0 && dy == 0 && pts.length > 4) {
2003 dx = pts[4] - pts[0];
2004 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002005 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002006 dx = pts[6] - pts[0];
2007 dy = pts[7] - pts[1];
2008 }
2009 }
2010 return Math.atan2(-dy, dx);
2011}
2012
2013function hodograph(cubic) {
2014 var hodo = [];
2015 hodo[0] = 3 * (cubic[2] - cubic[0]);
2016 hodo[1] = 3 * (cubic[3] - cubic[1]);
2017 hodo[2] = 3 * (cubic[4] - cubic[2]);
2018 hodo[3] = 3 * (cubic[5] - cubic[3]);
2019 hodo[4] = 3 * (cubic[6] - cubic[4]);
2020 hodo[5] = 3 * (cubic[7] - cubic[5]);
2021 return hodo;
2022}
2023
2024function hodograph2(cubic) {
2025 var quad = hodograph(cubic);
2026 var hodo = [];
2027 hodo[0] = 2 * (quad[2] - quad[0]);
2028 hodo[1] = 2 * (quad[3] - quad[1]);
2029 hodo[2] = 2 * (quad[4] - quad[2]);
2030 hodo[3] = 2 * (quad[5] - quad[3]);
2031 return hodo;
2032}
2033
2034function quadraticRootsReal(A, B, C, s) {
2035 if (A == 0) {
2036 if (B == 0) {
2037 s[0] = 0;
2038 return C == 0;
2039 }
2040 s[0] = -C / B;
2041 return 1;
2042 }
2043 /* normal form: x^2 + px + q = 0 */
2044 var p = B / (2 * A);
2045 var q = C / A;
2046 var p2 = p * p;
2047 if (p2 < q) {
2048 return 0;
2049 }
2050 var sqrt_D = 0;
2051 if (p2 > q) {
2052 sqrt_D = sqrt(p2 - q);
2053 }
2054 s[0] = sqrt_D - p;
2055 s[1] = -sqrt_D - p;
2056 return 1 + s[0] != s[1];
2057}
2058
2059function add_valid_ts(s, realRoots, t) {
2060 var foundRoots = 0;
2061 for (var index = 0; index < realRoots; ++index) {
2062 var tValue = s[index];
2063 if (tValue >= 0 && tValue <= 1) {
2064 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2065 if (t[idx2] != tValue) {
2066 t[foundRoots++] = tValue;
2067 }
2068 }
2069 }
2070 }
2071 return foundRoots;
2072}
2073
2074function quadraticRootsValidT(a, b, c, t) {
2075 var s = [];
2076 var realRoots = quadraticRootsReal(A, B, C, s);
2077 var foundRoots = add_valid_ts(s, realRoots, t);
2078 return foundRoots != 0;
2079}
2080
2081function find_cubic_inflections(cubic, tValues) {
2082 var Ax = src[2] - src[0];
2083 var Ay = src[3] - src[1];
2084 var Bx = src[4] - 2 * src[2] + src[0];
2085 var By = src[5] - 2 * src[3] + src[1];
2086 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2087 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2088 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2089 Ax * By - Ay * Bx, tValues);
2090}
2091
2092function dxy_at_t(curve, type, t) {
2093 var dxy = {};
2094 if (type == PATH_QUAD) {
2095 var a = t - 1;
2096 var b = 1 - 2 * t;
2097 var c = t;
2098 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2099 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002100 } else if (type == PATH_CONIC) {
2101 var p20x = curve[4] - curve[0];
2102 var p20y = curve[5] - curve[1];
2103 var p10xw = (curve[2] - curve[0]) * curve[6];
2104 var p10yw = (curve[3] - curve[1]) * curve[6];
2105 var coeff0x = curve[6] * p20x - p20x;
2106 var coeff0y = curve[6] * p20y - p20y;
2107 var coeff1x = p20x - 2 * p10xw;
2108 var coeff1y = p20y - 2 * p10yw;
2109 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2110 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002111 } else if (type == PATH_CUBIC) {
2112 var one_t = 1 - t;
2113 var a = curve[0];
2114 var b = curve[2];
2115 var c = curve[4];
2116 var d = curve[6];
2117 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2118 a = curve[1];
2119 b = curve[3];
2120 c = curve[5];
2121 d = curve[7];
2122 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2123 }
2124 return dxy;
2125}
2126
2127function drawLabel(num, px, py) {
2128 ctx.beginPath();
2129 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2130 ctx.closePath();
2131 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2132 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2133 ctx.stroke();
2134 ctx.fillStyle = "black";
2135 ctx.font = "normal 10px Arial";
2136 // ctx.rotate(0.001);
2137 ctx.fillText(num, px - 2, py + 3);
2138 // ctx.rotate(-0.001);
2139}
2140
2141function drawLabelX(ymin, num, loc) {
2142 var px = (loc - srcLeft) * scale;
2143 var py = (ymin - srcTop) * scale - 20;
2144 drawLabel(num, px, py);
2145}
2146
2147function drawLabelY(xmin, num, loc) {
2148 var px = (xmin - srcLeft) * scale - 20;
2149 var py = (loc - srcTop) * scale;
2150 drawLabel(num, px, py);
2151}
2152
2153function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2154 ctx.beginPath();
2155 ctx.moveTo(hx, hy - 100);
2156 ctx.lineTo(hx, hy);
2157 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2158 ctx.stroke();
2159 ctx.beginPath();
2160 ctx.moveTo(hx, hy);
2161 ctx.lineTo(hx, hy + 100);
2162 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2163 ctx.stroke();
2164 ctx.beginPath();
2165 ctx.moveTo(hx - 100, hy);
2166 ctx.lineTo(hx, hy);
2167 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2168 ctx.stroke();
2169 ctx.beginPath();
2170 ctx.moveTo(hx, hy);
2171 ctx.lineTo(hx + 100, hy);
2172 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2173 ctx.stroke();
2174}
2175
2176function scalexy(x, y, mag) {
2177 var length = Math.sqrt(x * x + y * y);
2178 return mag / length;
2179}
2180
caryclark03b03ca2015-04-23 09:13:37 -07002181function drawArrow(x, y, dx, dy, s) {
2182 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002183 dx *= dscale;
2184 dy *= dscale;
2185 ctx.beginPath();
2186 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2187 x += dx;
2188 y += dy;
2189 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2190 dx /= 10;
2191 dy /= 10;
2192 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2193 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2194 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2195 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2196 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2197 ctx.stroke();
2198}
2199
2200function x_at_t(curve, t) {
2201 var one_t = 1 - t;
2202 if (curve.length == 4) {
2203 return one_t * curve[0] + t * curve[2];
2204 }
2205 var one_t2 = one_t * one_t;
2206 var t2 = t * t;
2207 if (curve.length == 6) {
2208 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2209 }
caryclark1049f122015-04-20 08:31:59 -07002210 if (curve.length == 7) {
2211 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2212 / (one_t2 +2 * one_t * t * curve[6] + t2);
2213 }
caryclarkdac1d172014-06-17 05:15:38 -07002214 var a = one_t2 * one_t;
2215 var b = 3 * one_t2 * t;
2216 var c = 3 * one_t * t2;
2217 var d = t2 * t;
2218 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2219}
2220
2221function y_at_t(curve, t) {
2222 var one_t = 1 - t;
2223 if (curve.length == 4) {
2224 return one_t * curve[1] + t * curve[3];
2225 }
2226 var one_t2 = one_t * one_t;
2227 var t2 = t * t;
2228 if (curve.length == 6) {
2229 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2230 }
caryclark1049f122015-04-20 08:31:59 -07002231 if (curve.length == 7) {
2232 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2233 / (one_t2 +2 * one_t * t * curve[6] + t2);
2234 }
caryclarkdac1d172014-06-17 05:15:38 -07002235 var a = one_t2 * one_t;
2236 var b = 3 * one_t2 * t;
2237 var c = 3 * one_t * t2;
2238 var d = t2 * t;
2239 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2240}
2241
2242function drawOrder(curve, label) {
2243 var px = x_at_t(curve, 0.75);
2244 var py = y_at_t(curve, 0.75);
2245 var _px = (px - srcLeft) * scale;
2246 var _py = (py - srcTop) * scale;
2247 ctx.beginPath();
2248 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2249 ctx.closePath();
2250 ctx.fillStyle = "white";
2251 ctx.fill();
2252 if (label == 'L') {
2253 ctx.strokeStyle = "rgba(255,0,0, 1)";
2254 ctx.fillStyle = "rgba(255,0,0, 1)";
2255 } else {
2256 ctx.strokeStyle = "rgba(0,0,255, 1)";
2257 ctx.fillStyle = "rgba(0,0,255, 1)";
2258 }
2259 ctx.stroke();
2260 ctx.font = "normal 16px Arial";
2261 ctx.textAlign = "center";
2262 ctx.fillText(label, _px, _py + 5);
2263 ctx.font = "normal 10px Arial";
2264}
2265
2266function drawID(curve, id) {
2267 var px = x_at_t(curve, 0.5);
2268 var py = y_at_t(curve, 0.5);
2269 var _px = (px - srcLeft) * scale;
2270 var _py = (py - srcTop) * scale;
2271 draw_id_at(id, _px, _py);
2272}
2273
2274function draw_id_at(id, _px, _py) {
2275 ctx.beginPath();
2276 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2277 ctx.closePath();
2278 ctx.fillStyle = "white";
2279 ctx.fill();
2280 ctx.strokeStyle = "rgba(127,127,0, 1)";
2281 ctx.fillStyle = "rgba(127,127,0, 1)";
2282 ctx.stroke();
2283 ctx.font = "normal 16px Arial";
2284 ctx.textAlign = "center";
2285 ctx.fillText(id, _px, _py + 5);
2286 ctx.font = "normal 10px Arial";
2287}
2288
2289function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2290 var curve = [x1, y1, x2, y2];
2291 drawCurvePartialID(id, curve, t1, t2);
2292}
2293
2294function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2295 var curve = [x1, y1, x2, y2, x3, y3];
2296 drawCurvePartialID(id, curve, t1, t2);
2297}
2298
caryclark1049f122015-04-20 08:31:59 -07002299function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2300 var curve = [x1, y1, x2, y2, x3, y3, w];
2301 drawCurvePartialID(id, curve, t1, t2);
2302}
2303
caryclarkdac1d172014-06-17 05:15:38 -07002304function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2305 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2306 drawCurvePartialID(id, curve, t1, t2);
2307}
2308
2309function drawCurvePartialID(id, curve, t1, t2) {
2310 var px = x_at_t(curve, (t1 + t2) / 2);
2311 var py = y_at_t(curve, (t1 + t2) / 2);
2312 var _px = (px - srcLeft) * scale;
2313 var _py = (py - srcTop) * scale;
2314 draw_id_at(id, _px, _py);
2315}
2316
2317function drawCurveSpecials(test, curve, type) {
2318 if (pt_labels) {
2319 drawPoints(curve, type, pt_labels == 2);
2320 }
2321 if (control_lines != 0) {
2322 drawControlLines(curve, type, control_lines);
2323 }
2324 if (curve_t) {
2325 drawPointAtT(curve, type);
2326 }
2327 if (draw_midpoint) {
2328 var mid = pointAtT(curve, type, 0.5);
2329 drawPoint(mid.x, mid.y, true);
2330 }
2331 if (draw_id) {
2332 var id = idByCurve(test, curve, type);
2333 if (id >= 0) {
2334 drawID(curve, id);
2335 }
2336 }
2337 if (type == PATH_LINE) {
2338 return;
2339 }
2340 if (draw_deriviatives > 0) {
2341 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002342 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002343 if (draw_deriviatives == 2) {
2344 d = dxy_at_t(curve, type, 1);
2345 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002346 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002347 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002348 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002349 }
2350 }
2351 if (draw_midpoint) {
2352 var mid = pointAtT(curve, type, 0.5);
2353 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002354 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002355 }
2356 }
2357 if (type != PATH_CUBIC) {
2358 return;
2359 }
caryclarkdac1d172014-06-17 05:15:38 -07002360 if (draw_sequence) {
2361 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2362 for (var i = 0; i < 8; i+= 2) {
2363 drawLabelX(ymin, i >> 1, curve[i]);
2364 }
2365 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2366 for (var i = 1; i < 8; i+= 2) {
2367 drawLabelY(xmin, i >> 1, curve[i]);
2368 }
2369 }
2370}
2371
2372function logCurves(test) {
2373 for (curves in test) {
2374 var curve = test[curves];
2375 dumpCurve(curve);
2376 }
2377}
2378
2379function curveToString(curve) {
2380 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002381 var length = curve.length == 7 ? 6 : curve.length;
2382 if (curve.length == 7) {
2383 str += "{";
2384 }
2385 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002386 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2387 if (i < curve.length - 2) {
2388 str += "}, {";
2389 }
2390 }
caryclark1049f122015-04-20 08:31:59 -07002391 str += "}";
2392 if (curve.length == 7) {
2393 str += "}, " + curve[6].toFixed(decimal_places);
2394 }
2395 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002396 return str;
2397}
2398
2399function dumpCurve(curve) {
2400 console.log(curveToString(curve));
2401}
2402
2403function draw(test, lines, title) {
2404 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2405 ctx.font = "normal 50px Arial";
2406 ctx.textAlign = "left";
2407 ctx.fillText(title, 50, 50);
2408 ctx.font = "normal 10px Arial";
2409 ctx.lineWidth = "1.001"; "0.999";
2410 var secondPath = test.length;
2411 var closeCount = 0;
2412 logStart = -1;
2413 logRange = 0;
2414 // find last active rec type at this step
2415 var curType = test[0];
2416 var curStep = 0;
2417 var hasOp = false;
2418 var lastActive = 0;
2419 var lastAdd = 0;
2420 var lastSect = 0;
2421 var lastSort = 0;
2422 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002423 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002424 activeCount = 0;
2425 addCount = 0;
2426 angleCount = 0;
2427 opCount = 0;
2428 sectCount = 0;
2429 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002430 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002431 markCount = 0;
2432 activeMax = 0;
2433 addMax = 0;
2434 angleMax = 0;
2435 opMax = 0;
2436 sectMax = 0;
2437 sectMax2 = 0;
2438 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002439 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002440 markMax = 0;
2441 lastIndex = test.length - 3;
2442 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2443 var recType = test[tIndex];
2444 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2445 console.log("unknown rec type: " + recType);
2446 throw "stop execution";
2447 }
2448 // if (curType == recType && curType != REC_TYPE_ADD) {
2449 // continue;
2450 // }
2451 var inStepRange = step_limit == 0 || curStep < step_limit;
2452 curType = recType;
2453 if (recType == REC_TYPE_OP) {
2454 hasOp = true;
2455 continue;
2456 }
2457 if (recType == REC_TYPE_UNKNOWN) {
2458 // these types do not advance step
2459 continue;
2460 }
2461 var bumpStep = false;
2462 var records = test[tIndex + 2];
2463 var fragType = records[0];
2464 if (recType == REC_TYPE_ADD) {
2465 if (records.length != 2) {
2466 console.log("expect only two elements: " + records.length);
2467 throw "stop execution";
2468 }
2469 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2470 continue;
2471 }
2472 ++addMax;
2473 if (!draw_add || !inStepRange) {
2474 continue;
2475 }
2476 lastAdd = tIndex;
2477 ++addCount;
2478 bumpStep = true;
2479 }
2480 if (recType == REC_TYPE_PATH && hasOp) {
2481 secondPath = tIndex;
2482 }
caryclark54359292015-03-26 07:52:43 -07002483 if (recType == REC_TYPE_PATH2 && hasOp) {
2484 secondPath = tIndex;
2485 }
caryclarkdac1d172014-06-17 05:15:38 -07002486 if (recType == REC_TYPE_ACTIVE) {
2487 ++activeMax;
2488 if (!draw_active || !inStepRange) {
2489 continue;
2490 }
2491 lastActive = tIndex;
2492 ++activeCount;
2493 bumpStep = true;
2494 }
2495 if (recType == REC_TYPE_ACTIVE_OP) {
2496 ++opMax;
2497 if (!draw_op || !inStepRange) {
2498 continue;
2499 }
2500 lastOp = tIndex;
2501 ++opCount;
2502 bumpStep = true;
2503 }
caryclark54359292015-03-26 07:52:43 -07002504 if (recType == REC_TYPE_AFTERPART) {
2505 if (draw_angle != 3 || !inStepRange) {
2506 continue;
2507 }
2508 lastAngle = tIndex;
2509 ++angleCount;
2510 bumpStep = true;
2511 }
caryclarkdac1d172014-06-17 05:15:38 -07002512 if (recType == REC_TYPE_ANGLE) {
2513 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002514 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002515 continue;
2516 }
2517 lastAngle = tIndex;
2518 ++angleCount;
2519 bumpStep = true;
2520 }
2521 if (recType == REC_TYPE_SECT) {
2522 if (records.length != 2) {
2523 console.log("expect only two elements: " + records.length);
2524 throw "stop execution";
2525 }
2526 ++sectMax;
2527 var sectBump = 1;
2528 switch (fragType) {
2529 case INTERSECT_LINE:
2530 case INTERSECT_QUAD_LINE:
2531 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002532 case INTERSECT_CONIC_LINE:
2533 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002534 case INTERSECT_SELF_CUBIC:
2535 case INTERSECT_CUBIC_LINE:
2536 case INTERSECT_CUBIC_QUAD:
2537 case INTERSECT_CUBIC:
2538 sectBump = 1;
2539 break;
2540 case INTERSECT_LINE_2:
2541 case INTERSECT_QUAD_LINE_2:
2542 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002543 case INTERSECT_CONIC_LINE_2:
2544 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002545 case INTERSECT_CUBIC_LINE_2:
2546 case INTERSECT_CUBIC_QUAD_2:
2547 case INTERSECT_CUBIC_2:
2548 sectBump = 2;
2549 break;
2550 case INTERSECT_LINE_NO:
2551 case INTERSECT_QUAD_LINE_NO:
2552 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002553 case INTERSECT_CONIC_LINE_NO:
2554 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002555 case INTERSECT_SELF_CUBIC_NO:
2556 case INTERSECT_CUBIC_LINE_NO:
2557 case INTERSECT_CUBIC_QUAD_NO:
2558 case INTERSECT_CUBIC_NO:
2559 sectBump = 0;
2560 break;
2561 case INTERSECT_CUBIC_LINE_3:
2562 case INTERSECT_CUBIC_QUAD_3:
2563 case INTERSECT_CUBIC_3:
2564 sectBump = 3;
2565 break;
2566 case INTERSECT_CUBIC_QUAD_4:
2567 case INTERSECT_CUBIC_4:
2568 sectBump = 4;
2569 break;
2570 default:
2571 console.log("missing case " + records.length);
2572 throw "stop execution";
2573 }
2574 sectMax2 += sectBump;
2575 if (draw_intersection <= 1 || !inStepRange) {
2576 continue;
2577 }
2578 lastSect = tIndex;
2579 sectCount += sectBump;
2580 bumpStep = true;
2581 }
2582 if (recType == REC_TYPE_SORT) {
2583 ++sortMax;
2584 if (!draw_sort || !inStepRange) {
2585 continue;
2586 }
2587 lastSort = tIndex;
2588 ++sortCount;
2589 bumpStep = true;
2590 }
caryclark03b03ca2015-04-23 09:13:37 -07002591 if (recType == REC_TYPE_TOP) {
2592 ++topMax;
2593 if (!draw_top || !inStepRange) {
2594 continue;
2595 }
2596 lastTop = tIndex;
2597 ++topCount;
2598 bumpStep = true;
2599 }
caryclarkdac1d172014-06-17 05:15:38 -07002600 if (recType == REC_TYPE_MARK) {
2601 ++markMax;
2602 if (!draw_mark || !inStepRange) {
2603 continue;
2604 }
2605 lastMark = tIndex;
2606 ++markCount;
2607 bumpStep = true;
2608 }
2609 if (bumpStep) {
2610 lastIndex = tIndex;
2611 logStart = test[tIndex + 1];
2612 logRange = records.length / 2;
2613 ++curStep;
2614 }
2615 }
2616 stepMax = (draw_add ? addMax : 0)
2617 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002618 + (draw_angle ? angleMax : 0)
caryclark54359292015-03-26 07:52:43 -07002619 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002620 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002621 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002622 + (draw_mark ? markMax : 0)
2623 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2624 if (stepMax == 0) {
caryclark03b03ca2015-04-23 09:13:37 -07002625 stepMax = addMax + activeMax + angleMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002626 }
2627 drawnPts = [];
2628 drawnLines = [];
2629 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002630 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002631 drawnCubics = [];
2632 focusXmin = focusYmin = Infinity;
2633 focusXmax = focusYmax = -Infinity;
2634 var pathIndex = 0;
2635 var opLetter = 'S';
2636 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2637 var recType = test[tIndex];
2638 var records = test[tIndex + 2];
2639 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2640 var fragType = records[recordIndex];
2641 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2642 console.log("unknown in range frag type: " + fragType);
2643 throw "stop execution";
2644 }
2645 var frags = records[recordIndex + 1];
2646 focus_enabled = false;
2647 switch (recType) {
2648 case REC_TYPE_COMPUTED:
2649 if (draw_computed == 0) {
2650 continue;
2651 }
2652 ctx.lineWidth = 1;
2653 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2654 ctx.fillStyle = "blue";
2655 var drawThis = false;
2656 switch (fragType) {
2657 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002658 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2659 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002660 drawQuad(frags[0], frags[1], frags[2], frags[3],
2661 frags[4], frags[5]);
2662 drawThis = true;
2663 }
2664 break;
caryclark1049f122015-04-20 08:31:59 -07002665 case PATH_CONIC:
2666 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2667 && (draw_computed & 7) == pathIndex)) {
2668 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2669 frags[4], frags[5], frags[6]);
2670 drawThis = true;
2671 }
2672 break;
caryclarkdac1d172014-06-17 05:15:38 -07002673 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002674 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2675 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002676 drawCubic(frags[0], frags[1], frags[2], frags[3],
2677 frags[4], frags[5], frags[6], frags[7]);
2678 drawThis = true;
2679 }
2680 ++pathIndex;
2681 break;
2682 case COMPUTED_SET_1:
2683 pathIndex = 0;
2684 break;
2685 case COMPUTED_SET_2:
2686 pathIndex = 1;
2687 break;
2688 default:
2689 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2690 throw "stop execution";
2691 }
2692 if (!drawThis || collect_bounds) {
2693 break;
2694 }
2695 drawCurveSpecials(test, frags, fragType);
2696 break;
2697 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002698 case REC_TYPE_PATH2:
caryclarkdac1d172014-06-17 05:15:38 -07002699 if (!draw_path) {
2700 continue;
2701 }
2702 var firstPath = tIndex < secondPath;
2703 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2704 continue;
2705 }
2706 ctx.lineWidth = 1;
2707 ctx.strokeStyle = firstPath ? "black" : "red";
2708 ctx.fillStyle = "blue";
caryclark54359292015-03-26 07:52:43 -07002709 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002710 switch (fragType) {
2711 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002712 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2713 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002714 break;
2715 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002716 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2717 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2718 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002719 break;
caryclark1049f122015-04-20 08:31:59 -07002720 case PATH_CONIC:
2721 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2722 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2723 frags2[4], frags2[5], frags2[6]);
2724 break;
caryclarkdac1d172014-06-17 05:15:38 -07002725 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002726 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2727 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2728 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07002729 break;
2730 default:
caryclark54359292015-03-26 07:52:43 -07002731 console.log("unknown REC_TYPE_PATH2 frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002732 throw "stop execution";
2733 }
2734 if (collect_bounds) {
2735 break;
2736 }
caryclark54359292015-03-26 07:52:43 -07002737 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002738 break;
2739 case REC_TYPE_OP:
2740 switch (fragType) {
2741 case OP_INTERSECT: opLetter = 'I'; break;
2742 case OP_DIFFERENCE: opLetter = 'D'; break;
2743 case OP_UNION: opLetter = 'U'; break;
2744 case OP_XOR: opLetter = 'X'; break;
2745 default:
2746 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2747 throw "stop execution";
2748 }
2749 break;
2750 case REC_TYPE_ACTIVE:
2751 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2752 continue;
2753 }
2754 var x1 = frags[SPAN_X1];
2755 var y1 = frags[SPAN_Y1];
2756 var x2 = frags[SPAN_X2];
2757 var y2 = frags[SPAN_Y2];
caryclark1049f122015-04-20 08:31:59 -07002758 var x3, y3, x3, y4, t1, t2, w;
caryclarkdac1d172014-06-17 05:15:38 -07002759 ctx.lineWidth = 3;
2760 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2761 focus_enabled = true;
2762 switch (fragType) {
2763 case ACTIVE_LINE_SPAN:
2764 t1 = frags[SPAN_L_T];
2765 t2 = frags[SPAN_L_TEND];
2766 drawLinePartial(x1, y1, x2, y2, t1, t2);
2767 if (draw_id) {
2768 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
2769 }
2770 break;
2771 case ACTIVE_QUAD_SPAN:
2772 x3 = frags[SPAN_X3];
2773 y3 = frags[SPAN_Y3];
2774 t1 = frags[SPAN_Q_T];
2775 t2 = frags[SPAN_Q_TEND];
2776 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
2777 if (draw_id) {
2778 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
2779 }
2780 break;
caryclark1049f122015-04-20 08:31:59 -07002781 case ACTIVE_CONIC_SPAN:
2782 x3 = frags[SPAN_X3];
2783 y3 = frags[SPAN_Y3];
2784 t1 = frags[SPAN_K_T];
2785 t2 = frags[SPAN_K_TEND];
2786 w = frags[SPAN_K_W];
2787 drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
2788 if (draw_id) {
2789 drawConicPartialID(frags[0], x1, y1, x2, y2, x3, y3, w, t1, t2);
2790 }
2791 break;
caryclarkdac1d172014-06-17 05:15:38 -07002792 case ACTIVE_CUBIC_SPAN:
2793 x3 = frags[SPAN_X3];
2794 y3 = frags[SPAN_Y3];
2795 x4 = frags[SPAN_X4];
2796 y4 = frags[SPAN_Y4];
2797 t1 = frags[SPAN_C_T];
2798 t2 = frags[SPAN_C_TEND];
2799 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2800 if (draw_id) {
2801 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2802 }
2803 break;
2804 default:
2805 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2806 throw "stop execution";
2807 }
2808 break;
2809 case REC_TYPE_ACTIVE_OP:
2810 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2811 continue;
2812 }
2813 focus_enabled = true;
2814 ctx.lineWidth = 3;
2815 var activeSpan = frags[7] == "1";
2816 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2817 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2818 drawCurve(curve);
2819 if (draw_op > 1) {
2820 drawArc(curve, false, frags[3], frags[4]);
2821 drawArc(curve, true, frags[5], frags[6]);
2822 }
2823 break;
2824 case REC_TYPE_ADD:
2825 if (!draw_add) {
2826 continue;
2827 }
2828 ctx.lineWidth = 3;
2829 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2830 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2831 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2832 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2833 : "rgba(127,0,127, 0.3)";
2834 focus_enabled = true;
2835 switch (fragType) {
2836 case ADD_MOVETO:
2837 break;
2838 case ADD_LINETO:
2839 if (step_limit == 0 || tIndex >= lastAdd) {
2840 drawLine(frags[0], frags[1], frags[2], frags[3]);
2841 }
2842 break;
2843 case ADD_QUADTO:
2844 if (step_limit == 0 || tIndex >= lastAdd) {
2845 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2846 }
2847 break;
caryclark1049f122015-04-20 08:31:59 -07002848 case ADD_CONICTO:
2849 if (step_limit == 0 || tIndex >= lastAdd) {
2850 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2851 frags[4], frags[5], frags[6]);
2852 }
2853 break;
caryclarkdac1d172014-06-17 05:15:38 -07002854 case ADD_CUBICTO:
2855 if (step_limit == 0 || tIndex >= lastAdd) {
2856 drawCubic(frags[0], frags[1], frags[2], frags[3],
2857 frags[4], frags[5], frags[6], frags[7]);
2858 }
2859 break;
2860 case ADD_CLOSE:
2861 ++closeCount;
2862 break;
2863 case ADD_FILL:
2864 break;
2865 default:
2866 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2867 throw "stop execution";
2868 }
2869 break;
2870 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07002871 angleBetween = frags[18] == "T";
2872 afterIndex = 0;
2873 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07002874 continue;
2875 }
2876 focus_enabled = true;
2877 ctx.lineWidth = 3;
2878 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07002879 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2880 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2881 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07002882 drawCurve(leftCurve);
2883 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07002884 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07002885 drawCurve(midCurve);
2886 if (draw_angle > 1) {
2887 drawOrder(leftCurve, 'L');
2888 drawOrder(rightCurve, 'R');
2889 }
2890 break;
caryclark54359292015-03-26 07:52:43 -07002891 case REC_TYPE_AFTERPART:
2892 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
2893 continue;
2894 }
2895 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
2896 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
2897 : "rgba(0,0,255, 1.0)";
2898 switch (fragType) {
2899 case PATH_LINE:
2900 drawLine(frags[0], frags[1], frags[2], frags[3]);
2901 break;
2902 case PATH_QUAD:
2903 drawQuad(frags[0], frags[1], frags[2], frags[3],
2904 frags[4], frags[5]);
2905 break;
caryclark1049f122015-04-20 08:31:59 -07002906 case PATH_CONIC:
2907 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2908 frags[4], frags[5], frags[6]);
2909 break;
caryclark54359292015-03-26 07:52:43 -07002910 case PATH_CUBIC:
2911 drawCubic(frags[0], frags[1], frags[2], frags[3],
caryclark1049f122015-04-20 08:31:59 -07002912 frags[4], frags[5], frags[6], frags[7]);
caryclark54359292015-03-26 07:52:43 -07002913 break;
2914 default:
2915 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
2916 throw "stop execution";
2917 }
2918 ++afterIndex;
2919 break;
caryclarkdac1d172014-06-17 05:15:38 -07002920 case REC_TYPE_SECT:
2921 if (!draw_intersection) {
2922 continue;
2923 }
2924 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
2925 continue;
2926 }
2927 // draw_intersection == 1 : show all
2928 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
2929 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
2930 ctx.lineWidth = 1;
2931 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2932 ctx.fillStyle = "blue";
2933 focus_enabled = true;
2934 var f = [];
2935 var c1s;
2936 var c1l;
2937 var c2s;
2938 var c2l;
2939 switch (fragType) {
2940 case INTERSECT_LINE:
2941 f.push(5, 6, 0, 7);
2942 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
2943 break;
2944 case INTERSECT_LINE_2:
2945 f.push(5, 6, 0, 10);
2946 f.push(8, 9, 7, 15);
2947 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
2948 break;
2949 case INTERSECT_LINE_NO:
2950 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2951 break;
2952 case INTERSECT_QUAD_LINE:
2953 f.push(7, 8, 0, 9);
2954 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
2955 break;
2956 case INTERSECT_QUAD_LINE_2:
2957 f.push(7, 8, 0, 12);
2958 f.push(10, 11, 9, 17);
2959 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
2960 break;
2961 case INTERSECT_QUAD_LINE_NO:
2962 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2963 break;
2964 case INTERSECT_QUAD:
2965 f.push(7, 8, 0, 9);
2966 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
2967 break;
2968 case INTERSECT_QUAD_2:
2969 f.push(7, 8, 0, 12);
2970 f.push(10, 11, 9, 19);
2971 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
2972 break;
2973 case INTERSECT_QUAD_NO:
2974 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2975 break;
caryclark1049f122015-04-20 08:31:59 -07002976 case INTERSECT_CONIC_LINE:
2977 f.push(8, 9, 0, 10);
2978 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
2979 break;
2980 case INTERSECT_CONIC_LINE_2:
2981 f.push(8, 9, 0, 12);
2982 f.push(11, 12, 10, 18);
2983 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
2984 break;
2985 case INTERSECT_CONIC_LINE_NO:
2986 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
2987 break;
2988 case INTERSECT_CONIC:
2989 f.push(8, 9, 0, 10);
2990 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
2991 break;
2992 case INTERSECT_CONIC_2:
2993 f.push(8, 9, 0, 13);
2994 f.push(11, 12, 10, 21);
2995 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
2996 break;
2997 case INTERSECT_CONIC_NO:
2998 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
2999 break;
caryclarkdac1d172014-06-17 05:15:38 -07003000 case INTERSECT_SELF_CUBIC:
3001 f.push(9, 10, 0, 11);
3002 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3003 break;
3004 case INTERSECT_SELF_CUBIC_NO:
3005 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3006 break;
3007 case INTERSECT_CUBIC_LINE:
3008 f.push(9, 10, 0, 11);
3009 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3010 break;
3011 case INTERSECT_CUBIC_LINE_2:
3012 f.push(9, 10, 0, 14);
3013 f.push(12, 13, 11, 19);
3014 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3015 break;
3016 case INTERSECT_CUBIC_LINE_3:
3017 f.push(9, 10, 0, 17);
3018 f.push(12, 13, 11, 22);
3019 f.push(15, 16, 14, 23);
3020 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3021 break;
3022 case INTERSECT_CUBIC_QUAD_NO:
3023 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3024 break;
3025 case INTERSECT_CUBIC_QUAD:
3026 f.push(9, 10, 0, 11);
3027 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3028 break;
3029 case INTERSECT_CUBIC_QUAD_2:
3030 f.push(9, 10, 0, 14);
3031 f.push(12, 13, 11, 21);
3032 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3033 break;
3034 case INTERSECT_CUBIC_QUAD_3:
3035 f.push(9, 10, 0, 17);
3036 f.push(12, 13, 11, 24);
3037 f.push(15, 16, 14, 25);
3038 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3039 break;
3040 case INTERSECT_CUBIC_QUAD_4:
3041 f.push(9, 10, 0, 20);
3042 f.push(12, 13, 11, 27);
3043 f.push(15, 16, 14, 28);
3044 f.push(18, 19, 17, 29);
3045 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3046 break;
3047 case INTERSECT_CUBIC_LINE_NO:
3048 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3049 break;
3050 case INTERSECT_CUBIC:
3051 f.push(9, 10, 0, 11);
3052 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3053 break;
3054 case INTERSECT_CUBIC_2:
3055 f.push(9, 10, 0, 14);
3056 f.push(12, 13, 11, 23);
3057 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3058 break;
3059 case INTERSECT_CUBIC_3:
3060 f.push(9, 10, 0, 17);
3061 f.push(12, 13, 11, 26);
3062 f.push(15, 16, 14, 27);
3063 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3064 break;
3065 case INTERSECT_CUBIC_4:
3066 f.push(9, 10, 0, 20);
3067 f.push(12, 13, 11, 29);
3068 f.push(15, 16, 14, 30);
3069 f.push(18, 19, 17, 31);
3070 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3071 break;
3072 case INTERSECT_CUBIC_NO:
3073 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3074 break;
3075 default:
3076 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3077 throw "stop execution";
3078 }
3079 if (draw_intersection != 1) {
3080 var id = -1;
3081 var curve;
3082 switch (c1l) {
3083 case 4:
3084 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3085 if (draw_id) {
3086 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3087 id = idByCurve(test, curve, PATH_LINE);
3088 }
3089 break;
3090 case 6:
3091 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3092 frags[c1s + 4], frags[c1s + 5]);
3093 if (draw_id) {
3094 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3095 frags[c1s + 4], frags[c1s + 5]];
3096 id = idByCurve(test, curve, PATH_QUAD);
3097 }
3098 break;
caryclark1049f122015-04-20 08:31:59 -07003099 case 7:
3100 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3101 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3102 if (draw_id) {
3103 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3104 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3105 id = idByCurve(test, curve, PATH_CONIC);
3106 }
3107 break;
caryclarkdac1d172014-06-17 05:15:38 -07003108 case 8:
3109 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3110 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3111 if (draw_id) {
3112 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3113 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3114 id = idByCurve(test, curve, PATH_CUBIC);
3115 }
3116 break;
3117 }
3118 if (id >= 0) {
3119 drawID(curve, id);
3120 }
3121 id = -1;
3122 switch (c2l) {
3123 case 0:
3124 break;
3125 case 4:
3126 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3127 if (draw_id) {
3128 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3129 id = idByCurve(test, curve, PATH_LINE);
3130 }
3131 break;
3132 case 6:
3133 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3134 frags[c2s + 4], frags[c2s + 5]);
3135 if (draw_id) {
3136 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3137 frags[c2s + 4], frags[c2s + 5]];
3138 id = idByCurve(test, curve, PATH_QUAD);
3139 }
3140 break;
caryclark1049f122015-04-20 08:31:59 -07003141 case 7:
3142 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3143 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3144 if (draw_id) {
3145 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3146 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3147 id = idByCurve(test, curve, PATH_CONIC);
3148 }
3149 break;
caryclarkdac1d172014-06-17 05:15:38 -07003150 case 8:
3151 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3152 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3153 if (draw_id) {
3154 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3155 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3156 id = idByCurve(test, curve, PATH_CUBIC);
3157 }
3158 break;
3159 }
3160 if (id >= 0) {
3161 drawID(curve, id);
3162 }
3163 }
3164 if (collect_bounds) {
3165 break;
3166 }
caryclark54359292015-03-26 07:52:43 -07003167 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3168 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003169 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3170 }
3171 }
3172 if (!draw_intersectT) {
3173 break;
3174 }
3175 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003176 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3177 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003178 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3179 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3180 }
3181 }
3182 break;
3183 case REC_TYPE_SORT:
3184 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3185 continue;
3186 }
3187 ctx.lineWidth = 3;
3188 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3189 focus_enabled = true;
3190 switch (fragType) {
3191 case SORT_UNARY:
3192 case SORT_BINARY:
3193 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3194 drawCurve(curve);
3195 break;
3196 default:
3197 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3198 throw "stop execution";
3199 }
3200 break;
caryclark03b03ca2015-04-23 09:13:37 -07003201 case REC_TYPE_TOP:
3202 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3203 continue;
3204 }
3205 ctx.lineWidth = 3;
3206 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3207 focus_enabled = true;
3208 {
3209 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3210 drawCurve(curve);
3211 var type = PATH_LINE + (curve.length / 2 - 2);
3212 var mid = pointAtT(curve, type, 0.5);
3213 var d = dxy_at_t(curve, type, 0.5);
3214 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3215 }
3216 break;
caryclarkdac1d172014-06-17 05:15:38 -07003217 case REC_TYPE_MARK:
3218 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3219 continue;
3220 }
3221 ctx.lineWidth = 3;
3222 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3223 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3224 focus_enabled = true;
3225 switch (fragType) {
3226 case MARK_LINE:
3227 case MARK_DONE_LINE:
3228 case MARK_UNSORTABLE_LINE:
3229 case MARK_SIMPLE_LINE:
3230 case MARK_SIMPLE_DONE_LINE:
3231 case MARK_DONE_UNARY_LINE:
3232 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3233 frags[5], frags[9]);
3234 if (draw_id) {
3235 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3236 frags[5], frags[9]);
3237 }
3238 break;
3239 case MARK_QUAD:
3240 case MARK_DONE_QUAD:
3241 case MARK_UNSORTABLE_QUAD:
3242 case MARK_SIMPLE_QUAD:
3243 case MARK_SIMPLE_DONE_QUAD:
3244 case MARK_DONE_UNARY_QUAD:
3245 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3246 frags[5], frags[6], frags[7], frags[11]);
3247 if (draw_id) {
3248 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3249 frags[5], frags[6], frags[7], frags[11]);
3250 }
3251 break;
3252 case MARK_CUBIC:
3253 case MARK_DONE_CUBIC:
3254 case MARK_UNSORTABLE_CUBIC:
3255 case MARK_SIMPLE_CUBIC:
3256 case MARK_SIMPLE_DONE_CUBIC:
3257 case MARK_DONE_UNARY_CUBIC:
3258 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3259 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3260 if (draw_id) {
3261 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3262 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3263 }
3264 break;
3265 case MARK_ANGLE_LAST:
3266 // FIXME: ignored for now
3267 break;
3268 default:
3269 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3270 throw "stop execution";
3271 }
3272 break;
3273 default:
3274 continue;
3275 }
3276 }
3277 switch (recType) {
3278 case REC_TYPE_SORT:
3279 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3280 break;
3281 }
3282 var angles = []; // use tangent lines to describe arcs
3283 var windFrom = [];
3284 var windTo = [];
3285 var opp = [];
3286 var minXY = Number.MAX_VALUE;
3287 var partial;
3288 focus_enabled = true;
3289 var someUnsortable = false;
3290 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3291 var fragType = records[recordIndex];
3292 var frags = records[recordIndex + 1];
3293 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3294 (fragType == SORT_BINARY && frags[16]);
3295 someUnsortable |= unsortable;
3296 switch (fragType) {
3297 case SORT_UNARY:
3298 case SORT_BINARY:
3299 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3300 break;
3301 default:
3302 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3303 throw "stop execution";
3304 }
3305 var dx = boundsWidth(partial);
3306 var dy = boundsHeight(partial);
3307 minXY = Math.min(minXY, dx * dx + dy * dy);
3308 if (collect_bounds) {
3309 continue;
3310 }
3311 angles.push(tangent(partial));
3312 var from = frags[12];
3313 var to = frags[12];
3314 var sgn = frags[10];
3315 if (sgn < 0) {
3316 from -= frags[11];
3317 } else if (sgn > 0) {
3318 to -= frags[11];
3319 }
3320 windFrom.push(from + (unsortable ? "!" : ""));
3321 windTo.push(to + (unsortable ? "!" : ""));
3322 opp.push(fragType == SORT_BINARY);
3323 if (draw_sort == 1) {
3324 drawOrder(partial, frags[12]);
3325 } else {
3326 drawOrder(partial, (recordIndex / 2) + 1);
3327 }
3328 }
3329 var radius = Math.sqrt(minXY) / 2 * scale;
3330 radius = Math.min(50, radius);
3331 var scaledRadius = radius / scale;
3332 var centerX = partial[0];
3333 var centerY = partial[1];
3334 if (collect_bounds) {
3335 if (focus_enabled) {
3336 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3337 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3338 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3339 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3340 }
3341 break;
3342 }
3343 break;
3344 default:
3345 break;
3346 }
3347 }
3348 if (collect_bounds) {
3349 return;
3350 }
3351 if (draw_log && logStart >= 0) {
3352 ctx.font = "normal 10px Arial";
3353 ctx.textAlign = "left";
3354 ctx.beginPath();
3355 var top = screenHeight - 20 - (logRange + 2) * 10;
3356 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3357 ctx.fillStyle = "white";
3358 ctx.fill();
3359 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3360 if (logStart > 0) {
3361 ctx.fillText(lines[logStart - 1], 50, top + 8);
3362 }
3363 ctx.fillStyle = "black";
3364 for (var idx = 0; idx < logRange; ++idx) {
3365 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3366 }
3367 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3368 if (logStart + logRange < lines.length) {
3369 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3370 }
3371 }
3372 if (draw_legend) {
3373 var pos = 0;
caryclark54359292015-03-26 07:52:43 -07003374 var drawSomething = draw_add | draw_active | draw_angle | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003375 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3376 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3377 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3378 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3379 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
3380 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3381 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003382 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003383 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
3384 drawBox(pos++, "black", "white",
3385 (new Array('P', 'P1', 'P2', 'P'))[draw_path], draw_path != 0, pathKey);
3386 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3387 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3388 draw_computed != 0, computedKey);
3389 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3390 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3391 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3392 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3393 if (curve_t) {
3394 drawCurveTControl();
3395 }
3396 ctx.font = "normal 20px Arial";
3397 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3398 ctx.textAlign = "right";
3399 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3400 }
3401 if (draw_hints) {
3402 ctx.font = "normal 10px Arial";
3403 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3404 ctx.textAlign = "right";
3405 var y = 4;
3406 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3407 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3408 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3409 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003410 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3411 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3412 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3413 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3414 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3415 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3416 }
3417}
3418
3419function drawBox(y, backC, foreC, str, enable, label) {
3420 ctx.beginPath();
3421 ctx.fillStyle = backC;
3422 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3423 ctx.fill();
3424 ctx.font = "normal 16px Arial";
3425 ctx.fillStyle = foreC;
3426 ctx.textAlign = "center";
3427 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3428 if (!enable) {
3429 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3430 ctx.fill();
3431 }
3432 if (label != '') {
3433 ctx.font = "normal 9px Arial";
3434 ctx.fillStyle = "black";
3435 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3436 }
3437}
3438
3439function drawCurveTControl() {
3440 ctx.lineWidth = 2;
3441 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3442 ctx.beginPath();
3443 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3444 ctx.stroke();
3445 var ty = 40 + curveT * (screenHeight - 80);
3446 ctx.beginPath();
3447 ctx.moveTo(screenWidth - 80, ty);
3448 ctx.lineTo(screenWidth - 85, ty - 5);
3449 ctx.lineTo(screenWidth - 85, ty + 5);
3450 ctx.lineTo(screenWidth - 80, ty);
3451 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3452 ctx.fill();
3453 var num = curveT.toFixed(decimal_places);
3454 ctx.font = "normal 10px Arial";
3455 ctx.textAlign = "left";
3456 ctx.fillText(num, screenWidth - 78, ty);
3457}
3458
3459function ptInTControl() {
3460 var e = window.event;
3461 var tgt = e.target || e.srcElement;
3462 var left = tgt.offsetLeft;
3463 var top = tgt.offsetTop;
3464 var x = (e.clientX - left);
3465 var y = (e.clientY - top);
3466 if (x < screenWidth - 80 || x > screenWidth - 50) {
3467 return false;
3468 }
3469 if (y < 40 || y > screenHeight - 80) {
3470 return false;
3471 }
3472 curveT = (y - 40) / (screenHeight - 120);
3473 if (curveT < 0 || curveT > 1) {
3474 throw "stop execution";
3475 }
3476 return true;
3477}
3478
3479function drawTop() {
3480 if (tests[testIndex] == null) {
3481 var str = testDivs[testIndex].textContent;
3482 parse_all(str);
3483 var title = testDivs[testIndex].id.toString();
3484 testTitles[testIndex] = title;
3485 }
3486 init(tests[testIndex]);
3487 redraw();
3488}
3489
3490function redraw() {
3491 if (focus_on_selection) {
3492 collect_bounds = true;
3493 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3494 collect_bounds = false;
3495 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3496 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3497 }
3498 }
3499 ctx.beginPath();
3500 ctx.fillStyle = "white";
3501 ctx.rect(0, 0, screenWidth, screenHeight);
3502 ctx.fill();
3503 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3504}
3505
3506function dumpCurvePartial(test, id, t0, t1) {
3507 var curve = curveByID(test, id);
3508 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3509 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3510 + " t0=" + t0 + " t1=" + t1
3511 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3512}
3513
3514function dumpAngleTest(test, id, t0, t1) {
3515 var curve = curveByID(test, id);
3516 console.log(" { {" + curveToString(curve) + "}, "
3517 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3518}
3519
3520function dumpLogToConsole() {
3521 if (logStart < 0) {
3522 return;
3523 }
3524 var test = tests[testIndex];
3525 var recType = REC_TYPE_UNKNOWN;
3526 var records;
3527 for (var index = 0; index < test.length; index += 3) {
3528 var lastLineNo = test[index + 1];
3529 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3530 recType = test[index];
3531 records = test[index + 2];
3532 break;
3533 }
3534 }
3535 if (recType == REC_TYPE_UNKNOWN) {
3536 return;
3537 }
3538 var lines = testLines[testIndex];
3539 for (var idx = 0; idx < logRange; ++idx) {
3540 var line = lines[logStart + idx];
3541 console.log(line);
3542 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3543 var fragType = records[recordIndex];
3544 var frags = records[recordIndex + 1];
3545 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003546 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3547 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3548 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3549 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3550 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3551 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3552 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3553 console.log("}; //");
3554 }
3555 }
3556 }
3557}
3558
3559var activeKey = 'a';
3560var pathKey = 'b';
3561var pathBackKey = 'B';
3562var centerKey = 'c';
3563var addKey = 'd';
3564var deriviativesKey = 'f';
3565var angleKey = 'g';
3566var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003567var intersectionKey = 'i';
3568var intersectionBackKey = 'I';
3569var sequenceKey = 'j';
3570var midpointKey = 'k';
3571var logKey = 'l';
3572var logToConsoleKey = 'L';
3573var markKey = 'm';
3574var sortKey = 'o';
3575var opKey = 'p';
3576var opBackKey = 'P';
3577var computedKey = 'q';
3578var computedBackKey = 'Q';
3579var stepKey = 's';
3580var stepBackKey = 'S';
3581var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003582var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003583var curveTKey = 'u';
3584var controlLinesBackKey = 'V';
3585var controlLinesKey = 'v';
3586var ptsKey = 'x';
3587var xyKey = 'y';
3588var logCurvesKey = 'z';
3589var focusKey = '`';
3590var idKey = '.';
3591var retinaKey = '\\';
3592
3593function doKeyPress(evt) {
3594 var char = String.fromCharCode(evt.charCode);
3595 var focusWasOn = false;
3596 switch (char) {
3597 case '0':
3598 case '1':
3599 case '2':
3600 case '3':
3601 case '4':
3602 case '5':
3603 case '6':
3604 case '7':
3605 case '8':
3606 case '9':
3607 decimal_places = char - '0';
3608 redraw();
3609 break;
3610 case activeKey:
3611 draw_active ^= true;
3612 redraw();
3613 break;
3614 case addKey:
3615 draw_add ^= true;
3616 redraw();
3617 break;
3618 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003619 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003620 redraw();
3621 break;
3622 case angleBackKey:
3623 draw_angle = (draw_angle + 2) % 3;
3624 redraw();
3625 break;
3626 case centerKey:
3627 setScale(xmin, xmax, ymin, ymax);
3628 redraw();
3629 break;
3630 case controlLinesBackKey:
3631 control_lines = (control_lines + 3) % 4;
3632 redraw();
3633 break;
3634 case controlLinesKey:
3635 control_lines = (control_lines + 1) % 4;
3636 redraw();
3637 break;
3638 case computedBackKey:
3639 draw_computed = (draw_computed + 5) % 6;
3640 redraw();
3641 break;
3642 case computedKey:
3643 draw_computed = (draw_computed + 1) % 6;
3644 redraw();
3645 break;
3646 case curveTKey:
3647 curve_t ^= true;
3648 if (curve_t) {
3649 draw_legend = true;
3650 }
3651 redraw();
3652 break;
3653 case deriviativesKey:
3654 draw_deriviatives = (draw_deriviatives + 1) % 3;
3655 redraw();
3656 break;
3657 case focusKey:
3658 focus_on_selection ^= true;
3659 setScale(xmin, xmax, ymin, ymax);
3660 redraw();
3661 break;
caryclarkdac1d172014-06-17 05:15:38 -07003662 case idKey:
3663 draw_id ^= true;
3664 redraw();
3665 break;
3666 case intersectionBackKey:
3667 draw_intersection = (draw_intersection + 3) % 4;
3668 redraw();
3669 break;
3670 case intersectionKey:
3671 draw_intersection = (draw_intersection + 1) % 4;
3672 redraw();
3673 break;
3674 case intersectTKey:
3675 draw_intersectT ^= true;
3676 redraw();
3677 break;
3678 case logCurvesKey:
3679 logCurves(tests[testIndex]);
3680 break;
3681 case logKey:
3682 draw_log ^= true;
3683 redraw();
3684 break;
3685 case logToConsoleKey:
3686 if (draw_log) {
3687 dumpLogToConsole();
3688 }
3689 break;
3690 case markKey:
3691 draw_mark ^= true;
3692 redraw();
3693 break;
3694 case midpointKey:
3695 draw_midpoint ^= true;
3696 redraw();
3697 break;
3698 case opKey:
3699 draw_op = (draw_op + 1) % 3;
3700 redraw();
3701 break;
3702 case opBackKey:
3703 draw_op = (draw_op + 2) % 3;
3704 redraw();
3705 break;
3706 case pathKey:
3707 draw_path = (draw_path + 1) % 4;
3708 redraw();
3709 break;
3710 case pathBackKey:
3711 draw_path = (draw_path + 3) % 4;
3712 redraw();
3713 break;
3714 case ptsKey:
3715 pt_labels = (pt_labels + 1) % 3;
3716 redraw();
3717 break;
3718 case retinaKey:
3719 retina_scale ^= true;
3720 drawTop();
3721 break;
3722 case sequenceKey:
3723 draw_sequence ^= true;
3724 redraw();
3725 break;
3726 case sortKey:
3727 draw_sort = (draw_sort + 1) % 3;
3728 drawTop();
3729 break;
3730 case stepKey:
3731 step_limit++;
3732 if (step_limit > stepMax) {
3733 step_limit = stepMax;
3734 }
3735 redraw();
3736 break;
3737 case stepBackKey:
3738 step_limit--;
3739 if (step_limit < 0) {
3740 step_limit = 0;
3741 }
3742 redraw();
3743 break;
caryclark03b03ca2015-04-23 09:13:37 -07003744 case topKey:
3745 draw_top ^= true;
3746 redraw();
3747 break;
caryclarkdac1d172014-06-17 05:15:38 -07003748 case xyKey:
3749 debug_xy = (debug_xy + 1) % 3;
3750 redraw();
3751 break;
3752 case '-':
3753 focusWasOn = focus_on_selection;
3754 if (focusWasOn) {
3755 focus_on_selection = false;
3756 scale /= 1.2;
3757 } else {
3758 scale /= 2;
3759 calcLeftTop();
3760 }
3761 redraw();
3762 focus_on_selection = focusWasOn;
3763 break;
3764 case '=':
3765 case '+':
3766 focusWasOn = focus_on_selection;
3767 if (focusWasOn) {
3768 focus_on_selection = false;
3769 scale *= 1.2;
3770 } else {
3771 scale *= 2;
3772 calcLeftTop();
3773 }
3774 redraw();
3775 focus_on_selection = focusWasOn;
3776 break;
3777 case '?':
3778 draw_hints ^= true;
3779 if (draw_hints && !draw_legend) {
3780 draw_legend = true;
3781 }
3782 redraw();
3783 break;
3784 case '/':
3785 draw_legend ^= true;
3786 redraw();
3787 break;
3788 }
3789}
3790
3791function doKeyDown(evt) {
3792 var char = evt.keyCode;
3793 var preventDefault = false;
3794 switch (char) {
3795 case 37: // left arrow
3796 if (evt.shiftKey) {
3797 testIndex -= 9;
3798 }
3799 if (--testIndex < 0)
3800 testIndex = tests.length - 1;
3801 drawTop();
3802 preventDefault = true;
3803 break;
3804 case 39: // right arrow
3805 if (evt.shiftKey) {
3806 testIndex += 9;
3807 }
3808 if (++testIndex >= tests.length)
3809 testIndex = 0;
3810 drawTop();
3811 preventDefault = true;
3812 break;
3813 }
3814 if (preventDefault) {
3815 evt.preventDefault();
3816 return false;
3817 }
3818 return true;
3819}
3820
3821(function() {
3822 var hidden = "hidden";
3823
3824 // Standards:
3825 if (hidden in document)
3826 document.addEventListener("visibilitychange", onchange);
3827 else if ((hidden = "mozHidden") in document)
3828 document.addEventListener("mozvisibilitychange", onchange);
3829 else if ((hidden = "webkitHidden") in document)
3830 document.addEventListener("webkitvisibilitychange", onchange);
3831 else if ((hidden = "msHidden") in document)
3832 document.addEventListener("msvisibilitychange", onchange);
3833 // IE 9 and lower:
3834 else if ('onfocusin' in document)
3835 document.onfocusin = document.onfocusout = onchange;
3836 // All others:
3837 else
3838 window.onpageshow = window.onpagehide
3839 = window.onfocus = window.onblur = onchange;
3840
3841 function onchange (evt) {
3842 var v = 'visible', h = 'hidden',
3843 evtMap = {
3844 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3845 };
3846
3847 evt = evt || window.event;
3848 if (evt.type in evtMap)
3849 document.body.className = evtMap[evt.type];
3850 else
3851 document.body.className = this[hidden] ? "hidden" : "visible";
3852 }
3853})();
3854
3855function calcXY() {
3856 var e = window.event;
3857 var tgt = e.target || e.srcElement;
3858 var left = tgt.offsetLeft;
3859 var top = tgt.offsetTop;
3860 mouseX = (e.clientX - left) / scale + srcLeft;
3861 mouseY = (e.clientY - top) / scale + srcTop;
3862}
3863
3864function calcLeftTop() {
3865 srcLeft = mouseX - screenWidth / 2 / scale;
3866 srcTop = mouseY - screenHeight / 2 / scale;
3867}
3868
3869var disableClick = false;
3870
3871function handleMouseClick() {
3872 if (disableClick) {
3873 return;
3874 }
3875 if (!curve_t || !ptInTControl()) {
3876 calcXY();
3877 calcLeftTop();
3878 }
3879 redraw();
3880// if (!curve_t || !ptInTControl()) {
3881// mouseX = screenWidth / 2 / scale + srcLeft;
3882// mouseY = screenHeight / 2 / scale + srcTop;
3883// }
3884}
3885
3886function handleMouseOver() {
3887 calcXY();
3888 if (debug_xy != 2) {
3889 return;
3890 }
3891 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3892 ctx.beginPath();
3893 ctx.rect(300,100,num.length * 6,10);
3894 ctx.fillStyle="white";
3895 ctx.fill();
3896 ctx.font = "normal 10px Arial";
3897 ctx.fillStyle="black";
3898 ctx.textAlign = "left";
3899 ctx.fillText(num, 300, 108);
3900}
3901
3902function start() {
3903 for (var i = 0; i < testDivs.length; ++i) {
3904 tests[i] = null;
3905 }
3906 testIndex = 0;
3907 drawTop();
3908 window.addEventListener('keypress', doKeyPress, true);
3909 window.addEventListener('keydown', doKeyDown, true);
3910 window.onresize = function() {
3911 drawTop();
3912 }
3913 /*
3914 window.onpagehide = function() {
3915 disableClick = true;
3916 }
3917 */
3918 window.onpageshow = function () {
3919 disableClick = false;
3920 }
3921}
3922
3923</script>
3924</head>
3925
3926<body onLoad="start();">
3927<canvas id="canvas" width="750" height="500"
3928 onmousemove="handleMouseOver()"
3929 onclick="handleMouseClick()"
3930 ></canvas >
3931</body>
3932</html>