blob: 8be938cc771dd3cdedc685707395d58a3d5d9d13 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
Cary Clark59d5a0e2017-01-23 14:38:52 +00003<div height="0" hidden="true">
Ben Wagner29380bd2017-10-09 14:43:00 -04004
Cary Clarkea2a6322018-08-27 13:19:09 -04005<div id="bug8228">
6seg=1 {{{31.6666698f, 73.3333359f}, {31.6666698f, 13.333334f}}}
7seg=2 {{{{31.6666698f, 13.333334f}, {31.6666698f, 10.0000019f}, {35, 10.0000019f}}}, 0.707106769f}
8seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}}
9seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f}
10seg=5 {{{59.4444466f, 13.333334f}, {59.4444466f, 73.3333359f}}}
11seg=6 {{{{59.4444466f, 73.3333359f}, {59.4444466f, 76.6666641f}, {56.1111107f, 76.6666641f}}}, 0.707106769f}
12seg=7 {{{56.1111107f, 76.6666641f}, {35, 76.6666641f}}}
13seg=8 {{{{35, 76.6666641f}, {31.6666698f, 76.6666641f}, {31.6666698f, 73.3333359f}}}, 0.707106769f}
14op sect
15seg=9 {{{10, 10}, {29.3922844f, 10}}}
16seg=10 {{{{29.3922844f, 10}, {29.2278862f, 10.4838676f}, {29.2278862f, 10.9948997f}}}, 0.986621082f}
17seg=11 {{{29.2278862f, 10.9948997f}, {29.2278862f, 66.6626663f}}}
18seg=12 {{{{29.2278862f, 66.6626663f}, {29.2278862f, 69.7553177f}, {32.3205376f, 69.7553177f}}}, 0.707106769f}
19seg=13 {{{32.3205376f, 69.7553177f}, {51.9073448f, 69.7553177f}}}
20seg=14 {{{{51.9073448f, 69.7553177f}, {54.9999962f, 69.7553177f}, {54.9999962f, 66.6626663f}}}, 0.707106769f}
21seg=15 {{{54.9999962f, 66.6626663f}, {54.9999962f, 10.9948997f}}}
22seg=16 {{{{54.9999962f, 10.9948997f}, {54.9999962f, 10.4838676f}, {54.835598f, 10}}}, 0.986621082f}
23seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}}
24seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f}
25seg=19 {{{65.3088455f, 10.9948997f}, {65.3088455f, 66.6626663f}}}
26seg=20 {{{{65.3088455f, 66.6626663f}, {65.3088455f, 69.7553177f}, {68.4014969f, 69.7553177f}}}, 0.707106769f}
27seg=21 {{{68.4014969f, 69.7553177f}, {87.9883041f, 69.7553177f}}}
28seg=22 {{{{87.9883041f, 69.7553177f}, {91.0809555f, 69.7553177f}, {91.0809555f, 66.6626663f}}}, 0.707106769f}
29seg=23 {{{91.0809555f, 66.6626663f}, {91.0809555f, 10.9948997f}}}
30seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f}
31seg=25 {{{90.9165573f, 10}, {110, 10}}}
32seg=26 {{{110, 10}, {110, 110}}}
33seg=27 {{{110, 110}, {10, 110}}}
34seg=28 {{{10, 110}, {10, 10}}}
35debugShowConicLineIntersection wtTs[0]=0 {{{{29.3922844,10}, {29.2278862,10.4838676}, {29.2278862,10.9948997}}}, 0.986621082} {{29.3922844,10}} wnTs[0]=1 {{{10,10}, {29.3922844,10}}}
36debugShowLineIntersection wtTs[0]=1 {{{10,110}, {10,10}}} {{10,10}} wnTs[0]=0 {{{10,10}, {29.3922844,10}}}
37debugShowConicLineIntersection wtTs[0]=1 {{{{29.3922844,10}, {29.2278862,10.4838676}, {29.2278862,10.9948997}}}, 0.986621082} {{29.2278862,10.9948997}} wnTs[0]=0 {{{29.2278862,10.9948997}, {29.2278862,66.6626663}}}
38debugShowConicLineIntersection wtTs[0]=0 {{{{29.2278862,66.6626663}, {29.2278862,69.7553177}, {32.3205376,69.7553177}}}, 0.707106769} {{29.2278862,66.6626663}} wnTs[0]=1 {{{29.2278862,10.9948997}, {29.2278862,66.6626663}}}
39debugShowConicLineIntersection wtTs[0]=1 {{{{29.2278862,66.6626663}, {29.2278862,69.7553177}, {32.3205376,69.7553177}}}, 0.707106769} {{32.3205376,69.7553177}} wnTs[0]=0 {{{32.3205376,69.7553177}, {51.9073448,69.7553177}}}
40debugShowConicLineIntersection wtTs[0]=0 {{{{51.9073448,69.7553177}, {54.9999962,69.7553177}, {54.9999962,66.6626663}}}, 0.707106769} {{51.9073448,69.7553177}} wnTs[0]=1 {{{32.3205376,69.7553177}, {51.9073448,69.7553177}}}
41debugShowConicLineIntersection wtTs[0]=1 {{{{51.9073448,69.7553177}, {54.9999962,69.7553177}, {54.9999962,66.6626663}}}, 0.707106769} {{54.9999962,66.6626663}} wnTs[0]=0 {{{54.9999962,66.6626663}, {54.9999962,10.9948997}}}
42debugShowConicLineIntersection wtTs[0]=0 {{{{54.9999962,10.9948997}, {54.9999962,10.4838676}, {54.835598,10}}}, 0.986621082} {{54.9999962,10.9948997}} wnTs[0]=1 {{{54.9999962,66.6626663}, {54.9999962,10.9948997}}}
43debugShowConicLineIntersection wtTs[0]=1 {{{{54.9999962,10.9948997}, {54.9999962,10.4838676}, {54.835598,10}}}, 0.986621082} {{54.835598,10}} wnTs[0]=0 {{{54.835598,10}, {65.4732437,10}}}
44debugShowConicLineIntersection wtTs[0]=0 {{{{65.4732437,10}, {65.3088455,10.4838676}, {65.3088455,10.9948997}}}, 0.986621082} {{65.4732437,10}} wnTs[0]=1 {{{54.835598,10}, {65.4732437,10}}}
45debugShowConicLineIntersection wtTs[0]=1 {{{{65.4732437,10}, {65.3088455,10.4838676}, {65.3088455,10.9948997}}}, 0.986621082} {{65.3088455,10.9948997}} wnTs[0]=0 {{{65.3088455,10.9948997}, {65.3088455,66.6626663}}}
46debugShowConicLineIntersection wtTs[0]=0 {{{{65.3088455,66.6626663}, {65.3088455,69.7553177}, {68.4014969,69.7553177}}}, 0.707106769} {{65.3088455,66.6626663}} wnTs[0]=1 {{{65.3088455,10.9948997}, {65.3088455,66.6626663}}}
47debugShowConicLineIntersection wtTs[0]=1 {{{{65.3088455,66.6626663}, {65.3088455,69.7553177}, {68.4014969,69.7553177}}}, 0.707106769} {{68.4014969,69.7553177}} wnTs[0]=0 {{{68.4014969,69.7553177}, {87.9883041,69.7553177}}}
48debugShowConicLineIntersection wtTs[0]=0 {{{{87.9883041,69.7553177}, {91.0809555,69.7553177}, {91.0809555,66.6626663}}}, 0.707106769} {{87.9883041,69.7553177}} wnTs[0]=1 {{{68.4014969,69.7553177}, {87.9883041,69.7553177}}}
49debugShowConicLineIntersection wtTs[0]=1 {{{{87.9883041,69.7553177}, {91.0809555,69.7553177}, {91.0809555,66.6626663}}}, 0.707106769} {{91.0809555,66.6626663}} wnTs[0]=0 {{{91.0809555,66.6626663}, {91.0809555,10.9948997}}}
50debugShowConicLineIntersection wtTs[0]=0 {{{{91.0809555,10.9948997}, {91.0809555,10.4838676}, {90.9165573,10}}}, 0.986621082} {{91.0809555,10.9948997}} wnTs[0]=1 {{{91.0809555,66.6626663}, {91.0809555,10.9948997}}}
51debugShowConicLineIntersection wtTs[0]=1 {{{{91.0809555,10.9948997}, {91.0809555,10.4838676}, {90.9165573,10}}}, 0.986621082} {{90.9165573,10}} wnTs[0]=0 {{{90.9165573,10}, {110,10}}}
52debugShowLineIntersection wtTs[0]=0 {{{110,10}, {110,110}}} {{110,10}} wnTs[0]=1 {{{90.9165573,10}, {110,10}}}
53debugShowLineIntersection wtTs[0]=0 {{{110,110}, {10,110}}} {{110,110}} wnTs[0]=1 {{{110,10}, {110,110}}}
54debugShowLineIntersection wtTs[0]=0 {{{10,110}, {10,10}}} {{10,110}} wnTs[0]=1 {{{110,110}, {10,110}}}
55debugShowConicLineIntersection wtTs[0]=0.855202762 {{{{29.2278862,66.6626663}, {29.2278862,69.7553177}, {32.3205376,69.7553177}}}, 0.707106769} {{31.6666698,69.6854019}} wnTs[0]=0.0607988 {{{31.6666698,73.3333359}, {31.6666698,13.333334}}}
56SkOpSegment::addT insert t=0.855202762 segID=12 spanID=57
57SkOpSegment::addT insert t=0.0607988451 segID=1 spanID=58
58debugShowConicLineIntersection wtTs[0]=0.999998002 {{{{54.9999962,10.9948997}, {54.9999962,10.4838676}, {54.835598,10}}}, 0.986621082} {{54.835598,10.0000019}} wnTs[0]=0.939581 {{{35,10.0000019}, {56.1111107,10.0000019}}}
59SkOpSegment::addT insert t=0.939581007 segID=3 spanID=59
60debugShowLineIntersection no intersect {{{35,10.0000019}, {56.1111107,10.0000019}}} {{{54.835598,10}, {65.4732437,10}}}
61debugShowConicLineIntersection no intersect {{{{56.1111107,10.0000019}, {59.4444466,10.0000019}, {59.4444466,13.333334}}}, 0.707106769} {{{54.835598,10}, {65.4732437,10}}}
62debugShowConicLineIntersection wtTs[0]=0 {{{{31.6666698,13.333334}, {31.6666698,10.0000019}, {35,10.0000019}}}, 0.707106769} {{31.6666698,13.333334}} wnTs[0]=1 {{{31.6666698,73.3333359}, {31.6666698,13.333334}}}
63debugShowConicLineIntersection wtTs[0]=1 {{{{35,76.6666641}, {31.6666698,76.6666641}, {31.6666698,73.3333359}}}, 0.707106769} {{31.6666698,73.3333359}} wnTs[0]=0 {{{31.6666698,73.3333359}, {31.6666698,13.333334}}}
64debugShowConicLineIntersection wtTs[0]=1 {{{{31.6666698,13.333334}, {31.6666698,10.0000019}, {35,10.0000019}}}, 0.707106769} {{35,10.0000019}} wnTs[0]=0 {{{35,10.0000019}, {56.1111107,10.0000019}}}
65debugShowConicLineIntersection wtTs[0]=0 {{{{56.1111107,10.0000019}, {59.4444466,10.0000019}, {59.4444466,13.333334}}}, 0.707106769} {{56.1111107,10.0000019}} wnTs[0]=1 {{{35,10.0000019}, {56.1111107,10.0000019}}}
66debugShowConicLineIntersection wtTs[0]=1 {{{{56.1111107,10.0000019}, {59.4444466,10.0000019}, {59.4444466,13.333334}}}, 0.707106769} {{59.4444466,13.333334}} wnTs[0]=0 {{{59.4444466,13.333334}, {59.4444466,73.3333359}}}
67debugShowConicLineIntersection wtTs[0]=0 {{{{59.4444466,73.3333359}, {59.4444466,76.6666641}, {56.1111107,76.6666641}}}, 0.707106769} {{59.4444466,73.3333359}} wnTs[0]=1 {{{59.4444466,13.333334}, {59.4444466,73.3333359}}}
68debugShowConicLineIntersection wtTs[0]=1 {{{{59.4444466,73.3333359}, {59.4444466,76.6666641}, {56.1111107,76.6666641}}}, 0.707106769} {{56.1111107,76.6666641}} wnTs[0]=0 {{{56.1111107,76.6666641}, {35,76.6666641}}}
69debugShowConicLineIntersection wtTs[0]=0 {{{{35,76.6666641}, {31.6666698,76.6666641}, {31.6666698,73.3333359}}}, 0.707106769} {{35,76.6666641}} wnTs[0]=1 {{{56.1111107,76.6666641}, {35,76.6666641}}}
70-------------------------------------- addExpanded
71SkOpSegment::debugShowActiveSpans id=9 (10,10 29.3922844,10) t=0 tEnd=1 windSum=? windValue=1
72SkOpSegment::debugShowActiveSpans id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997 0.986621082f) t=0 tEnd=1 windSum=? windValue=1
73SkOpSegment::debugShowActiveSpans id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 tEnd=1 windSum=? windValue=1
74SkOpSegment::debugShowActiveSpans id=12 (29.2278862,66.6626663 29.2278862,69.1578563 31.6666698,69.6854019 0.778275728f) t=0 tEnd=0.855202762 windSum=? windValue=1
75SkOpSegment::debugShowActiveSpans id=12 (31.6666698,69.6854019 31.9898661,69.7553177 32.3205376,69.7553177 0.994332433f) t=0.855202762 tEnd=1 windSum=? windValue=1
76SkOpSegment::debugShowActiveSpans id=13 (32.3205376,69.7553177 51.9073448,69.7553177) t=0 tEnd=1 windSum=? windValue=1
77SkOpSegment::debugShowActiveSpans id=14 (51.9073448,69.7553177 54.9999962,69.7553177 54.9999962,66.6626663 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
78SkOpSegment::debugShowActiveSpans id=15 (54.9999962,66.6626663 54.9999962,10.9948997) t=0 tEnd=1 windSum=? windValue=1
79SkOpSegment::debugShowActiveSpans id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10 0.986621082f) t=0 tEnd=1 windSum=? windValue=1
80SkOpSegment::debugShowActiveSpans id=17 (54.835598,10 65.4732437,10) t=0 tEnd=1 windSum=? windValue=1
81SkOpSegment::debugShowActiveSpans id=18 (65.4732437,10 65.3088455,10.4838676 65.3088455,10.9948997 0.986621082f) t=0 tEnd=1 windSum=? windValue=1
82SkOpSegment::debugShowActiveSpans id=19 (65.3088455,10.9948997 65.3088455,66.6626663) t=0 tEnd=1 windSum=? windValue=1
83SkOpSegment::debugShowActiveSpans id=20 (65.3088455,66.6626663 65.3088455,69.7553177 68.4014969,69.7553177 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
84SkOpSegment::debugShowActiveSpans id=21 (68.4014969,69.7553177 87.9883041,69.7553177) t=0 tEnd=1 windSum=? windValue=1
85SkOpSegment::debugShowActiveSpans id=22 (87.9883041,69.7553177 91.0809555,69.7553177 91.0809555,66.6626663 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
86SkOpSegment::debugShowActiveSpans id=23 (91.0809555,66.6626663 91.0809555,10.9948997) t=0 tEnd=1 windSum=? windValue=1
87SkOpSegment::debugShowActiveSpans id=24 (91.0809555,10.9948997 91.0809555,10.4838676 90.9165573,10 0.986621082f) t=0 tEnd=1 windSum=? windValue=1
88SkOpSegment::debugShowActiveSpans id=25 (90.9165573,10 110,10) t=0 tEnd=1 windSum=? windValue=1
89SkOpSegment::debugShowActiveSpans id=26 (110,10 110,110) t=0 tEnd=1 windSum=? windValue=1
90SkOpSegment::debugShowActiveSpans id=27 (110,110 10,110) t=0 tEnd=1 windSum=? windValue=1
91SkOpSegment::debugShowActiveSpans id=28 (10,110 10,10) t=0 tEnd=1 windSum=? windValue=1
92SkOpSegment::debugShowActiveSpans id=1 (31.6666698,73.3333359 31.6666698,69.6854019) t=0 tEnd=0.0607988451 windSum=? windValue=1
93SkOpSegment::debugShowActiveSpans id=1 (31.6666698,69.6854019 31.6666698,13.333334) t=0.0607988451 tEnd=1 windSum=? windValue=1
94SkOpSegment::debugShowActiveSpans id=2 (31.6666698,13.333334 31.6666698,10.0000019 35,10.0000019 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
95SkOpSegment::debugShowActiveSpans id=3 (35,10.0000019 54.835598,10.0000019) t=0 tEnd=0.939581007 windSum=? windValue=1
96SkOpSegment::debugShowActiveSpans id=3 (54.835598,10.0000019 56.1111107,10.0000019) t=0.939581007 tEnd=1 windSum=? windValue=1
97SkOpSegment::debugShowActiveSpans id=4 (56.1111107,10.0000019 59.4444466,10.0000019 59.4444466,13.333334 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
98SkOpSegment::debugShowActiveSpans id=5 (59.4444466,13.333334 59.4444466,73.3333359) t=0 tEnd=1 windSum=? windValue=1
99SkOpSegment::debugShowActiveSpans id=6 (59.4444466,73.3333359 59.4444466,76.6666641 56.1111107,76.6666641 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
100SkOpSegment::debugShowActiveSpans id=7 (56.1111107,76.6666641 35,76.6666641) t=0 tEnd=1 windSum=? windValue=1
101SkOpSegment::debugShowActiveSpans id=8 (35,76.6666641 31.6666698,76.6666641 31.6666698,73.3333359 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
102-------------------------------------- move_multiples
103-------------------------------------- move_nearby
104-------------------------------------- correctEnds
105-------------------------------------- addEndMovedSpans
106-------------------------------------- expand
107-------------------------------------- addExpanded
108-------------------------------------- mark
109-------------------------------------- missing_coincidence
110-------------------------------------- expand
111-------------------------------------- expand
112-------------------------------------- apply
113-------------------------------------- findOverlaps
114-------------------------------------- calc_angles
115SkOpSegment::sortAngles [12] tStart=0.855202762 [57]
116SkOpAngle::after [12/1] 13/9 tStart=0.855202762 tEnd=0 < [1/5] 23/23 tStart=0.0607988451 tEnd=0 < [12/2] 29/29 tStart=0.855202762 tEnd=1 T 4
117SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {29.2278862,69.1578563}, {29.2278862,66.6626663}}}, 0.778275728} id=12
118SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,73.3333359}}} id=1
119SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {31.9898661,69.7553177}, {32.3205376,69.7553177}}}, 0.994332433} id=12
120SkOpAngle::after [12/1] 13/9 tStart=0.855202762 tEnd=0 < [1/6] 7/7 tStart=0.0607988451 tEnd=1 < [1/5] 23/23 tStart=0.0607988451 tEnd=0 F 4
121SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {29.2278862,69.1578563}, {29.2278862,66.6626663}}}, 0.778275728} id=12
122SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,13.333334}}} id=1
123SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,73.3333359}}} id=1
124SkOpAngle::after [1/5] 23/23 tStart=0.0607988451 tEnd=0 < [1/6] 7/7 tStart=0.0607988451 tEnd=1 < [12/2] 29/29 tStart=0.855202762 tEnd=1 F 4
125SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,73.3333359}}} id=1
126SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,13.333334}}} id=1
127SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {31.9898661,69.7553177}, {32.3205376,69.7553177}}}, 0.994332433} id=12
128SkOpAngle::after [12/2] 29/29 tStart=0.855202762 tEnd=1 < [1/6] 7/7 tStart=0.0607988451 tEnd=1 < [12/1] 13/9 tStart=0.855202762 tEnd=0 T 4
129SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {31.9898661,69.7553177}, {32.3205376,69.7553177}}}, 0.994332433} id=12
130SkOpAngle::afterPart {{{31.6666698,69.6854019}, {31.6666698,13.333334}}} id=1
131SkOpAngle::afterPart {{{{31.6666698,69.6854019}, {29.2278862,69.1578563}, {29.2278862,66.6626663}}}, 0.778275728} id=12
132SkOpSegment::sortAngles [16] tStart=1 [32]
133SkOpAngle::after [16/3] 25/25 tStart=1 tEnd=0 < [3/8] 31/31 tStart=0.939581007 tEnd=1 < [3/7] 15/15 tStart=0.939581007 tEnd=0 T 4
134SkOpAngle::afterPart {{{{54.835598,10.0000019}, {54.9999962,10.4838696}, {54.9999962,10.9949017}}}, 0.986621082} id=16
135SkOpAngle::afterPart {{{54.835598,10.0000019}, {56.1111107,10.0000019}}} id=3
136SkOpAngle::afterPart {{{54.835598,10.0000019}, {35,10.0000019}}} id=3
137SkOpAngle::after [16/3] 25/25 tStart=1 tEnd=0 < [17/4] 31/31 tStart=0 tEnd=1 < [3/8] 31/31 tStart=0.939581007 tEnd=1 T 7
138SkOpAngle::afterPart {{{{54.835598,10}, {54.9999962,10.4838676}, {54.9999962,10.9948997}}}, 0.986621082} id=16
139SkOpAngle::afterPart {{{54.835598,10}, {65.4732437,10}}} id=17
140SkOpAngle::afterPart {{{54.835598,10}, {56.1111107,10}}} id=3
141SkOpSegment::sortAngles [17] tStart=0 [33]
142SkOpSegment::sortAngles [1] tStart=0.0607988451 [58]
143SkOpSegment::sortAngles [3] tStart=0.939581007 [59]
144SkOpSpan::sortableTop dir=kTop seg=9 t=0.5 pt=(19.6961422,10)
145SkOpSpan::sortableTop [0] valid=1 operand=1 span=17 ccw=1 seg=9 {{{10, 10}, {29.3922844f, 10}}} t=0.5 pt=(19.6961422,10) slope=(19.3922844,0)
146SkOpSegment::markWinding id=9 (10,10 29.3922844,10) t=0 [17] (10,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
147SkOpSegment::markWinding id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997) t=0 [19] (29.3922844,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
148SkOpSegment::markWinding id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 [21] (29.2278862,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
149SkOpSegment::markWinding id=12 (29.2278862,66.6626663 29.2278862,69.7553177 32.3205376,69.7553177) t=0 [23] (29.2278862,66.6626663) tEnd=0.855202762 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
150SkOpSegment::markWinding id=9 (10,10 29.3922844,10) t=0 [17] (10,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
151SkOpSegment::markWinding id=28 (10,110 10,10) t=0 [55] (10,110) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
152SkOpSegment::markWinding id=27 (110,110 10,110) t=0 [53] (110,110) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
153SkOpSegment::markWinding id=26 (110,10 110,110) t=0 [51] (110,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
154SkOpSegment::markWinding id=25 (90.9165573,10 110,10) t=0 [49] (90.9165573,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
155SkOpSegment::markWinding id=24 (91.0809555,10.9948997 91.0809555,10.4838676 90.9165573,10) t=0 [47] (91.0809555,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
156SkOpSegment::markWinding id=23 (91.0809555,66.6626663 91.0809555,10.9948997) t=0 [45] (91.0809555,66.6626663) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
157SkOpSegment::markWinding id=22 (87.9883041,69.7553177 91.0809555,69.7553177 91.0809555,66.6626663) t=0 [43] (87.9883041,69.7553177) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
158SkOpSegment::markWinding id=21 (68.4014969,69.7553177 87.9883041,69.7553177) t=0 [41] (68.4014969,69.7553177) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
159SkOpSegment::markWinding id=20 (65.3088455,66.6626663 65.3088455,69.7553177 68.4014969,69.7553177) t=0 [39] (65.3088455,66.6626663) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
160SkOpSegment::markWinding id=19 (65.3088455,10.9948997 65.3088455,66.6626663) t=0 [37] (65.3088455,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
161SkOpSegment::markWinding id=18 (65.4732437,10 65.3088455,10.4838676 65.3088455,10.9948997) t=0 [35] (65.4732437,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
162SkOpSegment::markWinding id=17 (54.835598,10 65.4732437,10) t=0 [33] (54.835598,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
163SkOpSegment::activeOp id=9 t=1 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
164SkOpSegment::markDone id=9 (10,10 29.3922844,10) t=0 [17] (10,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
165SkOpSegment::markDone id=28 (10,110 10,10) t=0 [55] (10,110) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
166SkOpSegment::markDone id=27 (110,110 10,110) t=0 [53] (110,110) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
167SkOpSegment::markDone id=26 (110,10 110,110) t=0 [51] (110,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
168SkOpSegment::markDone id=25 (90.9165573,10 110,10) t=0 [49] (90.9165573,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
169SkOpSegment::markDone id=24 (91.0809555,10.9948997 91.0809555,10.4838676 90.9165573,10) t=0 [47] (91.0809555,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
170SkOpSegment::markDone id=23 (91.0809555,66.6626663 91.0809555,10.9948997) t=0 [45] (91.0809555,66.6626663) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
171SkOpSegment::markDone id=22 (87.9883041,69.7553177 91.0809555,69.7553177 91.0809555,66.6626663) t=0 [43] (87.9883041,69.7553177) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
172SkOpSegment::markDone id=21 (68.4014969,69.7553177 87.9883041,69.7553177) t=0 [41] (68.4014969,69.7553177) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
173SkOpSegment::markDone id=20 (65.3088455,66.6626663 65.3088455,69.7553177 68.4014969,69.7553177) t=0 [39] (65.3088455,66.6626663) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
174SkOpSegment::markDone id=19 (65.3088455,10.9948997 65.3088455,66.6626663) t=0 [37] (65.3088455,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
175SkOpSegment::markDone id=18 (65.4732437,10 65.3088455,10.4838676 65.3088455,10.9948997) t=0 [35] (65.4732437,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
176SkOpSegment::markDone id=17 (54.835598,10 65.4732437,10) t=0 [33] (54.835598,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
177bridgeOp chase.append id=17 windSum=-1
178SkOpSpan::sortableTop dir=kTop seg=3 t=0.969790504 pt=(55.4733543,10.0000019)
179SkOpSpan::sortableTop [0] valid=0 operand=1 span=33 ccw=0 seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}} t=0.0599527719 pt=(55.4733543,10) slope=(0,0)
180SkOpSpan::sortableTop [1] valid=1 operand=0 span=59 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.969790504 pt=(55.4733543,10.0000019) slope=(21.1111107,0)
181SkOpSpan::sortableTop dir=kRight seg=3 t=0.969790504 pt=(55.4733543,10.0000019)
182SkOpSpan::sortableTop [0] valid=0 operand=1 span=51 ccw=0 seg=26 {{{110, 10}, {110, 110}}} t=1.90734863e-08 pt=(110,10) slope=(0,0)
183SkOpSpan::sortableTop [1] valid=1 operand=1 span=47 ccw=0 seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f} t=0.999998002 pt=(90.9165573,10.0000019) slope=(-0.162198404,-0.4773941)
184SkOpSpan::sortableTop [2] valid=1 operand=1 span=35 ccw=1 seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f} t=1.9976668e-06 pt=(65.4732437,10.0000019) slope=(-0.162198404,0.4773941)
185SkOpSpan::sortableTop [3] valid=0 operand=0 span=7 ccw=0 seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f} t=0 pt=(56.1111107,10.0000019) slope=(0,0)
186SkOpSpan::sortableTop [4] valid=1 operand=0 span=59 ccw=0 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.969790504 pt=(55.4733543,10.0000019) slope=(21.1111107,0)
187SkOpSpan::sortableTop dir=kTop seg=3 t=0.954685755 pt=(55.1544762,10.0000019)
188SkOpSpan::sortableTop [0] valid=0 operand=1 span=33 ccw=0 seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}} t=0.029976386 pt=(55.1544762,10) slope=(0,0)
189SkOpSpan::sortableTop [1] valid=1 operand=0 span=59 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.954685755 pt=(55.1544762,10.0000019) slope=(21.1111107,0)
190SkOpSpan::sortableTop dir=kRight seg=3 t=0.954685755 pt=(55.1544762,10.0000019)
191SkOpSpan::sortableTop [0] valid=0 operand=1 span=51 ccw=0 seg=26 {{{110, 10}, {110, 110}}} t=1.90734863e-08 pt=(110,10) slope=(0,0)
192SkOpSpan::sortableTop [1] valid=1 operand=1 span=47 ccw=0 seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f} t=0.999998002 pt=(90.9165573,10.0000019) slope=(-0.162198404,-0.4773941)
193SkOpSpan::sortableTop [2] valid=1 operand=1 span=35 ccw=1 seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f} t=1.9976668e-06 pt=(65.4732437,10.0000019) slope=(-0.162198404,0.4773941)
194SkOpSpan::sortableTop [3] valid=0 operand=0 span=7 ccw=0 seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f} t=0 pt=(56.1111107,10.0000019) slope=(0,0)
195SkOpSpan::sortableTop [4] valid=1 operand=0 span=59 ccw=0 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.954685755 pt=(55.1544762,10.0000019) slope=(21.1111107,0)
196SkOpSpan::sortableTop dir=kTop seg=3 t=0.962238129 pt=(55.3139153,10.0000019)
197SkOpSpan::sortableTop [0] valid=0 operand=1 span=33 ccw=0 seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}} t=0.0449645789 pt=(55.3139153,10) slope=(0,0)
198SkOpSpan::sortableTop [1] valid=1 operand=0 span=59 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.962238129 pt=(55.3139153,10.0000019) slope=(21.1111107,0)
199SkOpSpan::sortableTop dir=kRight seg=3 t=0.962238129 pt=(55.3139153,10.0000019)
200SkOpSpan::sortableTop [0] valid=0 operand=1 span=51 ccw=0 seg=26 {{{110, 10}, {110, 110}}} t=1.90734863e-08 pt=(110,10) slope=(0,0)
201SkOpSpan::sortableTop [1] valid=1 operand=1 span=47 ccw=0 seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f} t=0.999998002 pt=(90.9165573,10.0000019) slope=(-0.162198404,-0.4773941)
202SkOpSpan::sortableTop [2] valid=1 operand=1 span=35 ccw=1 seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f} t=1.9976668e-06 pt=(65.4732437,10.0000019) slope=(-0.162198404,0.4773941)
203SkOpSpan::sortableTop [3] valid=0 operand=0 span=7 ccw=0 seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f} t=0 pt=(56.1111107,10.0000019) slope=(0,0)
204SkOpSpan::sortableTop [4] valid=1 operand=0 span=59 ccw=0 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.962238129 pt=(55.3139153,10.0000019) slope=(21.1111107,0)
205SkOpSpan::sortableTop dir=kTop seg=3 t=0.977342878 pt=(55.6327934,10.0000019)
206SkOpSpan::sortableTop [0] valid=0 operand=1 span=33 ccw=0 seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}} t=0.0749409649 pt=(55.6327934,10) slope=(0,0)
207SkOpSpan::sortableTop [1] valid=1 operand=0 span=59 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.977342878 pt=(55.6327934,10.0000019) slope=(21.1111107,0)
208SkOpSpan::sortableTop dir=kRight seg=3 t=0.977342878 pt=(55.6327934,10.0000019)
209SkOpSpan::sortableTop [0] valid=0 operand=1 span=51 ccw=0 seg=26 {{{110, 10}, {110, 110}}} t=1.90734863e-08 pt=(110,10) slope=(0,0)
210SkOpSpan::sortableTop [1] valid=1 operand=1 span=47 ccw=0 seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f} t=0.999998002 pt=(90.9165573,10.0000019) slope=(-0.162198404,-0.4773941)
211SkOpSpan::sortableTop [2] valid=1 operand=1 span=35 ccw=1 seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f} t=1.9976668e-06 pt=(65.4732437,10.0000019) slope=(-0.162198404,0.4773941)
212SkOpSpan::sortableTop [3] valid=0 operand=0 span=7 ccw=0 seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f} t=0 pt=(56.1111107,10.0000019) slope=(0,0)
213SkOpSpan::sortableTop [4] valid=1 operand=0 span=59 ccw=0 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.977342878 pt=(55.6327934,10.0000019) slope=(21.1111107,0)
214SkOpSpan::sortableTop dir=kTop seg=3 t=0.966014316 pt=(55.3936348,10.0000019)
215SkOpSpan::sortableTop [0] valid=0 operand=1 span=33 ccw=0 seg=17 {{{54.835598f, 10}, {65.4732437f, 10}}} t=0.0524586754 pt=(55.3936348,10) slope=(0,0)
216SkOpSpan::sortableTop [1] valid=1 operand=0 span=59 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.966014316 pt=(55.3936348,10.0000019) slope=(21.1111107,0)
217SkOpSpan::sortableTop dir=kRight seg=3 t=0.966014316 pt=(55.3936348,10.0000019)
218SkOpSpan::sortableTop [0] valid=0 operand=1 span=51 ccw=0 seg=26 {{{110, 10}, {110, 110}}} t=1.90734863e-08 pt=(110,10) slope=(0,0)
219SkOpSpan::sortableTop [1] valid=1 operand=1 span=47 ccw=0 seg=24 {{{{91.0809555f, 10.9948997f}, {91.0809555f, 10.4838676f}, {90.9165573f, 10}}}, 0.986621082f} t=0.999998002 pt=(90.9165573,10.0000019) slope=(-0.162198404,-0.4773941)
220SkOpSpan::sortableTop [2] valid=1 operand=1 span=35 ccw=1 seg=18 {{{{65.4732437f, 10}, {65.3088455f, 10.4838676f}, {65.3088455f, 10.9948997f}}}, 0.986621082f} t=1.9976668e-06 pt=(65.4732437,10.0000019) slope=(-0.162198404,0.4773941)
221SkOpSpan::sortableTop [3] valid=0 operand=0 span=7 ccw=0 seg=4 {{{{56.1111107f, 10.0000019f}, {59.4444466f, 10.0000019f}, {59.4444466f, 13.333334f}}}, 0.707106769f} t=0 pt=(56.1111107,10.0000019) slope=(0,0)
222SkOpSpan::sortableTop [4] valid=1 operand=0 span=59 ccw=0 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.966014316 pt=(55.3936348,10.0000019) slope=(21.1111107,0)
223SkOpSpan::sortableTop dir=kTop seg=3 t=0.469790504 pt=(44.9178009,10.0000019)
224SkOpSpan::sortableTop [0] valid=1 operand=0 span=5 ccw=1 seg=3 {{{35, 10.0000019f}, {56.1111107f, 10.0000019f}}} t=0.469790504 pt=(44.9178009,10.0000019) slope=(21.1111107,0)
225SkOpSegment::markWinding id=3 (35,10.0000019 56.1111107,10.0000019) t=0 [5] (35,10.0000019) tEnd=0.939581007 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
226SkOpSegment::markWinding id=3 (35,10.0000019 56.1111107,10.0000019) t=0 [5] (35,10.0000019) tEnd=0.939581007 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
227SkOpSegment::markWinding id=2 (31.6666698,13.333334 31.6666698,10.0000019 35,10.0000019) t=0 [3] (31.6666698,13.333334) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
228SkOpSegment::markWinding id=1 (31.6666698,73.3333359 31.6666698,13.333334) t=0.0607988451 [58] (31.6666698,69.6854019) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
229SkOpSpan::sortableTop dir=kLeft seg=16 t=0.5 pt=(54.9586182,10.4907045)
230SkOpSpan::sortableTop [0] valid=1 operand=1 span=55 ccw=1 seg=28 {{{10, 110}, {10, 10}}} t=0.995092955 pt=(10,10.4907045) slope=(0,-100)
231SkOpSpan::sortableTop [1] valid=1 operand=1 span=19 ccw=0 seg=10 {{{{29.3922844f, 10}, {29.2278862f, 10.4838676f}, {29.2278862f, 10.9948997f}}}, 0.986621082f} t=0.500000041 pt=(29.2692623,10.4907045) slope=(-0.0816492225,0.494122205)
232SkOpSpan::sortableTop [2] valid=1 operand=0 span=3 ccw=1 seg=2 {{{{31.6666698f, 13.333334f}, {31.6666698f, 10.0000019f}, {35, 10.0000019f}}}, 0.707106769f} t=0.643045062 pt=(33.2591515,10.4907045) slope=(1.73977059,-1.06545097)
233SkOpSpan::sortableTop [3] valid=1 operand=1 span=31 ccw=1 seg=16 {{{{54.9999962f, 10.9948997f}, {54.9999962f, 10.4838676f}, {54.835598f, 10}}}, 0.986621082f} t=0.5 pt=(54.9586182,10.4907045) slope=(-0.0816492292,-0.494122204)
234SkOpSegment::markWinding id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10) t=0 [31] (54.9999962,10.9948997) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
235SkOpSegment::markWinding id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10) t=0 [31] (54.9999962,10.9948997) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
236SkOpSegment::markWinding id=15 (54.9999962,66.6626663 54.9999962,10.9948997) t=0 [29] (54.9999962,66.6626663) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
237SkOpSegment::markWinding id=14 (51.9073448,69.7553177 54.9999962,69.7553177 54.9999962,66.6626663) t=0 [27] (51.9073448,69.7553177) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
238SkOpSegment::markWinding id=13 (32.3205376,69.7553177 51.9073448,69.7553177) t=0 [25] (32.3205376,69.7553177) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
239SkOpSegment::markWinding id=12 (29.2278862,66.6626663 29.2278862,69.7553177 32.3205376,69.7553177) t=0.855202762 [57] (31.6666698,69.6854019) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
240SkOpSegment::debugShowActiveSpans id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997 0.986621082f) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
241SkOpSegment::debugShowActiveSpans id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
242SkOpSegment::debugShowActiveSpans id=12 (29.2278862,66.6626663 29.2278862,69.1578563 31.6666698,69.6854019 0.778275728f) t=0 tEnd=0.855202762 windSum=-1 oppSum=0 windValue=1 oppValue=0
243SkOpSegment::debugShowActiveSpans id=12 (31.6666698,69.6854019 31.9898661,69.7553177 32.3205376,69.7553177 0.994332433f) t=0.855202762 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
244SkOpSegment::debugShowActiveSpans id=13 (32.3205376,69.7553177 51.9073448,69.7553177) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
245SkOpSegment::debugShowActiveSpans id=14 (51.9073448,69.7553177 54.9999962,69.7553177 54.9999962,66.6626663 0.707106769f) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
246SkOpSegment::debugShowActiveSpans id=15 (54.9999962,66.6626663 54.9999962,10.9948997) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
247SkOpSegment::debugShowActiveSpans id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10 0.986621082f) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
248SkOpSegment::debugShowActiveSpans id=1 (31.6666698,73.3333359 31.6666698,69.6854019) t=0 tEnd=0.0607988451 windSum=? windValue=1
249SkOpSegment::debugShowActiveSpans id=1 (31.6666698,69.6854019 31.6666698,13.333334) t=0.0607988451 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
250SkOpSegment::debugShowActiveSpans id=2 (31.6666698,13.333334 31.6666698,10.0000019 35,10.0000019 0.707106769f) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
251SkOpSegment::debugShowActiveSpans id=3 (35,10.0000019 54.835598,10.0000019) t=0 tEnd=0.939581007 windSum=-1 oppSum=0 windValue=1 oppValue=0
252SkOpSegment::debugShowActiveSpans id=3 (54.835598,10.0000019 56.1111107,10.0000019) t=0.939581007 tEnd=1 windSum=? windValue=1
253SkOpSegment::debugShowActiveSpans id=4 (56.1111107,10.0000019 59.4444466,10.0000019 59.4444466,13.333334 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
254SkOpSegment::debugShowActiveSpans id=5 (59.4444466,13.333334 59.4444466,73.3333359) t=0 tEnd=1 windSum=? windValue=1
255SkOpSegment::debugShowActiveSpans id=6 (59.4444466,73.3333359 59.4444466,76.6666641 56.1111107,76.6666641 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
256SkOpSegment::debugShowActiveSpans id=7 (56.1111107,76.6666641 35,76.6666641) t=0 tEnd=1 windSum=? windValue=1
257SkOpSegment::debugShowActiveSpans id=8 (35,76.6666641 31.6666698,76.6666641 31.6666698,73.3333359 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
258SkOpSegment::activeOp id=3 t=0.939581007 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
259SkOpSegment::markDone id=3 (35,10.0000019 56.1111107,10.0000019) t=0 [5] (35,10.0000019) tEnd=0.939581007 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
260SkOpSegment::markDone id=2 (31.6666698,13.333334 31.6666698,10.0000019 35,10.0000019) t=0 [3] (31.6666698,13.333334) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
261SkOpSegment::markDone id=1 (31.6666698,73.3333359 31.6666698,13.333334) t=0.0607988451 [58] (31.6666698,69.6854019) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
262bridgeOp chase.append id=1 windSum=-1
263SkOpSegment::debugShowActiveSpans id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997 0.986621082f) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
264SkOpSegment::debugShowActiveSpans id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
265SkOpSegment::debugShowActiveSpans id=12 (29.2278862,66.6626663 29.2278862,69.1578563 31.6666698,69.6854019 0.778275728f) t=0 tEnd=0.855202762 windSum=-1 oppSum=0 windValue=1 oppValue=0
266SkOpSegment::debugShowActiveSpans id=12 (31.6666698,69.6854019 31.9898661,69.7553177 32.3205376,69.7553177 0.994332433f) t=0.855202762 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
267SkOpSegment::debugShowActiveSpans id=13 (32.3205376,69.7553177 51.9073448,69.7553177) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
268SkOpSegment::debugShowActiveSpans id=14 (51.9073448,69.7553177 54.9999962,69.7553177 54.9999962,66.6626663 0.707106769f) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
269SkOpSegment::debugShowActiveSpans id=15 (54.9999962,66.6626663 54.9999962,10.9948997) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
270SkOpSegment::debugShowActiveSpans id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10 0.986621082f) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0
271SkOpSegment::debugShowActiveSpans id=1 (31.6666698,73.3333359 31.6666698,69.6854019) t=0 tEnd=0.0607988451 windSum=? windValue=1
272SkOpSegment::debugShowActiveSpans id=3 (54.835598,10.0000019 56.1111107,10.0000019) t=0.939581007 tEnd=1 windSum=? windValue=1
273SkOpSegment::debugShowActiveSpans id=4 (56.1111107,10.0000019 59.4444466,10.0000019 59.4444466,13.333334 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
274SkOpSegment::debugShowActiveSpans id=5 (59.4444466,13.333334 59.4444466,73.3333359) t=0 tEnd=1 windSum=? windValue=1
275SkOpSegment::debugShowActiveSpans id=6 (59.4444466,73.3333359 59.4444466,76.6666641 56.1111107,76.6666641 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
276SkOpSegment::debugShowActiveSpans id=7 (56.1111107,76.6666641 35,76.6666641) t=0 tEnd=1 windSum=? windValue=1
277SkOpSegment::debugShowActiveSpans id=8 (35,76.6666641 31.6666698,76.6666641 31.6666698,73.3333359 0.707106769f) t=0 tEnd=1 windSum=? windValue=1
278SkOpSegment::activeOp id=12 t=0.855202762 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
279SkOpSegment::findNextOp simple
280SkOpSegment::markDone id=12 (29.2278862,66.6626663 29.2278862,69.7553177 32.3205376,69.7553177) t=0.855202762 [57] (31.6666698,69.6854019) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
281bridgeOp current id=12 from=(31.6666698,69.6854019) to=(32.3205376,69.7553177)
282path.moveTo(31.6666698,69.6854019);
283path.conicTo(31.9898663,69.7553177, 32.3205376,69.7553177, 0.994332433);
284SkOpSegment::findNextOp simple
285SkOpSegment::markDone id=13 (32.3205376,69.7553177 51.9073448,69.7553177) t=0 [25] (32.3205376,69.7553177) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
286bridgeOp current id=13 from=(32.3205376,69.7553177) to=(51.9073448,69.7553177)
287SkOpSegment::findNextOp simple
288SkOpSegment::markDone id=14 (51.9073448,69.7553177 54.9999962,69.7553177 54.9999962,66.6626663) t=0 [27] (51.9073448,69.7553177) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
289bridgeOp current id=14 from=(51.9073448,69.7553177) to=(54.9999962,66.6626663)
290path.lineTo(51.9073448,69.7553177);
291path.conicTo(54.9999962,69.7553177, 54.9999962,66.6626663, 0.707106769);
292SkOpSegment::findNextOp simple
293SkOpSegment::markDone id=15 (54.9999962,66.6626663 54.9999962,10.9948997) t=0 [29] (54.9999962,66.6626663) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
294bridgeOp current id=15 from=(54.9999962,66.6626663) to=(54.9999962,10.9948997)
295SkOpSegment::findNextOp
296SkOpAngle::dumpOne [16/3] next=17/4 sect=25/25 s=1 [32] e=0 [31] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand
297SkOpAngle::dumpOne [17/4] next=3/8 sect=31/31 s=0 [33] e=1 [34] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done unorderable operand
298SkOpAngle::dumpOne [3/8] next=3/7 sect=31/31 s=0.939581007 [59] e=1 [6] sgn=-1 windVal=1 windSum=? unorderable
299SkOpAngle::dumpOne [3/7] next=16/3 sect=15/15 s=0.939581007 [59] e=0 [5] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done
300SkOpSegment::activeOp id=17 t=0 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1
301SkOpSegment::activeOp id=3 t=0.939581007 tEnd=1 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
302SkOpSegment::markDone id=3 (35,10.0000019 56.1111107,10.0000019) t=0.939581007 [59] (54.835598,10.0000019) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
303SkOpSegment::markDone id=4 (56.1111107,10.0000019 59.4444466,10.0000019 59.4444466,13.333334) t=0 [7] (56.1111107,10.0000019) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
304SkOpSegment::markDone id=5 (59.4444466,13.333334 59.4444466,73.3333359) t=0 [9] (59.4444466,13.333334) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
305SkOpSegment::markDone id=6 (59.4444466,73.3333359 59.4444466,76.6666641 56.1111107,76.6666641) t=0 [11] (59.4444466,73.3333359) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
306SkOpSegment::markDone id=7 (56.1111107,76.6666641 35,76.6666641) t=0 [13] (56.1111107,76.6666641) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
307SkOpSegment::markDone id=8 (35,76.6666641 31.6666698,76.6666641 31.6666698,73.3333359) t=0 [15] (35,76.6666641) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
308SkOpSegment::markDone id=1 (31.6666698,73.3333359 31.6666698,13.333334) t=0 [1] (31.6666698,73.3333359) tEnd=0.0607988451 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=1 oppValue=0
309SkOpSegment::activeOp id=3 t=0.939581007 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
310SkOpSegment::markDone id=16 (54.9999962,10.9948997 54.9999962,10.4838676 54.835598,10) t=0 [31] (54.9999962,10.9948997) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
311SkOpSegment::findNextOp from:[16] to:[17] start=-2068759720 end=-2068759576
312bridgeOp current id=16 from=(54.9999962,10.9948997) to=(54.835598,10)
313path.lineTo(54.9999962,10.9948997);
314path.conicTo(54.9999962,10.4838676, 54.835598,10, 0.986621082);
315SkOpSegment::debugShowActiveSpans id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997 0.986621082f) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
316SkOpSegment::debugShowActiveSpans id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
317SkOpSegment::debugShowActiveSpans id=12 (29.2278862,66.6626663 29.2278862,69.1578563 31.6666698,69.6854019 0.778275728f) t=0 tEnd=0.855202762 windSum=-1 oppSum=0 windValue=1 oppValue=0
318SkOpSegment::activeOp id=12 t=0.855202762 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
319SkOpSegment::markDone id=12 (29.2278862,66.6626663 29.2278862,69.7553177 32.3205376,69.7553177) t=0 [23] (29.2278862,66.6626663) tEnd=0.855202762 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
320SkOpSegment::markDone id=11 (29.2278862,10.9948997 29.2278862,66.6626663) t=0 [21] (29.2278862,10.9948997) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
321SkOpSegment::markDone id=10 (29.3922844,10 29.2278862,10.4838676 29.2278862,10.9948997) t=0 [19] (29.3922844,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
Cary Clark1d314432018-07-10 10:57:54 -0400322</div>
323
caryclarkdac1d172014-06-17 05:15:38 -0700324</div>
325
326<script type="text/javascript">
327
caryclark55888e42016-07-18 10:01:36 -0700328 var testDivs = [
Cary Clarkea2a6322018-08-27 13:19:09 -0400329 bug8228,
caryclark30b9fdd2016-08-31 14:36:29 -0700330 ];
caryclarkdac1d172014-06-17 05:15:38 -0700331
332var decimal_places = 3; // make this 3 to show more precision
333
334var tests = [];
335var testLines = [];
336var testTitles = [];
337var testIndex = 0;
338var ctx;
339
340var xmin, xmax, focusXmin, focusXmax;
341var ymin, ymax, focusYmin, focusYmax;
342var scale;
343var mouseX, mouseY;
344var srcLeft, srcTop;
345var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700346var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700347var curveT = 0;
348
349var pt_labels = 2;
350var collect_bounds = false;
351var control_lines = 0;
352var curve_t = false;
353var debug_xy = 1;
354var focus_enabled = false;
355var focus_on_selection = false;
356var step_limit = 0;
357var draw_active = false;
358var draw_add = false;
359var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700360var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700361var draw_deriviatives = 0;
Cary Clarkff114282016-12-14 11:56:16 -0500362var draw_direction = false;
caryclarkdac1d172014-06-17 05:15:38 -0700363var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700364var draw_id = false;
365var draw_intersection = 0;
366var draw_intersectT = false;
367var draw_legend = true;
368var draw_log = false;
369var draw_mark = false;
370var draw_midpoint = false;
371var draw_op = 0;
372var draw_sequence = false;
373var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700374var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700375var draw_path = 3;
376var draw_computed = 0;
377var retina_scale = !!window.devicePixelRatio;
378
379var activeCount = 0;
380var addCount = 0;
381var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700382var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700383var opCount = 0;
384var sectCount = 0;
385var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700386var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700387var markCount = 0;
388var activeMax = 0;
389var addMax = 0;
390var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700391var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700392var sectMax = 0;
393var sectMax2 = 0;
394var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700395var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700396var markMax = 0;
397var opMax = 0;
398var stepMax = 0;
399var lastIndex = 0;
400var hasPath = false;
caryclark26ad22a2015-10-16 09:03:38 -0700401var hasAlignedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -0700402var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700403var angleBetween = false;
404var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700405
406var firstActiveSpan = -1;
407var logStart = -1;
408var logRange = 0;
409
410var SPAN_ID = 0;
411var SPAN_X1 = SPAN_ID + 1;
412var SPAN_Y1 = SPAN_X1 + 1;
413var SPAN_X2 = SPAN_Y1 + 1;
414var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700415
caryclark55888e42016-07-18 10:01:36 -0700416var SPAN_L_TX = SPAN_Y2 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700417var SPAN_L_TY = SPAN_L_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700418var SPAN_L_OTHER = SPAN_L_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700419var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
420var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
421var SPAN_L_SUM = SPAN_L_OTHERI + 1;
422var SPAN_L_VAL = SPAN_L_SUM + 1;
423var SPAN_L_OPP = SPAN_L_VAL + 1;
424
425var SPAN_X3 = SPAN_Y2 + 1;
426var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700427
caryclark55888e42016-07-18 10:01:36 -0700428var SPAN_Q_TX = SPAN_Y3 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700429var SPAN_Q_TY = SPAN_Q_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700430var SPAN_Q_OTHER = SPAN_Q_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700431var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
432var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
433var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
434var SPAN_Q_VAL = SPAN_Q_SUM + 1;
435var SPAN_Q_OPP = SPAN_Q_VAL + 1;
436
caryclark1049f122015-04-20 08:31:59 -0700437var SPAN_K_W = SPAN_Y3 + 1;
caryclark55888e42016-07-18 10:01:36 -0700438var SPAN_K_TX = SPAN_K_W + 1;
caryclark1049f122015-04-20 08:31:59 -0700439var SPAN_K_TY = SPAN_K_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700440var SPAN_K_OTHER = SPAN_K_TY + 1;
caryclark1049f122015-04-20 08:31:59 -0700441var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
442var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
443var SPAN_K_SUM = SPAN_K_OTHERI + 1;
444var SPAN_K_VAL = SPAN_K_SUM + 1;
445var SPAN_K_OPP = SPAN_K_VAL + 1;
446
caryclarkdac1d172014-06-17 05:15:38 -0700447var SPAN_X4 = SPAN_Y3 + 1;
448var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700449
caryclark55888e42016-07-18 10:01:36 -0700450var SPAN_C_TX = SPAN_Y4 + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700451var SPAN_C_TY = SPAN_C_TX + 1;
caryclark55888e42016-07-18 10:01:36 -0700452var SPAN_C_OTHER = SPAN_C_TY + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700453var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
454var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
455var SPAN_C_SUM = SPAN_C_OTHERI + 1;
456var SPAN_C_VAL = SPAN_C_SUM + 1;
457var SPAN_C_OPP = SPAN_C_VAL + 1;
458
459var ACTIVE_LINE_SPAN = 1;
460var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700461var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
462var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700463
464var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
465var ADD_LINETO = ADD_MOVETO + 1;
466var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700467var ADD_CONICTO = ADD_QUADTO + 1;
468var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700469var ADD_CLOSE = ADD_CUBICTO + 1;
470var ADD_FILL = ADD_CLOSE + 1;
471
472var PATH_LINE = ADD_FILL + 1;
473var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700474var PATH_CONIC = PATH_QUAD + 1;
475var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700476
477var INTERSECT_LINE = PATH_CUBIC + 1;
478var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
479var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
480var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
481var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
482var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
483var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
484var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
485var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700486var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
487var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
488var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
caryclark55888e42016-07-18 10:01:36 -0700489var INTERSECT_CONIC_QUAD = INTERSECT_CONIC_LINE_NO + 1;
490var INTERSECT_CONIC_QUAD_2 = INTERSECT_CONIC_QUAD + 1;
caryclark6c3b9cd2016-09-26 05:36:58 -0700491var INTERSECT_CONIC_QUAD_3 = INTERSECT_CONIC_QUAD_2 + 1;
492var INTERSECT_CONIC_QUAD_4 = INTERSECT_CONIC_QUAD_3 + 1;
493var INTERSECT_CONIC_QUAD_NO = INTERSECT_CONIC_QUAD_4 + 1;
caryclark55888e42016-07-18 10:01:36 -0700494var INTERSECT_CONIC = INTERSECT_CONIC_QUAD_NO + 1;
caryclark1049f122015-04-20 08:31:59 -0700495var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
496var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
497var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700498var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
499var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
500var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
501var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
502var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
503var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
504var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
505var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
506var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
507var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
508var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
509var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
510var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
511var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
512// FIXME: add cubic 5- 9
513var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
514
515var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
516var SORT_BINARY = SORT_UNARY + 1;
517
518var OP_DIFFERENCE = SORT_BINARY + 1;
519var OP_INTERSECT = OP_DIFFERENCE + 1;
520var OP_UNION = OP_INTERSECT + 1;
521var OP_XOR = OP_UNION + 1;
522
523var MARK_LINE = OP_XOR + 1;
524var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700525var MARK_CONIC = MARK_QUAD + 1;
526var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700527var MARK_DONE_LINE = MARK_CUBIC + 1;
528var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700529var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
530var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700531var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
532var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700533var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
534var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700535var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
536var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700537var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
538var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700539var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
540var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700541var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
542var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700543var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
544var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700545var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
546var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700547var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
548
549var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
550var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
551
caryclark624637c2015-05-11 07:21:27 -0700552var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700553var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700554
caryclark54359292015-03-26 07:52:43 -0700555var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700556
caryclark624637c2015-05-11 07:21:27 -0700557var COIN_MAIN_SPAN = ACTIVE_OP + 1;
558var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
559
560var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700561
562var REC_TYPE_UNKNOWN = -1;
563var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700564var REC_TYPE_PATH2 = 1;
565var REC_TYPE_SECT = 2;
566var REC_TYPE_ACTIVE = 3;
567var REC_TYPE_ADD = 4;
568var REC_TYPE_SORT = 5;
569var REC_TYPE_OP = 6;
570var REC_TYPE_MARK = 7;
571var REC_TYPE_COMPUTED = 8;
572var REC_TYPE_COIN = 9;
573var REC_TYPE_ANGLE = 10;
574var REC_TYPE_ACTIVE_OP = 11;
575var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700576var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700577var REC_TYPE_COINCIDENCE = 14;
caryclark26ad22a2015-10-16 09:03:38 -0700578var REC_TYPE_ALIGNED = 15;
579var REC_TYPE_LAST = REC_TYPE_ALIGNED;
caryclarkdac1d172014-06-17 05:15:38 -0700580
581function strs_to_nums(strs) {
582 var result = [];
583 for (var idx = 1; idx < strs.length; ++idx) {
584 var str = strs[idx];
585 var num = parseFloat(str);
586 if (isNaN(num)) {
587 result.push(str);
588 } else {
589 result.push(num);
590 }
591 }
592 return result;
593}
594
595function filter_str_by(id, str, regex, array) {
596 if (regex.test(str)) {
597 var strs = regex.exec(str);
598 var result = strs_to_nums(strs);
599 array.push(id);
600 array.push(result);
601 return true;
602 }
603 return false;
604}
605
606function construct_regexp2(pattern) {
607 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
608 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
609 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700610 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700611 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
612 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
613 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700614 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700615 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
616 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
617 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700618 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700619 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700620 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700621 escape = escape.replace(/NUM/g, "(-?\\d+)");
622 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
623 return new RegExp(escape, 'i');
624}
625
626function construct_regexp2c(pattern) {
627 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
628 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700629 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700630 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700631 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
632 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700633 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700634 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700635 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700636 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 -0700637 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700638 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700639 escape = escape.replace(/OPER/g, "[a-z]+");
640 escape = escape.replace(/PATH/g, "pathB?");
641 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700642 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700643 escape = escape.replace(/NUM/g, "(-?\\d+)");
644 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
645 return new RegExp(escape, 'i');
646}
647
648function match_regexp(str, lineNo, array, id, pattern) {
649 var regex = construct_regexp2(pattern);
650 if (filter_str_by(id, str, regex, array)) {
651 return true;
652 }
653 regex = construct_regexp2c(pattern);
654 return filter_str_by(id, str, regex, array);
655}
656
657function endsWith(str, suffix) {
658 return str.indexOf(suffix, str.length - suffix.length) !== -1;
659}
660
661function parse_all(test) {
662 var lines = test.match(/[^\r\n]+/g);
663 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
664 var record = [];
665 var recType = REC_TYPE_UNKNOWN;
666 var lastLineNo;
667 var moveX, moveY;
668 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
669 var line = lines[lineNo];
670 if (line.length == 0) {
671 continue;
672 }
673 var opStart = "SkOpSegment::";
674 if (line.lastIndexOf(opStart, 0) === 0) {
675 line = line.substr(opStart.length);
676 }
677 var angleStart = "SkOpAngle::";
678 if (line.lastIndexOf(angleStart, 0) === 0) {
679 line = line.substr(angleStart.length);
680 }
caryclark624637c2015-05-11 07:21:27 -0700681 var coinStart = "SkOpCoincidence::";
682 if (line.lastIndexOf(coinStart, 0) === 0) {
683 line = line.substr(coinStart.length);
684 }
caryclark54359292015-03-26 07:52:43 -0700685 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700686 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700687 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclark55888e42016-07-18 10:01:36 -0700688 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700689 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700690 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
691 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
692 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
693 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
caryclark26ad22a2015-10-16 09:03:38 -0700694 : line.lastIndexOf("aligned=", 0) === 0 ? REC_TYPE_ALIGNED
caryclarkdac1d172014-06-17 05:15:38 -0700695 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700696 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700697 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
698 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
Cary Clark59d5a0e2017-01-23 14:38:52 +0000699 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
caryclarkdac1d172014-06-17 05:15:38 -0700700 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
701 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700702 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700703 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
704 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
705 : REC_TYPE_UNKNOWN;
706 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
707 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
708 if (recType != REC_TYPE_UNKNOWN) {
709 records.push(recType);
710 records.push(lastLineNo);
711 records.push(record);
712 }
713 record = [];
714 recType = type;
715 lastLineNo = lineNo;
716 }
717 var found = false;
718 switch (recType) {
719 case REC_TYPE_ACTIVE:
720 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700721" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700722 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700723" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700724 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700725" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700726 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700727" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark624637c2015-05-11 07:21:27 -0700728 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700729" id=IDX LINE_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700730 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700731" id=IDX QUAD_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700732 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700733" id=IDX CONIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclark624637c2015-05-11 07:21:27 -0700734 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark55888e42016-07-18 10:01:36 -0700735" id=IDX CUBIC_VAL t=T_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700736 );
737 break;
738 case REC_TYPE_ACTIVE_OP:
739 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
740" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
741 );
742 break;
743 case REC_TYPE_ADD:
744 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
745 moveX = record[1][0];
746 moveY = record[1][1];
747 found = true;
748 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
749 record[1].unshift(moveY);
750 record[1].unshift(moveX);
751 moveX = record[1][2];
752 moveY = record[1][3];
753 found = true;
754 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
755 record[1].unshift(moveY);
756 record[1].unshift(moveX);
757 moveX = record[1][4];
758 moveY = record[1][5];
759 found = true;
caryclark1049f122015-04-20 08:31:59 -0700760 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
761 record[1].unshift(moveY);
762 record[1].unshift(moveX);
763 moveX = record[1][4];
764 moveY = record[1][5];
765 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700766 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
767 record[1].unshift(moveY);
768 record[1].unshift(moveX);
769 moveX = record[1][6];
770 moveY = record[1][7];
771 found = true;
772 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
773 found = true;
774 } else {
775 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
776 }
777 break;
caryclark54359292015-03-26 07:52:43 -0700778 case REC_TYPE_AFTERPART:
Cary Clarkff114282016-12-14 11:56:16 -0500779 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL id=IDX")
780 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL id=IDX")
781 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL id=IDX")
782 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL id=IDX")
caryclark54359292015-03-26 07:52:43 -0700783 break;
caryclark26ad22a2015-10-16 09:03:38 -0700784 case REC_TYPE_ALIGNED:
785 found = match_regexp(line, lineNo, record, PATH_LINE, "aligned=IDX LINE_VAL"
786 ) || match_regexp(line, lineNo, record, PATH_QUAD, "aligned=IDX QUAD_VAL"
787 ) || match_regexp(line, lineNo, record, PATH_CONIC, "aligned=IDX CONIC_VAL"
788 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "aligned=IDX CUBIC_VAL"
789 );
790 break;
caryclarkdac1d172014-06-17 05:15:38 -0700791 case REC_TYPE_ANGLE:
Cary Clark59d5a0e2017-01-23 14:38:52 +0000792 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700793"[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");
794 break;
795 case REC_TYPE_COIN:
796 found = true;
797 break;
caryclark624637c2015-05-11 07:21:27 -0700798 case REC_TYPE_COINCIDENCE:
799 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
800" + id=IDX t=T_VAL tEnd=T_VAL"
801 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
802" - id=IDX t=T_VAL tEnd=T_VAL"
803 );
804 break;
caryclarkdac1d172014-06-17 05:15:38 -0700805 case REC_TYPE_COMPUTED:
806 found = line == "computed quadratics given"
807 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
808 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
809 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700810 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700811 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
812 );
813 break;
814 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700815 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
816 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700817 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700818 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
819 );
820 break;
821 case REC_TYPE_PATH2:
822 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
823 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700824 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700825 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700826 );
827 break;
828 case REC_TYPE_SECT:
829 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
830" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
831 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
832" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
833 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
834" no intersect LINE_VAL LINE_VAL"
835 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
836" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
837 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
838" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
839 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
840" no intersect QUAD_VAL LINE_VAL"
841 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
842" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
843 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
844" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
845 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
846" no intersect QUAD_VAL QUAD_VAL"
caryclark55888e42016-07-18 10:01:36 -0700847
caryclark1049f122015-04-20 08:31:59 -0700848 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
849" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
850 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
851" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
852 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
853" no intersect CONIC_VAL LINE_VAL"
caryclark55888e42016-07-18 10:01:36 -0700854
855 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD, "debugShowConicQuadIntersection" +
856" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
857 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_2, "debugShowConicQuadIntersection" +
858" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
caryclark6c3b9cd2016-09-26 05:36:58 -0700859 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_3, "debugShowConicQuadIntersection" +
860" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL"
861 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_4, "debugShowConicQuadIntersection" +
862" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wtTs[2]=T_VAL PT_VAL wtTs[3]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL wnTs[2]=T_VAL wnTs[3]=T_VAL"
caryclark55888e42016-07-18 10:01:36 -0700863 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_QUAD_NO, "debugShowConicQuadIntersection" +
864" no intersect CONIC_VAL QUAD_VAL"
865
caryclark1049f122015-04-20 08:31:59 -0700866 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
867" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
868 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
869" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
870 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
871" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700872 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
873" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
874 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
875" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
876 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
877" 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"
878 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
879" no intersect CUBIC_VAL LINE_VAL"
880 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
881" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
882 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
883" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
884 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
885" 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"
886 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
887" 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"
888 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
889" no intersect CUBIC_VAL QUAD_VAL"
890 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
891" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
892 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
893" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
894 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
895" 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"
896 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
897" 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"
898 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
899" no intersect CUBIC_VAL CUBIC_VAL"
900 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
901" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
902 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
903" no self intersect CUBIC_VAL"
904 );
905 break;
906 case REC_TYPE_SORT:
907 var hasDone = / done/.test(line);
908 var hasUnorderable = / unorderable/.test(line);
909 var hasSmall = / small/.test(line);
910 var hasTiny = / tiny/.test(line);
911 var hasOperand = / operand/.test(line);
912 var hasStop = / stop/.test(line);
913 line.replace(/[ a-z]+$/, "");
914 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
915" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
916 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
917" [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"
918 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
919" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
920 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
921" [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"
922 );
923 if (found) {
924 record[1].push(hasDone);
925 record[1].push(hasUnorderable);
926 record[1].push(hasSmall);
927 record[1].push(hasTiny);
928 record[1].push(hasOperand);
929 record[1].push(hasStop);
930 }
931 break;
caryclark03b03ca2015-04-23 09:13:37 -0700932 case REC_TYPE_TOP:
933 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
934" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
935 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
936" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
937 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
938" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
939 );
940 break;
caryclarkdac1d172014-06-17 05:15:38 -0700941 case REC_TYPE_MARK:
942 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700943" 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 -0700944 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700945" 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 -0700946 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
947" 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 -0700948 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700949" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
950 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
951" 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"
952 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
953" 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 -0700954 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
955" 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 -0700956 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
957" 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 -0700958 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
959" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
960 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
961" 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 -0700962 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
963" 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 -0700964 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
965" 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 -0700966 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700967" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700968 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark55888e42016-07-18 10:01:36 -0700969" last seg=IDX span=IDX"
970 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
971" last segment=IDX span=IDX windSum=OPT"
972 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
973" last seg=IDX span=IDX windSum=OPT"
974 );
caryclarkdac1d172014-06-17 05:15:38 -0700975 break;
976 case REC_TYPE_OP:
977 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
978 || line.lastIndexOf("operator<", 0) === 0) {
979 found = true;
980 break;
981 }
caryclark54359292015-03-26 07:52:43 -0700982 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700983 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700984 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700985 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
986 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
987 );
988 break;
989 case REC_TYPE_UNKNOWN:
990 found = true;
991 break;
992 }
993 if (!found) {
994 console.log(line + " [" + lineNo + "] of type " + type + " not found");
995 }
996 }
997 if (recType != REC_TYPE_UNKNOWN) {
998 records.push(recType);
999 records.push(lastLineNo);
1000 records.push(record);
1001 }
1002 if (records.length >= 1) {
1003 tests[testIndex] = records;
1004 testLines[testIndex] = lines;
1005 }
1006}
1007
1008function init(test) {
1009 var canvas = document.getElementById('canvas');
1010 if (!canvas.getContext) return;
1011 ctx = canvas.getContext('2d');
1012 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
1013 var unscaledWidth = window.innerWidth - 20;
1014 var unscaledHeight = window.innerHeight - 20;
1015 screenWidth = unscaledWidth;
1016 screenHeight = unscaledHeight;
1017 canvas.width = unscaledWidth * resScale;
1018 canvas.height = unscaledHeight * resScale;
1019 canvas.style.width = unscaledWidth + 'px';
1020 canvas.style.height = unscaledHeight + 'px';
1021 if (resScale != 1) {
1022 ctx.scale(resScale, resScale);
1023 }
1024 xmin = Infinity;
1025 xmax = -Infinity;
1026 ymin = Infinity;
1027 ymax = -Infinity;
caryclark26ad22a2015-10-16 09:03:38 -07001028 hasPath = hasAlignedPath = hasComputedPath = false;
caryclarkdac1d172014-06-17 05:15:38 -07001029 firstActiveSpan = -1;
1030 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1031 var recType = test[tIndex];
1032 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
1033 console.log("unknown rec type: " + recType);
1034 throw "stop execution";
1035 }
1036 var records = test[tIndex + 2];
1037 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1038 var fragType = records[recordIndex];
1039 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
1040 console.log("unknown in range frag type: " + fragType);
1041 throw "stop execution";
1042 }
1043 var frags = records[recordIndex + 1];
1044 var first = 0;
1045 var last = -1;
1046 var first2 = 0;
1047 var last2 = 0;
1048 switch (recType) {
caryclark26ad22a2015-10-16 09:03:38 -07001049 case REC_TYPE_ALIGNED:
1050 hasAlignedPath = true;
caryclarkdac1d172014-06-17 05:15:38 -07001051 case REC_TYPE_COMPUTED:
1052 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
1053 break;
1054 }
caryclark26ad22a2015-10-16 09:03:38 -07001055 if (REC_TYPE_COMPUTED == recType) {
1056 hasComputedPath = true;
1057 }
caryclarkdac1d172014-06-17 05:15:38 -07001058 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07001059 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -07001060 switch (fragType) {
1061 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07001062 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -07001063 break;
caryclark1049f122015-04-20 08:31:59 -07001064 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07001065 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07001066 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -07001067 break;
1068 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07001069 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -07001070 break;
1071 default:
caryclark55888e42016-07-18 10:01:36 -07001072 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
caryclarkdac1d172014-06-17 05:15:38 -07001073 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
1074 throw "stop execution";
1075 }
1076 if (recType == REC_TYPE_PATH) {
1077 hasPath = true;
1078 }
1079 break;
caryclark54359292015-03-26 07:52:43 -07001080 case REC_TYPE_PATH2:
1081 first = 1;
1082 switch (fragType) {
1083 case PATH_LINE:
1084 last = 5;
1085 break;
caryclark1049f122015-04-20 08:31:59 -07001086 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001087 case PATH_QUAD:
1088 last = 7;
1089 break;
1090 case PATH_CUBIC:
1091 last = 9;
1092 break;
1093 default:
caryclark55888e42016-07-18 10:01:36 -07001094 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
caryclark54359292015-03-26 07:52:43 -07001095 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
1096 throw "stop execution";
1097 }
1098 if (recType == REC_TYPE_PATH2) {
1099 hasPath = true;
1100 }
1101 break;
caryclarkdac1d172014-06-17 05:15:38 -07001102 case REC_TYPE_ACTIVE:
1103 if (firstActiveSpan < 0) {
1104 firstActiveSpan = tIndex;
1105 }
1106 first = 1;
1107 switch (fragType) {
1108 case ACTIVE_LINE_SPAN:
1109 last = 5;
1110 break;
caryclark1049f122015-04-20 08:31:59 -07001111 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -07001112 case ACTIVE_QUAD_SPAN:
1113 last = 7;
1114 break;
1115 case ACTIVE_CUBIC_SPAN:
1116 last = 9;
1117 break;
1118 default:
1119 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
1120 throw "stop execution";
1121 }
1122 break;
1123 case REC_TYPE_ADD:
1124 switch (fragType) {
1125 case ADD_MOVETO:
1126 break;
1127 case ADD_LINETO:
1128 last = 4;
1129 break;
caryclark1049f122015-04-20 08:31:59 -07001130 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -07001131 case ADD_QUADTO:
1132 last = 6;
1133 break;
1134 case ADD_CUBICTO:
1135 last = 8;
1136 break;
1137 case ADD_CLOSE:
1138 case ADD_FILL:
1139 break;
1140 default:
1141 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
1142 throw "stop execution";
1143 }
1144 break;
caryclark54359292015-03-26 07:52:43 -07001145 case REC_TYPE_AFTERPART:
1146 switch (fragType) {
1147 case PATH_LINE:
1148 last = 4;
1149 break;
caryclark1049f122015-04-20 08:31:59 -07001150 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -07001151 case PATH_QUAD:
1152 last = 6;
1153 break;
1154 case PATH_CUBIC:
1155 last = 8;
1156 break;
1157 default:
1158 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
1159 throw "stop execution";
1160 }
1161 break;
caryclarkdac1d172014-06-17 05:15:38 -07001162 case REC_TYPE_SECT:
1163 switch (fragType) {
1164 case INTERSECT_LINE:
1165 first = 1; last = 5; first2 = 8; last2 = 12;
1166 break;
1167 case INTERSECT_LINE_2:
1168 first = 1; last = 5; first2 = 11; last2 = 15;
1169 break;
1170 case INTERSECT_LINE_NO:
1171 first = 0; last = 4; first2 = 4; last2 = 8;
1172 break;
caryclark1049f122015-04-20 08:31:59 -07001173 case INTERSECT_CONIC_LINE:
1174 first = 1; last = 7; first2 = 11; last2 = 15;
1175 break;
caryclarkdac1d172014-06-17 05:15:38 -07001176 case INTERSECT_QUAD_LINE:
1177 first = 1; last = 7; first2 = 10; last2 = 14;
1178 break;
caryclark1049f122015-04-20 08:31:59 -07001179 case INTERSECT_CONIC_LINE_2:
1180 first = 1; last = 7; first2 = 14; last2 = 18;
1181 break;
caryclarkdac1d172014-06-17 05:15:38 -07001182 case INTERSECT_QUAD_LINE_2:
1183 first = 1; last = 7; first2 = 13; last2 = 17;
1184 break;
caryclark1049f122015-04-20 08:31:59 -07001185 case INTERSECT_CONIC_LINE_NO:
1186 first = 0; last = 6; first2 = 7; last2 = 11;
1187 break;
caryclarkdac1d172014-06-17 05:15:38 -07001188 case INTERSECT_QUAD_LINE_NO:
1189 first = 0; last = 6; first2 = 6; last2 = 10;
1190 break;
caryclark1049f122015-04-20 08:31:59 -07001191 case INTERSECT_CONIC:
1192 first = 1; last = 7; first2 = 11; last2 = 17;
1193 break;
caryclarkdac1d172014-06-17 05:15:38 -07001194 case INTERSECT_QUAD:
1195 first = 1; last = 7; first2 = 10; last2 = 16;
1196 break;
caryclark1049f122015-04-20 08:31:59 -07001197 case INTERSECT_CONIC_2:
1198 first = 1; last = 7; first2 = 14; last2 = 20;
1199 break;
caryclarkdac1d172014-06-17 05:15:38 -07001200 case INTERSECT_QUAD_2:
1201 first = 1; last = 7; first2 = 13; last2 = 19;
1202 break;
caryclark1049f122015-04-20 08:31:59 -07001203 case INTERSECT_CONIC_NO:
1204 first = 0; last = 6; first2 = 7; last2 = 13;
1205 break;
caryclarkdac1d172014-06-17 05:15:38 -07001206 case INTERSECT_QUAD_NO:
1207 first = 0; last = 6; first2 = 6; last2 = 12;
1208 break;
1209 case INTERSECT_SELF_CUBIC:
1210 first = 1; last = 9;
1211 break;
1212 case INTERSECT_SELF_CUBIC_NO:
1213 first = 0; last = 8;
1214 break;
1215 case INTERSECT_CUBIC_LINE:
1216 first = 1; last = 9; first2 = 12; last2 = 16;
1217 break;
1218 case INTERSECT_CUBIC_LINE_2:
1219 first = 1; last = 9; first2 = 15; last2 = 19;
1220 break;
1221 case INTERSECT_CUBIC_LINE_3:
1222 first = 1; last = 9; first2 = 18; last2 = 22;
1223 break;
1224 case INTERSECT_CUBIC_LINE_NO:
1225 first = 0; last = 8; first2 = 8; last2 = 12;
1226 break;
caryclark55888e42016-07-18 10:01:36 -07001227 case INTERSECT_CONIC_QUAD:
1228 first = 1; last = 7; first2 = 11; last2 = 17;
1229 break;
1230 case INTERSECT_CONIC_QUAD_2:
1231 first = 1; last = 7; first2 = 14; last2 = 20;
1232 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07001233 case INTERSECT_CONIC_QUAD_3:
1234 first = 1; last = 7; first2 = 17; last2 = 23;
1235 break;
1236 case INTERSECT_CONIC_QUAD_4:
1237 first = 1; last = 7; first2 = 20; last2 = 26;
1238 break;
caryclark55888e42016-07-18 10:01:36 -07001239 case INTERSECT_CONIC_QUAD_NO:
1240 first = 0; last = 6; first2 = 7; last2 = 13;
1241 break;
caryclarkdac1d172014-06-17 05:15:38 -07001242 case INTERSECT_CUBIC_QUAD:
1243 first = 1; last = 9; first2 = 12; last2 = 18;
1244 break;
1245 case INTERSECT_CUBIC_QUAD_2:
1246 first = 1; last = 9; first2 = 15; last2 = 21;
1247 break;
1248 case INTERSECT_CUBIC_QUAD_3:
1249 first = 1; last = 9; first2 = 18; last2 = 24;
1250 break;
1251 case INTERSECT_CUBIC_QUAD_4:
1252 first = 1; last = 9; first2 = 21; last2 = 27;
1253 break;
1254 case INTERSECT_CUBIC_QUAD_NO:
1255 first = 0; last = 8; first2 = 8; last2 = 14;
1256 break;
1257 case INTERSECT_CUBIC:
1258 first = 1; last = 9; first2 = 12; last2 = 20;
1259 break;
1260 case INTERSECT_CUBIC_2:
1261 first = 1; last = 9; first2 = 15; last2 = 23;
1262 break;
1263 case INTERSECT_CUBIC_3:
1264 first = 1; last = 9; first2 = 18; last2 = 26;
1265 break;
1266 case INTERSECT_CUBIC_4:
1267 first = 1; last = 9; first2 = 21; last2 = 29;
1268 break;
1269 case INTERSECT_CUBIC_NO:
1270 first = 0; last = 8; first2 = 8; last2 = 16;
1271 break;
1272 default:
1273 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1274 throw "stop execution";
1275 }
1276 break;
1277 default:
1278 continue;
1279 }
1280 for (var idx = first; idx < last; idx += 2) {
1281 xmin = Math.min(xmin, frags[idx]);
1282 xmax = Math.max(xmax, frags[idx]);
1283 ymin = Math.min(ymin, frags[idx + 1]);
1284 ymax = Math.max(ymax, frags[idx + 1]);
1285 }
1286 for (var idx = first2; idx < last2; idx += 2) {
1287 xmin = Math.min(xmin, frags[idx]);
1288 xmax = Math.max(xmax, frags[idx]);
1289 ymin = Math.min(ymin, frags[idx + 1]);
1290 ymax = Math.max(ymax, frags[idx + 1]);
1291 }
1292 }
1293 }
1294 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1295 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1296 var recType = test[tIndex];
1297 var records = test[tIndex + 2];
1298 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1299 var fragType = records[recordIndex];
1300 var frags = records[recordIndex + 1];
1301 switch (recType) {
1302 case REC_TYPE_ACTIVE_OP:
1303 if (!draw_op) {
1304 break;
1305 }
1306 {
1307 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1308 curve_extremes(curve, angleBounds);
1309 }
1310 break;
1311 case REC_TYPE_ANGLE:
1312 if (!draw_angle) {
1313 break;
1314 }
caryclark54359292015-03-26 07:52:43 -07001315 {
caryclarkdac1d172014-06-17 05:15:38 -07001316 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1317 curve_extremes(curve, angleBounds);
1318 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1319 curve_extremes(curve, angleBounds);
1320 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1321 }
1322 break;
caryclark624637c2015-05-11 07:21:27 -07001323 case REC_TYPE_COINCIDENCE:
1324 if (!draw_coincidence) {
1325 break;
1326 }
1327 {
1328 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1329 curve_extremes(curve, angleBounds);
1330 }
1331 break;
caryclarkdac1d172014-06-17 05:15:38 -07001332 case REC_TYPE_SORT:
1333 if (!draw_sort) {
1334 break;
1335 }
1336 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1337 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1338 curve_extremes(curve, angleBounds);
1339 }
1340 break;
caryclark03b03ca2015-04-23 09:13:37 -07001341 case REC_TYPE_TOP:
1342 if (!draw_top) {
1343 break;
1344 }
1345 {
1346 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1347 curve_extremes(curve, angleBounds);
1348 }
1349 break;
caryclarkdac1d172014-06-17 05:15:38 -07001350 }
1351 }
1352 }
1353 xmin = Math.min(xmin, angleBounds[0]);
1354 ymin = Math.min(ymin, angleBounds[1]);
1355 xmax = Math.max(xmax, angleBounds[2]);
1356 ymax = Math.max(ymax, angleBounds[3]);
1357 setScale(xmin, xmax, ymin, ymax);
1358 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001359 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001360 }
1361 if (hasPath == true && hasComputedPath == false && draw_computed) {
1362 draw_computed = 0;
1363 }
1364}
1365
caryclark26ad22a2015-10-16 09:03:38 -07001366function curveByIDMatch(test, id, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001367 var tIndex = -3;
1368 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001369 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001370 if (recType == REC_TYPE_OP) {
1371 continue;
1372 }
caryclark26ad22a2015-10-16 09:03:38 -07001373 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001374 return [];
1375 }
1376 var records = test[tIndex + 2];
1377 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1378 var fragType = records[recordIndex];
1379 var frags = records[recordIndex + 1];
1380 if (frags[0] == id) {
1381 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001382 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001383 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001384 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001385 return [frags[1], frags[2], frags[3], frags[4],
1386 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001387 case PATH_CONIC:
1388 return [frags[1], frags[2], frags[3], frags[4],
1389 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001390 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001391 return [frags[1], frags[2], frags[3], frags[4],
1392 frags[5], frags[6], frags[7], frags[8]];
1393 }
1394 }
1395 }
caryclarkdac1d172014-06-17 05:15:38 -07001396 }
1397 return [];
1398}
1399
caryclark26ad22a2015-10-16 09:03:38 -07001400function curveByID(test, id) {
1401 var result = draw_path >= 4 ? curveByIDMatch(test, id, REC_TYPE_ALIGNED) : [];
1402 if (!result.length) {
1403 result = curveByIDMatch(test, id, REC_TYPE_PATH);
1404 }
1405 return result;
1406}
1407
1408function curvePartialByIDMatch(test, id, t0, t1, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001409 var tIndex = -3;
1410 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001411 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001412 if (recType == REC_TYPE_OP) {
1413 continue;
1414 }
caryclark26ad22a2015-10-16 09:03:38 -07001415 if (recType != recMatch) {
caryclarkdac1d172014-06-17 05:15:38 -07001416 return [];
1417 }
1418 var records = test[tIndex + 2];
1419 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1420 var fragType = records[recordIndex];
1421 var frags = records[recordIndex + 1];
1422 if (frags[0] == id) {
1423 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001424 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001425 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001426 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001427 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1428 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001429 case PATH_CONIC:
1430 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1431 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001432 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001433 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1434 frags[5], frags[6], frags[7], frags[8], t0, t1);
1435 }
1436 }
1437 }
caryclarkdac1d172014-06-17 05:15:38 -07001438 }
1439 return [];
1440}
1441
caryclark26ad22a2015-10-16 09:03:38 -07001442function curvePartialByID(test, id, t0, t1) {
1443 var result = draw_path >= 4 ? curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_ALIGNED) : [];
1444 if (!result.length) {
1445 result = curvePartialByIDMatch(test, id, t0, t1, REC_TYPE_PATH);
1446 }
1447 return result;
1448}
1449
1450function idByCurveIDMatch(test, frag, type, recMatch) {
caryclark54359292015-03-26 07:52:43 -07001451 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001452 while (tIndex < test.length) {
1453 var recType = test[tIndex];
caryclark26ad22a2015-10-16 09:03:38 -07001454 if (recType != recMatch) {
caryclark54359292015-03-26 07:52:43 -07001455 ++tIndex;
1456 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001457 }
1458 var records = test[tIndex + 2];
1459 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1460 var fragType = records[recordIndex];
1461 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001462 if (frag.length != frags.length - 1) {
1463 continue;
1464 }
caryclarkdac1d172014-06-17 05:15:38 -07001465 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001466 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001467 if (frag[0] != frags[1] || frag[1] != frags[2]
1468 || frag[2] != frags[3] || frag[3] != frags[4]) {
1469 continue;
1470 }
1471 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001472 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001473 if (frag[0] != frags[1] || frag[1] != frags[2]
1474 || frag[2] != frags[3] || frag[3] != frags[4]
1475 || frag[4] != frags[5] || frag[5] != frags[6]) {
1476 continue;
1477 }
1478 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001479 case PATH_CONIC:
1480 if (frag[0] != frags[1] || frag[1] != frags[2]
1481 || frag[2] != frags[3] || frag[3] != frags[4]
1482 || frag[4] != frags[5] || frag[5] != frags[6]
1483 || frag[6] != frags[7]) {
1484 continue;
1485 }
1486 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001487 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001488 if (frag[0] != frags[1] || frag[1] != frags[2]
1489 || frag[2] != frags[3] || frag[3] != frags[4]
1490 || frag[4] != frags[5] || frag[5] != frags[6]
1491 || frag[6] != frags[7] || frag[7] != frags[8]) {
1492 continue;
1493 }
1494 return frags[0];
1495 }
1496 }
1497 ++tIndex;
1498 }
1499 return -1;
1500}
1501
caryclark26ad22a2015-10-16 09:03:38 -07001502function idByCurve(test, frag, type) {
1503 var result = draw_path >= 4 ? idByCurveIDMatch(test, frag, type, REC_TYPE_ALIGNED) : [];
1504 if (!result.length) {
1505 result = idByCurveIDMatch(test, frag, type, REC_TYPE_PATH);
1506 }
1507 return result;
1508}
1509
caryclarkdac1d172014-06-17 05:15:38 -07001510function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001511 var length = curve.length == 7 ? 6 : curve.length;
caryclarked0935a2015-10-22 07:23:52 -07001512 for (var index = 0; index < length; index += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001513 var x = curve[index];
1514 var y = curve[index + 1];
1515 bounds[0] = Math.min(bounds[0], x);
1516 bounds[1] = Math.min(bounds[1], y);
1517 bounds[2] = Math.max(bounds[2], x);
1518 bounds[3] = Math.max(bounds[3], y);
1519 }
1520}
1521
1522function setScale(x0, x1, y0, y1) {
1523 var srcWidth = x1 - x0;
1524 var srcHeight = y1 - y0;
1525 var usableWidth = screenWidth;
1526 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1527 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1528 usableWidth -= (xDigits + yDigits) * 10;
1529 usableWidth -= decimal_places * 10;
1530 if (draw_legend) {
1531 usableWidth -= 40;
1532 }
1533 var hscale = usableWidth / srcWidth;
1534 var vscale = screenHeight / srcHeight;
1535 scale = Math.min(hscale, vscale);
1536 var invScale = 1 / scale;
1537 var sxmin = x0 - invScale * 5;
1538 var symin = y0 - invScale * 10;
1539 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1540 var symax = y1 + invScale * 10;
1541 srcWidth = sxmax - sxmin;
1542 srcHeight = symax - symin;
1543 hscale = usableWidth / srcWidth;
1544 vscale = screenHeight / srcHeight;
1545 scale = Math.min(hscale, vscale);
1546 srcLeft = sxmin;
1547 srcTop = symin;
1548}
1549
1550function drawArc(curve, op, from, to) {
1551 var type = PATH_LINE + (curve.length / 2 - 2);
1552 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1553 var dy = pt.y - curve[1];
1554 var dx = pt.x - curve[0];
1555 var dist = Math.sqrt(dy * dy + dx * dx);
1556 var _dist = dist * scale;
1557 var angle = Math.atan2(dy, dx);
1558 var _px = (curve[0] - srcLeft) * scale;
1559 var _py = (curve[1] - srcTop) * scale;
1560 var divisor = 4;
1561 var endDist;
1562 do {
1563 var ends = [];
1564 for (var index = -1; index <= 1; index += 2) {
1565 var px = Math.cos(index * Math.PI / divisor);
1566 var py = Math.sin(index * Math.PI / divisor);
1567 ends.push(px);
1568 ends.push(py);
1569 }
1570 var endDx = (ends[2] - ends[0]) * scale * dist;
1571 var endDy = (ends[3] - ends[1]) * scale * dist;
1572 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1573 if (endDist < 100) {
1574 break;
1575 }
1576 divisor *= 2;
1577 } while (true);
1578 if (endDist < 30) {
1579 return;
1580 }
1581 if (op) {
1582 divisor *= 2;
1583 }
1584 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1585 ctx.beginPath();
1586 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1587 ctx.stroke();
1588 var saveAlign = ctx.textAlign;
1589 var saveStyle = ctx.fillStyle;
1590 var saveFont = ctx.font;
1591 ctx.textAlign = "center";
1592 ctx.fillStyle = "black";
1593 ctx.font = "normal 24px Arial";
1594 divisor *= 0.8;
1595 for (var index = -1; index <= 1; index += 2) {
1596 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1597 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1598 var _px = (px - srcLeft) * scale;
1599 var _py = (py - srcTop) * scale;
1600 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1601 }
1602 ctx.textAlign = saveAlign;
1603 ctx.fillStyle = saveStyle;
1604 ctx.font = saveFont;
1605}
1606
1607function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001608 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1609 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001610 var x = drawnPts[pts];
1611 var y = drawnPts[pts + 1];
1612 if (px == x && py == y) {
1613 return;
1614 }
1615 }
1616 drawnPts.push(px);
1617 drawnPts.push(py);
1618 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1619 var _px = (px - srcLeft) * scale;
1620 var _py = (py - srcTop) * scale;
1621 ctx.beginPath();
1622 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1623 ctx.closePath();
1624 if (end) {
1625 ctx.fill();
1626 } else {
1627 ctx.stroke();
1628 }
1629 if (debug_xy) {
1630 ctx.textAlign = "left";
1631 ctx.fillText(label, _px + 5, _py);
1632 }
1633}
1634
caryclark1049f122015-04-20 08:31:59 -07001635function coordCount(curveType) {
1636 switch (curveType) {
1637 case PATH_LINE:
1638 return 4;
1639 case PATH_QUAD:
1640 return 6;
1641 case PATH_CONIC:
1642 return 6;
1643 case PATH_CUBIC:
1644 return 8;
1645 }
1646 return -1;
1647}
1648
caryclarkdac1d172014-06-17 05:15:38 -07001649function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001650 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001651 for (var idx = 0; idx < count; idx += 2) {
1652 if (!drawControls && idx != 0 && idx != count - 2) {
1653 continue;
1654 }
1655 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1656 }
1657}
1658
1659function drawControlLines(curve, curveType, drawEnd) {
1660 if (curveType == PATH_LINE) {
1661 return;
1662 }
1663 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1664 drawLine(curve[0], curve[1], curve[2], curve[3]);
1665 drawLine(curve[2], curve[3], curve[4], curve[5]);
1666 if (curveType == PATH_CUBIC) {
1667 drawLine(curve[4], curve[5], curve[6], curve[7]);
1668 if (drawEnd > 1) {
1669 drawLine(curve[6], curve[7], curve[0], curve[1]);
1670 if (drawEnd > 2) {
1671 drawLine(curve[0], curve[1], curve[4], curve[5]);
1672 drawLine(curve[6], curve[7], curve[2], curve[3]);
1673 }
1674 }
1675 } else if (drawEnd > 1) {
1676 drawLine(curve[4], curve[5], curve[0], curve[1]);
1677 }
1678}
1679
1680function pointAtT(curve, curveType, t) {
1681 var xy = {};
1682 switch (curveType) {
1683 case PATH_LINE:
1684 var a = 1 - t;
1685 var b = t;
1686 xy.x = a * curve[0] + b * curve[2];
1687 xy.y = a * curve[1] + b * curve[3];
1688 break;
1689 case PATH_QUAD:
1690 var one_t = 1 - t;
1691 var a = one_t * one_t;
1692 var b = 2 * one_t * t;
1693 var c = t * t;
1694 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1695 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1696 break;
caryclark1049f122015-04-20 08:31:59 -07001697 case PATH_CONIC:
1698 var one_t = 1 - t;
1699 var a = one_t * one_t;
1700 var b = 2 * one_t * t;
1701 var c = t * t;
1702 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1703 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1704 var d = a + b * curve[6] + c;
1705 xy.x /= d;
1706 xy.y /= d;
1707 break;
caryclarkdac1d172014-06-17 05:15:38 -07001708 case PATH_CUBIC:
1709 var one_t = 1 - t;
1710 var one_t2 = one_t * one_t;
1711 var a = one_t2 * one_t;
1712 var b = 3 * one_t2 * t;
1713 var t2 = t * t;
1714 var c = 3 * one_t * t2;
1715 var d = t2 * t;
1716 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1717 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1718 break;
1719 }
1720 return xy;
1721}
caryclark55888e42016-07-18 10:01:36 -07001722
caryclarkdac1d172014-06-17 05:15:38 -07001723function drawPointAtT(curve, curveType) {
1724 var x, y;
1725 var xy = pointAtT(curve, curveType, curveT);
1726 drawPoint(xy.x, xy.y, true);
1727 if (!draw_intersectT) {
1728 return;
1729 }
1730 ctx.fillStyle = "red";
1731 drawTAtPointUp(xy.x, xy.y, curveT);
1732}
1733
1734function drawTAtPointUp(px, py, t) {
1735 var label = t.toFixed(decimal_places);
1736 var _px = (px - srcLeft)* scale;
1737 var _py = (py - srcTop) * scale;
1738 ctx.fillText(label, _px + 5, _py - 10);
1739}
1740
1741function drawTAtPointDown(px, py, t) {
1742 var label = t.toFixed(decimal_places);
1743 var _px = (px - srcLeft)* scale;
1744 var _py = (py - srcTop) * scale;
1745 ctx.fillText(label, _px + 5, _py + 10);
1746}
1747
1748function alreadyDrawnLine(x1, y1, x2, y2) {
1749 if (collect_bounds) {
1750 if (focus_enabled) {
1751 focusXmin = Math.min(focusXmin, x1, x2);
1752 focusYmin = Math.min(focusYmin, y1, y2);
1753 focusXmax = Math.max(focusXmax, x1, x2);
1754 focusYmax = Math.max(focusYmax, y1, y2);
1755 }
1756 return true;
1757 }
1758 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1759 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1760 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1761 return true;
1762 }
1763 }
1764 drawnLines.push(x1);
1765 drawnLines.push(y1);
1766 drawnLines.push(x2);
1767 drawnLines.push(y2);
1768 return false;
1769}
1770
1771function drawLine(x1, y1, x2, y2) {
1772 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1773 return;
1774 }
1775 ctx.beginPath();
1776 ctx.moveTo((x1 - srcLeft) * scale,
1777 (y1 - srcTop) * scale);
1778 ctx.lineTo((x2 - srcLeft) * scale,
1779 (y2 - srcTop) * scale);
1780 ctx.stroke();
1781}
1782
1783function linePartial(x1, y1, x2, y2, t1, t2) {
1784 var dx = x1 - x2;
1785 var dy = y1 - y2;
1786 var array = [
1787 x1 - t1 * dx,
1788 y1 - t1 * dy,
1789 x1 - t2 * dx,
1790 y1 - t2 * dy
1791 ];
1792 return array;
1793}
1794
1795function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1796 var a = linePartial(x1, y1, x2, y2, t1, t2);
1797 var ax = a[0];
1798 var ay = a[1];
1799 var bx = a[2];
1800 var by = a[3];
1801 if (alreadyDrawnLine(ax, ay, bx, by)) {
1802 return;
1803 }
1804 ctx.beginPath();
1805 ctx.moveTo((ax - srcLeft) * scale,
1806 (ay - srcTop) * scale);
1807 ctx.lineTo((bx - srcLeft) * scale,
1808 (by - srcTop) * scale);
1809 ctx.stroke();
1810}
1811
1812function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1813 if (collect_bounds) {
1814 if (focus_enabled) {
1815 focusXmin = Math.min(focusXmin, x1, x2, x3);
1816 focusYmin = Math.min(focusYmin, y1, y2, y3);
1817 focusXmax = Math.max(focusXmax, x1, x2, x3);
1818 focusYmax = Math.max(focusYmax, y1, y2, y3);
1819 }
1820 return true;
1821 }
1822 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1823 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1824 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1825 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1826 return true;
1827 }
1828 }
1829 drawnQuads.push(x1);
1830 drawnQuads.push(y1);
1831 drawnQuads.push(x2);
1832 drawnQuads.push(y2);
1833 drawnQuads.push(x3);
1834 drawnQuads.push(y3);
1835 return false;
1836}
1837
1838function drawQuad(x1, y1, x2, y2, x3, y3) {
1839 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1840 return;
1841 }
1842 ctx.beginPath();
1843 ctx.moveTo((x1 - srcLeft) * scale,
1844 (y1 - srcTop) * scale);
1845 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1846 (y2 - srcTop) * scale,
1847 (x3 - srcLeft) * scale,
1848 (y3 - srcTop) * scale);
1849 ctx.stroke();
1850}
1851
1852function interp(A, B, t) {
1853 return A + (B - A) * t;
1854}
1855
1856function interp_quad_coords(x1, x2, x3, t)
1857{
1858 var ab = interp(x1, x2, t);
1859 var bc = interp(x2, x3, t);
1860 var abc = interp(ab, bc, t);
1861 return abc;
1862}
1863
1864function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1865 var ax = interp_quad_coords(x1, x2, x3, t1);
1866 var ay = interp_quad_coords(y1, y2, y3, t1);
1867 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1868 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1869 var cx = interp_quad_coords(x1, x2, x3, t2);
1870 var cy = interp_quad_coords(y1, y2, y3, t2);
1871 var bx = 2*dx - (ax + cx)/2;
1872 var by = 2*dy - (ay + cy)/2;
1873 var array = [
1874 ax, ay, bx, by, cx, cy
1875 ];
1876 return array;
1877}
1878
1879function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1880 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1881 var ax = a[0];
1882 var ay = a[1];
1883 var bx = a[2];
1884 var by = a[3];
1885 var cx = a[4];
1886 var cy = a[5];
1887 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1888 return;
1889 }
1890 ctx.beginPath();
1891 ctx.moveTo((ax - srcLeft) * scale,
1892 (ay - srcTop) * scale);
1893 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1894 (by - srcTop) * scale,
1895 (cx - srcLeft) * scale,
1896 (cy - srcTop) * scale);
1897 ctx.stroke();
1898}
1899
caryclark1049f122015-04-20 08:31:59 -07001900function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1901 if (collect_bounds) {
1902 if (focus_enabled) {
1903 focusXmin = Math.min(focusXmin, x1, x2, x3);
1904 focusYmin = Math.min(focusYmin, y1, y2, y3);
1905 focusXmax = Math.max(focusXmax, x1, x2, x3);
1906 focusYmax = Math.max(focusYmax, y1, y2, y3);
1907 }
1908 return true;
1909 }
1910 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1911 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07001912 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1913 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclark1049f122015-04-20 08:31:59 -07001914 && w == drawnCubics[pts + 6]) {
1915 return true;
1916 }
1917 }
1918 drawnConics.push(x1);
1919 drawnConics.push(y1);
1920 drawnConics.push(x2);
1921 drawnConics.push(y2);
1922 drawnConics.push(x3);
1923 drawnConics.push(y3);
1924 drawnCubics.push(w);
1925 return false;
1926}
1927
1928var kMaxConicToQuadPOW2 = 5;
1929
1930function computeQuadPOW2(curve, tol) {
1931 var a = curve[6] - 1;
1932 var k = a / (4 * (2 + a));
1933 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1934 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1935
1936 var error = Math.sqrt(x * x + y * y);
1937 var pow2;
1938 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1939 if (error <= tol) {
1940 break;
1941 }
1942 error *= 0.25;
1943 }
1944 return pow2;
1945}
1946
1947function subdivide_w_value(w) {
1948 return Math.sqrt(0.5 + w * 0.5);
1949}
1950
1951function chop(curve, part1, part2) {
1952 var w = curve[6];
1953 var scale = 1 / (1 + w);
1954 part1[0] = curve[0];
1955 part1[1] = curve[1];
1956 part1[2] = (curve[0] + curve[2] * w) * scale;
1957 part1[3] = (curve[1] + curve[3] * w) * scale;
1958 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1959 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1960 part2[2] = (curve[2] * w + curve[4]) * scale;
1961 part2[3] = (curve[3] * w + curve[5]) * scale;
1962 part2[4] = curve[4];
1963 part2[5] = curve[5];
1964 part1[6] = part2[6] = subdivide_w_value(w);
1965}
1966
1967function subdivide(curve, level, pts) {
1968 if (0 == level) {
1969 pts.push(curve[2]);
1970 pts.push(curve[3]);
1971 pts.push(curve[4]);
1972 pts.push(curve[5]);
1973 } else {
1974 var part1 = [], part2 = [];
1975 chop(curve, part1, part2);
1976 --level;
1977 subdivide(part1, level, pts);
1978 subdivide(part2, level, pts);
1979 }
1980}
1981
1982function chopIntoQuadsPOW2(curve, pow2, pts) {
1983 subdivide(curve, pow2, pts);
1984 return 1 << pow2;
1985}
1986
1987function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1988 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1989 return;
1990 }
1991 ctx.beginPath();
1992 ctx.moveTo((x1 - srcLeft) * scale,
1993 (y1 - srcTop) * scale);
1994 var tol = 1 / scale;
1995 var curve = [x1, y1, x2, y2, x3, y3, w];
1996 var pow2 = computeQuadPOW2(curve, tol);
1997 var pts = [];
1998 chopIntoQuadsPOW2(curve, pow2, pts);
1999 for (var i = 0; i < pts.length; i += 4) {
2000 ctx.quadraticCurveTo(
2001 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
2002 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
2003 }
2004 ctx.stroke();
2005}
2006
2007function conic_eval_numerator(x1, x2, x3, w, t) {
2008 var src2w = x2 * w;
2009 var C = x1;
2010 var A = x3 - 2 * src2w + C;
2011 var B = 2 * (src2w - C);
2012 return (A * t + B) * t + C;
2013}
2014
2015
2016function conic_eval_denominator(w, t) {
2017 var B = 2 * (w - 1);
2018 var C = 1;
2019 var A = -B;
2020 return (A * t + B) * t + C;
2021}
2022
2023function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
2024 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
2025 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
2026 var az = conic_eval_denominator(w, t1);
2027 var midT = (t1 + t2) / 2;
2028 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
2029 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
2030 var dz = conic_eval_denominator(w, midT);
2031 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
2032 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
2033 var cz = conic_eval_denominator(w, t2);
2034 var bx = 2 * dx - (ax + cx) / 2;
2035 var by = 2 * dy - (ay + cy) / 2;
2036 var bz = 2 * dz - (az + cz) / 2;
2037 var dt = t2 - t1;
2038 var dt_1 = 1 - dt;
caryclark1049f122015-04-20 08:31:59 -07002039 var array = [
caryclarked0935a2015-10-22 07:23:52 -07002040 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, 0
caryclark1049f122015-04-20 08:31:59 -07002041 ];
caryclarked0935a2015-10-22 07:23:52 -07002042 var dMidAC = { x:(array[0] + array[4]) / 2, y:(array[1] + array[5]) / 2 };
2043 var dMid = { x:dx / dz, y:dy / dz };
2044 var dWNumer = { x:dMidAC.x - dMid.x, y:dMidAC.y - dMid.y };
2045 var dWDenom = { x:dMid.x - array[2], y:dMid.y - array[3] };
2046 var partW = Math.sqrt(dWNumer.x * dWNumer.x + dWNumer.y * dWNumer.y)
2047 / Math.sqrt(dWDenom.x * dWDenom.x + dWDenom.y * dWDenom.y);
2048 array[6] = partW;
caryclark1049f122015-04-20 08:31:59 -07002049 return array;
2050}
caryclark55888e42016-07-18 10:01:36 -07002051
caryclark1049f122015-04-20 08:31:59 -07002052function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
2053 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
2054 var ax = a[0];
2055 var ay = a[1];
2056 var bx = a[2];
2057 var by = a[3];
2058 var cx = a[4];
2059 var cy = a[5];
2060 var w_ = a[6];
2061 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
2062}
2063
caryclarkdac1d172014-06-17 05:15:38 -07002064function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
2065 if (collect_bounds) {
2066 if (focus_enabled) {
2067 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
2068 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
2069 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
2070 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
2071 }
2072 return true;
2073 }
2074 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
2075 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
caryclark55888e42016-07-18 10:01:36 -07002076 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
2077 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
caryclarkdac1d172014-06-17 05:15:38 -07002078 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
2079 return true;
2080 }
2081 }
2082 drawnCubics.push(x1);
2083 drawnCubics.push(y1);
2084 drawnCubics.push(x2);
2085 drawnCubics.push(y2);
2086 drawnCubics.push(x3);
2087 drawnCubics.push(y3);
2088 drawnCubics.push(x4);
2089 drawnCubics.push(y4);
2090 return false;
2091}
2092
2093function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
2094 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
2095 return;
2096 }
2097 ctx.beginPath();
2098 ctx.moveTo((x1 - srcLeft) * scale,
2099 (y1 - srcTop) * scale);
2100 ctx.bezierCurveTo((x2 - srcLeft) * scale,
2101 (y2 - srcTop) * scale,
2102 (x3 - srcLeft) * scale,
2103 (y3 - srcTop) * scale,
2104 (x4 - srcLeft) * scale,
2105 (y4 - srcTop) * scale);
2106 ctx.stroke();
2107}
2108
2109function interp_cubic_coords(x1, x2, x3, x4, t)
2110{
2111 var ab = interp(x1, x2, t);
2112 var bc = interp(x2, x3, t);
2113 var cd = interp(x3, x4, t);
2114 var abc = interp(ab, bc, t);
2115 var bcd = interp(bc, cd, t);
2116 var abcd = interp(abc, bcd, t);
2117 return abcd;
2118}
2119
2120function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2121 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
2122 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
2123 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
2124 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
2125 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
2126 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
2127 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
2128 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
2129 var mx = ex * 27 - ax * 8 - dx;
2130 var my = ey * 27 - ay * 8 - dy;
2131 var nx = fx * 27 - ax - dx * 8;
2132 var ny = fy * 27 - ay - dy * 8;
2133 var bx = (mx * 2 - nx) / 18;
2134 var by = (my * 2 - ny) / 18;
2135 var cx = (nx * 2 - mx) / 18;
2136 var cy = (ny * 2 - my) / 18;
2137 var array = [
2138 ax, ay, bx, by, cx, cy, dx, dy
2139 ];
2140 return array;
2141}
caryclark55888e42016-07-18 10:01:36 -07002142
caryclarkdac1d172014-06-17 05:15:38 -07002143function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2144 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2145 var ax = a[0];
2146 var ay = a[1];
2147 var bx = a[2];
2148 var by = a[3];
2149 var cx = a[4];
2150 var cy = a[5];
2151 var dx = a[6];
2152 var dy = a[7];
2153 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
2154 return;
2155 }
2156 ctx.beginPath();
2157 ctx.moveTo((ax - srcLeft) * scale,
2158 (ay - srcTop) * scale);
2159 ctx.bezierCurveTo((bx - srcLeft) * scale,
2160 (by - srcTop) * scale,
2161 (cx - srcLeft) * scale,
2162 (cy - srcTop) * scale,
2163 (dx - srcLeft) * scale,
2164 (dy - srcTop) * scale);
2165 ctx.stroke();
2166}
2167
2168function drawCurve(c) {
2169 switch (c.length) {
2170 case 4:
2171 drawLine(c[0], c[1], c[2], c[3]);
2172 break;
2173 case 6:
2174 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
2175 break;
caryclark1049f122015-04-20 08:31:59 -07002176 case 7:
2177 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
2178 break;
caryclarkdac1d172014-06-17 05:15:38 -07002179 case 8:
2180 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
2181 break;
2182 }
2183}
2184
2185function boundsWidth(pts) {
2186 var min = pts[0];
2187 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07002188 var length = pts.length == 7 ? 6 : pts.length;
2189 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002190 min = Math.min(min, pts[idx]);
2191 max = Math.max(max, pts[idx]);
2192 }
2193 return max - min;
2194}
2195
2196function boundsHeight(pts) {
2197 var min = pts[1];
2198 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07002199 var length = pts.length == 7 ? 6 : pts.length;
2200 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002201 min = Math.min(min, pts[idx]);
2202 max = Math.max(max, pts[idx]);
2203 }
2204 return max - min;
2205}
2206
2207function tangent(pts) {
2208 var dx = pts[2] - pts[0];
2209 var dy = pts[3] - pts[1];
2210 if (dx == 0 && dy == 0 && pts.length > 4) {
2211 dx = pts[4] - pts[0];
2212 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002213 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002214 dx = pts[6] - pts[0];
2215 dy = pts[7] - pts[1];
2216 }
2217 }
2218 return Math.atan2(-dy, dx);
2219}
2220
2221function hodograph(cubic) {
2222 var hodo = [];
2223 hodo[0] = 3 * (cubic[2] - cubic[0]);
2224 hodo[1] = 3 * (cubic[3] - cubic[1]);
2225 hodo[2] = 3 * (cubic[4] - cubic[2]);
2226 hodo[3] = 3 * (cubic[5] - cubic[3]);
2227 hodo[4] = 3 * (cubic[6] - cubic[4]);
2228 hodo[5] = 3 * (cubic[7] - cubic[5]);
2229 return hodo;
2230}
2231
2232function hodograph2(cubic) {
2233 var quad = hodograph(cubic);
2234 var hodo = [];
2235 hodo[0] = 2 * (quad[2] - quad[0]);
2236 hodo[1] = 2 * (quad[3] - quad[1]);
2237 hodo[2] = 2 * (quad[4] - quad[2]);
2238 hodo[3] = 2 * (quad[5] - quad[3]);
2239 return hodo;
2240}
2241
2242function quadraticRootsReal(A, B, C, s) {
2243 if (A == 0) {
2244 if (B == 0) {
2245 s[0] = 0;
2246 return C == 0;
2247 }
2248 s[0] = -C / B;
2249 return 1;
2250 }
2251 /* normal form: x^2 + px + q = 0 */
2252 var p = B / (2 * A);
2253 var q = C / A;
2254 var p2 = p * p;
2255 if (p2 < q) {
2256 return 0;
2257 }
2258 var sqrt_D = 0;
2259 if (p2 > q) {
2260 sqrt_D = sqrt(p2 - q);
2261 }
2262 s[0] = sqrt_D - p;
2263 s[1] = -sqrt_D - p;
2264 return 1 + s[0] != s[1];
2265}
2266
2267function add_valid_ts(s, realRoots, t) {
2268 var foundRoots = 0;
2269 for (var index = 0; index < realRoots; ++index) {
2270 var tValue = s[index];
2271 if (tValue >= 0 && tValue <= 1) {
2272 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2273 if (t[idx2] != tValue) {
2274 t[foundRoots++] = tValue;
2275 }
2276 }
2277 }
2278 }
2279 return foundRoots;
2280}
2281
2282function quadraticRootsValidT(a, b, c, t) {
2283 var s = [];
2284 var realRoots = quadraticRootsReal(A, B, C, s);
2285 var foundRoots = add_valid_ts(s, realRoots, t);
2286 return foundRoots != 0;
2287}
2288
2289function find_cubic_inflections(cubic, tValues) {
2290 var Ax = src[2] - src[0];
2291 var Ay = src[3] - src[1];
2292 var Bx = src[4] - 2 * src[2] + src[0];
2293 var By = src[5] - 2 * src[3] + src[1];
2294 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2295 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2296 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2297 Ax * By - Ay * Bx, tValues);
2298}
2299
2300function dxy_at_t(curve, type, t) {
2301 var dxy = {};
Cary Clarkff114282016-12-14 11:56:16 -05002302 if (type == PATH_LINE) {
2303 dxy.x = curve[2] - curve[0];
2304 dxy.y = curve[3] - curve[1];
2305 } else if (type == PATH_QUAD) {
caryclarkdac1d172014-06-17 05:15:38 -07002306 var a = t - 1;
2307 var b = 1 - 2 * t;
2308 var c = t;
2309 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2310 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002311 } else if (type == PATH_CONIC) {
2312 var p20x = curve[4] - curve[0];
2313 var p20y = curve[5] - curve[1];
2314 var p10xw = (curve[2] - curve[0]) * curve[6];
2315 var p10yw = (curve[3] - curve[1]) * curve[6];
2316 var coeff0x = curve[6] * p20x - p20x;
2317 var coeff0y = curve[6] * p20y - p20y;
2318 var coeff1x = p20x - 2 * p10xw;
2319 var coeff1y = p20y - 2 * p10yw;
2320 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2321 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002322 } else if (type == PATH_CUBIC) {
2323 var one_t = 1 - t;
2324 var a = curve[0];
2325 var b = curve[2];
2326 var c = curve[4];
2327 var d = curve[6];
2328 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2329 a = curve[1];
2330 b = curve[3];
2331 c = curve[5];
2332 d = curve[7];
2333 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2334 }
2335 return dxy;
2336}
2337
Ben Wagner29380bd2017-10-09 14:43:00 -04002338function dpt_at_t(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002339 var type = PATH_LINE + (curve.length / 2 - 2);
Ben Wagner29380bd2017-10-09 14:43:00 -04002340 return dxy_at_t(curve, type, t);
Cary Clarkff114282016-12-14 11:56:16 -05002341}
2342
caryclarkdac1d172014-06-17 05:15:38 -07002343function drawLabel(num, px, py) {
2344 ctx.beginPath();
2345 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2346 ctx.closePath();
2347 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2348 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2349 ctx.stroke();
2350 ctx.fillStyle = "black";
2351 ctx.font = "normal 10px Arial";
2352 // ctx.rotate(0.001);
2353 ctx.fillText(num, px - 2, py + 3);
2354 // ctx.rotate(-0.001);
2355}
2356
2357function drawLabelX(ymin, num, loc) {
2358 var px = (loc - srcLeft) * scale;
2359 var py = (ymin - srcTop) * scale - 20;
2360 drawLabel(num, px, py);
2361}
2362
2363function drawLabelY(xmin, num, loc) {
2364 var px = (xmin - srcLeft) * scale - 20;
2365 var py = (loc - srcTop) * scale;
2366 drawLabel(num, px, py);
2367}
2368
2369function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2370 ctx.beginPath();
2371 ctx.moveTo(hx, hy - 100);
2372 ctx.lineTo(hx, hy);
2373 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2374 ctx.stroke();
2375 ctx.beginPath();
2376 ctx.moveTo(hx, hy);
2377 ctx.lineTo(hx, hy + 100);
2378 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2379 ctx.stroke();
2380 ctx.beginPath();
2381 ctx.moveTo(hx - 100, hy);
2382 ctx.lineTo(hx, hy);
2383 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2384 ctx.stroke();
2385 ctx.beginPath();
2386 ctx.moveTo(hx, hy);
2387 ctx.lineTo(hx + 100, hy);
2388 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2389 ctx.stroke();
2390}
2391
2392function scalexy(x, y, mag) {
2393 var length = Math.sqrt(x * x + y * y);
2394 return mag / length;
2395}
2396
caryclark03b03ca2015-04-23 09:13:37 -07002397function drawArrow(x, y, dx, dy, s) {
2398 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002399 dx *= dscale;
2400 dy *= dscale;
2401 ctx.beginPath();
2402 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2403 x += dx;
2404 y += dy;
2405 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2406 dx /= 10;
2407 dy /= 10;
2408 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2409 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2410 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2411 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2412 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2413 ctx.stroke();
2414}
2415
2416function x_at_t(curve, t) {
2417 var one_t = 1 - t;
2418 if (curve.length == 4) {
2419 return one_t * curve[0] + t * curve[2];
2420 }
2421 var one_t2 = one_t * one_t;
2422 var t2 = t * t;
2423 if (curve.length == 6) {
2424 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2425 }
caryclark1049f122015-04-20 08:31:59 -07002426 if (curve.length == 7) {
2427 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2428 / (one_t2 +2 * one_t * t * curve[6] + t2);
2429 }
caryclarkdac1d172014-06-17 05:15:38 -07002430 var a = one_t2 * one_t;
2431 var b = 3 * one_t2 * t;
2432 var c = 3 * one_t * t2;
2433 var d = t2 * t;
2434 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2435}
2436
2437function y_at_t(curve, t) {
2438 var one_t = 1 - t;
2439 if (curve.length == 4) {
2440 return one_t * curve[1] + t * curve[3];
2441 }
2442 var one_t2 = one_t * one_t;
2443 var t2 = t * t;
2444 if (curve.length == 6) {
2445 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2446 }
caryclark1049f122015-04-20 08:31:59 -07002447 if (curve.length == 7) {
2448 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2449 / (one_t2 +2 * one_t * t * curve[6] + t2);
2450 }
caryclarkdac1d172014-06-17 05:15:38 -07002451 var a = one_t2 * one_t;
2452 var b = 3 * one_t2 * t;
2453 var c = 3 * one_t * t2;
2454 var d = t2 * t;
2455 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2456}
2457
Ben Wagner29380bd2017-10-09 14:43:00 -04002458function pt_at_t(curve, t) {
2459 var pt = {};
2460 pt.x = x_at_t(curve, t);
2461 pt.y = y_at_t(curve, t);
2462 return pt;
Cary Clarkff114282016-12-14 11:56:16 -05002463}
2464
2465function drawOrder(curve, t, label) {
2466 var px = x_at_t(curve, t);
2467 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002468 var _px = (px - srcLeft) * scale;
2469 var _py = (py - srcTop) * scale;
2470 ctx.beginPath();
2471 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2472 ctx.closePath();
2473 ctx.fillStyle = "white";
2474 ctx.fill();
2475 if (label == 'L') {
2476 ctx.strokeStyle = "rgba(255,0,0, 1)";
2477 ctx.fillStyle = "rgba(255,0,0, 1)";
2478 } else {
2479 ctx.strokeStyle = "rgba(0,0,255, 1)";
2480 ctx.fillStyle = "rgba(0,0,255, 1)";
2481 }
2482 ctx.stroke();
2483 ctx.font = "normal 16px Arial";
2484 ctx.textAlign = "center";
2485 ctx.fillText(label, _px, _py + 5);
2486 ctx.font = "normal 10px Arial";
2487}
2488
Ben Wagner29380bd2017-10-09 14:43:00 -04002489function drawVisibleOrder(curve, label) {
2490 var s = pt_at_t(curve, 0);
2491 var e = pt_at_t(curve, 1);
2492 var sOn = ptOnScreen(s);
2493 var eOn = ptOnScreen(e);
2494 var defaultT = 0.85;
2495 if (sOn && eOn)
2496 return drawOrder(curve, defaultT, label);
2497 if (sOn || eOn) {
2498 if (eOn) {
2499 defaultT = 1 - defaultT;
2500 }
2501 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2502 var t = defaultT;
2503 var tries = 16;
2504 do {
2505 var mid = pt_at_t(curve, t);
2506 if (ptOnScreen(mid))
2507 return drawOrder(curve, t, label);
2508 t += step;
2509 step /= 2;
2510 } while (--tries > 0);
2511 drawOrder(curve, defaultT, label);
2512 }
2513 // scattershot until we find a visible point
2514 var denom = 2; // visit odd number num / denom to hit unique pts
2515 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2516 do {
2517 for (var numer = 1; numer < denom; numer += 2) {
2518 var t = numer / denom + 0.1;
2519 if (t >= 1) {
2520 break;
2521 }
2522 var mid = pt_at_t(curve, t);
2523 if (ptOnScreen(mid))
2524 return drawOrder(curve, t, label);
2525 }
2526 denom *= 2;
2527 } while (--tries > 0);
2528 drawOrder(curve, defaultT, label);
Cary Clarkff114282016-12-14 11:56:16 -05002529}
2530
Ben Wagner29380bd2017-10-09 14:43:00 -04002531function set_length(pt, newLen) {
2532 var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);
2533 var scale = newLen / len;
2534 var newPt = { x: pt.x * scale, y: pt.y * scale };
2535 return newPt;
Cary Clarkff114282016-12-14 11:56:16 -05002536}
2537
Ben Wagner29380bd2017-10-09 14:43:00 -04002538function drawDirection(curve, t) {
Cary Clarkff114282016-12-14 11:56:16 -05002539 var d = dpt_at_t(curve, t);
2540 d = set_length(d, 16);
Ben Wagner29380bd2017-10-09 14:43:00 -04002541 var pt = localToGlobal(pt_at_t(curve, t));
Cary Clarkff114282016-12-14 11:56:16 -05002542 ctx.beginPath();
2543 ctx.moveTo(pt.x - d.y, pt.y + d.x);
2544 ctx.lineTo(pt.x + d.x, pt.y + d.y);
2545 ctx.lineTo(pt.x + d.y, pt.y - d.x);
2546 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2547 ctx.stroke();
2548}
2549
Ben Wagner29380bd2017-10-09 14:43:00 -04002550function drawVisibleDirection(curve) {
2551 var s = pt_at_t(curve, 0);
2552 var e = pt_at_t(curve, 1);
2553 var sOn = ptOnScreen(s);
2554 var eOn = ptOnScreen(e);
2555 var defaultT = 0.65;
2556 if (sOn && eOn) {
2557 return drawDirection(curve, defaultT);
2558 }
2559 if (sOn || eOn) {
2560 if (eOn) {
2561 defaultT = 1 - defaultT;
2562 }
2563 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2564 var t = defaultT;
2565 var tries = 16;
2566 do {
2567 var mid = pt_at_t(curve, t);
2568 if (ptOnScreen(mid))
2569 return drawDirection(curve, t);
2570 t += step;
2571 step /= 2;
2572 } while (--tries > 0);
2573 drawDirection(curve, defaultT);
2574 }
2575 // scattershot until we find a visible point
2576 var denom = 2; // visit odd number num / denom to hit unique pts
2577 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2578 do {
2579 for (var numer = 1; numer < denom; numer += 2) {
2580 var t = numer / denom + 0.1;
2581 if (t >= 1) {
2582 break;
2583 }
2584 var mid = pt_at_t(curve, t);
2585 if (ptOnScreen(mid))
2586 return drawDirection(curve, t);
2587 }
2588 denom *= 2;
2589 } while (--tries > 0);
2590 drawDirection(curve, defaultT);
Cary Clarkff114282016-12-14 11:56:16 -05002591}
2592
2593function drawID(curve, t, id) {
2594 var px = x_at_t(curve, t);
2595 var py = y_at_t(curve, t);
caryclarkdac1d172014-06-17 05:15:38 -07002596 var _px = (px - srcLeft) * scale;
2597 var _py = (py - srcTop) * scale;
2598 draw_id_at(id, _px, _py);
2599}
2600
Ben Wagner29380bd2017-10-09 14:43:00 -04002601function localToGlobal(local) {
2602 var global = {};
2603 global.x = (local.x - srcLeft) * scale;
2604 global.y = (local.y - srcTop) * scale;
2605 return global;
Cary Clarkff114282016-12-14 11:56:16 -05002606}
2607
Ben Wagner29380bd2017-10-09 14:43:00 -04002608function ptOnScreen(local) {
2609 var pt = localToGlobal(local);
2610 return 10 <= pt.x && pt.x <= screenWidth - 10
2611 && 10 <= pt.y && pt.y <= screenHeight - 10;
Cary Clarkff114282016-12-14 11:56:16 -05002612}
2613
Ben Wagner29380bd2017-10-09 14:43:00 -04002614function drawVisibleID(curve, defaultT, id) {
2615 // determine if either or both ends are visible
2616 var s = pt_at_t(curve, 0);
2617 var e = pt_at_t(curve, 1);
2618 var sOn = ptOnScreen(s);
2619 var eOn = ptOnScreen(e);
2620 if (sOn && eOn)
2621 return drawID(curve, defaultT, id);
2622 if (sOn || eOn) {
2623 var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
2624 var t = defaultT;
2625 var tries = 16;
2626 do {
2627 var mid = pt_at_t(curve, t);
2628 if (ptOnScreen(mid))
2629 return drawID(curve, t, id);
2630 t += step;
2631 step /= 2;
2632 } while (--tries > 0);
2633 drawID(curve, defaultT, id);
2634 }
2635 // scattershot until we find a visible point
2636 var denom = 2; // visit odd number num / denom to hit unique pts
2637 var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
2638 do {
2639 for (var numer = 1; numer < denom; numer += 2) {
2640 var t = numer / denom;
2641 var mid = pt_at_t(curve, t);
2642 if (ptOnScreen(mid))
2643 return drawID(curve, t, id);
2644 }
2645 denom *= 2;
2646 } while (--tries > 0);
2647 drawID(curve, defaultT, id);
Cary Clarkff114282016-12-14 11:56:16 -05002648}
2649
caryclarkdac1d172014-06-17 05:15:38 -07002650function draw_id_at(id, _px, _py) {
2651 ctx.beginPath();
2652 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2653 ctx.closePath();
2654 ctx.fillStyle = "white";
2655 ctx.fill();
2656 ctx.strokeStyle = "rgba(127,127,0, 1)";
2657 ctx.fillStyle = "rgba(127,127,0, 1)";
2658 ctx.stroke();
2659 ctx.font = "normal 16px Arial";
2660 ctx.textAlign = "center";
2661 ctx.fillText(id, _px, _py + 5);
2662 ctx.font = "normal 10px Arial";
2663}
2664
2665function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2666 var curve = [x1, y1, x2, y2];
2667 drawCurvePartialID(id, curve, t1, t2);
2668}
2669
caryclark55888e42016-07-18 10:01:36 -07002670function drawLineID(id, x1, y1, x2, y2) {
2671 drawLinePartialID(id, x1, y1, x2, y2, 0, 1);
2672}
2673
caryclarkdac1d172014-06-17 05:15:38 -07002674function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2675 var curve = [x1, y1, x2, y2, x3, y3];
2676 drawCurvePartialID(id, curve, t1, t2);
2677}
2678
caryclark55888e42016-07-18 10:01:36 -07002679function drawQuadID(id, x1, y1, x2, y2, x3, y3) {
2680 drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, 0, 1);
2681}
2682
caryclark1049f122015-04-20 08:31:59 -07002683function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2684 var curve = [x1, y1, x2, y2, x3, y3, w];
2685 drawCurvePartialID(id, curve, t1, t2);
2686}
2687
caryclark55888e42016-07-18 10:01:36 -07002688function drawConicID(id, x1, y1, x2, y2, x3, y3, w) {
2689 drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, 0, 1);
2690}
2691
caryclarkdac1d172014-06-17 05:15:38 -07002692function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2693 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2694 drawCurvePartialID(id, curve, t1, t2);
2695}
2696
caryclark55888e42016-07-18 10:01:36 -07002697function drawCubicID(id, x1, y1, x2, y2, x3, y3, x4, y4) {
2698 drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, 0, 1);
2699}
2700
caryclarkdac1d172014-06-17 05:15:38 -07002701function drawCurvePartialID(id, curve, t1, t2) {
Cary Clarkff114282016-12-14 11:56:16 -05002702 drawVisibleID(curve, (t1 + t2) / 2, id);
caryclarkdac1d172014-06-17 05:15:38 -07002703}
2704
2705function drawCurveSpecials(test, curve, type) {
2706 if (pt_labels) {
2707 drawPoints(curve, type, pt_labels == 2);
2708 }
2709 if (control_lines != 0) {
2710 drawControlLines(curve, type, control_lines);
2711 }
2712 if (curve_t) {
2713 drawPointAtT(curve, type);
2714 }
2715 if (draw_midpoint) {
2716 var mid = pointAtT(curve, type, 0.5);
2717 drawPoint(mid.x, mid.y, true);
2718 }
2719 if (draw_id) {
2720 var id = idByCurve(test, curve, type);
2721 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05002722 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07002723 }
2724 }
Ben Wagner29380bd2017-10-09 14:43:00 -04002725 if (draw_direction) {
2726 drawVisibleDirection(curve);
Cary Clarkff114282016-12-14 11:56:16 -05002727 }
caryclarkdac1d172014-06-17 05:15:38 -07002728 if (type == PATH_LINE) {
2729 return;
2730 }
2731 if (draw_deriviatives > 0) {
2732 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002733 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002734 if (draw_deriviatives == 2) {
2735 d = dxy_at_t(curve, type, 1);
2736 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002737 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002738 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002739 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002740 }
2741 }
2742 if (draw_midpoint) {
2743 var mid = pointAtT(curve, type, 0.5);
2744 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002745 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002746 }
2747 }
2748 if (type != PATH_CUBIC) {
2749 return;
2750 }
caryclarkdac1d172014-06-17 05:15:38 -07002751 if (draw_sequence) {
2752 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2753 for (var i = 0; i < 8; i+= 2) {
2754 drawLabelX(ymin, i >> 1, curve[i]);
2755 }
2756 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2757 for (var i = 1; i < 8; i+= 2) {
2758 drawLabelY(xmin, i >> 1, curve[i]);
2759 }
2760 }
2761}
2762
2763function logCurves(test) {
2764 for (curves in test) {
2765 var curve = test[curves];
2766 dumpCurve(curve);
2767 }
2768}
2769
2770function curveToString(curve) {
2771 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002772 var length = curve.length == 7 ? 6 : curve.length;
2773 if (curve.length == 7) {
2774 str += "{";
2775 }
2776 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002777 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2778 if (i < curve.length - 2) {
2779 str += "}, {";
2780 }
2781 }
caryclark1049f122015-04-20 08:31:59 -07002782 str += "}";
2783 if (curve.length == 7) {
2784 str += "}, " + curve[6].toFixed(decimal_places);
2785 }
2786 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002787 return str;
2788}
2789
2790function dumpCurve(curve) {
2791 console.log(curveToString(curve));
2792}
2793
2794function draw(test, lines, title) {
2795 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2796 ctx.font = "normal 50px Arial";
2797 ctx.textAlign = "left";
2798 ctx.fillText(title, 50, 50);
2799 ctx.font = "normal 10px Arial";
2800 ctx.lineWidth = "1.001"; "0.999";
2801 var secondPath = test.length;
2802 var closeCount = 0;
2803 logStart = -1;
2804 logRange = 0;
2805 // find last active rec type at this step
2806 var curType = test[0];
2807 var curStep = 0;
2808 var hasOp = false;
2809 var lastActive = 0;
2810 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002811 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002812 var lastSect = 0;
2813 var lastSort = 0;
2814 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002815 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002816 activeCount = 0;
2817 addCount = 0;
2818 angleCount = 0;
2819 opCount = 0;
2820 sectCount = 0;
2821 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002822 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002823 markCount = 0;
2824 activeMax = 0;
2825 addMax = 0;
2826 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002827 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002828 opMax = 0;
2829 sectMax = 0;
2830 sectMax2 = 0;
2831 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002832 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002833 markMax = 0;
2834 lastIndex = test.length - 3;
2835 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2836 var recType = test[tIndex];
2837 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2838 console.log("unknown rec type: " + recType);
2839 throw "stop execution";
2840 }
2841 // if (curType == recType && curType != REC_TYPE_ADD) {
2842 // continue;
2843 // }
2844 var inStepRange = step_limit == 0 || curStep < step_limit;
2845 curType = recType;
2846 if (recType == REC_TYPE_OP) {
2847 hasOp = true;
2848 continue;
2849 }
2850 if (recType == REC_TYPE_UNKNOWN) {
2851 // these types do not advance step
2852 continue;
2853 }
2854 var bumpStep = false;
2855 var records = test[tIndex + 2];
2856 var fragType = records[0];
2857 if (recType == REC_TYPE_ADD) {
2858 if (records.length != 2) {
2859 console.log("expect only two elements: " + records.length);
2860 throw "stop execution";
2861 }
2862 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2863 continue;
2864 }
2865 ++addMax;
2866 if (!draw_add || !inStepRange) {
2867 continue;
2868 }
2869 lastAdd = tIndex;
2870 ++addCount;
2871 bumpStep = true;
2872 }
2873 if (recType == REC_TYPE_PATH && hasOp) {
2874 secondPath = tIndex;
2875 }
caryclark54359292015-03-26 07:52:43 -07002876 if (recType == REC_TYPE_PATH2 && hasOp) {
2877 secondPath = tIndex;
2878 }
caryclarkdac1d172014-06-17 05:15:38 -07002879 if (recType == REC_TYPE_ACTIVE) {
2880 ++activeMax;
2881 if (!draw_active || !inStepRange) {
2882 continue;
2883 }
2884 lastActive = tIndex;
2885 ++activeCount;
2886 bumpStep = true;
2887 }
2888 if (recType == REC_TYPE_ACTIVE_OP) {
2889 ++opMax;
2890 if (!draw_op || !inStepRange) {
2891 continue;
2892 }
2893 lastOp = tIndex;
2894 ++opCount;
2895 bumpStep = true;
2896 }
caryclark54359292015-03-26 07:52:43 -07002897 if (recType == REC_TYPE_AFTERPART) {
2898 if (draw_angle != 3 || !inStepRange) {
2899 continue;
2900 }
2901 lastAngle = tIndex;
2902 ++angleCount;
2903 bumpStep = true;
2904 }
caryclarkdac1d172014-06-17 05:15:38 -07002905 if (recType == REC_TYPE_ANGLE) {
2906 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002907 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002908 continue;
2909 }
2910 lastAngle = tIndex;
2911 ++angleCount;
2912 bumpStep = true;
2913 }
caryclark624637c2015-05-11 07:21:27 -07002914 if (recType == REC_TYPE_COINCIDENCE) {
2915 ++coinMax;
2916 if (!draw_coincidence || !inStepRange) {
2917 continue;
2918 }
2919 lastCoin = tIndex;
2920 ++coinCount;
2921 bumpStep = true;
2922 }
caryclarkdac1d172014-06-17 05:15:38 -07002923 if (recType == REC_TYPE_SECT) {
2924 if (records.length != 2) {
2925 console.log("expect only two elements: " + records.length);
2926 throw "stop execution";
2927 }
2928 ++sectMax;
2929 var sectBump = 1;
2930 switch (fragType) {
2931 case INTERSECT_LINE:
2932 case INTERSECT_QUAD_LINE:
2933 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002934 case INTERSECT_CONIC_LINE:
caryclark55888e42016-07-18 10:01:36 -07002935 case INTERSECT_CONIC_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002936 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002937 case INTERSECT_SELF_CUBIC:
2938 case INTERSECT_CUBIC_LINE:
2939 case INTERSECT_CUBIC_QUAD:
2940 case INTERSECT_CUBIC:
2941 sectBump = 1;
2942 break;
2943 case INTERSECT_LINE_2:
2944 case INTERSECT_QUAD_LINE_2:
2945 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002946 case INTERSECT_CONIC_LINE_2:
caryclark55888e42016-07-18 10:01:36 -07002947 case INTERSECT_CONIC_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002948 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002949 case INTERSECT_CUBIC_LINE_2:
2950 case INTERSECT_CUBIC_QUAD_2:
2951 case INTERSECT_CUBIC_2:
2952 sectBump = 2;
2953 break;
2954 case INTERSECT_LINE_NO:
2955 case INTERSECT_QUAD_LINE_NO:
2956 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002957 case INTERSECT_CONIC_LINE_NO:
caryclark55888e42016-07-18 10:01:36 -07002958 case INTERSECT_CONIC_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002959 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002960 case INTERSECT_SELF_CUBIC_NO:
2961 case INTERSECT_CUBIC_LINE_NO:
2962 case INTERSECT_CUBIC_QUAD_NO:
2963 case INTERSECT_CUBIC_NO:
2964 sectBump = 0;
2965 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002966 case INTERSECT_CONIC_QUAD_3:
caryclarkdac1d172014-06-17 05:15:38 -07002967 case INTERSECT_CUBIC_LINE_3:
2968 case INTERSECT_CUBIC_QUAD_3:
2969 case INTERSECT_CUBIC_3:
2970 sectBump = 3;
2971 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07002972 case INTERSECT_CONIC_QUAD_4:
caryclarkdac1d172014-06-17 05:15:38 -07002973 case INTERSECT_CUBIC_QUAD_4:
2974 case INTERSECT_CUBIC_4:
2975 sectBump = 4;
2976 break;
2977 default:
2978 console.log("missing case " + records.length);
2979 throw "stop execution";
2980 }
2981 sectMax2 += sectBump;
2982 if (draw_intersection <= 1 || !inStepRange) {
2983 continue;
2984 }
2985 lastSect = tIndex;
2986 sectCount += sectBump;
2987 bumpStep = true;
2988 }
2989 if (recType == REC_TYPE_SORT) {
2990 ++sortMax;
2991 if (!draw_sort || !inStepRange) {
2992 continue;
2993 }
2994 lastSort = tIndex;
2995 ++sortCount;
2996 bumpStep = true;
2997 }
caryclark03b03ca2015-04-23 09:13:37 -07002998 if (recType == REC_TYPE_TOP) {
2999 ++topMax;
3000 if (!draw_top || !inStepRange) {
3001 continue;
3002 }
3003 lastTop = tIndex;
3004 ++topCount;
3005 bumpStep = true;
3006 }
caryclarkdac1d172014-06-17 05:15:38 -07003007 if (recType == REC_TYPE_MARK) {
3008 ++markMax;
3009 if (!draw_mark || !inStepRange) {
3010 continue;
3011 }
3012 lastMark = tIndex;
3013 ++markCount;
3014 bumpStep = true;
3015 }
3016 if (bumpStep) {
3017 lastIndex = tIndex;
3018 logStart = test[tIndex + 1];
3019 logRange = records.length / 2;
3020 ++curStep;
3021 }
3022 }
3023 stepMax = (draw_add ? addMax : 0)
3024 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07003025 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07003026 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07003027 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07003028 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07003029 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07003030 + (draw_mark ? markMax : 0)
3031 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
3032 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07003033 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07003034 }
3035 drawnPts = [];
3036 drawnLines = [];
3037 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07003038 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07003039 drawnCubics = [];
3040 focusXmin = focusYmin = Infinity;
3041 focusXmax = focusYmax = -Infinity;
3042 var pathIndex = 0;
3043 var opLetter = 'S';
3044 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
3045 var recType = test[tIndex];
3046 var records = test[tIndex + 2];
3047 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3048 var fragType = records[recordIndex];
3049 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
3050 console.log("unknown in range frag type: " + fragType);
3051 throw "stop execution";
3052 }
3053 var frags = records[recordIndex + 1];
3054 focus_enabled = false;
3055 switch (recType) {
3056 case REC_TYPE_COMPUTED:
3057 if (draw_computed == 0) {
3058 continue;
3059 }
3060 ctx.lineWidth = 1;
3061 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
3062 ctx.fillStyle = "blue";
3063 var drawThis = false;
3064 switch (fragType) {
3065 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07003066 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
3067 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07003068 drawQuad(frags[0], frags[1], frags[2], frags[3],
3069 frags[4], frags[5]);
3070 drawThis = true;
3071 }
3072 break;
caryclark1049f122015-04-20 08:31:59 -07003073 case PATH_CONIC:
3074 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
3075 && (draw_computed & 7) == pathIndex)) {
3076 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
3077 frags[4], frags[5], frags[6]);
3078 drawThis = true;
3079 }
3080 break;
caryclarkdac1d172014-06-17 05:15:38 -07003081 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07003082 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
3083 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07003084 drawCubic(frags[0], frags[1], frags[2], frags[3],
3085 frags[4], frags[5], frags[6], frags[7]);
3086 drawThis = true;
3087 }
3088 ++pathIndex;
3089 break;
3090 case COMPUTED_SET_1:
3091 pathIndex = 0;
3092 break;
3093 case COMPUTED_SET_2:
3094 pathIndex = 1;
3095 break;
3096 default:
3097 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
3098 throw "stop execution";
3099 }
3100 if (!drawThis || collect_bounds) {
3101 break;
3102 }
3103 drawCurveSpecials(test, frags, fragType);
3104 break;
caryclark26ad22a2015-10-16 09:03:38 -07003105 case REC_TYPE_ALIGNED:
3106 if (draw_path < 4) {
3107 continue;
3108 }
caryclarkdac1d172014-06-17 05:15:38 -07003109 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07003110 case REC_TYPE_PATH2:
caryclark26ad22a2015-10-16 09:03:38 -07003111 if (REC_TYPE_ALIGNED != recType && draw_path >= 4) {
3112 continue;
3113 }
caryclarkdac1d172014-06-17 05:15:38 -07003114 if (!draw_path) {
3115 continue;
3116 }
3117 var firstPath = tIndex < secondPath;
3118 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
3119 continue;
3120 }
3121 ctx.lineWidth = 1;
3122 ctx.strokeStyle = firstPath ? "black" : "red";
3123 ctx.fillStyle = "blue";
caryclark55888e42016-07-18 10:01:36 -07003124 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07003125 switch (fragType) {
3126 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07003127 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
3128 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07003129 break;
3130 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07003131 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
3132 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
3133 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07003134 break;
caryclark1049f122015-04-20 08:31:59 -07003135 case PATH_CONIC:
3136 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
3137 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
3138 frags2[4], frags2[5], frags2[6]);
3139 break;
caryclarkdac1d172014-06-17 05:15:38 -07003140 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07003141 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
3142 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
3143 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07003144 break;
3145 default:
caryclark26ad22a2015-10-16 09:03:38 -07003146 console.log("unknown " + recType + " frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003147 throw "stop execution";
3148 }
3149 if (collect_bounds) {
3150 break;
3151 }
caryclark54359292015-03-26 07:52:43 -07003152 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07003153 break;
3154 case REC_TYPE_OP:
3155 switch (fragType) {
3156 case OP_INTERSECT: opLetter = 'I'; break;
3157 case OP_DIFFERENCE: opLetter = 'D'; break;
3158 case OP_UNION: opLetter = 'U'; break;
3159 case OP_XOR: opLetter = 'X'; break;
3160 default:
3161 console.log("unknown REC_TYPE_OP frag type: " + fragType);
3162 throw "stop execution";
3163 }
3164 break;
3165 case REC_TYPE_ACTIVE:
3166 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
3167 continue;
3168 }
3169 var x1 = frags[SPAN_X1];
3170 var y1 = frags[SPAN_Y1];
3171 var x2 = frags[SPAN_X2];
3172 var y2 = frags[SPAN_Y2];
caryclark55888e42016-07-18 10:01:36 -07003173 var x3, y3, x3, y4, w;
caryclarkdac1d172014-06-17 05:15:38 -07003174 ctx.lineWidth = 3;
3175 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3176 focus_enabled = true;
3177 switch (fragType) {
3178 case ACTIVE_LINE_SPAN:
caryclark55888e42016-07-18 10:01:36 -07003179 drawLine(x1, y1, x2, y2);
caryclarkdac1d172014-06-17 05:15:38 -07003180 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003181 drawLineID(frags[0], x1, y1, x2, y2);
3182 }
3183 if (pt_labels) {
3184 var curve = [x1, y1, x2, y2];
3185 ctx.fillStyle = "blue";
3186 drawPoints(curve, PATH_LINE, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003187 }
3188 break;
3189 case ACTIVE_QUAD_SPAN:
3190 x3 = frags[SPAN_X3];
3191 y3 = frags[SPAN_Y3];
caryclark55888e42016-07-18 10:01:36 -07003192 drawQuad(x1, y1, x2, y2, x3, y3);
caryclarkdac1d172014-06-17 05:15:38 -07003193 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003194 drawQuadID(frags[0], x1, y1, x2, y2, x3, y3);
3195 }
3196 if (pt_labels) {
3197 var curve = [x1, y1, x2, y2, x3, y3];
3198 ctx.fillStyle = "blue";
3199 drawPoints(curve, PATH_QUAD, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003200 }
3201 break;
caryclark1049f122015-04-20 08:31:59 -07003202 case ACTIVE_CONIC_SPAN:
3203 x3 = frags[SPAN_X3];
3204 y3 = frags[SPAN_Y3];
caryclark1049f122015-04-20 08:31:59 -07003205 w = frags[SPAN_K_W];
caryclark55888e42016-07-18 10:01:36 -07003206 drawConicWithQuads(x1, y1, x2, y2, x3, y3, w);
caryclark1049f122015-04-20 08:31:59 -07003207 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003208 drawConicID(frags[0], x1, y1, x2, y2, x3, y3, w);
3209 }
3210 if (pt_labels) {
3211 var curve = [x1, y1, x2, y2, x3, y3, w];
3212 ctx.fillStyle = "blue";
3213 drawPoints(curve, PATH_CONIC, pt_labels == 2);
caryclark1049f122015-04-20 08:31:59 -07003214 }
3215 break;
caryclarkdac1d172014-06-17 05:15:38 -07003216 case ACTIVE_CUBIC_SPAN:
3217 x3 = frags[SPAN_X3];
3218 y3 = frags[SPAN_Y3];
3219 x4 = frags[SPAN_X4];
3220 y4 = frags[SPAN_Y4];
caryclark55888e42016-07-18 10:01:36 -07003221 drawCubic(x1, y1, x2, y2, x3, y3, x4, y4);
caryclarkdac1d172014-06-17 05:15:38 -07003222 if (draw_id) {
caryclark55888e42016-07-18 10:01:36 -07003223 drawCubicID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4);
3224 }
3225 if (pt_labels) {
3226 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
3227 ctx.fillStyle = "blue";
3228 drawPoints(curve, PATH_CUBIC, pt_labels == 2);
caryclarkdac1d172014-06-17 05:15:38 -07003229 }
3230 break;
3231 default:
3232 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
3233 throw "stop execution";
3234 }
3235 break;
3236 case REC_TYPE_ACTIVE_OP:
3237 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
3238 continue;
3239 }
3240 focus_enabled = true;
3241 ctx.lineWidth = 3;
3242 var activeSpan = frags[7] == "1";
3243 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
3244 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3245 drawCurve(curve);
3246 if (draw_op > 1) {
3247 drawArc(curve, false, frags[3], frags[4]);
3248 drawArc(curve, true, frags[5], frags[6]);
3249 }
3250 break;
3251 case REC_TYPE_ADD:
3252 if (!draw_add) {
3253 continue;
3254 }
3255 ctx.lineWidth = 3;
3256 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
3257 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
3258 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
3259 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
3260 : "rgba(127,0,127, 0.3)";
3261 focus_enabled = true;
3262 switch (fragType) {
3263 case ADD_MOVETO:
3264 break;
3265 case ADD_LINETO:
3266 if (step_limit == 0 || tIndex >= lastAdd) {
3267 drawLine(frags[0], frags[1], frags[2], frags[3]);
3268 }
3269 break;
3270 case ADD_QUADTO:
3271 if (step_limit == 0 || tIndex >= lastAdd) {
3272 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
3273 }
3274 break;
caryclark1049f122015-04-20 08:31:59 -07003275 case ADD_CONICTO:
3276 if (step_limit == 0 || tIndex >= lastAdd) {
3277 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
3278 frags[4], frags[5], frags[6]);
3279 }
3280 break;
caryclarkdac1d172014-06-17 05:15:38 -07003281 case ADD_CUBICTO:
3282 if (step_limit == 0 || tIndex >= lastAdd) {
3283 drawCubic(frags[0], frags[1], frags[2], frags[3],
3284 frags[4], frags[5], frags[6], frags[7]);
3285 }
3286 break;
3287 case ADD_CLOSE:
3288 ++closeCount;
3289 break;
3290 case ADD_FILL:
3291 break;
3292 default:
3293 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
3294 throw "stop execution";
3295 }
3296 break;
3297 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07003298 angleBetween = frags[18] == "T";
3299 afterIndex = 0;
3300 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07003301 continue;
3302 }
3303 focus_enabled = true;
3304 ctx.lineWidth = 3;
3305 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07003306 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
3307 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
3308 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07003309 drawCurve(leftCurve);
3310 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07003311 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07003312 drawCurve(midCurve);
3313 if (draw_angle > 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003314 drawVisibleOrder(leftCurve, 'L');
3315 drawVisibleOrder(rightCurve, 'R');
3316 }
Ben Wagner29380bd2017-10-09 14:43:00 -04003317 if (draw_id) {
3318 drawVisibleID(leftCurve, 0.5, frags[0]);
3319 drawVisibleID(midCurve, 0.5, frags[6]);
3320 drawVisibleID(rightCurve, 0.5, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003321 }
3322 break;
caryclark54359292015-03-26 07:52:43 -07003323 case REC_TYPE_AFTERPART:
3324 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
3325 continue;
3326 }
3327 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
3328 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
Cary Clarkff114282016-12-14 11:56:16 -05003329 : "rgba(0,0,255, 1.0)";
3330 var curve;
3331 var id;
caryclark54359292015-03-26 07:52:43 -07003332 switch (fragType) {
3333 case PATH_LINE:
Cary Clarkff114282016-12-14 11:56:16 -05003334 curve = [ frags[0], frags[1], frags[2], frags[3] ];
3335 id = frags[4];
caryclark54359292015-03-26 07:52:43 -07003336 break;
3337 case PATH_QUAD:
Cary Clarkff114282016-12-14 11:56:16 -05003338 curve = [ frags[0], frags[1], frags[2], frags[3],
3339 frags[4], frags[5] ];
3340 id = frags[6];
caryclark54359292015-03-26 07:52:43 -07003341 break;
caryclark1049f122015-04-20 08:31:59 -07003342 case PATH_CONIC:
Cary Clarkff114282016-12-14 11:56:16 -05003343 curve = [ frags[0], frags[1], frags[2], frags[3],
3344 frags[4], frags[5], frags[6] ];
3345 id = frags[7];
caryclark1049f122015-04-20 08:31:59 -07003346 break;
caryclark54359292015-03-26 07:52:43 -07003347 case PATH_CUBIC:
Cary Clarkff114282016-12-14 11:56:16 -05003348 curve = [ frags[0], frags[1], frags[2], frags[3],
3349 frags[4], frags[5], frags[6], frags[7] ];
3350 id = frags[8];
caryclark54359292015-03-26 07:52:43 -07003351 break;
3352 default:
3353 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
3354 throw "stop execution";
3355 }
Cary Clarkff114282016-12-14 11:56:16 -05003356 drawCurve(curve);
Ben Wagner29380bd2017-10-09 14:43:00 -04003357 if (draw_id) {
3358 drawVisibleID(curve, 0.5, id);
Cary Clarkff114282016-12-14 11:56:16 -05003359 }
caryclark54359292015-03-26 07:52:43 -07003360 ++afterIndex;
3361 break;
caryclark624637c2015-05-11 07:21:27 -07003362 case REC_TYPE_COINCIDENCE:
3363 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
3364 continue;
3365 }
3366 focus_enabled = true;
3367 ctx.lineWidth = 3;
3368 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
3369 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3370 drawCurve(curve);
3371 break;
caryclarkdac1d172014-06-17 05:15:38 -07003372 case REC_TYPE_SECT:
3373 if (!draw_intersection) {
3374 continue;
3375 }
3376 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
3377 continue;
3378 }
3379 // draw_intersection == 1 : show all
3380 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
3381 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
3382 ctx.lineWidth = 1;
3383 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
3384 ctx.fillStyle = "blue";
3385 focus_enabled = true;
3386 var f = [];
3387 var c1s;
3388 var c1l;
3389 var c2s;
3390 var c2l;
3391 switch (fragType) {
3392 case INTERSECT_LINE:
3393 f.push(5, 6, 0, 7);
3394 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
3395 break;
3396 case INTERSECT_LINE_2:
3397 f.push(5, 6, 0, 10);
3398 f.push(8, 9, 7, 15);
3399 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
3400 break;
3401 case INTERSECT_LINE_NO:
3402 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
3403 break;
3404 case INTERSECT_QUAD_LINE:
3405 f.push(7, 8, 0, 9);
3406 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
3407 break;
3408 case INTERSECT_QUAD_LINE_2:
3409 f.push(7, 8, 0, 12);
3410 f.push(10, 11, 9, 17);
3411 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
3412 break;
3413 case INTERSECT_QUAD_LINE_NO:
3414 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
3415 break;
3416 case INTERSECT_QUAD:
3417 f.push(7, 8, 0, 9);
3418 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
3419 break;
3420 case INTERSECT_QUAD_2:
3421 f.push(7, 8, 0, 12);
3422 f.push(10, 11, 9, 19);
3423 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
3424 break;
3425 case INTERSECT_QUAD_NO:
3426 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
3427 break;
caryclark1049f122015-04-20 08:31:59 -07003428 case INTERSECT_CONIC_LINE:
3429 f.push(8, 9, 0, 10);
3430 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
3431 break;
3432 case INTERSECT_CONIC_LINE_2:
3433 f.push(8, 9, 0, 12);
3434 f.push(11, 12, 10, 18);
3435 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3436 break;
3437 case INTERSECT_CONIC_LINE_NO:
3438 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3439 break;
caryclark55888e42016-07-18 10:01:36 -07003440 case INTERSECT_CONIC_QUAD:
3441 f.push(8, 9, 0, 10);
3442 c1s = 1; c1l = 7; c2s = 11; c2l = 6;
3443 break;
3444 case INTERSECT_CONIC_QUAD_2:
3445 f.push(8, 9, 0, 12);
3446 f.push(11, 12, 10, 18);
3447 c1s = 1; c1l = 7; c2s = 14; c2l = 6;
3448 break;
caryclark6c3b9cd2016-09-26 05:36:58 -07003449 case INTERSECT_CONIC_QUAD_3:
3450 f.push(8, 9, 0, 15);
3451 f.push(11, 12, 10, 21);
3452 f.push(14, 15, 13, 22);
3453 c1s = 1; c1l = 7; c2s = 17; c2l = 6;
3454 break;
3455 case INTERSECT_CONIC_QUAD_4:
3456 f.push(8, 9, 0, 18);
3457 f.push(11, 12, 10, 24);
3458 f.push(14, 15, 13, 25);
3459 f.push(17, 18, 16, 26);
3460 c1s = 1; c1l = 7; c2s = 20; c2l = 6;
3461 break;
caryclark55888e42016-07-18 10:01:36 -07003462 case INTERSECT_CONIC_QUAD_NO:
3463 c1s = 0; c1l = 7; c2s = 7; c2l = 6;
3464 break;
caryclark1049f122015-04-20 08:31:59 -07003465 case INTERSECT_CONIC:
3466 f.push(8, 9, 0, 10);
3467 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3468 break;
3469 case INTERSECT_CONIC_2:
3470 f.push(8, 9, 0, 13);
3471 f.push(11, 12, 10, 21);
3472 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3473 break;
3474 case INTERSECT_CONIC_NO:
3475 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3476 break;
caryclarkdac1d172014-06-17 05:15:38 -07003477 case INTERSECT_SELF_CUBIC:
3478 f.push(9, 10, 0, 11);
3479 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3480 break;
3481 case INTERSECT_SELF_CUBIC_NO:
3482 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3483 break;
3484 case INTERSECT_CUBIC_LINE:
3485 f.push(9, 10, 0, 11);
3486 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3487 break;
3488 case INTERSECT_CUBIC_LINE_2:
3489 f.push(9, 10, 0, 14);
3490 f.push(12, 13, 11, 19);
3491 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3492 break;
3493 case INTERSECT_CUBIC_LINE_3:
3494 f.push(9, 10, 0, 17);
3495 f.push(12, 13, 11, 22);
3496 f.push(15, 16, 14, 23);
3497 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3498 break;
3499 case INTERSECT_CUBIC_QUAD_NO:
3500 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3501 break;
3502 case INTERSECT_CUBIC_QUAD:
3503 f.push(9, 10, 0, 11);
3504 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3505 break;
3506 case INTERSECT_CUBIC_QUAD_2:
3507 f.push(9, 10, 0, 14);
3508 f.push(12, 13, 11, 21);
3509 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3510 break;
3511 case INTERSECT_CUBIC_QUAD_3:
3512 f.push(9, 10, 0, 17);
3513 f.push(12, 13, 11, 24);
3514 f.push(15, 16, 14, 25);
3515 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3516 break;
3517 case INTERSECT_CUBIC_QUAD_4:
3518 f.push(9, 10, 0, 20);
3519 f.push(12, 13, 11, 27);
3520 f.push(15, 16, 14, 28);
3521 f.push(18, 19, 17, 29);
3522 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3523 break;
3524 case INTERSECT_CUBIC_LINE_NO:
3525 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3526 break;
3527 case INTERSECT_CUBIC:
3528 f.push(9, 10, 0, 11);
3529 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3530 break;
3531 case INTERSECT_CUBIC_2:
3532 f.push(9, 10, 0, 14);
3533 f.push(12, 13, 11, 23);
3534 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3535 break;
3536 case INTERSECT_CUBIC_3:
3537 f.push(9, 10, 0, 17);
3538 f.push(12, 13, 11, 26);
3539 f.push(15, 16, 14, 27);
3540 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3541 break;
3542 case INTERSECT_CUBIC_4:
3543 f.push(9, 10, 0, 20);
3544 f.push(12, 13, 11, 29);
3545 f.push(15, 16, 14, 30);
3546 f.push(18, 19, 17, 31);
3547 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3548 break;
3549 case INTERSECT_CUBIC_NO:
3550 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3551 break;
3552 default:
3553 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3554 throw "stop execution";
3555 }
3556 if (draw_intersection != 1) {
3557 var id = -1;
3558 var curve;
3559 switch (c1l) {
caryclark55888e42016-07-18 10:01:36 -07003560 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003561 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3562 if (draw_id) {
3563 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3564 id = idByCurve(test, curve, PATH_LINE);
3565 }
3566 break;
3567 case 6:
3568 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3569 frags[c1s + 4], frags[c1s + 5]);
3570 if (draw_id) {
3571 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3572 frags[c1s + 4], frags[c1s + 5]];
3573 id = idByCurve(test, curve, PATH_QUAD);
3574 }
3575 break;
caryclark1049f122015-04-20 08:31:59 -07003576 case 7:
3577 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3578 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3579 if (draw_id) {
3580 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3581 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3582 id = idByCurve(test, curve, PATH_CONIC);
3583 }
3584 break;
caryclarkdac1d172014-06-17 05:15:38 -07003585 case 8:
3586 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3587 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3588 if (draw_id) {
3589 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3590 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3591 id = idByCurve(test, curve, PATH_CUBIC);
3592 }
3593 break;
3594 }
3595 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003596 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003597 }
3598 id = -1;
3599 switch (c2l) {
3600 case 0:
3601 break;
caryclark55888e42016-07-18 10:01:36 -07003602 case 4:
caryclarkdac1d172014-06-17 05:15:38 -07003603 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3604 if (draw_id) {
3605 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3606 id = idByCurve(test, curve, PATH_LINE);
3607 }
3608 break;
3609 case 6:
3610 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3611 frags[c2s + 4], frags[c2s + 5]);
3612 if (draw_id) {
3613 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3614 frags[c2s + 4], frags[c2s + 5]];
3615 id = idByCurve(test, curve, PATH_QUAD);
3616 }
3617 break;
caryclark1049f122015-04-20 08:31:59 -07003618 case 7:
3619 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3620 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3621 if (draw_id) {
3622 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3623 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3624 id = idByCurve(test, curve, PATH_CONIC);
3625 }
3626 break;
caryclarkdac1d172014-06-17 05:15:38 -07003627 case 8:
3628 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3629 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3630 if (draw_id) {
3631 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3632 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3633 id = idByCurve(test, curve, PATH_CUBIC);
3634 }
3635 break;
3636 }
3637 if (id >= 0) {
Cary Clarkff114282016-12-14 11:56:16 -05003638 drawVisibleID(curve, 0.5, id);
caryclarkdac1d172014-06-17 05:15:38 -07003639 }
3640 }
3641 if (collect_bounds) {
3642 break;
3643 }
caryclark54359292015-03-26 07:52:43 -07003644 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3645 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003646 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3647 }
3648 }
3649 if (!draw_intersectT) {
3650 break;
3651 }
3652 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003653 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3654 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003655 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3656 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3657 }
3658 }
3659 break;
3660 case REC_TYPE_SORT:
3661 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3662 continue;
3663 }
3664 ctx.lineWidth = 3;
3665 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3666 focus_enabled = true;
3667 switch (fragType) {
3668 case SORT_UNARY:
3669 case SORT_BINARY:
3670 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3671 drawCurve(curve);
3672 break;
3673 default:
3674 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3675 throw "stop execution";
3676 }
3677 break;
caryclark03b03ca2015-04-23 09:13:37 -07003678 case REC_TYPE_TOP:
3679 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3680 continue;
3681 }
3682 ctx.lineWidth = 3;
3683 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3684 focus_enabled = true;
3685 {
3686 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3687 drawCurve(curve);
3688 var type = PATH_LINE + (curve.length / 2 - 2);
3689 var mid = pointAtT(curve, type, 0.5);
3690 var d = dxy_at_t(curve, type, 0.5);
3691 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3692 }
3693 break;
caryclarkdac1d172014-06-17 05:15:38 -07003694 case REC_TYPE_MARK:
3695 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3696 continue;
3697 }
3698 ctx.lineWidth = 3;
3699 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3700 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3701 focus_enabled = true;
3702 switch (fragType) {
3703 case MARK_LINE:
3704 case MARK_DONE_LINE:
3705 case MARK_UNSORTABLE_LINE:
3706 case MARK_SIMPLE_LINE:
3707 case MARK_SIMPLE_DONE_LINE:
3708 case MARK_DONE_UNARY_LINE:
3709 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3710 frags[5], frags[9]);
3711 if (draw_id) {
3712 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3713 frags[5], frags[9]);
3714 }
3715 break;
3716 case MARK_QUAD:
3717 case MARK_DONE_QUAD:
3718 case MARK_UNSORTABLE_QUAD:
3719 case MARK_SIMPLE_QUAD:
3720 case MARK_SIMPLE_DONE_QUAD:
3721 case MARK_DONE_UNARY_QUAD:
3722 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3723 frags[5], frags[6], frags[7], frags[11]);
3724 if (draw_id) {
3725 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3726 frags[5], frags[6], frags[7], frags[11]);
3727 }
3728 break;
3729 case MARK_CUBIC:
3730 case MARK_DONE_CUBIC:
3731 case MARK_UNSORTABLE_CUBIC:
3732 case MARK_SIMPLE_CUBIC:
3733 case MARK_SIMPLE_DONE_CUBIC:
3734 case MARK_DONE_UNARY_CUBIC:
3735 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3736 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3737 if (draw_id) {
3738 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3739 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3740 }
3741 break;
3742 case MARK_ANGLE_LAST:
3743 // FIXME: ignored for now
3744 break;
3745 default:
3746 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3747 throw "stop execution";
3748 }
3749 break;
3750 default:
3751 continue;
3752 }
3753 }
3754 switch (recType) {
3755 case REC_TYPE_SORT:
3756 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3757 break;
3758 }
3759 var angles = []; // use tangent lines to describe arcs
3760 var windFrom = [];
3761 var windTo = [];
3762 var opp = [];
3763 var minXY = Number.MAX_VALUE;
3764 var partial;
3765 focus_enabled = true;
3766 var someUnsortable = false;
3767 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3768 var fragType = records[recordIndex];
3769 var frags = records[recordIndex + 1];
3770 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3771 (fragType == SORT_BINARY && frags[16]);
3772 someUnsortable |= unsortable;
3773 switch (fragType) {
3774 case SORT_UNARY:
3775 case SORT_BINARY:
3776 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3777 break;
3778 default:
3779 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3780 throw "stop execution";
3781 }
3782 var dx = boundsWidth(partial);
3783 var dy = boundsHeight(partial);
3784 minXY = Math.min(minXY, dx * dx + dy * dy);
3785 if (collect_bounds) {
3786 continue;
3787 }
3788 angles.push(tangent(partial));
3789 var from = frags[12];
3790 var to = frags[12];
3791 var sgn = frags[10];
3792 if (sgn < 0) {
3793 from -= frags[11];
3794 } else if (sgn > 0) {
3795 to -= frags[11];
3796 }
3797 windFrom.push(from + (unsortable ? "!" : ""));
3798 windTo.push(to + (unsortable ? "!" : ""));
3799 opp.push(fragType == SORT_BINARY);
3800 if (draw_sort == 1) {
Cary Clarkff114282016-12-14 11:56:16 -05003801 drawVisibleOrder(partial, frags[12]);
caryclarkdac1d172014-06-17 05:15:38 -07003802 } else {
Cary Clarkff114282016-12-14 11:56:16 -05003803 drawVisibleOrder(partial, (recordIndex / 2) + 1);
caryclarkdac1d172014-06-17 05:15:38 -07003804 }
3805 }
3806 var radius = Math.sqrt(minXY) / 2 * scale;
3807 radius = Math.min(50, radius);
3808 var scaledRadius = radius / scale;
3809 var centerX = partial[0];
3810 var centerY = partial[1];
3811 if (collect_bounds) {
3812 if (focus_enabled) {
3813 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3814 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3815 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3816 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3817 }
3818 break;
3819 }
3820 break;
3821 default:
3822 break;
3823 }
3824 }
3825 if (collect_bounds) {
3826 return;
3827 }
3828 if (draw_log && logStart >= 0) {
3829 ctx.font = "normal 10px Arial";
3830 ctx.textAlign = "left";
3831 ctx.beginPath();
3832 var top = screenHeight - 20 - (logRange + 2) * 10;
3833 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3834 ctx.fillStyle = "white";
3835 ctx.fill();
3836 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3837 if (logStart > 0) {
3838 ctx.fillText(lines[logStart - 1], 50, top + 8);
3839 }
3840 ctx.fillStyle = "black";
3841 for (var idx = 0; idx < logRange; ++idx) {
3842 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3843 }
3844 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3845 if (logStart + logRange < lines.length) {
3846 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3847 }
3848 }
3849 if (draw_legend) {
3850 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003851 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003852 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3853 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3854 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3855 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3856 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003857 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003858 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3859 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003860 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003861 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
caryclark55888e42016-07-18 10:01:36 -07003862 drawBox(pos++, "black", "white",
caryclark26ad22a2015-10-16 09:03:38 -07003863 (new Array('P', 'P1', 'P2', 'P', 'p', 'p1', 'p2'))[draw_path], draw_path != 0, pathKey);
caryclarkdac1d172014-06-17 05:15:38 -07003864 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3865 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3866 draw_computed != 0, computedKey);
3867 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3868 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3869 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3870 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3871 if (curve_t) {
3872 drawCurveTControl();
3873 }
3874 ctx.font = "normal 20px Arial";
3875 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3876 ctx.textAlign = "right";
3877 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3878 }
3879 if (draw_hints) {
3880 ctx.font = "normal 10px Arial";
3881 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3882 ctx.textAlign = "right";
3883 var y = 4;
3884 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3885 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3886 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3887 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003888 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3889 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3890 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3891 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3892 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3893 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3894 }
3895}
3896
3897function drawBox(y, backC, foreC, str, enable, label) {
3898 ctx.beginPath();
3899 ctx.fillStyle = backC;
3900 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3901 ctx.fill();
3902 ctx.font = "normal 16px Arial";
3903 ctx.fillStyle = foreC;
3904 ctx.textAlign = "center";
3905 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3906 if (!enable) {
3907 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3908 ctx.fill();
3909 }
3910 if (label != '') {
3911 ctx.font = "normal 9px Arial";
3912 ctx.fillStyle = "black";
3913 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3914 }
3915}
3916
3917function drawCurveTControl() {
3918 ctx.lineWidth = 2;
3919 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3920 ctx.beginPath();
3921 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3922 ctx.stroke();
3923 var ty = 40 + curveT * (screenHeight - 80);
3924 ctx.beginPath();
3925 ctx.moveTo(screenWidth - 80, ty);
3926 ctx.lineTo(screenWidth - 85, ty - 5);
3927 ctx.lineTo(screenWidth - 85, ty + 5);
3928 ctx.lineTo(screenWidth - 80, ty);
3929 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3930 ctx.fill();
3931 var num = curveT.toFixed(decimal_places);
3932 ctx.font = "normal 10px Arial";
3933 ctx.textAlign = "left";
3934 ctx.fillText(num, screenWidth - 78, ty);
3935}
3936
3937function ptInTControl() {
3938 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07003939 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07003940 var left = tgt.offsetLeft;
3941 var top = tgt.offsetTop;
3942 var x = (e.clientX - left);
3943 var y = (e.clientY - top);
3944 if (x < screenWidth - 80 || x > screenWidth - 50) {
3945 return false;
3946 }
3947 if (y < 40 || y > screenHeight - 80) {
3948 return false;
3949 }
3950 curveT = (y - 40) / (screenHeight - 120);
3951 if (curveT < 0 || curveT > 1) {
3952 throw "stop execution";
3953 }
3954 return true;
3955}
3956
3957function drawTop() {
3958 if (tests[testIndex] == null) {
3959 var str = testDivs[testIndex].textContent;
3960 parse_all(str);
3961 var title = testDivs[testIndex].id.toString();
3962 testTitles[testIndex] = title;
3963 }
3964 init(tests[testIndex]);
3965 redraw();
3966}
3967
3968function redraw() {
3969 if (focus_on_selection) {
3970 collect_bounds = true;
3971 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3972 collect_bounds = false;
3973 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3974 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3975 }
3976 }
3977 ctx.beginPath();
3978 ctx.fillStyle = "white";
3979 ctx.rect(0, 0, screenWidth, screenHeight);
3980 ctx.fill();
3981 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3982}
3983
3984function dumpCurvePartial(test, id, t0, t1) {
3985 var curve = curveByID(test, id);
3986 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3987 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3988 + " t0=" + t0 + " t1=" + t1
3989 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3990}
3991
3992function dumpAngleTest(test, id, t0, t1) {
3993 var curve = curveByID(test, id);
caryclark55888e42016-07-18 10:01:36 -07003994 console.log(" { {" + curveToString(curve) + "}, "
caryclarkdac1d172014-06-17 05:15:38 -07003995 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3996}
3997
3998function dumpLogToConsole() {
3999 if (logStart < 0) {
4000 return;
4001 }
4002 var test = tests[testIndex];
4003 var recType = REC_TYPE_UNKNOWN;
4004 var records;
4005 for (var index = 0; index < test.length; index += 3) {
4006 var lastLineNo = test[index + 1];
4007 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
4008 recType = test[index];
4009 records = test[index + 2];
4010 break;
4011 }
4012 }
4013 if (recType == REC_TYPE_UNKNOWN) {
4014 return;
4015 }
4016 var lines = testLines[testIndex];
4017 for (var idx = 0; idx < logRange; ++idx) {
4018 var line = lines[logStart + idx];
4019 console.log(line);
4020 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
4021 var fragType = records[recordIndex];
4022 var frags = records[recordIndex + 1];
4023 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07004024 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
4025 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
4026 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
4027 console.log("\nstatic IntersectData intersectDataSet[] = { //");
4028 dumpAngleTest(test, frags[0], frags[4], frags[5]);
4029 dumpAngleTest(test, frags[6], frags[10], frags[11]);
4030 dumpAngleTest(test, frags[12], frags[16], frags[17]);
4031 console.log("}; //");
4032 }
4033 }
4034 }
4035}
4036
4037var activeKey = 'a';
4038var pathKey = 'b';
4039var pathBackKey = 'B';
4040var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07004041var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07004042var addKey = 'd';
4043var deriviativesKey = 'f';
4044var angleKey = 'g';
4045var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07004046var intersectionKey = 'i';
4047var intersectionBackKey = 'I';
4048var sequenceKey = 'j';
4049var midpointKey = 'k';
4050var logKey = 'l';
4051var logToConsoleKey = 'L';
4052var markKey = 'm';
4053var sortKey = 'o';
4054var opKey = 'p';
4055var opBackKey = 'P';
4056var computedKey = 'q';
4057var computedBackKey = 'Q';
Cary Clarkff114282016-12-14 11:56:16 -05004058var directionKey = 'r';
caryclarkdac1d172014-06-17 05:15:38 -07004059var stepKey = 's';
4060var stepBackKey = 'S';
4061var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07004062var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07004063var curveTKey = 'u';
4064var controlLinesBackKey = 'V';
4065var controlLinesKey = 'v';
4066var ptsKey = 'x';
4067var xyKey = 'y';
4068var logCurvesKey = 'z';
4069var focusKey = '`';
4070var idKey = '.';
4071var retinaKey = '\\';
4072
4073function doKeyPress(evt) {
4074 var char = String.fromCharCode(evt.charCode);
4075 var focusWasOn = false;
4076 switch (char) {
4077 case '0':
4078 case '1':
4079 case '2':
4080 case '3':
4081 case '4':
4082 case '5':
4083 case '6':
4084 case '7':
4085 case '8':
4086 case '9':
4087 decimal_places = char - '0';
4088 redraw();
4089 break;
4090 case activeKey:
4091 draw_active ^= true;
caryclark55888e42016-07-18 10:01:36 -07004092 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004093 break;
4094 case addKey:
4095 draw_add ^= true;
caryclark55888e42016-07-18 10:01:36 -07004096 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004097 break;
4098 case angleKey:
caryclark54359292015-03-26 07:52:43 -07004099 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07004100 redraw();
4101 break;
4102 case angleBackKey:
4103 draw_angle = (draw_angle + 2) % 3;
4104 redraw();
4105 break;
4106 case centerKey:
4107 setScale(xmin, xmax, ymin, ymax);
caryclark55888e42016-07-18 10:01:36 -07004108 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004109 break;
caryclark624637c2015-05-11 07:21:27 -07004110 case coincidenceKey:
4111 draw_coincidence ^= true;
4112 redraw();
4113 break;
caryclarkdac1d172014-06-17 05:15:38 -07004114 case controlLinesBackKey:
4115 control_lines = (control_lines + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004116 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004117 break;
4118 case controlLinesKey:
4119 control_lines = (control_lines + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004120 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004121 break;
4122 case computedBackKey:
4123 draw_computed = (draw_computed + 5) % 6;
caryclark55888e42016-07-18 10:01:36 -07004124 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004125 break;
4126 case computedKey:
4127 draw_computed = (draw_computed + 1) % 6;
caryclark55888e42016-07-18 10:01:36 -07004128 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004129 break;
4130 case curveTKey:
4131 curve_t ^= true;
4132 if (curve_t) {
4133 draw_legend = true;
4134 }
4135 redraw();
4136 break;
4137 case deriviativesKey:
4138 draw_deriviatives = (draw_deriviatives + 1) % 3;
4139 redraw();
4140 break;
Cary Clarkff114282016-12-14 11:56:16 -05004141 case directionKey:
4142 draw_direction ^= true;
4143 redraw();
4144 break;
caryclarkdac1d172014-06-17 05:15:38 -07004145 case focusKey:
4146 focus_on_selection ^= true;
4147 setScale(xmin, xmax, ymin, ymax);
4148 redraw();
4149 break;
caryclarkdac1d172014-06-17 05:15:38 -07004150 case idKey:
4151 draw_id ^= true;
4152 redraw();
4153 break;
4154 case intersectionBackKey:
4155 draw_intersection = (draw_intersection + 3) % 4;
caryclark55888e42016-07-18 10:01:36 -07004156 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004157 break;
4158 case intersectionKey:
4159 draw_intersection = (draw_intersection + 1) % 4;
caryclark55888e42016-07-18 10:01:36 -07004160 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004161 break;
4162 case intersectTKey:
4163 draw_intersectT ^= true;
4164 redraw();
4165 break;
4166 case logCurvesKey:
4167 logCurves(tests[testIndex]);
4168 break;
4169 case logKey:
4170 draw_log ^= true;
4171 redraw();
4172 break;
4173 case logToConsoleKey:
4174 if (draw_log) {
4175 dumpLogToConsole();
4176 }
4177 break;
4178 case markKey:
4179 draw_mark ^= true;
4180 redraw();
4181 break;
4182 case midpointKey:
4183 draw_midpoint ^= true;
4184 redraw();
4185 break;
4186 case opKey:
4187 draw_op = (draw_op + 1) % 3;
4188 redraw();
4189 break;
4190 case opBackKey:
4191 draw_op = (draw_op + 2) % 3;
4192 redraw();
4193 break;
4194 case pathKey:
caryclark26ad22a2015-10-16 09:03:38 -07004195 draw_path = (draw_path + 1) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004196 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004197 break;
4198 case pathBackKey:
caryclark26ad22a2015-10-16 09:03:38 -07004199 draw_path = (draw_path + 3 + (hasAlignedPath ? 3 : 0)) % (4 + (hasAlignedPath ? 3 : 0));
caryclark55888e42016-07-18 10:01:36 -07004200 redraw();
caryclarkdac1d172014-06-17 05:15:38 -07004201 break;
4202 case ptsKey:
4203 pt_labels = (pt_labels + 1) % 3;
4204 redraw();
4205 break;
4206 case retinaKey:
4207 retina_scale ^= true;
4208 drawTop();
4209 break;
4210 case sequenceKey:
4211 draw_sequence ^= true;
4212 redraw();
4213 break;
4214 case sortKey:
4215 draw_sort = (draw_sort + 1) % 3;
4216 drawTop();
4217 break;
4218 case stepKey:
4219 step_limit++;
4220 if (step_limit > stepMax) {
4221 step_limit = stepMax;
4222 }
4223 redraw();
4224 break;
4225 case stepBackKey:
4226 step_limit--;
4227 if (step_limit < 0) {
4228 step_limit = 0;
4229 }
4230 redraw();
4231 break;
caryclark03b03ca2015-04-23 09:13:37 -07004232 case topKey:
4233 draw_top ^= true;
4234 redraw();
4235 break;
caryclarkdac1d172014-06-17 05:15:38 -07004236 case xyKey:
4237 debug_xy = (debug_xy + 1) % 3;
4238 redraw();
4239 break;
4240 case '-':
4241 focusWasOn = focus_on_selection;
4242 if (focusWasOn) {
4243 focus_on_selection = false;
4244 scale /= 1.2;
4245 } else {
4246 scale /= 2;
4247 calcLeftTop();
4248 }
4249 redraw();
4250 focus_on_selection = focusWasOn;
4251 break;
4252 case '=':
4253 case '+':
4254 focusWasOn = focus_on_selection;
4255 if (focusWasOn) {
4256 focus_on_selection = false;
4257 scale *= 1.2;
4258 } else {
4259 scale *= 2;
4260 calcLeftTop();
4261 }
4262 redraw();
4263 focus_on_selection = focusWasOn;
4264 break;
4265 case '?':
4266 draw_hints ^= true;
4267 if (draw_hints && !draw_legend) {
4268 draw_legend = true;
4269 }
4270 redraw();
4271 break;
4272 case '/':
4273 draw_legend ^= true;
4274 redraw();
4275 break;
4276 }
4277}
4278
4279function doKeyDown(evt) {
4280 var char = evt.keyCode;
4281 var preventDefault = false;
4282 switch (char) {
4283 case 37: // left arrow
4284 if (evt.shiftKey) {
4285 testIndex -= 9;
4286 }
4287 if (--testIndex < 0)
4288 testIndex = tests.length - 1;
4289 drawTop();
4290 preventDefault = true;
4291 break;
4292 case 39: // right arrow
4293 if (evt.shiftKey) {
4294 testIndex += 9;
4295 }
4296 if (++testIndex >= tests.length)
4297 testIndex = 0;
4298 drawTop();
4299 preventDefault = true;
4300 break;
4301 }
4302 if (preventDefault) {
4303 evt.preventDefault();
4304 return false;
4305 }
4306 return true;
4307}
4308
4309(function() {
4310 var hidden = "hidden";
4311
4312 // Standards:
4313 if (hidden in document)
4314 document.addEventListener("visibilitychange", onchange);
4315 else if ((hidden = "mozHidden") in document)
4316 document.addEventListener("mozvisibilitychange", onchange);
4317 else if ((hidden = "webkitHidden") in document)
4318 document.addEventListener("webkitvisibilitychange", onchange);
4319 else if ((hidden = "msHidden") in document)
4320 document.addEventListener("msvisibilitychange", onchange);
4321 // IE 9 and lower:
4322 else if ('onfocusin' in document)
4323 document.onfocusin = document.onfocusout = onchange;
4324 // All others:
4325 else
caryclark55888e42016-07-18 10:01:36 -07004326 window.onpageshow = window.onpagehide
caryclarkdac1d172014-06-17 05:15:38 -07004327 = window.onfocus = window.onblur = onchange;
4328
4329 function onchange (evt) {
4330 var v = 'visible', h = 'hidden',
caryclark55888e42016-07-18 10:01:36 -07004331 evtMap = {
4332 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
caryclarkdac1d172014-06-17 05:15:38 -07004333 };
4334
4335 evt = evt || window.event;
4336 if (evt.type in evtMap)
4337 document.body.className = evtMap[evt.type];
caryclark55888e42016-07-18 10:01:36 -07004338 else
caryclarkdac1d172014-06-17 05:15:38 -07004339 document.body.className = this[hidden] ? "hidden" : "visible";
4340 }
4341})();
4342
4343function calcXY() {
4344 var e = window.event;
caryclark55888e42016-07-18 10:01:36 -07004345 var tgt = e.target || e.srcElement;
caryclarkdac1d172014-06-17 05:15:38 -07004346 var left = tgt.offsetLeft;
4347 var top = tgt.offsetTop;
4348 mouseX = (e.clientX - left) / scale + srcLeft;
4349 mouseY = (e.clientY - top) / scale + srcTop;
4350}
4351
4352function calcLeftTop() {
4353 srcLeft = mouseX - screenWidth / 2 / scale;
4354 srcTop = mouseY - screenHeight / 2 / scale;
4355}
4356
4357var disableClick = false;
4358
4359function handleMouseClick() {
4360 if (disableClick) {
4361 return;
4362 }
4363 if (!curve_t || !ptInTControl()) {
4364 calcXY();
4365 calcLeftTop();
4366 }
4367 redraw();
4368// if (!curve_t || !ptInTControl()) {
4369// mouseX = screenWidth / 2 / scale + srcLeft;
4370// mouseY = screenHeight / 2 / scale + srcTop;
4371// }
4372}
4373
4374function handleMouseOver() {
4375 calcXY();
4376 if (debug_xy != 2) {
4377 return;
4378 }
4379 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
4380 ctx.beginPath();
4381 ctx.rect(300,100,num.length * 6,10);
4382 ctx.fillStyle="white";
4383 ctx.fill();
4384 ctx.font = "normal 10px Arial";
4385 ctx.fillStyle="black";
4386 ctx.textAlign = "left";
4387 ctx.fillText(num, 300, 108);
4388}
4389
4390function start() {
4391 for (var i = 0; i < testDivs.length; ++i) {
4392 tests[i] = null;
4393 }
4394 testIndex = 0;
4395 drawTop();
4396 window.addEventListener('keypress', doKeyPress, true);
4397 window.addEventListener('keydown', doKeyDown, true);
4398 window.onresize = function() {
4399 drawTop();
4400 }
4401 /*
4402 window.onpagehide = function() {
4403 disableClick = true;
4404 }
4405 */
4406 window.onpageshow = function () {
4407 disableClick = false;
4408 }
4409}
4410
4411</script>
4412</head>
4413
4414<body onLoad="start();">
4415<canvas id="canvas" width="750" height="500"
4416 onmousemove="handleMouseOver()"
4417 onclick="handleMouseClick()"
4418 ></canvas >
4419</body>
4420</html>