blob: 194c89980d948844bd709d0890a6c7f92da98551 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
3<div height="0" hidden="true">
caryclarkdac1d172014-06-17 05:15:38 -07004
caryclark27c8eb82015-07-06 11:38:33 -07005<div id="battleOp183">
6seg=1 {{{6.31801322e-006f, -60}, {0, -83}}}
7seg=2 {{{0, -83}, {32.0712242f, -83}, {61.2726326f, -64.5230865f}, {75.0056381f, -35.5408783f}}}
8seg=3 {{{75.0056381f, -35.5408783f}, {88.7386475f, -6.55867052f}, {84.545517f, 27.7420006f}, {64.2353287f, 52.562561f}}}
9seg=4 {{{64.2353287f, 52.562561f}, {60.2773972f, 57.3994484f}, {55.7858162f, 61.773819f}, {50.8459854f, 65.6024933f}}}
10seg=5 {{{50.8459854f, 65.6024933f}, {36.756134f, 47.423481f}}}
11seg=6 {{{36.756134f, 47.423481f}, {40.3270988f, 44.6557693f}, {43.5740242f, 41.493576f}, {46.4351768f, 37.9970322f}}}
12seg=7 {{{46.4351768f, 37.9970322f}, {61.1172447f, 20.0544662f}, {64.1484222f, -4.74120331f}, {54.2209473f, -25.6921959f}}}
13seg=8 {{{54.2209473f, -25.6921959f}, {44.2934723f, -46.6431847f}, {23.1840267f, -60}, {6.31801322e-006f, -60}}}
14op union
15seg=9 {{{50.8459854f, 65.6024857f}, {23.334074f, 86.9259186f}, {-14.5602179f, 88.8177719f}, {-44.0591507f, 70.3405457f}}}
16seg=10 {{{-44.0591507f, 70.3405457f}, {-73.5580902f, 51.8633156f}, {-88.3942261f, 16.9427452f}, {-81.2158127f, -17.116993f}}}
17seg=11 {{{-81.2158127f, -17.116993f}, {-74.0374069f, -51.1767159f}, {-46.3696136f, -77.1391754f}, {-11.9226456f, -82.1392059f}}}
18seg=12 {{{-11.9226456f, -82.1392059f}, {-8.61876869f, -59.3777466f}}}
19seg=13 {{{-8.61876869f, -59.3777466f}, {-33.5202026f, -55.7632599f}, {-53.5210152f, -36.9952087f}, {-58.7102203f, -12.3737135f}}}
20seg=14 {{{-58.7102203f, -12.3737135f}, {-63.8994179f, 12.2477798f}, {-53.1744957f, 37.4915581f}, {-31.849966f, 50.8485832f}}}
21seg=15 {{{-31.849966f, 50.8485832f}, {-10.5254354f, 64.2056046f}, {16.8680305f, 62.8380051f}, {36.7561607f, 47.4234695f}}}
22seg=16 {{{36.7561607f, 47.4234695f}, {50.8459854f, 65.6024857f}}}
23debugShowCubicLineIntersection wtTs[0]=0 {{{0,-83}, {32.0712242,-83}, {61.2726326,-64.5230865}, {75.0056381,-35.5408783}}} {{0,-83}} wnTs[0]=1 {{{6.31801322e-006,-60}, {0,-83}}}
24debugShowCubicLineIntersection wtTs[0]=1 {{{54.2209473,-25.6921959}, {44.2934723,-46.6431847}, {23.1840267,-60}, {6.31801322e-006,-60}}} {{6.31801322e-006,-60}} wnTs[0]=0 {{{6.31801322e-006,-60}, {0,-83}}}
25debugShowCubicIntersection wtTs[0]=1 {{{0,-83}, {32.0712242,-83}, {61.2726326,-64.5230865}, {75.0056381,-35.5408783}}} {{75.0056381,-35.5408783}} wnTs[0]=0 {{{75.0056381,-35.5408783}, {88.7386475,-6.55867052}, {84.545517,27.7420006}, {64.2353287,52.562561}}}
26debugShowCubicIntersection no intersect {{{0,-83}, {32.0712242,-83}, {61.2726326,-64.5230865}, {75.0056381,-35.5408783}}} {{{54.2209473,-25.6921959}, {44.2934723,-46.6431847}, {23.1840267,-60}, {6.31801322e-006,-60}}}
27debugShowCubicIntersection wtTs[0]=1 {{{75.0056381,-35.5408783}, {88.7386475,-6.55867052}, {84.545517,27.7420006}, {64.2353287,52.562561}}} {{64.2353287,52.562561}} wnTs[0]=0 {{{64.2353287,52.562561}, {60.2773972,57.3994484}, {55.7858162,61.773819}, {50.8459854,65.6024933}}}
28debugShowCubicLineIntersection wtTs[0]=1 {{{64.2353287,52.562561}, {60.2773972,57.3994484}, {55.7858162,61.773819}, {50.8459854,65.6024933}}} {{50.8459854,65.6024933}} wnTs[0]=0 {{{50.8459854,65.6024933}, {36.756134,47.423481}}}
29debugShowCubicLineIntersection wtTs[0]=0 {{{36.756134,47.423481}, {40.3270988,44.6557693}, {43.5740242,41.493576}, {46.4351768,37.9970322}}} {{36.756134,47.423481}} wnTs[0]=1 {{{50.8459854,65.6024933}, {36.756134,47.423481}}}
30debugShowCubicIntersection wtTs[0]=1 {{{36.756134,47.423481}, {40.3270988,44.6557693}, {43.5740242,41.493576}, {46.4351768,37.9970322}}} {{46.4351768,37.9970322}} wnTs[0]=0 {{{46.4351768,37.9970322}, {61.1172447,20.0544662}, {64.1484222,-4.74120331}, {54.2209473,-25.6921959}}}
31debugShowCubicIntersection wtTs[0]=1 {{{46.4351768,37.9970322}, {61.1172447,20.0544662}, {64.1484222,-4.74120331}, {54.2209473,-25.6921959}}} {{54.2209473,-25.6921959}} wnTs[0]=0 {{{54.2209473,-25.6921959}, {44.2934723,-46.6431847}, {23.1840267,-60}, {6.31801322e-006,-60}}}
32debugShowCubicIntersection no intersect {{{64.2353287,52.562561}, {60.2773972,57.3994484}, {55.7858162,61.773819}, {50.8459854,65.6024933}}} {{{50.8459854,65.6024857}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}}
33debugShowCubicLineIntersection no intersect {{{64.2353287,52.562561}, {60.2773972,57.3994484}, {55.7858162,61.773819}, {50.8459854,65.6024933}}} {{{36.7561607,47.4234695}, {50.8459854,65.6024857}}}
34debugShowCubicLineIntersection wtTs[0]=0 {{{50.8459854,65.6024857}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} {{50.8459854,65.6024857}} wnTs[0]=2.62183e-007 {{{50.8459854,65.6024933}, {36.756134,47.423481}}}
35SkOpSegment::addT alias t=2.62182896e-007 segID=5 spanID=9
36debugShowCubicLineIntersection wtTs[0]=0.999999628 {{{-31.849966,50.8485832}, {-10.5254354,64.2056046}, {16.8680305,62.8380051}, {36.7561607,47.4234695}}} {{36.7561378,47.4234886}} wnTs[0]=1 {{{50.8459854,65.6024933}, {36.756134,47.423481}}}
37SkOpSegment::addT alias t=0.999999682 segID=5 spanID=10
38SkOpSegment::addT insert t=0.999999628 segID=15 spanID=33
39debugShowLineIntersection wtTs[0]=2.62182896e-007 {{{50.8459854,65.6024933}, {36.756134,47.423481}}} {{50.8459854,65.6024857}} wnTs[0]=1 {{{36.7561607,47.4234695}, {50.8459854,65.6024857}}}
40debugShowCubicIntersection no intersect {{{36.756134,47.423481}, {40.3270988,44.6557693}, {43.5740242,41.493576}, {46.4351768,37.9970322}}} {{{-31.849966,50.8485832}, {-10.5254354,64.2056046}, {16.8680305,62.8380051}, {36.7561607,47.4234695}}}
41debugShowCubicLineIntersection no intersect {{{36.756134,47.423481}, {40.3270988,44.6557693}, {43.5740242,41.493576}, {46.4351768,37.9970322}}} {{{36.7561607,47.4234695}, {50.8459854,65.6024857}}}
42debugShowCubicIntersection wtTs[0]=1 {{{50.8459854,65.6024857}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} {{-44.0591507,70.3405457}} wnTs[0]=0 {{{-44.0591507,70.3405457}, {-73.5580902,51.8633156}, {-88.3942261,16.9427452}, {-81.2158127,-17.116993}}}
43debugShowCubicLineIntersection wtTs[0]=0 {{{50.8459854,65.6024857}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} {{50.8459854,65.6024857}} wnTs[0]=1 {{{36.7561607,47.4234695}, {50.8459854,65.6024857}}}
44debugShowCubicIntersection wtTs[0]=1 {{{-44.0591507,70.3405457}, {-73.5580902,51.8633156}, {-88.3942261,16.9427452}, {-81.2158127,-17.116993}}} {{-81.2158127,-17.116993}} wnTs[0]=0 {{{-81.2158127,-17.116993}, {-74.0374069,-51.1767159}, {-46.3696136,-77.1391754}, {-11.9226456,-82.1392059}}}
45debugShowCubicIntersection no intersect {{{-44.0591507,70.3405457}, {-73.5580902,51.8633156}, {-88.3942261,16.9427452}, {-81.2158127,-17.116993}}} {{{-8.61876869,-59.3777466}, {-33.5202026,-55.7632599}, {-53.5210152,-36.9952087}, {-58.7102203,-12.3737135}}}
46debugShowCubicIntersection no intersect {{{-44.0591507,70.3405457}, {-73.5580902,51.8633156}, {-88.3942261,16.9427452}, {-81.2158127,-17.116993}}} {{{-58.7102203,-12.3737135}, {-63.8994179,12.2477798}, {-53.1744957,37.4915581}, {-31.849966,50.8485832}}}
47debugShowCubicLineIntersection wtTs[0]=1 {{{-81.2158127,-17.116993}, {-74.0374069,-51.1767159}, {-46.3696136,-77.1391754}, {-11.9226456,-82.1392059}}} {{-11.9226456,-82.1392059}} wnTs[0]=0 {{{-11.9226456,-82.1392059}, {-8.61876869,-59.3777466}}}
48debugShowCubicIntersection no intersect {{{-81.2158127,-17.116993}, {-74.0374069,-51.1767159}, {-46.3696136,-77.1391754}, {-11.9226456,-82.1392059}}} {{{-8.61876869,-59.3777466}, {-33.5202026,-55.7632599}, {-53.5210152,-36.9952087}, {-58.7102203,-12.3737135}}}
49debugShowCubicLineIntersection wtTs[0]=0 {{{-8.61876869,-59.3777466}, {-33.5202026,-55.7632599}, {-53.5210152,-36.9952087}, {-58.7102203,-12.3737135}}} {{-8.61876869,-59.3777466}} wnTs[0]=1 {{{-11.9226456,-82.1392059}, {-8.61876869,-59.3777466}}}
50debugShowCubicIntersection wtTs[0]=1 {{{-8.61876869,-59.3777466}, {-33.5202026,-55.7632599}, {-53.5210152,-36.9952087}, {-58.7102203,-12.3737135}}} {{-58.7102203,-12.3737135}} wnTs[0]=0 {{{-58.7102203,-12.3737135}, {-63.8994179,12.2477798}, {-53.1744957,37.4915581}, {-31.849966,50.8485832}}}
51debugShowCubicIntersection wtTs[0]=1 {{{-58.7102203,-12.3737135}, {-63.8994179,12.2477798}, {-53.1744957,37.4915581}, {-31.849966,50.8485832}}} {{-31.849966,50.8485832}} wnTs[0]=0 {{{-31.849966,50.8485832}, {-10.5254354,64.2056046}, {16.8680305,62.8380051}, {36.7561607,47.4234695}}}
52debugShowCubicLineIntersection wtTs[0]=1 {{{-31.849966,50.8485832}, {-10.5254354,64.2056046}, {16.8680305,62.8380051}, {36.7561607,47.4234695}}} {{36.7561607,47.4234695}} wnTs[0]=0 {{{36.7561607,47.4234695}, {50.8459854,65.6024857}}}
53SkOpSegment::sortAngles [4] tStart=1 [8]
54SkOpAngle::after [4/1] 1/1 tStart=1 tEnd=0 < [16/8] 9/9 tStart=1 tEnd=0 < [5/2] 9/9 tStart=0 tEnd=1 T 7
55SkOpAngle::afterPart {{{50.8459854,65.6024933}, {55.7858162,61.773819}, {60.2773972,57.3994484}, {64.2353287,52.562561}}} id=4
56SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.7561607,47.4234695}}} id=16
57SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.756134,47.423481}}} id=5
58SkOpAngle::after [4/1] 1/1 tStart=1 tEnd=0 < [9/5] 17/17 tStart=0 tEnd=1 < [16/8] 9/9 tStart=1 tEnd=0 F 4
59SkOpAngle::afterPart {{{50.8459854,65.6024933}, {55.7858162,61.773819}, {60.2773972,57.3994484}, {64.2353287,52.562561}}} id=4
60SkOpAngle::afterPart {{{50.8459854,65.6024933}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} id=9
61SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.7561607,47.4234695}}} id=16
62SkOpAngle::after [16/8] 9/9 tStart=1 tEnd=0 < [9/5] 17/17 tStart=0 tEnd=1 < [5/2] 9/9 tStart=0 tEnd=1 F 5
63SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.7561607,47.4234695}}} id=16
64SkOpAngle::afterPart {{{50.8459854,65.6024933}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} id=9
65SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.756134,47.423481}}} id=5
66SkOpAngle::after [5/2] 9/9 tStart=0 tEnd=1 < [9/5] 17/17 tStart=0 tEnd=1 < [4/1] 1/1 tStart=1 tEnd=0 T 4
67SkOpAngle::afterPart {{{50.8459854,65.6024933}, {36.756134,47.423481}}} id=5
68SkOpAngle::afterPart {{{50.8459854,65.6024933}, {23.334074,86.9259186}, {-14.5602179,88.8177719}, {-44.0591507,70.3405457}}} id=9
69SkOpAngle::afterPart {{{50.8459854,65.6024933}, {55.7858162,61.773819}, {60.2773972,57.3994484}, {64.2353287,52.562561}}} id=4
70SkOpSegment::sortAngles [5] tStart=0 [9]
71SkOpSegment::sortAngles [5] tStart=1 [10]
72SkOpAngle::after [5/3] 25/25 tStart=1 tEnd=0 < [15/7] 1/1 tStart=0.999999628 tEnd=1 < [15/6] 17/17 tStart=0.999999628 tEnd=0 T 4
73SkOpAngle::afterPart {{{36.756134,47.423481}, {50.8459854,65.6024933}}} id=5
74SkOpAngle::afterPart {{{36.756134,47.423481}, {36.7561414,47.4234752}, {36.7561533,47.4234753}, {36.7561607,47.4234695}}} id=15
75SkOpAngle::afterPart {{{36.756134,47.423481}, {16.8680057,62.8380003}, {-10.5254434,64.2055996}, {-31.849966,50.8485832}}} id=15
76SkOpAngle::after [5/3] 25/25 tStart=1 tEnd=0 < [6/4] 1/1 tStart=0 tEnd=1 < [15/7] 1/1 tStart=0.999999628 tEnd=1 T 7
77SkOpAngle::afterPart {{{36.756134,47.423481}, {50.8459854,65.6024933}}} id=5
78SkOpAngle::afterPart {{{36.756134,47.423481}, {40.3270988,44.6557693}, {43.5740242,41.493576}, {46.4351768,37.9970322}}} id=6
79SkOpAngle::afterPart {{{36.756134,47.423481}, {36.7561414,47.4234752}, {36.7561533,47.4234753}, {36.7561607,47.4234695}}} id=15
80SkOpSegment::sortAngles [6] tStart=0 [11]
81SkOpSegment::sortAngles [9] tStart=0 [17]
82SkOpSegment::sortAngles [15] tStart=0.999999628 [33]
83SkOpSegment::sortAngles [16] tStart=1 [32]
84SkOpSegment::debugShowActiveSpans id=1 (6.31801322e-006,-60 0,-83) t=0 (6.31801322e-006,-60) tEnd=1 windSum=? windValue=1
85SkOpSegment::debugShowActiveSpans id=2 (0,-83 32.0712242,-83 61.2726326,-64.5230865 75.0056381,-35.5408783) t=0 (0,-83) tEnd=1 windSum=? windValue=1
86SkOpSegment::debugShowActiveSpans id=3 (75.0056381,-35.5408783 88.7386475,-6.55867052 84.545517,27.7420006 64.2353287,52.562561) t=0 (75.0056381,-35.5408783) tEnd=1 windSum=? windValue=1
87SkOpSegment::debugShowActiveSpans id=4 (64.2353287,52.562561 60.2773972,57.3994484 55.7858162,61.773819 50.8459854,65.6024933) t=0 (64.2353287,52.562561) tEnd=1 windSum=? windValue=1
88SkOpSegment::debugShowActiveSpans id=5 (50.8459854,65.6024933 36.756134,47.423481) t=0 (50.8459854,65.6024933) tEnd=1 windSum=? windValue=1
89SkOpSegment::debugShowActiveSpans id=6 (36.756134,47.423481 40.3270988,44.6557693 43.5740242,41.493576 46.4351768,37.9970322) t=0 (36.756134,47.423481) tEnd=1 windSum=? windValue=1
90SkOpSegment::debugShowActiveSpans id=7 (46.4351768,37.9970322 61.1172447,20.0544662 64.1484222,-4.74120331 54.2209473,-25.6921959) t=0 (46.4351768,37.9970322) tEnd=1 windSum=? windValue=1
91SkOpSegment::debugShowActiveSpans id=8 (54.2209473,-25.6921959 44.2934723,-46.6431847 23.1840267,-60 6.31801322e-006,-60) t=0 (54.2209473,-25.6921959) tEnd=1 windSum=? windValue=1
92SkOpSegment::debugShowActiveSpans id=9 (50.8459854,65.6024933 23.334074,86.9259186 -14.5602179,88.8177719 -44.0591507,70.3405457) t=0 (50.8459854,65.6024933) tEnd=1 windSum=? windValue=1
93SkOpSegment::debugShowActiveSpans id=10 (-44.0591507,70.3405457 -73.5580902,51.8633156 -88.3942261,16.9427452 -81.2158127,-17.116993) t=0 (-44.0591507,70.3405457) tEnd=1 windSum=? windValue=1
94SkOpSegment::debugShowActiveSpans id=11 (-81.2158127,-17.116993 -74.0374069,-51.1767159 -46.3696136,-77.1391754 -11.9226456,-82.1392059) t=0 (-81.2158127,-17.116993) tEnd=1 windSum=? windValue=1
95SkOpSegment::debugShowActiveSpans id=12 (-11.9226456,-82.1392059 -8.61876869,-59.3777466) t=0 (-11.9226456,-82.1392059) tEnd=1 windSum=? windValue=1
96SkOpSegment::debugShowActiveSpans id=13 (-8.61876869,-59.3777466 -33.5202026,-55.7632599 -53.5210152,-36.9952087 -58.7102203,-12.3737135) t=0 (-8.61876869,-59.3777466) tEnd=1 windSum=? windValue=1
97SkOpSegment::debugShowActiveSpans id=14 (-58.7102203,-12.3737135 -63.8994179,12.2477798 -53.1744957,37.4915581 -31.849966,50.8485832) t=0 (-58.7102203,-12.3737135) tEnd=1 windSum=? windValue=1
98SkOpSegment::debugShowActiveSpans id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0 (-31.849966,50.8485832) tEnd=0.999999628 windSum=? windValue=1
99SkOpSegment::debugShowActiveSpans id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0.999999628 (36.756134,47.423481) tEnd=1 windSum=? windValue=1
100SkOpSegment::debugShowActiveSpans id=16 (36.7561607,47.4234695 50.8459854,65.6024933) t=0 (36.7561607,47.4234695) tEnd=1 windSum=? windValue=1
101SkOpSpan::sortableTop dir=kLeft seg=1 t=0.5 pt=(3.15900661e-006,-71.5)
102SkOpSpan::sortableTop [0] valid=1 operand=1 span=21 ccw=1 seg=11 {{{-81.2158127f, -17.116993f}, {-74.0374069f, -51.1767159f}, {-46.3696136f, -77.1391754f}, {-11.9226456f, -82.1392059f}}} t=0.683500004 pt=(-42.1581116,-71.5) slope=(86.347103,-50.9415461)
103SkOpSpan::sortableTop [1] valid=1 operand=1 span=23 ccw=0 seg=12 {{{-11.9226456f, -82.1392059f}, {-8.61876869f, -59.3777466f}}} t=0.46742196 pt=(-10.3783407,-71.5) slope=(3.30387688,22.7614594)
104SkOpSpan::sortableTop [2] valid=1 operand=0 span=1 ccw=1 seg=1 {{{6.31801322e-006f, -60}, {0, -83}}} t=0.5 pt=(3.15900661e-006,-71.5) slope=(-6.31801322e-006,-23)
105SkOpSegment::markWinding id=11 (-81.2158127,-17.116993 -74.0374069,-51.1767159 -46.3696136,-77.1391754 -11.9226456,-82.1392059) t=0 [21] (-81.2158127,-17.116993) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
106SkOpSegment::markWinding id=12 (-11.9226456,-82.1392059 -8.61876869,-59.3777466) t=0 [23] (-11.9226456,-82.1392059) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
107SkOpSegment::markWinding id=13 (-8.61876869,-59.3777466 -33.5202026,-55.7632599 -53.5210152,-36.9952087 -58.7102203,-12.3737135) t=0 [25] (-8.61876869,-59.3777466) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
108SkOpSegment::markWinding id=14 (-58.7102203,-12.3737135 -63.8994179,12.2477798 -53.1744957,37.4915581 -31.849966,50.8485832) t=0 [27] (-58.7102203,-12.3737135) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
109SkOpSegment::markWinding id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0 [29] (-31.849966,50.8485832) tEnd=0.999999628 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
110SkOpSegment::markWinding id=11 (-81.2158127,-17.116993 -74.0374069,-51.1767159 -46.3696136,-77.1391754 -11.9226456,-82.1392059) t=0 [21] (-81.2158127,-17.116993) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
111SkOpSegment::markWinding id=10 (-44.0591507,70.3405457 -73.5580902,51.8633156 -88.3942261,16.9427452 -81.2158127,-17.116993) t=0 [19] (-44.0591507,70.3405457) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
112SkOpSegment::markWinding id=9 (50.8459854,65.6024933 23.334074,86.9259186 -14.5602179,88.8177719 -44.0591507,70.3405457) t=0 [17] (50.8459854,65.6024933) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
113SkOpSegment::markWinding id=1 (6.31801322e-006,-60 0,-83) t=0 [1] (6.31801322e-006,-60) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
114SkOpSegment::markWinding id=2 (0,-83 32.0712242,-83 61.2726326,-64.5230865 75.0056381,-35.5408783) t=0 [3] (0,-83) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
115SkOpSegment::markWinding id=3 (75.0056381,-35.5408783 88.7386475,-6.55867052 84.545517,27.7420006 64.2353287,52.562561) t=0 [5] (75.0056381,-35.5408783) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
116SkOpSegment::markWinding id=4 (64.2353287,52.562561 60.2773972,57.3994484 55.7858162,61.773819 50.8459854,65.6024933) t=0 [7] (64.2353287,52.562561) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
117SkOpSegment::markWinding id=1 (6.31801322e-006,-60 0,-83) t=0 [1] (6.31801322e-006,-60) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
118SkOpSegment::markWinding id=8 (54.2209473,-25.6921959 44.2934723,-46.6431847 23.1840267,-60 6.31801322e-006,-60) t=0 [15] (54.2209473,-25.6921959) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
119SkOpSegment::markWinding id=7 (46.4351768,37.9970322 61.1172447,20.0544662 64.1484222,-4.74120331 54.2209473,-25.6921959) t=0 [13] (46.4351768,37.9970322) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
120SkOpSegment::markWinding id=6 (36.756134,47.423481 40.3270988,44.6557693 43.5740242,41.493576 46.4351768,37.9970322) t=0 [11] (36.756134,47.423481) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
121SkOpSegment::activeOp id=1 t=1 tEnd=0 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
122SkOpSegment::findNextOp simple
123SkOpSegment::markDone id=1 (6.31801322e-006,-60 0,-83) t=0 [1] (6.31801322e-006,-60) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
124bridgeOp current id=1 from=(0,-83) to=(6.31801322e-006,-60)
125SkOpSegment::findNextOp simple
126SkOpSegment::markDone id=8 (54.2209473,-25.6921959 44.2934723,-46.6431847 23.1840267,-60 6.31801322e-006,-60) t=0 [15] (54.2209473,-25.6921959) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
127bridgeOp current id=8 from=(6.31801322e-006,-60) to=(54.2209473,-25.6921959)
128path.moveTo(0,-83);
129path.lineTo(6.31801322e-006,-60);
130path.cubicTo(23.1840267,-60, 44.2934723,-46.6431847, 54.2209473,-25.6921959);
131SkOpSegment::findNextOp simple
132SkOpSegment::markDone id=7 (46.4351768,37.9970322 61.1172447,20.0544662 64.1484222,-4.74120331 54.2209473,-25.6921959) t=0 [13] (46.4351768,37.9970322) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
133bridgeOp current id=7 from=(54.2209473,-25.6921959) to=(46.4351768,37.9970322)
134path.cubicTo(64.1484222,-4.74120331, 61.1172447,20.0544662, 46.4351768,37.9970322);
135SkOpSegment::markWinding id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0.999999628 [33] (36.756134,47.423481) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
136SkOpSegment::markWinding id=16 (36.7561607,47.4234695 50.8459854,65.6024933) t=0 [31] (36.7561607,47.4234695) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
137SkOpSegment::markAngle last segment=16 span=32
138SkOpSegment::markWinding id=5 (50.8459854,65.6024933 36.756134,47.423481) t=0 [9] (50.8459854,65.6024933) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0
139SkOpSegment::markAngle last segment=5 span=9 windSum=-1
140SkOpSegment::findNextOp
141SkOpAngle::dumpOne [6/4] next=15/7 sect=1/1 s=0 [11] e=1 [12] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
142SkOpAngle::dumpOne [15/7] next=15/6 sect=1/1 s=0.999999628 [33] e=1 [30] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
143SkOpAngle::dumpOne [15/6] next=5/3 sect=17/17 s=0.999999628 [33] e=0 [29] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
144SkOpAngle::dumpOne [5/3] next=6/4 sect=25/25 s=1 [10] e=0 [9] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1
145SkOpSegment::activeOp id=15 t=0.999999628 tEnd=1 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
146SkOpSegment::findNextOp chase.append segment=16 span=32
147SkOpSegment::activeOp id=15 t=0.999999628 tEnd=0 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
148SkOpSegment::activeOp id=5 t=1 tEnd=0 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
149SkOpSegment::findNextOp chase.append segment=5 span=9 windSum=-1
150SkOpSegment::markDone id=6 (36.756134,47.423481 40.3270988,44.6557693 43.5740242,41.493576 46.4351768,37.9970322) t=0 [11] (36.756134,47.423481) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
151SkOpSegment::findNextOp from:[6] to:[15] start=13585868 end=13585412
152bridgeOp current id=6 from=(46.4351768,37.9970322) to=(36.756134,47.423481)
153path.cubicTo(43.5740242,41.493576, 40.3270988,44.6557693, 36.756134,47.423481);
154SkOpSegment::findNextOp simple
155SkOpSegment::markDone id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0.999999628 [33] (36.756134,47.423481) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
156bridgeOp current id=15 from=(36.756134,47.423481) to=(36.7561607,47.4234695)
157path.cubicTo(36.7561417,47.4234734, 36.7561531,47.4234772, 36.7561607,47.4234695);
158SkOpSegment::findNextOp
159SkOpAngle::dumpOne [16/8] next=5/2 sect=9/9 s=1 [32] e=0 [31] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
160SkOpAngle::dumpOne [5/2] next=9/5 sect=9/9 s=0 [9] e=1 [10] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1
161SkOpAngle::dumpOne [9/5] next=4/1 sect=17/17 s=0 [17] e=1 [18] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
162SkOpAngle::dumpOne [4/1] next=16/8 sect=1/1 s=1 [8] e=0 [7] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
163SkOpSegment::activeOp id=5 t=0 tEnd=1 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
164SkOpSegment::activeOp id=9 t=0 tEnd=1 op=union miFrom=1 miTo=1 suFrom=0 suTo=1 result=0
165SkOpSegment::markDone id=9 (50.8459854,65.6024933 23.334074,86.9259186 -14.5602179,88.8177719 -44.0591507,70.3405457) t=0 [17] (50.8459854,65.6024933) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
166SkOpSegment::markDone id=10 (-44.0591507,70.3405457 -73.5580902,51.8633156 -88.3942261,16.9427452 -81.2158127,-17.116993) t=0 [19] (-44.0591507,70.3405457) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
167SkOpSegment::markDone id=11 (-81.2158127,-17.116993 -74.0374069,-51.1767159 -46.3696136,-77.1391754 -11.9226456,-82.1392059) t=0 [21] (-81.2158127,-17.116993) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
168SkOpSegment::markDone id=12 (-11.9226456,-82.1392059 -8.61876869,-59.3777466) t=0 [23] (-11.9226456,-82.1392059) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
169SkOpSegment::markDone id=13 (-8.61876869,-59.3777466 -33.5202026,-55.7632599 -53.5210152,-36.9952087 -58.7102203,-12.3737135) t=0 [25] (-8.61876869,-59.3777466) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
170SkOpSegment::markDone id=14 (-58.7102203,-12.3737135 -63.8994179,12.2477798 -53.1744957,37.4915581 -31.849966,50.8485832) t=0 [27] (-58.7102203,-12.3737135) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
171SkOpSegment::markDone id=15 (-31.849966,50.8485832 -10.5254354,64.2056046 16.8680305,62.8380051 36.7561607,47.4234695) t=0 [29] (-31.849966,50.8485832) tEnd=0.999999628 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
172SkOpSegment::activeOp id=4 t=1 tEnd=0 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
173SkOpSegment::markDone id=4 (64.2353287,52.562561 60.2773972,57.3994484 55.7858162,61.773819 50.8459854,65.6024933) t=0 [7] (64.2353287,52.562561) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
174SkOpSegment::markDone id=3 (75.0056381,-35.5408783 88.7386475,-6.55867052 84.545517,27.7420006 64.2353287,52.562561) t=0 [5] (75.0056381,-35.5408783) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
175SkOpSegment::markDone id=2 (0,-83 32.0712242,-83 61.2726326,-64.5230865 75.0056381,-35.5408783) t=0 [3] (0,-83) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
176SkOpSegment::markDone id=16 (36.7561607,47.4234695 50.8459854,65.6024933) t=0 [31] (36.7561607,47.4234695) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
177SkOpSegment::findNextOp from:[16] to:[5] start=13582764 end=13582868
178bridgeOp current id=16 from=(36.7561607,47.4234695) to=(50.8459854,65.6024933)
179SkOpSegment::findNextOp
180SkOpAngle::dumpOne [5/3] next=6/4 sect=25/25 s=1 [10] e=0 [9] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1
181SkOpAngle::dumpOne [6/4] next=15/7 sect=1/1 s=0 [11] e=1 [12] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done
182SkOpAngle::dumpOne [15/7] next=15/6 sect=1/1 s=0.999999628 [33] e=1 [30] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
183SkOpAngle::dumpOne [15/6] next=5/3 sect=17/17 s=0.999999628 [33] e=0 [29] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done operand
184SkOpSegment::activeOp id=6 t=0 tEnd=1 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
185SkOpSegment::activeOp id=15 t=0.999999628 tEnd=1 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
186SkOpSegment::activeOp id=15 t=0.999999628 tEnd=0 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
187SkOpSegment::markDone id=5 (50.8459854,65.6024933 36.756134,47.423481) t=0 [9] (50.8459854,65.6024933) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0
188SkOpSegment::findNextOp from:[5] to:[15] start=13585868 end=13585412
189bridgeOp current id=5 from=(50.8459854,65.6024933) to=(36.756134,47.423481)
190path.lineTo(50.8459854,65.6024933);
191path.lineTo(36.756134,47.423481);
caryclarkdac1d172014-06-17 05:15:38 -0700192</div>
caryclarkdac1d172014-06-17 05:15:38 -0700193</div>
194
195<script type="text/javascript">
196
197var testDivs = [
caryclark27c8eb82015-07-06 11:38:33 -0700198 battleOp183,
caryclarkdac1d172014-06-17 05:15:38 -0700199];
200
201var decimal_places = 3; // make this 3 to show more precision
202
203var tests = [];
204var testLines = [];
205var testTitles = [];
206var testIndex = 0;
207var ctx;
208
209var xmin, xmax, focusXmin, focusXmax;
210var ymin, ymax, focusYmin, focusYmax;
211var scale;
212var mouseX, mouseY;
213var srcLeft, srcTop;
214var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700215var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700216var curveT = 0;
217
218var pt_labels = 2;
219var collect_bounds = false;
220var control_lines = 0;
221var curve_t = false;
222var debug_xy = 1;
223var focus_enabled = false;
224var focus_on_selection = false;
225var step_limit = 0;
226var draw_active = false;
227var draw_add = false;
228var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700229var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700230var draw_deriviatives = 0;
231var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700232var draw_id = false;
233var draw_intersection = 0;
234var draw_intersectT = false;
235var draw_legend = true;
236var draw_log = false;
237var draw_mark = false;
238var draw_midpoint = false;
239var draw_op = 0;
240var draw_sequence = false;
241var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700242var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700243var draw_path = 3;
244var draw_computed = 0;
245var retina_scale = !!window.devicePixelRatio;
246
247var activeCount = 0;
248var addCount = 0;
249var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700250var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700251var opCount = 0;
252var sectCount = 0;
253var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700254var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700255var markCount = 0;
256var activeMax = 0;
257var addMax = 0;
258var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700259var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700260var sectMax = 0;
261var sectMax2 = 0;
262var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700263var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700264var markMax = 0;
265var opMax = 0;
266var stepMax = 0;
267var lastIndex = 0;
268var hasPath = false;
269var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700270var angleBetween = false;
271var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700272
273var firstActiveSpan = -1;
274var logStart = -1;
275var logRange = 0;
276
277var SPAN_ID = 0;
278var SPAN_X1 = SPAN_ID + 1;
279var SPAN_Y1 = SPAN_X1 + 1;
280var SPAN_X2 = SPAN_Y1 + 1;
281var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700282
caryclarkdac1d172014-06-17 05:15:38 -0700283var SPAN_L_T = SPAN_Y2 + 1;
284var SPAN_L_TX = SPAN_L_T + 1;
285var SPAN_L_TY = SPAN_L_TX + 1;
286var SPAN_L_TEND = SPAN_L_TY + 1;
287var SPAN_L_OTHER = SPAN_L_TEND + 1;
288var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
289var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
290var SPAN_L_SUM = SPAN_L_OTHERI + 1;
291var SPAN_L_VAL = SPAN_L_SUM + 1;
292var SPAN_L_OPP = SPAN_L_VAL + 1;
293
294var SPAN_X3 = SPAN_Y2 + 1;
295var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700296
caryclarkdac1d172014-06-17 05:15:38 -0700297var SPAN_Q_T = SPAN_Y3 + 1;
298var SPAN_Q_TX = SPAN_Q_T + 1;
299var SPAN_Q_TY = SPAN_Q_TX + 1;
300var SPAN_Q_TEND = SPAN_Q_TY + 1;
301var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
302var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
303var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
304var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
305var SPAN_Q_VAL = SPAN_Q_SUM + 1;
306var SPAN_Q_OPP = SPAN_Q_VAL + 1;
307
caryclark1049f122015-04-20 08:31:59 -0700308var SPAN_K_W = SPAN_Y3 + 1;
309var SPAN_K_T = SPAN_K_W + 1;
310var SPAN_K_TX = SPAN_K_T + 1;
311var SPAN_K_TY = SPAN_K_TX + 1;
312var SPAN_K_TEND = SPAN_K_TY + 1;
313var SPAN_K_OTHER = SPAN_K_TEND + 1;
314var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
315var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
316var SPAN_K_SUM = SPAN_K_OTHERI + 1;
317var SPAN_K_VAL = SPAN_K_SUM + 1;
318var SPAN_K_OPP = SPAN_K_VAL + 1;
319
caryclarkdac1d172014-06-17 05:15:38 -0700320var SPAN_X4 = SPAN_Y3 + 1;
321var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700322
caryclarkdac1d172014-06-17 05:15:38 -0700323var SPAN_C_T = SPAN_Y4 + 1;
324var SPAN_C_TX = SPAN_C_T + 1;
325var SPAN_C_TY = SPAN_C_TX + 1;
326var SPAN_C_TEND = SPAN_C_TY + 1;
327var SPAN_C_OTHER = SPAN_C_TEND + 1;
328var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
329var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
330var SPAN_C_SUM = SPAN_C_OTHERI + 1;
331var SPAN_C_VAL = SPAN_C_SUM + 1;
332var SPAN_C_OPP = SPAN_C_VAL + 1;
333
334var ACTIVE_LINE_SPAN = 1;
335var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700336var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
337var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700338
339var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
340var ADD_LINETO = ADD_MOVETO + 1;
341var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700342var ADD_CONICTO = ADD_QUADTO + 1;
343var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700344var ADD_CLOSE = ADD_CUBICTO + 1;
345var ADD_FILL = ADD_CLOSE + 1;
346
347var PATH_LINE = ADD_FILL + 1;
348var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700349var PATH_CONIC = PATH_QUAD + 1;
350var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700351
352var INTERSECT_LINE = PATH_CUBIC + 1;
353var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
354var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
355var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
356var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
357var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
358var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
359var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
360var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700361var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
362var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
363var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
364var INTERSECT_CONIC = INTERSECT_CONIC_LINE_NO + 1;
365var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
366var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
367var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700368var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
369var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
370var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
371var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
372var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
373var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
374var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
375var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
376var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
377var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
378var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
379var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
380var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
381var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
382// FIXME: add cubic 5- 9
383var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
384
385var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
386var SORT_BINARY = SORT_UNARY + 1;
387
388var OP_DIFFERENCE = SORT_BINARY + 1;
389var OP_INTERSECT = OP_DIFFERENCE + 1;
390var OP_UNION = OP_INTERSECT + 1;
391var OP_XOR = OP_UNION + 1;
392
393var MARK_LINE = OP_XOR + 1;
394var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700395var MARK_CONIC = MARK_QUAD + 1;
396var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700397var MARK_DONE_LINE = MARK_CUBIC + 1;
398var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700399var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
400var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700401var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
402var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700403var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
404var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700405var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
406var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700407var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
408var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700409var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
410var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700411var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
412var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700413var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
414var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700415var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
416var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700417var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
418
419var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
420var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
421
caryclark624637c2015-05-11 07:21:27 -0700422var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700423var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700424
caryclark54359292015-03-26 07:52:43 -0700425var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700426
caryclark624637c2015-05-11 07:21:27 -0700427var COIN_MAIN_SPAN = ACTIVE_OP + 1;
428var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
429
430var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700431
432var REC_TYPE_UNKNOWN = -1;
433var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700434var REC_TYPE_PATH2 = 1;
435var REC_TYPE_SECT = 2;
436var REC_TYPE_ACTIVE = 3;
437var REC_TYPE_ADD = 4;
438var REC_TYPE_SORT = 5;
439var REC_TYPE_OP = 6;
440var REC_TYPE_MARK = 7;
441var REC_TYPE_COMPUTED = 8;
442var REC_TYPE_COIN = 9;
443var REC_TYPE_ANGLE = 10;
444var REC_TYPE_ACTIVE_OP = 11;
445var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700446var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700447var REC_TYPE_COINCIDENCE = 14;
448var REC_TYPE_LAST = REC_TYPE_COINCIDENCE;
caryclarkdac1d172014-06-17 05:15:38 -0700449
450function strs_to_nums(strs) {
451 var result = [];
452 for (var idx = 1; idx < strs.length; ++idx) {
453 var str = strs[idx];
454 var num = parseFloat(str);
455 if (isNaN(num)) {
456 result.push(str);
457 } else {
458 result.push(num);
459 }
460 }
461 return result;
462}
463
464function filter_str_by(id, str, regex, array) {
465 if (regex.test(str)) {
466 var strs = regex.exec(str);
467 var result = strs_to_nums(strs);
468 array.push(id);
469 array.push(result);
470 return true;
471 }
472 return false;
473}
474
475function construct_regexp2(pattern) {
476 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
477 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
478 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700479 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700480 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
481 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
482 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700483 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700484 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
485 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
486 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700487 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700488 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700489 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700490 escape = escape.replace(/NUM/g, "(-?\\d+)");
491 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
492 return new RegExp(escape, 'i');
493}
494
495function construct_regexp2c(pattern) {
496 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
497 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700498 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700499 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700500 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
501 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700502 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700503 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700504 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700505 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 -0700506 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700507 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700508 escape = escape.replace(/OPER/g, "[a-z]+");
509 escape = escape.replace(/PATH/g, "pathB?");
510 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700511 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700512 escape = escape.replace(/NUM/g, "(-?\\d+)");
513 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
514 return new RegExp(escape, 'i');
515}
516
517function match_regexp(str, lineNo, array, id, pattern) {
518 var regex = construct_regexp2(pattern);
519 if (filter_str_by(id, str, regex, array)) {
520 return true;
521 }
522 regex = construct_regexp2c(pattern);
523 return filter_str_by(id, str, regex, array);
524}
525
526function endsWith(str, suffix) {
527 return str.indexOf(suffix, str.length - suffix.length) !== -1;
528}
529
530function parse_all(test) {
531 var lines = test.match(/[^\r\n]+/g);
532 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
533 var record = [];
534 var recType = REC_TYPE_UNKNOWN;
535 var lastLineNo;
536 var moveX, moveY;
537 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
538 var line = lines[lineNo];
539 if (line.length == 0) {
540 continue;
541 }
542 var opStart = "SkOpSegment::";
543 if (line.lastIndexOf(opStart, 0) === 0) {
544 line = line.substr(opStart.length);
545 }
546 var angleStart = "SkOpAngle::";
547 if (line.lastIndexOf(angleStart, 0) === 0) {
548 line = line.substr(angleStart.length);
549 }
caryclark624637c2015-05-11 07:21:27 -0700550 var coinStart = "SkOpCoincidence::";
551 if (line.lastIndexOf(coinStart, 0) === 0) {
552 line = line.substr(coinStart.length);
553 }
caryclark54359292015-03-26 07:52:43 -0700554 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700555 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700556 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclarkdac1d172014-06-17 05:15:38 -0700557 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700558 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700559 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
560 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
561 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
562 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
563 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700564 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700565 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
566 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
567 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
568 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
569 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700570 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700571 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
572 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
573 : REC_TYPE_UNKNOWN;
574 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
575 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
576 if (recType != REC_TYPE_UNKNOWN) {
577 records.push(recType);
578 records.push(lastLineNo);
579 records.push(record);
580 }
581 record = [];
582 recType = type;
583 lastLineNo = lineNo;
584 }
585 var found = false;
586 switch (recType) {
587 case REC_TYPE_ACTIVE:
588 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700589" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700590 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700591" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700592 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700593" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700594 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700595" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
596 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
597" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
598 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
599" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
600 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
601" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
602 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
603" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700604 );
605 break;
606 case REC_TYPE_ACTIVE_OP:
607 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
608" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
609 );
610 break;
611 case REC_TYPE_ADD:
612 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
613 moveX = record[1][0];
614 moveY = record[1][1];
615 found = true;
616 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
617 record[1].unshift(moveY);
618 record[1].unshift(moveX);
619 moveX = record[1][2];
620 moveY = record[1][3];
621 found = true;
622 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
623 record[1].unshift(moveY);
624 record[1].unshift(moveX);
625 moveX = record[1][4];
626 moveY = record[1][5];
627 found = true;
caryclark1049f122015-04-20 08:31:59 -0700628 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
629 record[1].unshift(moveY);
630 record[1].unshift(moveX);
631 moveX = record[1][4];
632 moveY = record[1][5];
633 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700634 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
635 record[1].unshift(moveY);
636 record[1].unshift(moveX);
637 moveX = record[1][6];
638 moveY = record[1][7];
639 found = true;
640 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
641 found = true;
642 } else {
643 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
644 }
645 break;
caryclark54359292015-03-26 07:52:43 -0700646 case REC_TYPE_AFTERPART:
647 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL")
648 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL")
caryclark1049f122015-04-20 08:31:59 -0700649 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL")
caryclark54359292015-03-26 07:52:43 -0700650 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL")
651 break;
caryclarkdac1d172014-06-17 05:15:38 -0700652 case REC_TYPE_ANGLE:
653 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700654"[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");
655 break;
656 case REC_TYPE_COIN:
657 found = true;
658 break;
caryclark624637c2015-05-11 07:21:27 -0700659 case REC_TYPE_COINCIDENCE:
660 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
661" + id=IDX t=T_VAL tEnd=T_VAL"
662 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
663" - id=IDX t=T_VAL tEnd=T_VAL"
664 );
665 break;
caryclarkdac1d172014-06-17 05:15:38 -0700666 case REC_TYPE_COMPUTED:
667 found = line == "computed quadratics given"
668 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
669 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
670 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700671 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700672 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
673 );
674 break;
675 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700676 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
677 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700678 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700679 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
680 );
681 break;
682 case REC_TYPE_PATH2:
683 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
684 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700685 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700686 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700687 );
688 break;
689 case REC_TYPE_SECT:
690 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
691" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
692 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
693" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
694 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
695" no intersect LINE_VAL LINE_VAL"
696 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
697" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
698 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
699" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
700 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
701" no intersect QUAD_VAL LINE_VAL"
702 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
703" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
704 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
705" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
706 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
707" no intersect QUAD_VAL QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700708 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
709" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
710 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
711" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
712 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
713" no intersect CONIC_VAL LINE_VAL"
714 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
715" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
716 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
717" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
718 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
719" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700720 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
721" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
722 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
723" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
724 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
725" 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"
726 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
727" no intersect CUBIC_VAL LINE_VAL"
728 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
729" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
730 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
731" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
732 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
733" 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"
734 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
735" 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"
736 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
737" no intersect CUBIC_VAL QUAD_VAL"
738 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
739" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
740 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
741" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
742 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
743" 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"
744 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
745" 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"
746 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
747" no intersect CUBIC_VAL CUBIC_VAL"
748 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
749" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
750 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
751" no self intersect CUBIC_VAL"
752 );
753 break;
754 case REC_TYPE_SORT:
755 var hasDone = / done/.test(line);
756 var hasUnorderable = / unorderable/.test(line);
757 var hasSmall = / small/.test(line);
758 var hasTiny = / tiny/.test(line);
759 var hasOperand = / operand/.test(line);
760 var hasStop = / stop/.test(line);
761 line.replace(/[ a-z]+$/, "");
762 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
763" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
764 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
765" [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"
766 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
767" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
768 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
769" [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"
770 );
771 if (found) {
772 record[1].push(hasDone);
773 record[1].push(hasUnorderable);
774 record[1].push(hasSmall);
775 record[1].push(hasTiny);
776 record[1].push(hasOperand);
777 record[1].push(hasStop);
778 }
779 break;
caryclark03b03ca2015-04-23 09:13:37 -0700780 case REC_TYPE_TOP:
781 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
782" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
783 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
784" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
785 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
786" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
787 );
788 break;
caryclarkdac1d172014-06-17 05:15:38 -0700789 case REC_TYPE_MARK:
790 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700791" 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 -0700792 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700793" 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 -0700794 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
795" 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 -0700796 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700797" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
798 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
799" 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"
800 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
801" 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 -0700802 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
803" 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 -0700804 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
805" 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 -0700806 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
807" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
808 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
809" 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 -0700810 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
811" 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 -0700812 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
813" 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 -0700814 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700815" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700816 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
817" last segment=IDX span=IDX windSum=OPT");
caryclarkdac1d172014-06-17 05:15:38 -0700818 break;
819 case REC_TYPE_OP:
820 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
821 || line.lastIndexOf("operator<", 0) === 0) {
822 found = true;
823 break;
824 }
caryclark54359292015-03-26 07:52:43 -0700825 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700826 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700827 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700828 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
829 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
830 );
831 break;
832 case REC_TYPE_UNKNOWN:
833 found = true;
834 break;
835 }
836 if (!found) {
837 console.log(line + " [" + lineNo + "] of type " + type + " not found");
838 }
839 }
840 if (recType != REC_TYPE_UNKNOWN) {
841 records.push(recType);
842 records.push(lastLineNo);
843 records.push(record);
844 }
845 if (records.length >= 1) {
846 tests[testIndex] = records;
847 testLines[testIndex] = lines;
848 }
849}
850
851function init(test) {
852 var canvas = document.getElementById('canvas');
853 if (!canvas.getContext) return;
854 ctx = canvas.getContext('2d');
855 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
856 var unscaledWidth = window.innerWidth - 20;
857 var unscaledHeight = window.innerHeight - 20;
858 screenWidth = unscaledWidth;
859 screenHeight = unscaledHeight;
860 canvas.width = unscaledWidth * resScale;
861 canvas.height = unscaledHeight * resScale;
862 canvas.style.width = unscaledWidth + 'px';
863 canvas.style.height = unscaledHeight + 'px';
864 if (resScale != 1) {
865 ctx.scale(resScale, resScale);
866 }
867 xmin = Infinity;
868 xmax = -Infinity;
869 ymin = Infinity;
870 ymax = -Infinity;
871 hasPath = hasComputedPath = false;
872 firstActiveSpan = -1;
873 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
874 var recType = test[tIndex];
875 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
876 console.log("unknown rec type: " + recType);
877 throw "stop execution";
878 }
879 var records = test[tIndex + 2];
880 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
881 var fragType = records[recordIndex];
882 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
883 console.log("unknown in range frag type: " + fragType);
884 throw "stop execution";
885 }
886 var frags = records[recordIndex + 1];
887 var first = 0;
888 var last = -1;
889 var first2 = 0;
890 var last2 = 0;
891 switch (recType) {
892 case REC_TYPE_COMPUTED:
893 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
894 break;
895 }
896 hasComputedPath = true;
897 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700898 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700899 switch (fragType) {
900 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700901 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700902 break;
caryclark1049f122015-04-20 08:31:59 -0700903 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700904 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700905 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700906 break;
907 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700908 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700909 break;
910 default:
911 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
912 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
913 throw "stop execution";
914 }
915 if (recType == REC_TYPE_PATH) {
916 hasPath = true;
917 }
918 break;
caryclark54359292015-03-26 07:52:43 -0700919 case REC_TYPE_PATH2:
920 first = 1;
921 switch (fragType) {
922 case PATH_LINE:
923 last = 5;
924 break;
caryclark1049f122015-04-20 08:31:59 -0700925 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700926 case PATH_QUAD:
927 last = 7;
928 break;
929 case PATH_CUBIC:
930 last = 9;
931 break;
932 default:
933 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
934 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
935 throw "stop execution";
936 }
937 if (recType == REC_TYPE_PATH2) {
938 hasPath = true;
939 }
940 break;
caryclarkdac1d172014-06-17 05:15:38 -0700941 case REC_TYPE_ACTIVE:
942 if (firstActiveSpan < 0) {
943 firstActiveSpan = tIndex;
944 }
945 first = 1;
946 switch (fragType) {
947 case ACTIVE_LINE_SPAN:
948 last = 5;
949 break;
caryclark1049f122015-04-20 08:31:59 -0700950 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700951 case ACTIVE_QUAD_SPAN:
952 last = 7;
953 break;
954 case ACTIVE_CUBIC_SPAN:
955 last = 9;
956 break;
957 default:
958 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
959 throw "stop execution";
960 }
961 break;
962 case REC_TYPE_ADD:
963 switch (fragType) {
964 case ADD_MOVETO:
965 break;
966 case ADD_LINETO:
967 last = 4;
968 break;
caryclark1049f122015-04-20 08:31:59 -0700969 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700970 case ADD_QUADTO:
971 last = 6;
972 break;
973 case ADD_CUBICTO:
974 last = 8;
975 break;
976 case ADD_CLOSE:
977 case ADD_FILL:
978 break;
979 default:
980 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
981 throw "stop execution";
982 }
983 break;
caryclark54359292015-03-26 07:52:43 -0700984 case REC_TYPE_AFTERPART:
985 switch (fragType) {
986 case PATH_LINE:
987 last = 4;
988 break;
caryclark1049f122015-04-20 08:31:59 -0700989 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700990 case PATH_QUAD:
991 last = 6;
992 break;
993 case PATH_CUBIC:
994 last = 8;
995 break;
996 default:
997 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
998 throw "stop execution";
999 }
1000 break;
caryclarkdac1d172014-06-17 05:15:38 -07001001 case REC_TYPE_SECT:
1002 switch (fragType) {
1003 case INTERSECT_LINE:
1004 first = 1; last = 5; first2 = 8; last2 = 12;
1005 break;
1006 case INTERSECT_LINE_2:
1007 first = 1; last = 5; first2 = 11; last2 = 15;
1008 break;
1009 case INTERSECT_LINE_NO:
1010 first = 0; last = 4; first2 = 4; last2 = 8;
1011 break;
caryclark1049f122015-04-20 08:31:59 -07001012 case INTERSECT_CONIC_LINE:
1013 first = 1; last = 7; first2 = 11; last2 = 15;
1014 break;
caryclarkdac1d172014-06-17 05:15:38 -07001015 case INTERSECT_QUAD_LINE:
1016 first = 1; last = 7; first2 = 10; last2 = 14;
1017 break;
caryclark1049f122015-04-20 08:31:59 -07001018 case INTERSECT_CONIC_LINE_2:
1019 first = 1; last = 7; first2 = 14; last2 = 18;
1020 break;
caryclarkdac1d172014-06-17 05:15:38 -07001021 case INTERSECT_QUAD_LINE_2:
1022 first = 1; last = 7; first2 = 13; last2 = 17;
1023 break;
caryclark1049f122015-04-20 08:31:59 -07001024 case INTERSECT_CONIC_LINE_NO:
1025 first = 0; last = 6; first2 = 7; last2 = 11;
1026 break;
caryclarkdac1d172014-06-17 05:15:38 -07001027 case INTERSECT_QUAD_LINE_NO:
1028 first = 0; last = 6; first2 = 6; last2 = 10;
1029 break;
caryclark1049f122015-04-20 08:31:59 -07001030 case INTERSECT_CONIC:
1031 first = 1; last = 7; first2 = 11; last2 = 17;
1032 break;
caryclarkdac1d172014-06-17 05:15:38 -07001033 case INTERSECT_QUAD:
1034 first = 1; last = 7; first2 = 10; last2 = 16;
1035 break;
caryclark1049f122015-04-20 08:31:59 -07001036 case INTERSECT_CONIC_2:
1037 first = 1; last = 7; first2 = 14; last2 = 20;
1038 break;
caryclarkdac1d172014-06-17 05:15:38 -07001039 case INTERSECT_QUAD_2:
1040 first = 1; last = 7; first2 = 13; last2 = 19;
1041 break;
caryclark1049f122015-04-20 08:31:59 -07001042 case INTERSECT_CONIC_NO:
1043 first = 0; last = 6; first2 = 7; last2 = 13;
1044 break;
caryclarkdac1d172014-06-17 05:15:38 -07001045 case INTERSECT_QUAD_NO:
1046 first = 0; last = 6; first2 = 6; last2 = 12;
1047 break;
1048 case INTERSECT_SELF_CUBIC:
1049 first = 1; last = 9;
1050 break;
1051 case INTERSECT_SELF_CUBIC_NO:
1052 first = 0; last = 8;
1053 break;
1054 case INTERSECT_CUBIC_LINE:
1055 first = 1; last = 9; first2 = 12; last2 = 16;
1056 break;
1057 case INTERSECT_CUBIC_LINE_2:
1058 first = 1; last = 9; first2 = 15; last2 = 19;
1059 break;
1060 case INTERSECT_CUBIC_LINE_3:
1061 first = 1; last = 9; first2 = 18; last2 = 22;
1062 break;
1063 case INTERSECT_CUBIC_LINE_NO:
1064 first = 0; last = 8; first2 = 8; last2 = 12;
1065 break;
1066 case INTERSECT_CUBIC_QUAD:
1067 first = 1; last = 9; first2 = 12; last2 = 18;
1068 break;
1069 case INTERSECT_CUBIC_QUAD_2:
1070 first = 1; last = 9; first2 = 15; last2 = 21;
1071 break;
1072 case INTERSECT_CUBIC_QUAD_3:
1073 first = 1; last = 9; first2 = 18; last2 = 24;
1074 break;
1075 case INTERSECT_CUBIC_QUAD_4:
1076 first = 1; last = 9; first2 = 21; last2 = 27;
1077 break;
1078 case INTERSECT_CUBIC_QUAD_NO:
1079 first = 0; last = 8; first2 = 8; last2 = 14;
1080 break;
1081 case INTERSECT_CUBIC:
1082 first = 1; last = 9; first2 = 12; last2 = 20;
1083 break;
1084 case INTERSECT_CUBIC_2:
1085 first = 1; last = 9; first2 = 15; last2 = 23;
1086 break;
1087 case INTERSECT_CUBIC_3:
1088 first = 1; last = 9; first2 = 18; last2 = 26;
1089 break;
1090 case INTERSECT_CUBIC_4:
1091 first = 1; last = 9; first2 = 21; last2 = 29;
1092 break;
1093 case INTERSECT_CUBIC_NO:
1094 first = 0; last = 8; first2 = 8; last2 = 16;
1095 break;
1096 default:
1097 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
1098 throw "stop execution";
1099 }
1100 break;
1101 default:
1102 continue;
1103 }
1104 for (var idx = first; idx < last; idx += 2) {
1105 xmin = Math.min(xmin, frags[idx]);
1106 xmax = Math.max(xmax, frags[idx]);
1107 ymin = Math.min(ymin, frags[idx + 1]);
1108 ymax = Math.max(ymax, frags[idx + 1]);
1109 }
1110 for (var idx = first2; idx < last2; idx += 2) {
1111 xmin = Math.min(xmin, frags[idx]);
1112 xmax = Math.max(xmax, frags[idx]);
1113 ymin = Math.min(ymin, frags[idx + 1]);
1114 ymax = Math.max(ymax, frags[idx + 1]);
1115 }
1116 }
1117 }
1118 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1119 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1120 var recType = test[tIndex];
1121 var records = test[tIndex + 2];
1122 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1123 var fragType = records[recordIndex];
1124 var frags = records[recordIndex + 1];
1125 switch (recType) {
1126 case REC_TYPE_ACTIVE_OP:
1127 if (!draw_op) {
1128 break;
1129 }
1130 {
1131 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1132 curve_extremes(curve, angleBounds);
1133 }
1134 break;
1135 case REC_TYPE_ANGLE:
1136 if (!draw_angle) {
1137 break;
1138 }
caryclark54359292015-03-26 07:52:43 -07001139 {
caryclarkdac1d172014-06-17 05:15:38 -07001140 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1141 curve_extremes(curve, angleBounds);
1142 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1143 curve_extremes(curve, angleBounds);
1144 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1145 }
1146 break;
caryclark624637c2015-05-11 07:21:27 -07001147 case REC_TYPE_COINCIDENCE:
1148 if (!draw_coincidence) {
1149 break;
1150 }
1151 {
1152 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1153 curve_extremes(curve, angleBounds);
1154 }
1155 break;
caryclarkdac1d172014-06-17 05:15:38 -07001156 case REC_TYPE_SORT:
1157 if (!draw_sort) {
1158 break;
1159 }
1160 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1161 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1162 curve_extremes(curve, angleBounds);
1163 }
1164 break;
caryclark03b03ca2015-04-23 09:13:37 -07001165 case REC_TYPE_TOP:
1166 if (!draw_top) {
1167 break;
1168 }
1169 {
1170 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1171 curve_extremes(curve, angleBounds);
1172 }
1173 break;
caryclarkdac1d172014-06-17 05:15:38 -07001174 }
1175 }
1176 }
1177 xmin = Math.min(xmin, angleBounds[0]);
1178 ymin = Math.min(ymin, angleBounds[1]);
1179 xmax = Math.max(xmax, angleBounds[2]);
1180 ymax = Math.max(ymax, angleBounds[3]);
1181 setScale(xmin, xmax, ymin, ymax);
1182 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001183 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001184 }
1185 if (hasPath == true && hasComputedPath == false && draw_computed) {
1186 draw_computed = 0;
1187 }
1188}
1189
1190function curveByID(test, id) {
caryclark54359292015-03-26 07:52:43 -07001191 var tIndex = -3;
1192 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001193 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001194 if (recType == REC_TYPE_OP) {
1195 continue;
1196 }
1197 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001198 return [];
1199 }
1200 var records = test[tIndex + 2];
1201 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1202 var fragType = records[recordIndex];
1203 var frags = records[recordIndex + 1];
1204 if (frags[0] == id) {
1205 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001206 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001207 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001208 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001209 return [frags[1], frags[2], frags[3], frags[4],
1210 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001211 case PATH_CONIC:
1212 return [frags[1], frags[2], frags[3], frags[4],
1213 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001214 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001215 return [frags[1], frags[2], frags[3], frags[4],
1216 frags[5], frags[6], frags[7], frags[8]];
1217 }
1218 }
1219 }
caryclarkdac1d172014-06-17 05:15:38 -07001220 }
1221 return [];
1222}
1223
1224function curvePartialByID(test, id, t0, t1) {
caryclark54359292015-03-26 07:52:43 -07001225 var tIndex = -3;
1226 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001227 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001228 if (recType == REC_TYPE_OP) {
1229 continue;
1230 }
1231 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001232 return [];
1233 }
1234 var records = test[tIndex + 2];
1235 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1236 var fragType = records[recordIndex];
1237 var frags = records[recordIndex + 1];
1238 if (frags[0] == id) {
1239 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001240 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001241 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001242 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001243 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1244 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001245 case PATH_CONIC:
1246 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1247 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001248 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001249 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1250 frags[5], frags[6], frags[7], frags[8], t0, t1);
1251 }
1252 }
1253 }
caryclarkdac1d172014-06-17 05:15:38 -07001254 }
1255 return [];
1256}
1257
1258function idByCurve(test, frag, type) {
caryclark54359292015-03-26 07:52:43 -07001259 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001260 while (tIndex < test.length) {
1261 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001262 if (recType != REC_TYPE_PATH) {
1263 ++tIndex;
1264 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001265 }
1266 var records = test[tIndex + 2];
1267 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1268 var fragType = records[recordIndex];
1269 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001270 if (frag.length != frags.length - 1) {
1271 continue;
1272 }
caryclarkdac1d172014-06-17 05:15:38 -07001273 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001274 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001275 if (frag[0] != frags[1] || frag[1] != frags[2]
1276 || frag[2] != frags[3] || frag[3] != frags[4]) {
1277 continue;
1278 }
1279 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001280 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001281 if (frag[0] != frags[1] || frag[1] != frags[2]
1282 || frag[2] != frags[3] || frag[3] != frags[4]
1283 || frag[4] != frags[5] || frag[5] != frags[6]) {
1284 continue;
1285 }
1286 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001287 case PATH_CONIC:
1288 if (frag[0] != frags[1] || frag[1] != frags[2]
1289 || frag[2] != frags[3] || frag[3] != frags[4]
1290 || frag[4] != frags[5] || frag[5] != frags[6]
1291 || frag[6] != frags[7]) {
1292 continue;
1293 }
1294 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001295 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001296 if (frag[0] != frags[1] || frag[1] != frags[2]
1297 || frag[2] != frags[3] || frag[3] != frags[4]
1298 || frag[4] != frags[5] || frag[5] != frags[6]
1299 || frag[6] != frags[7] || frag[7] != frags[8]) {
1300 continue;
1301 }
1302 return frags[0];
1303 }
1304 }
1305 ++tIndex;
1306 }
1307 return -1;
1308}
1309
1310function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001311 var length = curve.length == 7 ? 6 : curve.length;
caryclarkdac1d172014-06-17 05:15:38 -07001312 for (var index = 0; index < curve.length; index += 2) {
1313 var x = curve[index];
1314 var y = curve[index + 1];
1315 bounds[0] = Math.min(bounds[0], x);
1316 bounds[1] = Math.min(bounds[1], y);
1317 bounds[2] = Math.max(bounds[2], x);
1318 bounds[3] = Math.max(bounds[3], y);
1319 }
1320}
1321
1322function setScale(x0, x1, y0, y1) {
1323 var srcWidth = x1 - x0;
1324 var srcHeight = y1 - y0;
1325 var usableWidth = screenWidth;
1326 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1327 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1328 usableWidth -= (xDigits + yDigits) * 10;
1329 usableWidth -= decimal_places * 10;
1330 if (draw_legend) {
1331 usableWidth -= 40;
1332 }
1333 var hscale = usableWidth / srcWidth;
1334 var vscale = screenHeight / srcHeight;
1335 scale = Math.min(hscale, vscale);
1336 var invScale = 1 / scale;
1337 var sxmin = x0 - invScale * 5;
1338 var symin = y0 - invScale * 10;
1339 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1340 var symax = y1 + invScale * 10;
1341 srcWidth = sxmax - sxmin;
1342 srcHeight = symax - symin;
1343 hscale = usableWidth / srcWidth;
1344 vscale = screenHeight / srcHeight;
1345 scale = Math.min(hscale, vscale);
1346 srcLeft = sxmin;
1347 srcTop = symin;
1348}
1349
1350function drawArc(curve, op, from, to) {
1351 var type = PATH_LINE + (curve.length / 2 - 2);
1352 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1353 var dy = pt.y - curve[1];
1354 var dx = pt.x - curve[0];
1355 var dist = Math.sqrt(dy * dy + dx * dx);
1356 var _dist = dist * scale;
1357 var angle = Math.atan2(dy, dx);
1358 var _px = (curve[0] - srcLeft) * scale;
1359 var _py = (curve[1] - srcTop) * scale;
1360 var divisor = 4;
1361 var endDist;
1362 do {
1363 var ends = [];
1364 for (var index = -1; index <= 1; index += 2) {
1365 var px = Math.cos(index * Math.PI / divisor);
1366 var py = Math.sin(index * Math.PI / divisor);
1367 ends.push(px);
1368 ends.push(py);
1369 }
1370 var endDx = (ends[2] - ends[0]) * scale * dist;
1371 var endDy = (ends[3] - ends[1]) * scale * dist;
1372 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1373 if (endDist < 100) {
1374 break;
1375 }
1376 divisor *= 2;
1377 } while (true);
1378 if (endDist < 30) {
1379 return;
1380 }
1381 if (op) {
1382 divisor *= 2;
1383 }
1384 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1385 ctx.beginPath();
1386 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1387 ctx.stroke();
1388 var saveAlign = ctx.textAlign;
1389 var saveStyle = ctx.fillStyle;
1390 var saveFont = ctx.font;
1391 ctx.textAlign = "center";
1392 ctx.fillStyle = "black";
1393 ctx.font = "normal 24px Arial";
1394 divisor *= 0.8;
1395 for (var index = -1; index <= 1; index += 2) {
1396 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1397 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1398 var _px = (px - srcLeft) * scale;
1399 var _py = (py - srcTop) * scale;
1400 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1401 }
1402 ctx.textAlign = saveAlign;
1403 ctx.fillStyle = saveStyle;
1404 ctx.font = saveFont;
1405}
1406
1407function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001408 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1409 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001410 var x = drawnPts[pts];
1411 var y = drawnPts[pts + 1];
1412 if (px == x && py == y) {
1413 return;
1414 }
1415 }
1416 drawnPts.push(px);
1417 drawnPts.push(py);
1418 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1419 var _px = (px - srcLeft) * scale;
1420 var _py = (py - srcTop) * scale;
1421 ctx.beginPath();
1422 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1423 ctx.closePath();
1424 if (end) {
1425 ctx.fill();
1426 } else {
1427 ctx.stroke();
1428 }
1429 if (debug_xy) {
1430 ctx.textAlign = "left";
1431 ctx.fillText(label, _px + 5, _py);
1432 }
1433}
1434
caryclark1049f122015-04-20 08:31:59 -07001435function coordCount(curveType) {
1436 switch (curveType) {
1437 case PATH_LINE:
1438 return 4;
1439 case PATH_QUAD:
1440 return 6;
1441 case PATH_CONIC:
1442 return 6;
1443 case PATH_CUBIC:
1444 return 8;
1445 }
1446 return -1;
1447}
1448
caryclarkdac1d172014-06-17 05:15:38 -07001449function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001450 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001451 for (var idx = 0; idx < count; idx += 2) {
1452 if (!drawControls && idx != 0 && idx != count - 2) {
1453 continue;
1454 }
1455 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1456 }
1457}
1458
1459function drawControlLines(curve, curveType, drawEnd) {
1460 if (curveType == PATH_LINE) {
1461 return;
1462 }
1463 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1464 drawLine(curve[0], curve[1], curve[2], curve[3]);
1465 drawLine(curve[2], curve[3], curve[4], curve[5]);
1466 if (curveType == PATH_CUBIC) {
1467 drawLine(curve[4], curve[5], curve[6], curve[7]);
1468 if (drawEnd > 1) {
1469 drawLine(curve[6], curve[7], curve[0], curve[1]);
1470 if (drawEnd > 2) {
1471 drawLine(curve[0], curve[1], curve[4], curve[5]);
1472 drawLine(curve[6], curve[7], curve[2], curve[3]);
1473 }
1474 }
1475 } else if (drawEnd > 1) {
1476 drawLine(curve[4], curve[5], curve[0], curve[1]);
1477 }
1478}
1479
1480function pointAtT(curve, curveType, t) {
1481 var xy = {};
1482 switch (curveType) {
1483 case PATH_LINE:
1484 var a = 1 - t;
1485 var b = t;
1486 xy.x = a * curve[0] + b * curve[2];
1487 xy.y = a * curve[1] + b * curve[3];
1488 break;
1489 case PATH_QUAD:
1490 var one_t = 1 - t;
1491 var a = one_t * one_t;
1492 var b = 2 * one_t * t;
1493 var c = t * t;
1494 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1495 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1496 break;
caryclark1049f122015-04-20 08:31:59 -07001497 case PATH_CONIC:
1498 var one_t = 1 - t;
1499 var a = one_t * one_t;
1500 var b = 2 * one_t * t;
1501 var c = t * t;
1502 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1503 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1504 var d = a + b * curve[6] + c;
1505 xy.x /= d;
1506 xy.y /= d;
1507 break;
caryclarkdac1d172014-06-17 05:15:38 -07001508 case PATH_CUBIC:
1509 var one_t = 1 - t;
1510 var one_t2 = one_t * one_t;
1511 var a = one_t2 * one_t;
1512 var b = 3 * one_t2 * t;
1513 var t2 = t * t;
1514 var c = 3 * one_t * t2;
1515 var d = t2 * t;
1516 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1517 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1518 break;
1519 }
1520 return xy;
1521}
1522
1523function drawPointAtT(curve, curveType) {
1524 var x, y;
1525 var xy = pointAtT(curve, curveType, curveT);
1526 drawPoint(xy.x, xy.y, true);
1527 if (!draw_intersectT) {
1528 return;
1529 }
1530 ctx.fillStyle = "red";
1531 drawTAtPointUp(xy.x, xy.y, curveT);
1532}
1533
1534function drawTAtPointUp(px, py, t) {
1535 var label = t.toFixed(decimal_places);
1536 var _px = (px - srcLeft)* scale;
1537 var _py = (py - srcTop) * scale;
1538 ctx.fillText(label, _px + 5, _py - 10);
1539}
1540
1541function drawTAtPointDown(px, py, t) {
1542 var label = t.toFixed(decimal_places);
1543 var _px = (px - srcLeft)* scale;
1544 var _py = (py - srcTop) * scale;
1545 ctx.fillText(label, _px + 5, _py + 10);
1546}
1547
1548function alreadyDrawnLine(x1, y1, x2, y2) {
1549 if (collect_bounds) {
1550 if (focus_enabled) {
1551 focusXmin = Math.min(focusXmin, x1, x2);
1552 focusYmin = Math.min(focusYmin, y1, y2);
1553 focusXmax = Math.max(focusXmax, x1, x2);
1554 focusYmax = Math.max(focusYmax, y1, y2);
1555 }
1556 return true;
1557 }
1558 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1559 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1560 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1561 return true;
1562 }
1563 }
1564 drawnLines.push(x1);
1565 drawnLines.push(y1);
1566 drawnLines.push(x2);
1567 drawnLines.push(y2);
1568 return false;
1569}
1570
1571function drawLine(x1, y1, x2, y2) {
1572 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1573 return;
1574 }
1575 ctx.beginPath();
1576 ctx.moveTo((x1 - srcLeft) * scale,
1577 (y1 - srcTop) * scale);
1578 ctx.lineTo((x2 - srcLeft) * scale,
1579 (y2 - srcTop) * scale);
1580 ctx.stroke();
1581}
1582
1583function linePartial(x1, y1, x2, y2, t1, t2) {
1584 var dx = x1 - x2;
1585 var dy = y1 - y2;
1586 var array = [
1587 x1 - t1 * dx,
1588 y1 - t1 * dy,
1589 x1 - t2 * dx,
1590 y1 - t2 * dy
1591 ];
1592 return array;
1593}
1594
1595function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1596 var a = linePartial(x1, y1, x2, y2, t1, t2);
1597 var ax = a[0];
1598 var ay = a[1];
1599 var bx = a[2];
1600 var by = a[3];
1601 if (alreadyDrawnLine(ax, ay, bx, by)) {
1602 return;
1603 }
1604 ctx.beginPath();
1605 ctx.moveTo((ax - srcLeft) * scale,
1606 (ay - srcTop) * scale);
1607 ctx.lineTo((bx - srcLeft) * scale,
1608 (by - srcTop) * scale);
1609 ctx.stroke();
1610}
1611
1612function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1613 if (collect_bounds) {
1614 if (focus_enabled) {
1615 focusXmin = Math.min(focusXmin, x1, x2, x3);
1616 focusYmin = Math.min(focusYmin, y1, y2, y3);
1617 focusXmax = Math.max(focusXmax, x1, x2, x3);
1618 focusYmax = Math.max(focusYmax, y1, y2, y3);
1619 }
1620 return true;
1621 }
1622 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1623 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1624 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1625 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1626 return true;
1627 }
1628 }
1629 drawnQuads.push(x1);
1630 drawnQuads.push(y1);
1631 drawnQuads.push(x2);
1632 drawnQuads.push(y2);
1633 drawnQuads.push(x3);
1634 drawnQuads.push(y3);
1635 return false;
1636}
1637
1638function drawQuad(x1, y1, x2, y2, x3, y3) {
1639 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1640 return;
1641 }
1642 ctx.beginPath();
1643 ctx.moveTo((x1 - srcLeft) * scale,
1644 (y1 - srcTop) * scale);
1645 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1646 (y2 - srcTop) * scale,
1647 (x3 - srcLeft) * scale,
1648 (y3 - srcTop) * scale);
1649 ctx.stroke();
1650}
1651
1652function interp(A, B, t) {
1653 return A + (B - A) * t;
1654}
1655
1656function interp_quad_coords(x1, x2, x3, t)
1657{
1658 var ab = interp(x1, x2, t);
1659 var bc = interp(x2, x3, t);
1660 var abc = interp(ab, bc, t);
1661 return abc;
1662}
1663
1664function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1665 var ax = interp_quad_coords(x1, x2, x3, t1);
1666 var ay = interp_quad_coords(y1, y2, y3, t1);
1667 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1668 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1669 var cx = interp_quad_coords(x1, x2, x3, t2);
1670 var cy = interp_quad_coords(y1, y2, y3, t2);
1671 var bx = 2*dx - (ax + cx)/2;
1672 var by = 2*dy - (ay + cy)/2;
1673 var array = [
1674 ax, ay, bx, by, cx, cy
1675 ];
1676 return array;
1677}
1678
1679function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1680 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1681 var ax = a[0];
1682 var ay = a[1];
1683 var bx = a[2];
1684 var by = a[3];
1685 var cx = a[4];
1686 var cy = a[5];
1687 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1688 return;
1689 }
1690 ctx.beginPath();
1691 ctx.moveTo((ax - srcLeft) * scale,
1692 (ay - srcTop) * scale);
1693 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1694 (by - srcTop) * scale,
1695 (cx - srcLeft) * scale,
1696 (cy - srcTop) * scale);
1697 ctx.stroke();
1698}
1699
caryclark1049f122015-04-20 08:31:59 -07001700function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1701 if (collect_bounds) {
1702 if (focus_enabled) {
1703 focusXmin = Math.min(focusXmin, x1, x2, x3);
1704 focusYmin = Math.min(focusYmin, y1, y2, y3);
1705 focusXmax = Math.max(focusXmax, x1, x2, x3);
1706 focusYmax = Math.max(focusYmax, y1, y2, y3);
1707 }
1708 return true;
1709 }
1710 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1711 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
1712 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1713 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1714 && w == drawnCubics[pts + 6]) {
1715 return true;
1716 }
1717 }
1718 drawnConics.push(x1);
1719 drawnConics.push(y1);
1720 drawnConics.push(x2);
1721 drawnConics.push(y2);
1722 drawnConics.push(x3);
1723 drawnConics.push(y3);
1724 drawnCubics.push(w);
1725 return false;
1726}
1727
1728var kMaxConicToQuadPOW2 = 5;
1729
1730function computeQuadPOW2(curve, tol) {
1731 var a = curve[6] - 1;
1732 var k = a / (4 * (2 + a));
1733 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1734 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1735
1736 var error = Math.sqrt(x * x + y * y);
1737 var pow2;
1738 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1739 if (error <= tol) {
1740 break;
1741 }
1742 error *= 0.25;
1743 }
1744 return pow2;
1745}
1746
1747function subdivide_w_value(w) {
1748 return Math.sqrt(0.5 + w * 0.5);
1749}
1750
1751function chop(curve, part1, part2) {
1752 var w = curve[6];
1753 var scale = 1 / (1 + w);
1754 part1[0] = curve[0];
1755 part1[1] = curve[1];
1756 part1[2] = (curve[0] + curve[2] * w) * scale;
1757 part1[3] = (curve[1] + curve[3] * w) * scale;
1758 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1759 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1760 part2[2] = (curve[2] * w + curve[4]) * scale;
1761 part2[3] = (curve[3] * w + curve[5]) * scale;
1762 part2[4] = curve[4];
1763 part2[5] = curve[5];
1764 part1[6] = part2[6] = subdivide_w_value(w);
1765}
1766
1767function subdivide(curve, level, pts) {
1768 if (0 == level) {
1769 pts.push(curve[2]);
1770 pts.push(curve[3]);
1771 pts.push(curve[4]);
1772 pts.push(curve[5]);
1773 } else {
1774 var part1 = [], part2 = [];
1775 chop(curve, part1, part2);
1776 --level;
1777 subdivide(part1, level, pts);
1778 subdivide(part2, level, pts);
1779 }
1780}
1781
1782function chopIntoQuadsPOW2(curve, pow2, pts) {
1783 subdivide(curve, pow2, pts);
1784 return 1 << pow2;
1785}
1786
1787function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1788 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1789 return;
1790 }
1791 ctx.beginPath();
1792 ctx.moveTo((x1 - srcLeft) * scale,
1793 (y1 - srcTop) * scale);
1794 var tol = 1 / scale;
1795 var curve = [x1, y1, x2, y2, x3, y3, w];
1796 var pow2 = computeQuadPOW2(curve, tol);
1797 var pts = [];
1798 chopIntoQuadsPOW2(curve, pow2, pts);
1799 for (var i = 0; i < pts.length; i += 4) {
1800 ctx.quadraticCurveTo(
1801 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1802 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1803 }
1804 ctx.stroke();
1805}
1806
1807function conic_eval_numerator(x1, x2, x3, w, t) {
1808 var src2w = x2 * w;
1809 var C = x1;
1810 var A = x3 - 2 * src2w + C;
1811 var B = 2 * (src2w - C);
1812 return (A * t + B) * t + C;
1813}
1814
1815
1816function conic_eval_denominator(w, t) {
1817 var B = 2 * (w - 1);
1818 var C = 1;
1819 var A = -B;
1820 return (A * t + B) * t + C;
1821}
1822
1823function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1824 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1825 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1826 var az = conic_eval_denominator(w, t1);
1827 var midT = (t1 + t2) / 2;
1828 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1829 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1830 var dz = conic_eval_denominator(w, midT);
1831 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1832 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1833 var cz = conic_eval_denominator(w, t2);
1834 var bx = 2 * dx - (ax + cx) / 2;
1835 var by = 2 * dy - (ay + cy) / 2;
1836 var bz = 2 * dz - (az + cz) / 2;
1837 var dt = t2 - t1;
1838 var dt_1 = 1 - dt;
1839 var partW = (1 + dt * (w - 1)) / Math.sqrt(dt * dt + 2 * dt * dt_1 * w + dt_1 * dt_1);
1840 var array = [
1841 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, partW
1842 ];
1843 return array;
1844}
1845
1846function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1847 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1848 var ax = a[0];
1849 var ay = a[1];
1850 var bx = a[2];
1851 var by = a[3];
1852 var cx = a[4];
1853 var cy = a[5];
1854 var w_ = a[6];
1855 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1856}
1857
caryclarkdac1d172014-06-17 05:15:38 -07001858function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1859 if (collect_bounds) {
1860 if (focus_enabled) {
1861 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1862 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1863 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1864 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1865 }
1866 return true;
1867 }
1868 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1869 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
1870 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1871 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1872 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1873 return true;
1874 }
1875 }
1876 drawnCubics.push(x1);
1877 drawnCubics.push(y1);
1878 drawnCubics.push(x2);
1879 drawnCubics.push(y2);
1880 drawnCubics.push(x3);
1881 drawnCubics.push(y3);
1882 drawnCubics.push(x4);
1883 drawnCubics.push(y4);
1884 return false;
1885}
1886
1887function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1888 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1889 return;
1890 }
1891 ctx.beginPath();
1892 ctx.moveTo((x1 - srcLeft) * scale,
1893 (y1 - srcTop) * scale);
1894 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1895 (y2 - srcTop) * scale,
1896 (x3 - srcLeft) * scale,
1897 (y3 - srcTop) * scale,
1898 (x4 - srcLeft) * scale,
1899 (y4 - srcTop) * scale);
1900 ctx.stroke();
1901}
1902
1903function interp_cubic_coords(x1, x2, x3, x4, t)
1904{
1905 var ab = interp(x1, x2, t);
1906 var bc = interp(x2, x3, t);
1907 var cd = interp(x3, x4, t);
1908 var abc = interp(ab, bc, t);
1909 var bcd = interp(bc, cd, t);
1910 var abcd = interp(abc, bcd, t);
1911 return abcd;
1912}
1913
1914function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1915 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1916 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1917 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1918 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1919 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1920 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1921 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1922 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1923 var mx = ex * 27 - ax * 8 - dx;
1924 var my = ey * 27 - ay * 8 - dy;
1925 var nx = fx * 27 - ax - dx * 8;
1926 var ny = fy * 27 - ay - dy * 8;
1927 var bx = (mx * 2 - nx) / 18;
1928 var by = (my * 2 - ny) / 18;
1929 var cx = (nx * 2 - mx) / 18;
1930 var cy = (ny * 2 - my) / 18;
1931 var array = [
1932 ax, ay, bx, by, cx, cy, dx, dy
1933 ];
1934 return array;
1935}
1936
1937function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1938 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
1939 var ax = a[0];
1940 var ay = a[1];
1941 var bx = a[2];
1942 var by = a[3];
1943 var cx = a[4];
1944 var cy = a[5];
1945 var dx = a[6];
1946 var dy = a[7];
1947 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
1948 return;
1949 }
1950 ctx.beginPath();
1951 ctx.moveTo((ax - srcLeft) * scale,
1952 (ay - srcTop) * scale);
1953 ctx.bezierCurveTo((bx - srcLeft) * scale,
1954 (by - srcTop) * scale,
1955 (cx - srcLeft) * scale,
1956 (cy - srcTop) * scale,
1957 (dx - srcLeft) * scale,
1958 (dy - srcTop) * scale);
1959 ctx.stroke();
1960}
1961
1962function drawCurve(c) {
1963 switch (c.length) {
1964 case 4:
1965 drawLine(c[0], c[1], c[2], c[3]);
1966 break;
1967 case 6:
1968 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1969 break;
caryclark1049f122015-04-20 08:31:59 -07001970 case 7:
1971 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
1972 break;
caryclarkdac1d172014-06-17 05:15:38 -07001973 case 8:
1974 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1975 break;
1976 }
1977}
1978
1979function boundsWidth(pts) {
1980 var min = pts[0];
1981 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07001982 var length = pts.length == 7 ? 6 : pts.length;
1983 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001984 min = Math.min(min, pts[idx]);
1985 max = Math.max(max, pts[idx]);
1986 }
1987 return max - min;
1988}
1989
1990function boundsHeight(pts) {
1991 var min = pts[1];
1992 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07001993 var length = pts.length == 7 ? 6 : pts.length;
1994 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001995 min = Math.min(min, pts[idx]);
1996 max = Math.max(max, pts[idx]);
1997 }
1998 return max - min;
1999}
2000
2001function tangent(pts) {
2002 var dx = pts[2] - pts[0];
2003 var dy = pts[3] - pts[1];
2004 if (dx == 0 && dy == 0 && pts.length > 4) {
2005 dx = pts[4] - pts[0];
2006 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07002007 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07002008 dx = pts[6] - pts[0];
2009 dy = pts[7] - pts[1];
2010 }
2011 }
2012 return Math.atan2(-dy, dx);
2013}
2014
2015function hodograph(cubic) {
2016 var hodo = [];
2017 hodo[0] = 3 * (cubic[2] - cubic[0]);
2018 hodo[1] = 3 * (cubic[3] - cubic[1]);
2019 hodo[2] = 3 * (cubic[4] - cubic[2]);
2020 hodo[3] = 3 * (cubic[5] - cubic[3]);
2021 hodo[4] = 3 * (cubic[6] - cubic[4]);
2022 hodo[5] = 3 * (cubic[7] - cubic[5]);
2023 return hodo;
2024}
2025
2026function hodograph2(cubic) {
2027 var quad = hodograph(cubic);
2028 var hodo = [];
2029 hodo[0] = 2 * (quad[2] - quad[0]);
2030 hodo[1] = 2 * (quad[3] - quad[1]);
2031 hodo[2] = 2 * (quad[4] - quad[2]);
2032 hodo[3] = 2 * (quad[5] - quad[3]);
2033 return hodo;
2034}
2035
2036function quadraticRootsReal(A, B, C, s) {
2037 if (A == 0) {
2038 if (B == 0) {
2039 s[0] = 0;
2040 return C == 0;
2041 }
2042 s[0] = -C / B;
2043 return 1;
2044 }
2045 /* normal form: x^2 + px + q = 0 */
2046 var p = B / (2 * A);
2047 var q = C / A;
2048 var p2 = p * p;
2049 if (p2 < q) {
2050 return 0;
2051 }
2052 var sqrt_D = 0;
2053 if (p2 > q) {
2054 sqrt_D = sqrt(p2 - q);
2055 }
2056 s[0] = sqrt_D - p;
2057 s[1] = -sqrt_D - p;
2058 return 1 + s[0] != s[1];
2059}
2060
2061function add_valid_ts(s, realRoots, t) {
2062 var foundRoots = 0;
2063 for (var index = 0; index < realRoots; ++index) {
2064 var tValue = s[index];
2065 if (tValue >= 0 && tValue <= 1) {
2066 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
2067 if (t[idx2] != tValue) {
2068 t[foundRoots++] = tValue;
2069 }
2070 }
2071 }
2072 }
2073 return foundRoots;
2074}
2075
2076function quadraticRootsValidT(a, b, c, t) {
2077 var s = [];
2078 var realRoots = quadraticRootsReal(A, B, C, s);
2079 var foundRoots = add_valid_ts(s, realRoots, t);
2080 return foundRoots != 0;
2081}
2082
2083function find_cubic_inflections(cubic, tValues) {
2084 var Ax = src[2] - src[0];
2085 var Ay = src[3] - src[1];
2086 var Bx = src[4] - 2 * src[2] + src[0];
2087 var By = src[5] - 2 * src[3] + src[1];
2088 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
2089 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
2090 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
2091 Ax * By - Ay * Bx, tValues);
2092}
2093
2094function dxy_at_t(curve, type, t) {
2095 var dxy = {};
2096 if (type == PATH_QUAD) {
2097 var a = t - 1;
2098 var b = 1 - 2 * t;
2099 var c = t;
2100 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
2101 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07002102 } else if (type == PATH_CONIC) {
2103 var p20x = curve[4] - curve[0];
2104 var p20y = curve[5] - curve[1];
2105 var p10xw = (curve[2] - curve[0]) * curve[6];
2106 var p10yw = (curve[3] - curve[1]) * curve[6];
2107 var coeff0x = curve[6] * p20x - p20x;
2108 var coeff0y = curve[6] * p20y - p20y;
2109 var coeff1x = p20x - 2 * p10xw;
2110 var coeff1y = p20y - 2 * p10yw;
2111 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2112 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002113 } else if (type == PATH_CUBIC) {
2114 var one_t = 1 - t;
2115 var a = curve[0];
2116 var b = curve[2];
2117 var c = curve[4];
2118 var d = curve[6];
2119 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2120 a = curve[1];
2121 b = curve[3];
2122 c = curve[5];
2123 d = curve[7];
2124 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2125 }
2126 return dxy;
2127}
2128
2129function drawLabel(num, px, py) {
2130 ctx.beginPath();
2131 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2132 ctx.closePath();
2133 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2134 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2135 ctx.stroke();
2136 ctx.fillStyle = "black";
2137 ctx.font = "normal 10px Arial";
2138 // ctx.rotate(0.001);
2139 ctx.fillText(num, px - 2, py + 3);
2140 // ctx.rotate(-0.001);
2141}
2142
2143function drawLabelX(ymin, num, loc) {
2144 var px = (loc - srcLeft) * scale;
2145 var py = (ymin - srcTop) * scale - 20;
2146 drawLabel(num, px, py);
2147}
2148
2149function drawLabelY(xmin, num, loc) {
2150 var px = (xmin - srcLeft) * scale - 20;
2151 var py = (loc - srcTop) * scale;
2152 drawLabel(num, px, py);
2153}
2154
2155function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2156 ctx.beginPath();
2157 ctx.moveTo(hx, hy - 100);
2158 ctx.lineTo(hx, hy);
2159 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2160 ctx.stroke();
2161 ctx.beginPath();
2162 ctx.moveTo(hx, hy);
2163 ctx.lineTo(hx, hy + 100);
2164 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2165 ctx.stroke();
2166 ctx.beginPath();
2167 ctx.moveTo(hx - 100, hy);
2168 ctx.lineTo(hx, hy);
2169 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2170 ctx.stroke();
2171 ctx.beginPath();
2172 ctx.moveTo(hx, hy);
2173 ctx.lineTo(hx + 100, hy);
2174 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2175 ctx.stroke();
2176}
2177
2178function scalexy(x, y, mag) {
2179 var length = Math.sqrt(x * x + y * y);
2180 return mag / length;
2181}
2182
caryclark03b03ca2015-04-23 09:13:37 -07002183function drawArrow(x, y, dx, dy, s) {
2184 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002185 dx *= dscale;
2186 dy *= dscale;
2187 ctx.beginPath();
2188 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2189 x += dx;
2190 y += dy;
2191 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2192 dx /= 10;
2193 dy /= 10;
2194 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2195 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2196 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2197 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2198 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2199 ctx.stroke();
2200}
2201
2202function x_at_t(curve, t) {
2203 var one_t = 1 - t;
2204 if (curve.length == 4) {
2205 return one_t * curve[0] + t * curve[2];
2206 }
2207 var one_t2 = one_t * one_t;
2208 var t2 = t * t;
2209 if (curve.length == 6) {
2210 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2211 }
caryclark1049f122015-04-20 08:31:59 -07002212 if (curve.length == 7) {
2213 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2214 / (one_t2 +2 * one_t * t * curve[6] + t2);
2215 }
caryclarkdac1d172014-06-17 05:15:38 -07002216 var a = one_t2 * one_t;
2217 var b = 3 * one_t2 * t;
2218 var c = 3 * one_t * t2;
2219 var d = t2 * t;
2220 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2221}
2222
2223function y_at_t(curve, t) {
2224 var one_t = 1 - t;
2225 if (curve.length == 4) {
2226 return one_t * curve[1] + t * curve[3];
2227 }
2228 var one_t2 = one_t * one_t;
2229 var t2 = t * t;
2230 if (curve.length == 6) {
2231 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2232 }
caryclark1049f122015-04-20 08:31:59 -07002233 if (curve.length == 7) {
2234 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2235 / (one_t2 +2 * one_t * t * curve[6] + t2);
2236 }
caryclarkdac1d172014-06-17 05:15:38 -07002237 var a = one_t2 * one_t;
2238 var b = 3 * one_t2 * t;
2239 var c = 3 * one_t * t2;
2240 var d = t2 * t;
2241 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2242}
2243
2244function drawOrder(curve, label) {
2245 var px = x_at_t(curve, 0.75);
2246 var py = y_at_t(curve, 0.75);
2247 var _px = (px - srcLeft) * scale;
2248 var _py = (py - srcTop) * scale;
2249 ctx.beginPath();
2250 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2251 ctx.closePath();
2252 ctx.fillStyle = "white";
2253 ctx.fill();
2254 if (label == 'L') {
2255 ctx.strokeStyle = "rgba(255,0,0, 1)";
2256 ctx.fillStyle = "rgba(255,0,0, 1)";
2257 } else {
2258 ctx.strokeStyle = "rgba(0,0,255, 1)";
2259 ctx.fillStyle = "rgba(0,0,255, 1)";
2260 }
2261 ctx.stroke();
2262 ctx.font = "normal 16px Arial";
2263 ctx.textAlign = "center";
2264 ctx.fillText(label, _px, _py + 5);
2265 ctx.font = "normal 10px Arial";
2266}
2267
2268function drawID(curve, id) {
2269 var px = x_at_t(curve, 0.5);
2270 var py = y_at_t(curve, 0.5);
2271 var _px = (px - srcLeft) * scale;
2272 var _py = (py - srcTop) * scale;
2273 draw_id_at(id, _px, _py);
2274}
2275
2276function draw_id_at(id, _px, _py) {
2277 ctx.beginPath();
2278 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2279 ctx.closePath();
2280 ctx.fillStyle = "white";
2281 ctx.fill();
2282 ctx.strokeStyle = "rgba(127,127,0, 1)";
2283 ctx.fillStyle = "rgba(127,127,0, 1)";
2284 ctx.stroke();
2285 ctx.font = "normal 16px Arial";
2286 ctx.textAlign = "center";
2287 ctx.fillText(id, _px, _py + 5);
2288 ctx.font = "normal 10px Arial";
2289}
2290
2291function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2292 var curve = [x1, y1, x2, y2];
2293 drawCurvePartialID(id, curve, t1, t2);
2294}
2295
2296function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2297 var curve = [x1, y1, x2, y2, x3, y3];
2298 drawCurvePartialID(id, curve, t1, t2);
2299}
2300
caryclark1049f122015-04-20 08:31:59 -07002301function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2302 var curve = [x1, y1, x2, y2, x3, y3, w];
2303 drawCurvePartialID(id, curve, t1, t2);
2304}
2305
caryclarkdac1d172014-06-17 05:15:38 -07002306function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2307 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2308 drawCurvePartialID(id, curve, t1, t2);
2309}
2310
2311function drawCurvePartialID(id, curve, t1, t2) {
2312 var px = x_at_t(curve, (t1 + t2) / 2);
2313 var py = y_at_t(curve, (t1 + t2) / 2);
2314 var _px = (px - srcLeft) * scale;
2315 var _py = (py - srcTop) * scale;
2316 draw_id_at(id, _px, _py);
2317}
2318
2319function drawCurveSpecials(test, curve, type) {
2320 if (pt_labels) {
2321 drawPoints(curve, type, pt_labels == 2);
2322 }
2323 if (control_lines != 0) {
2324 drawControlLines(curve, type, control_lines);
2325 }
2326 if (curve_t) {
2327 drawPointAtT(curve, type);
2328 }
2329 if (draw_midpoint) {
2330 var mid = pointAtT(curve, type, 0.5);
2331 drawPoint(mid.x, mid.y, true);
2332 }
2333 if (draw_id) {
2334 var id = idByCurve(test, curve, type);
2335 if (id >= 0) {
2336 drawID(curve, id);
2337 }
2338 }
2339 if (type == PATH_LINE) {
2340 return;
2341 }
2342 if (draw_deriviatives > 0) {
2343 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002344 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002345 if (draw_deriviatives == 2) {
2346 d = dxy_at_t(curve, type, 1);
2347 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002348 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002349 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002350 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002351 }
2352 }
2353 if (draw_midpoint) {
2354 var mid = pointAtT(curve, type, 0.5);
2355 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002356 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002357 }
2358 }
2359 if (type != PATH_CUBIC) {
2360 return;
2361 }
caryclarkdac1d172014-06-17 05:15:38 -07002362 if (draw_sequence) {
2363 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2364 for (var i = 0; i < 8; i+= 2) {
2365 drawLabelX(ymin, i >> 1, curve[i]);
2366 }
2367 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2368 for (var i = 1; i < 8; i+= 2) {
2369 drawLabelY(xmin, i >> 1, curve[i]);
2370 }
2371 }
2372}
2373
2374function logCurves(test) {
2375 for (curves in test) {
2376 var curve = test[curves];
2377 dumpCurve(curve);
2378 }
2379}
2380
2381function curveToString(curve) {
2382 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002383 var length = curve.length == 7 ? 6 : curve.length;
2384 if (curve.length == 7) {
2385 str += "{";
2386 }
2387 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002388 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2389 if (i < curve.length - 2) {
2390 str += "}, {";
2391 }
2392 }
caryclark1049f122015-04-20 08:31:59 -07002393 str += "}";
2394 if (curve.length == 7) {
2395 str += "}, " + curve[6].toFixed(decimal_places);
2396 }
2397 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002398 return str;
2399}
2400
2401function dumpCurve(curve) {
2402 console.log(curveToString(curve));
2403}
2404
2405function draw(test, lines, title) {
2406 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2407 ctx.font = "normal 50px Arial";
2408 ctx.textAlign = "left";
2409 ctx.fillText(title, 50, 50);
2410 ctx.font = "normal 10px Arial";
2411 ctx.lineWidth = "1.001"; "0.999";
2412 var secondPath = test.length;
2413 var closeCount = 0;
2414 logStart = -1;
2415 logRange = 0;
2416 // find last active rec type at this step
2417 var curType = test[0];
2418 var curStep = 0;
2419 var hasOp = false;
2420 var lastActive = 0;
2421 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002422 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002423 var lastSect = 0;
2424 var lastSort = 0;
2425 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002426 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002427 activeCount = 0;
2428 addCount = 0;
2429 angleCount = 0;
2430 opCount = 0;
2431 sectCount = 0;
2432 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002433 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002434 markCount = 0;
2435 activeMax = 0;
2436 addMax = 0;
2437 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002438 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002439 opMax = 0;
2440 sectMax = 0;
2441 sectMax2 = 0;
2442 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002443 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002444 markMax = 0;
2445 lastIndex = test.length - 3;
2446 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2447 var recType = test[tIndex];
2448 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2449 console.log("unknown rec type: " + recType);
2450 throw "stop execution";
2451 }
2452 // if (curType == recType && curType != REC_TYPE_ADD) {
2453 // continue;
2454 // }
2455 var inStepRange = step_limit == 0 || curStep < step_limit;
2456 curType = recType;
2457 if (recType == REC_TYPE_OP) {
2458 hasOp = true;
2459 continue;
2460 }
2461 if (recType == REC_TYPE_UNKNOWN) {
2462 // these types do not advance step
2463 continue;
2464 }
2465 var bumpStep = false;
2466 var records = test[tIndex + 2];
2467 var fragType = records[0];
2468 if (recType == REC_TYPE_ADD) {
2469 if (records.length != 2) {
2470 console.log("expect only two elements: " + records.length);
2471 throw "stop execution";
2472 }
2473 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2474 continue;
2475 }
2476 ++addMax;
2477 if (!draw_add || !inStepRange) {
2478 continue;
2479 }
2480 lastAdd = tIndex;
2481 ++addCount;
2482 bumpStep = true;
2483 }
2484 if (recType == REC_TYPE_PATH && hasOp) {
2485 secondPath = tIndex;
2486 }
caryclark54359292015-03-26 07:52:43 -07002487 if (recType == REC_TYPE_PATH2 && hasOp) {
2488 secondPath = tIndex;
2489 }
caryclarkdac1d172014-06-17 05:15:38 -07002490 if (recType == REC_TYPE_ACTIVE) {
2491 ++activeMax;
2492 if (!draw_active || !inStepRange) {
2493 continue;
2494 }
2495 lastActive = tIndex;
2496 ++activeCount;
2497 bumpStep = true;
2498 }
2499 if (recType == REC_TYPE_ACTIVE_OP) {
2500 ++opMax;
2501 if (!draw_op || !inStepRange) {
2502 continue;
2503 }
2504 lastOp = tIndex;
2505 ++opCount;
2506 bumpStep = true;
2507 }
caryclark54359292015-03-26 07:52:43 -07002508 if (recType == REC_TYPE_AFTERPART) {
2509 if (draw_angle != 3 || !inStepRange) {
2510 continue;
2511 }
2512 lastAngle = tIndex;
2513 ++angleCount;
2514 bumpStep = true;
2515 }
caryclarkdac1d172014-06-17 05:15:38 -07002516 if (recType == REC_TYPE_ANGLE) {
2517 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002518 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002519 continue;
2520 }
2521 lastAngle = tIndex;
2522 ++angleCount;
2523 bumpStep = true;
2524 }
caryclark624637c2015-05-11 07:21:27 -07002525 if (recType == REC_TYPE_COINCIDENCE) {
2526 ++coinMax;
2527 if (!draw_coincidence || !inStepRange) {
2528 continue;
2529 }
2530 lastCoin = tIndex;
2531 ++coinCount;
2532 bumpStep = true;
2533 }
caryclarkdac1d172014-06-17 05:15:38 -07002534 if (recType == REC_TYPE_SECT) {
2535 if (records.length != 2) {
2536 console.log("expect only two elements: " + records.length);
2537 throw "stop execution";
2538 }
2539 ++sectMax;
2540 var sectBump = 1;
2541 switch (fragType) {
2542 case INTERSECT_LINE:
2543 case INTERSECT_QUAD_LINE:
2544 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002545 case INTERSECT_CONIC_LINE:
2546 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002547 case INTERSECT_SELF_CUBIC:
2548 case INTERSECT_CUBIC_LINE:
2549 case INTERSECT_CUBIC_QUAD:
2550 case INTERSECT_CUBIC:
2551 sectBump = 1;
2552 break;
2553 case INTERSECT_LINE_2:
2554 case INTERSECT_QUAD_LINE_2:
2555 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002556 case INTERSECT_CONIC_LINE_2:
2557 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002558 case INTERSECT_CUBIC_LINE_2:
2559 case INTERSECT_CUBIC_QUAD_2:
2560 case INTERSECT_CUBIC_2:
2561 sectBump = 2;
2562 break;
2563 case INTERSECT_LINE_NO:
2564 case INTERSECT_QUAD_LINE_NO:
2565 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002566 case INTERSECT_CONIC_LINE_NO:
2567 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002568 case INTERSECT_SELF_CUBIC_NO:
2569 case INTERSECT_CUBIC_LINE_NO:
2570 case INTERSECT_CUBIC_QUAD_NO:
2571 case INTERSECT_CUBIC_NO:
2572 sectBump = 0;
2573 break;
2574 case INTERSECT_CUBIC_LINE_3:
2575 case INTERSECT_CUBIC_QUAD_3:
2576 case INTERSECT_CUBIC_3:
2577 sectBump = 3;
2578 break;
2579 case INTERSECT_CUBIC_QUAD_4:
2580 case INTERSECT_CUBIC_4:
2581 sectBump = 4;
2582 break;
2583 default:
2584 console.log("missing case " + records.length);
2585 throw "stop execution";
2586 }
2587 sectMax2 += sectBump;
2588 if (draw_intersection <= 1 || !inStepRange) {
2589 continue;
2590 }
2591 lastSect = tIndex;
2592 sectCount += sectBump;
2593 bumpStep = true;
2594 }
2595 if (recType == REC_TYPE_SORT) {
2596 ++sortMax;
2597 if (!draw_sort || !inStepRange) {
2598 continue;
2599 }
2600 lastSort = tIndex;
2601 ++sortCount;
2602 bumpStep = true;
2603 }
caryclark03b03ca2015-04-23 09:13:37 -07002604 if (recType == REC_TYPE_TOP) {
2605 ++topMax;
2606 if (!draw_top || !inStepRange) {
2607 continue;
2608 }
2609 lastTop = tIndex;
2610 ++topCount;
2611 bumpStep = true;
2612 }
caryclarkdac1d172014-06-17 05:15:38 -07002613 if (recType == REC_TYPE_MARK) {
2614 ++markMax;
2615 if (!draw_mark || !inStepRange) {
2616 continue;
2617 }
2618 lastMark = tIndex;
2619 ++markCount;
2620 bumpStep = true;
2621 }
2622 if (bumpStep) {
2623 lastIndex = tIndex;
2624 logStart = test[tIndex + 1];
2625 logRange = records.length / 2;
2626 ++curStep;
2627 }
2628 }
2629 stepMax = (draw_add ? addMax : 0)
2630 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002631 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002632 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002633 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002634 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002635 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002636 + (draw_mark ? markMax : 0)
2637 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2638 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002639 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002640 }
2641 drawnPts = [];
2642 drawnLines = [];
2643 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002644 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002645 drawnCubics = [];
2646 focusXmin = focusYmin = Infinity;
2647 focusXmax = focusYmax = -Infinity;
2648 var pathIndex = 0;
2649 var opLetter = 'S';
2650 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2651 var recType = test[tIndex];
2652 var records = test[tIndex + 2];
2653 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2654 var fragType = records[recordIndex];
2655 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2656 console.log("unknown in range frag type: " + fragType);
2657 throw "stop execution";
2658 }
2659 var frags = records[recordIndex + 1];
2660 focus_enabled = false;
2661 switch (recType) {
2662 case REC_TYPE_COMPUTED:
2663 if (draw_computed == 0) {
2664 continue;
2665 }
2666 ctx.lineWidth = 1;
2667 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2668 ctx.fillStyle = "blue";
2669 var drawThis = false;
2670 switch (fragType) {
2671 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002672 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2673 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002674 drawQuad(frags[0], frags[1], frags[2], frags[3],
2675 frags[4], frags[5]);
2676 drawThis = true;
2677 }
2678 break;
caryclark1049f122015-04-20 08:31:59 -07002679 case PATH_CONIC:
2680 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2681 && (draw_computed & 7) == pathIndex)) {
2682 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2683 frags[4], frags[5], frags[6]);
2684 drawThis = true;
2685 }
2686 break;
caryclarkdac1d172014-06-17 05:15:38 -07002687 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002688 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2689 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002690 drawCubic(frags[0], frags[1], frags[2], frags[3],
2691 frags[4], frags[5], frags[6], frags[7]);
2692 drawThis = true;
2693 }
2694 ++pathIndex;
2695 break;
2696 case COMPUTED_SET_1:
2697 pathIndex = 0;
2698 break;
2699 case COMPUTED_SET_2:
2700 pathIndex = 1;
2701 break;
2702 default:
2703 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2704 throw "stop execution";
2705 }
2706 if (!drawThis || collect_bounds) {
2707 break;
2708 }
2709 drawCurveSpecials(test, frags, fragType);
2710 break;
2711 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002712 case REC_TYPE_PATH2:
caryclarkdac1d172014-06-17 05:15:38 -07002713 if (!draw_path) {
2714 continue;
2715 }
2716 var firstPath = tIndex < secondPath;
2717 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2718 continue;
2719 }
2720 ctx.lineWidth = 1;
2721 ctx.strokeStyle = firstPath ? "black" : "red";
2722 ctx.fillStyle = "blue";
caryclark54359292015-03-26 07:52:43 -07002723 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002724 switch (fragType) {
2725 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002726 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2727 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002728 break;
2729 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002730 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2731 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2732 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002733 break;
caryclark1049f122015-04-20 08:31:59 -07002734 case PATH_CONIC:
2735 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2736 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2737 frags2[4], frags2[5], frags2[6]);
2738 break;
caryclarkdac1d172014-06-17 05:15:38 -07002739 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002740 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2741 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2742 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07002743 break;
2744 default:
caryclark54359292015-03-26 07:52:43 -07002745 console.log("unknown REC_TYPE_PATH2 frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002746 throw "stop execution";
2747 }
2748 if (collect_bounds) {
2749 break;
2750 }
caryclark54359292015-03-26 07:52:43 -07002751 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002752 break;
2753 case REC_TYPE_OP:
2754 switch (fragType) {
2755 case OP_INTERSECT: opLetter = 'I'; break;
2756 case OP_DIFFERENCE: opLetter = 'D'; break;
2757 case OP_UNION: opLetter = 'U'; break;
2758 case OP_XOR: opLetter = 'X'; break;
2759 default:
2760 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2761 throw "stop execution";
2762 }
2763 break;
2764 case REC_TYPE_ACTIVE:
2765 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2766 continue;
2767 }
2768 var x1 = frags[SPAN_X1];
2769 var y1 = frags[SPAN_Y1];
2770 var x2 = frags[SPAN_X2];
2771 var y2 = frags[SPAN_Y2];
caryclark1049f122015-04-20 08:31:59 -07002772 var x3, y3, x3, y4, t1, t2, w;
caryclarkdac1d172014-06-17 05:15:38 -07002773 ctx.lineWidth = 3;
2774 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2775 focus_enabled = true;
2776 switch (fragType) {
2777 case ACTIVE_LINE_SPAN:
2778 t1 = frags[SPAN_L_T];
2779 t2 = frags[SPAN_L_TEND];
2780 drawLinePartial(x1, y1, x2, y2, t1, t2);
2781 if (draw_id) {
2782 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
2783 }
2784 break;
2785 case ACTIVE_QUAD_SPAN:
2786 x3 = frags[SPAN_X3];
2787 y3 = frags[SPAN_Y3];
2788 t1 = frags[SPAN_Q_T];
2789 t2 = frags[SPAN_Q_TEND];
2790 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
2791 if (draw_id) {
2792 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
2793 }
2794 break;
caryclark1049f122015-04-20 08:31:59 -07002795 case ACTIVE_CONIC_SPAN:
2796 x3 = frags[SPAN_X3];
2797 y3 = frags[SPAN_Y3];
2798 t1 = frags[SPAN_K_T];
2799 t2 = frags[SPAN_K_TEND];
2800 w = frags[SPAN_K_W];
2801 drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
2802 if (draw_id) {
2803 drawConicPartialID(frags[0], x1, y1, x2, y2, x3, y3, w, t1, t2);
2804 }
2805 break;
caryclarkdac1d172014-06-17 05:15:38 -07002806 case ACTIVE_CUBIC_SPAN:
2807 x3 = frags[SPAN_X3];
2808 y3 = frags[SPAN_Y3];
2809 x4 = frags[SPAN_X4];
2810 y4 = frags[SPAN_Y4];
2811 t1 = frags[SPAN_C_T];
2812 t2 = frags[SPAN_C_TEND];
2813 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2814 if (draw_id) {
2815 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2816 }
2817 break;
2818 default:
2819 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2820 throw "stop execution";
2821 }
2822 break;
2823 case REC_TYPE_ACTIVE_OP:
2824 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2825 continue;
2826 }
2827 focus_enabled = true;
2828 ctx.lineWidth = 3;
2829 var activeSpan = frags[7] == "1";
2830 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2831 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2832 drawCurve(curve);
2833 if (draw_op > 1) {
2834 drawArc(curve, false, frags[3], frags[4]);
2835 drawArc(curve, true, frags[5], frags[6]);
2836 }
2837 break;
2838 case REC_TYPE_ADD:
2839 if (!draw_add) {
2840 continue;
2841 }
2842 ctx.lineWidth = 3;
2843 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2844 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2845 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2846 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2847 : "rgba(127,0,127, 0.3)";
2848 focus_enabled = true;
2849 switch (fragType) {
2850 case ADD_MOVETO:
2851 break;
2852 case ADD_LINETO:
2853 if (step_limit == 0 || tIndex >= lastAdd) {
2854 drawLine(frags[0], frags[1], frags[2], frags[3]);
2855 }
2856 break;
2857 case ADD_QUADTO:
2858 if (step_limit == 0 || tIndex >= lastAdd) {
2859 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2860 }
2861 break;
caryclark1049f122015-04-20 08:31:59 -07002862 case ADD_CONICTO:
2863 if (step_limit == 0 || tIndex >= lastAdd) {
2864 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2865 frags[4], frags[5], frags[6]);
2866 }
2867 break;
caryclarkdac1d172014-06-17 05:15:38 -07002868 case ADD_CUBICTO:
2869 if (step_limit == 0 || tIndex >= lastAdd) {
2870 drawCubic(frags[0], frags[1], frags[2], frags[3],
2871 frags[4], frags[5], frags[6], frags[7]);
2872 }
2873 break;
2874 case ADD_CLOSE:
2875 ++closeCount;
2876 break;
2877 case ADD_FILL:
2878 break;
2879 default:
2880 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2881 throw "stop execution";
2882 }
2883 break;
2884 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07002885 angleBetween = frags[18] == "T";
2886 afterIndex = 0;
2887 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07002888 continue;
2889 }
2890 focus_enabled = true;
2891 ctx.lineWidth = 3;
2892 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07002893 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2894 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2895 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07002896 drawCurve(leftCurve);
2897 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07002898 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07002899 drawCurve(midCurve);
2900 if (draw_angle > 1) {
2901 drawOrder(leftCurve, 'L');
2902 drawOrder(rightCurve, 'R');
2903 }
2904 break;
caryclark54359292015-03-26 07:52:43 -07002905 case REC_TYPE_AFTERPART:
2906 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
2907 continue;
2908 }
2909 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
2910 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
2911 : "rgba(0,0,255, 1.0)";
2912 switch (fragType) {
2913 case PATH_LINE:
2914 drawLine(frags[0], frags[1], frags[2], frags[3]);
2915 break;
2916 case PATH_QUAD:
2917 drawQuad(frags[0], frags[1], frags[2], frags[3],
2918 frags[4], frags[5]);
2919 break;
caryclark1049f122015-04-20 08:31:59 -07002920 case PATH_CONIC:
2921 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2922 frags[4], frags[5], frags[6]);
2923 break;
caryclark54359292015-03-26 07:52:43 -07002924 case PATH_CUBIC:
2925 drawCubic(frags[0], frags[1], frags[2], frags[3],
caryclark1049f122015-04-20 08:31:59 -07002926 frags[4], frags[5], frags[6], frags[7]);
caryclark54359292015-03-26 07:52:43 -07002927 break;
2928 default:
2929 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
2930 throw "stop execution";
2931 }
2932 ++afterIndex;
2933 break;
caryclark624637c2015-05-11 07:21:27 -07002934 case REC_TYPE_COINCIDENCE:
2935 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
2936 continue;
2937 }
2938 focus_enabled = true;
2939 ctx.lineWidth = 3;
2940 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
2941 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2942 drawCurve(curve);
2943 break;
caryclarkdac1d172014-06-17 05:15:38 -07002944 case REC_TYPE_SECT:
2945 if (!draw_intersection) {
2946 continue;
2947 }
2948 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
2949 continue;
2950 }
2951 // draw_intersection == 1 : show all
2952 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
2953 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
2954 ctx.lineWidth = 1;
2955 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2956 ctx.fillStyle = "blue";
2957 focus_enabled = true;
2958 var f = [];
2959 var c1s;
2960 var c1l;
2961 var c2s;
2962 var c2l;
2963 switch (fragType) {
2964 case INTERSECT_LINE:
2965 f.push(5, 6, 0, 7);
2966 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
2967 break;
2968 case INTERSECT_LINE_2:
2969 f.push(5, 6, 0, 10);
2970 f.push(8, 9, 7, 15);
2971 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
2972 break;
2973 case INTERSECT_LINE_NO:
2974 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2975 break;
2976 case INTERSECT_QUAD_LINE:
2977 f.push(7, 8, 0, 9);
2978 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
2979 break;
2980 case INTERSECT_QUAD_LINE_2:
2981 f.push(7, 8, 0, 12);
2982 f.push(10, 11, 9, 17);
2983 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
2984 break;
2985 case INTERSECT_QUAD_LINE_NO:
2986 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2987 break;
2988 case INTERSECT_QUAD:
2989 f.push(7, 8, 0, 9);
2990 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
2991 break;
2992 case INTERSECT_QUAD_2:
2993 f.push(7, 8, 0, 12);
2994 f.push(10, 11, 9, 19);
2995 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
2996 break;
2997 case INTERSECT_QUAD_NO:
2998 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2999 break;
caryclark1049f122015-04-20 08:31:59 -07003000 case INTERSECT_CONIC_LINE:
3001 f.push(8, 9, 0, 10);
3002 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
3003 break;
3004 case INTERSECT_CONIC_LINE_2:
3005 f.push(8, 9, 0, 12);
3006 f.push(11, 12, 10, 18);
3007 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
3008 break;
3009 case INTERSECT_CONIC_LINE_NO:
3010 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
3011 break;
3012 case INTERSECT_CONIC:
3013 f.push(8, 9, 0, 10);
3014 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
3015 break;
3016 case INTERSECT_CONIC_2:
3017 f.push(8, 9, 0, 13);
3018 f.push(11, 12, 10, 21);
3019 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
3020 break;
3021 case INTERSECT_CONIC_NO:
3022 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
3023 break;
caryclarkdac1d172014-06-17 05:15:38 -07003024 case INTERSECT_SELF_CUBIC:
3025 f.push(9, 10, 0, 11);
3026 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
3027 break;
3028 case INTERSECT_SELF_CUBIC_NO:
3029 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
3030 break;
3031 case INTERSECT_CUBIC_LINE:
3032 f.push(9, 10, 0, 11);
3033 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
3034 break;
3035 case INTERSECT_CUBIC_LINE_2:
3036 f.push(9, 10, 0, 14);
3037 f.push(12, 13, 11, 19);
3038 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
3039 break;
3040 case INTERSECT_CUBIC_LINE_3:
3041 f.push(9, 10, 0, 17);
3042 f.push(12, 13, 11, 22);
3043 f.push(15, 16, 14, 23);
3044 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
3045 break;
3046 case INTERSECT_CUBIC_QUAD_NO:
3047 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
3048 break;
3049 case INTERSECT_CUBIC_QUAD:
3050 f.push(9, 10, 0, 11);
3051 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
3052 break;
3053 case INTERSECT_CUBIC_QUAD_2:
3054 f.push(9, 10, 0, 14);
3055 f.push(12, 13, 11, 21);
3056 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
3057 break;
3058 case INTERSECT_CUBIC_QUAD_3:
3059 f.push(9, 10, 0, 17);
3060 f.push(12, 13, 11, 24);
3061 f.push(15, 16, 14, 25);
3062 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
3063 break;
3064 case INTERSECT_CUBIC_QUAD_4:
3065 f.push(9, 10, 0, 20);
3066 f.push(12, 13, 11, 27);
3067 f.push(15, 16, 14, 28);
3068 f.push(18, 19, 17, 29);
3069 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
3070 break;
3071 case INTERSECT_CUBIC_LINE_NO:
3072 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
3073 break;
3074 case INTERSECT_CUBIC:
3075 f.push(9, 10, 0, 11);
3076 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
3077 break;
3078 case INTERSECT_CUBIC_2:
3079 f.push(9, 10, 0, 14);
3080 f.push(12, 13, 11, 23);
3081 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
3082 break;
3083 case INTERSECT_CUBIC_3:
3084 f.push(9, 10, 0, 17);
3085 f.push(12, 13, 11, 26);
3086 f.push(15, 16, 14, 27);
3087 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
3088 break;
3089 case INTERSECT_CUBIC_4:
3090 f.push(9, 10, 0, 20);
3091 f.push(12, 13, 11, 29);
3092 f.push(15, 16, 14, 30);
3093 f.push(18, 19, 17, 31);
3094 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
3095 break;
3096 case INTERSECT_CUBIC_NO:
3097 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
3098 break;
3099 default:
3100 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
3101 throw "stop execution";
3102 }
3103 if (draw_intersection != 1) {
3104 var id = -1;
3105 var curve;
3106 switch (c1l) {
3107 case 4:
3108 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3109 if (draw_id) {
3110 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3111 id = idByCurve(test, curve, PATH_LINE);
3112 }
3113 break;
3114 case 6:
3115 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3116 frags[c1s + 4], frags[c1s + 5]);
3117 if (draw_id) {
3118 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3119 frags[c1s + 4], frags[c1s + 5]];
3120 id = idByCurve(test, curve, PATH_QUAD);
3121 }
3122 break;
caryclark1049f122015-04-20 08:31:59 -07003123 case 7:
3124 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3125 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3126 if (draw_id) {
3127 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3128 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3129 id = idByCurve(test, curve, PATH_CONIC);
3130 }
3131 break;
caryclarkdac1d172014-06-17 05:15:38 -07003132 case 8:
3133 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3134 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3135 if (draw_id) {
3136 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3137 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3138 id = idByCurve(test, curve, PATH_CUBIC);
3139 }
3140 break;
3141 }
3142 if (id >= 0) {
3143 drawID(curve, id);
3144 }
3145 id = -1;
3146 switch (c2l) {
3147 case 0:
3148 break;
3149 case 4:
3150 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3151 if (draw_id) {
3152 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3153 id = idByCurve(test, curve, PATH_LINE);
3154 }
3155 break;
3156 case 6:
3157 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3158 frags[c2s + 4], frags[c2s + 5]);
3159 if (draw_id) {
3160 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3161 frags[c2s + 4], frags[c2s + 5]];
3162 id = idByCurve(test, curve, PATH_QUAD);
3163 }
3164 break;
caryclark1049f122015-04-20 08:31:59 -07003165 case 7:
3166 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3167 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3168 if (draw_id) {
3169 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3170 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3171 id = idByCurve(test, curve, PATH_CONIC);
3172 }
3173 break;
caryclarkdac1d172014-06-17 05:15:38 -07003174 case 8:
3175 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3176 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3177 if (draw_id) {
3178 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3179 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3180 id = idByCurve(test, curve, PATH_CUBIC);
3181 }
3182 break;
3183 }
3184 if (id >= 0) {
3185 drawID(curve, id);
3186 }
3187 }
3188 if (collect_bounds) {
3189 break;
3190 }
caryclark54359292015-03-26 07:52:43 -07003191 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3192 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003193 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3194 }
3195 }
3196 if (!draw_intersectT) {
3197 break;
3198 }
3199 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003200 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3201 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003202 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3203 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3204 }
3205 }
3206 break;
3207 case REC_TYPE_SORT:
3208 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3209 continue;
3210 }
3211 ctx.lineWidth = 3;
3212 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3213 focus_enabled = true;
3214 switch (fragType) {
3215 case SORT_UNARY:
3216 case SORT_BINARY:
3217 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3218 drawCurve(curve);
3219 break;
3220 default:
3221 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3222 throw "stop execution";
3223 }
3224 break;
caryclark03b03ca2015-04-23 09:13:37 -07003225 case REC_TYPE_TOP:
3226 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3227 continue;
3228 }
3229 ctx.lineWidth = 3;
3230 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3231 focus_enabled = true;
3232 {
3233 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3234 drawCurve(curve);
3235 var type = PATH_LINE + (curve.length / 2 - 2);
3236 var mid = pointAtT(curve, type, 0.5);
3237 var d = dxy_at_t(curve, type, 0.5);
3238 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3239 }
3240 break;
caryclarkdac1d172014-06-17 05:15:38 -07003241 case REC_TYPE_MARK:
3242 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3243 continue;
3244 }
3245 ctx.lineWidth = 3;
3246 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3247 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3248 focus_enabled = true;
3249 switch (fragType) {
3250 case MARK_LINE:
3251 case MARK_DONE_LINE:
3252 case MARK_UNSORTABLE_LINE:
3253 case MARK_SIMPLE_LINE:
3254 case MARK_SIMPLE_DONE_LINE:
3255 case MARK_DONE_UNARY_LINE:
3256 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3257 frags[5], frags[9]);
3258 if (draw_id) {
3259 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3260 frags[5], frags[9]);
3261 }
3262 break;
3263 case MARK_QUAD:
3264 case MARK_DONE_QUAD:
3265 case MARK_UNSORTABLE_QUAD:
3266 case MARK_SIMPLE_QUAD:
3267 case MARK_SIMPLE_DONE_QUAD:
3268 case MARK_DONE_UNARY_QUAD:
3269 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3270 frags[5], frags[6], frags[7], frags[11]);
3271 if (draw_id) {
3272 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3273 frags[5], frags[6], frags[7], frags[11]);
3274 }
3275 break;
3276 case MARK_CUBIC:
3277 case MARK_DONE_CUBIC:
3278 case MARK_UNSORTABLE_CUBIC:
3279 case MARK_SIMPLE_CUBIC:
3280 case MARK_SIMPLE_DONE_CUBIC:
3281 case MARK_DONE_UNARY_CUBIC:
3282 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3283 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3284 if (draw_id) {
3285 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3286 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3287 }
3288 break;
3289 case MARK_ANGLE_LAST:
3290 // FIXME: ignored for now
3291 break;
3292 default:
3293 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3294 throw "stop execution";
3295 }
3296 break;
3297 default:
3298 continue;
3299 }
3300 }
3301 switch (recType) {
3302 case REC_TYPE_SORT:
3303 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3304 break;
3305 }
3306 var angles = []; // use tangent lines to describe arcs
3307 var windFrom = [];
3308 var windTo = [];
3309 var opp = [];
3310 var minXY = Number.MAX_VALUE;
3311 var partial;
3312 focus_enabled = true;
3313 var someUnsortable = false;
3314 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3315 var fragType = records[recordIndex];
3316 var frags = records[recordIndex + 1];
3317 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3318 (fragType == SORT_BINARY && frags[16]);
3319 someUnsortable |= unsortable;
3320 switch (fragType) {
3321 case SORT_UNARY:
3322 case SORT_BINARY:
3323 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3324 break;
3325 default:
3326 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3327 throw "stop execution";
3328 }
3329 var dx = boundsWidth(partial);
3330 var dy = boundsHeight(partial);
3331 minXY = Math.min(minXY, dx * dx + dy * dy);
3332 if (collect_bounds) {
3333 continue;
3334 }
3335 angles.push(tangent(partial));
3336 var from = frags[12];
3337 var to = frags[12];
3338 var sgn = frags[10];
3339 if (sgn < 0) {
3340 from -= frags[11];
3341 } else if (sgn > 0) {
3342 to -= frags[11];
3343 }
3344 windFrom.push(from + (unsortable ? "!" : ""));
3345 windTo.push(to + (unsortable ? "!" : ""));
3346 opp.push(fragType == SORT_BINARY);
3347 if (draw_sort == 1) {
3348 drawOrder(partial, frags[12]);
3349 } else {
3350 drawOrder(partial, (recordIndex / 2) + 1);
3351 }
3352 }
3353 var radius = Math.sqrt(minXY) / 2 * scale;
3354 radius = Math.min(50, radius);
3355 var scaledRadius = radius / scale;
3356 var centerX = partial[0];
3357 var centerY = partial[1];
3358 if (collect_bounds) {
3359 if (focus_enabled) {
3360 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3361 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3362 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3363 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3364 }
3365 break;
3366 }
3367 break;
3368 default:
3369 break;
3370 }
3371 }
3372 if (collect_bounds) {
3373 return;
3374 }
3375 if (draw_log && logStart >= 0) {
3376 ctx.font = "normal 10px Arial";
3377 ctx.textAlign = "left";
3378 ctx.beginPath();
3379 var top = screenHeight - 20 - (logRange + 2) * 10;
3380 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3381 ctx.fillStyle = "white";
3382 ctx.fill();
3383 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3384 if (logStart > 0) {
3385 ctx.fillText(lines[logStart - 1], 50, top + 8);
3386 }
3387 ctx.fillStyle = "black";
3388 for (var idx = 0; idx < logRange; ++idx) {
3389 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3390 }
3391 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3392 if (logStart + logRange < lines.length) {
3393 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3394 }
3395 }
3396 if (draw_legend) {
3397 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003398 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003399 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3400 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3401 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3402 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3403 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003404 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003405 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3406 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003407 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003408 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
3409 drawBox(pos++, "black", "white",
3410 (new Array('P', 'P1', 'P2', 'P'))[draw_path], draw_path != 0, pathKey);
3411 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3412 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3413 draw_computed != 0, computedKey);
3414 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3415 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3416 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3417 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3418 if (curve_t) {
3419 drawCurveTControl();
3420 }
3421 ctx.font = "normal 20px Arial";
3422 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3423 ctx.textAlign = "right";
3424 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3425 }
3426 if (draw_hints) {
3427 ctx.font = "normal 10px Arial";
3428 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3429 ctx.textAlign = "right";
3430 var y = 4;
3431 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3432 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3433 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3434 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003435 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3436 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3437 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3438 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3439 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3440 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3441 }
3442}
3443
3444function drawBox(y, backC, foreC, str, enable, label) {
3445 ctx.beginPath();
3446 ctx.fillStyle = backC;
3447 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3448 ctx.fill();
3449 ctx.font = "normal 16px Arial";
3450 ctx.fillStyle = foreC;
3451 ctx.textAlign = "center";
3452 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3453 if (!enable) {
3454 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3455 ctx.fill();
3456 }
3457 if (label != '') {
3458 ctx.font = "normal 9px Arial";
3459 ctx.fillStyle = "black";
3460 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3461 }
3462}
3463
3464function drawCurveTControl() {
3465 ctx.lineWidth = 2;
3466 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3467 ctx.beginPath();
3468 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3469 ctx.stroke();
3470 var ty = 40 + curveT * (screenHeight - 80);
3471 ctx.beginPath();
3472 ctx.moveTo(screenWidth - 80, ty);
3473 ctx.lineTo(screenWidth - 85, ty - 5);
3474 ctx.lineTo(screenWidth - 85, ty + 5);
3475 ctx.lineTo(screenWidth - 80, ty);
3476 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3477 ctx.fill();
3478 var num = curveT.toFixed(decimal_places);
3479 ctx.font = "normal 10px Arial";
3480 ctx.textAlign = "left";
3481 ctx.fillText(num, screenWidth - 78, ty);
3482}
3483
3484function ptInTControl() {
3485 var e = window.event;
3486 var tgt = e.target || e.srcElement;
3487 var left = tgt.offsetLeft;
3488 var top = tgt.offsetTop;
3489 var x = (e.clientX - left);
3490 var y = (e.clientY - top);
3491 if (x < screenWidth - 80 || x > screenWidth - 50) {
3492 return false;
3493 }
3494 if (y < 40 || y > screenHeight - 80) {
3495 return false;
3496 }
3497 curveT = (y - 40) / (screenHeight - 120);
3498 if (curveT < 0 || curveT > 1) {
3499 throw "stop execution";
3500 }
3501 return true;
3502}
3503
3504function drawTop() {
3505 if (tests[testIndex] == null) {
3506 var str = testDivs[testIndex].textContent;
3507 parse_all(str);
3508 var title = testDivs[testIndex].id.toString();
3509 testTitles[testIndex] = title;
3510 }
3511 init(tests[testIndex]);
3512 redraw();
3513}
3514
3515function redraw() {
3516 if (focus_on_selection) {
3517 collect_bounds = true;
3518 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3519 collect_bounds = false;
3520 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3521 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3522 }
3523 }
3524 ctx.beginPath();
3525 ctx.fillStyle = "white";
3526 ctx.rect(0, 0, screenWidth, screenHeight);
3527 ctx.fill();
3528 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3529}
3530
3531function dumpCurvePartial(test, id, t0, t1) {
3532 var curve = curveByID(test, id);
3533 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3534 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3535 + " t0=" + t0 + " t1=" + t1
3536 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3537}
3538
3539function dumpAngleTest(test, id, t0, t1) {
3540 var curve = curveByID(test, id);
3541 console.log(" { {" + curveToString(curve) + "}, "
3542 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3543}
3544
3545function dumpLogToConsole() {
3546 if (logStart < 0) {
3547 return;
3548 }
3549 var test = tests[testIndex];
3550 var recType = REC_TYPE_UNKNOWN;
3551 var records;
3552 for (var index = 0; index < test.length; index += 3) {
3553 var lastLineNo = test[index + 1];
3554 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3555 recType = test[index];
3556 records = test[index + 2];
3557 break;
3558 }
3559 }
3560 if (recType == REC_TYPE_UNKNOWN) {
3561 return;
3562 }
3563 var lines = testLines[testIndex];
3564 for (var idx = 0; idx < logRange; ++idx) {
3565 var line = lines[logStart + idx];
3566 console.log(line);
3567 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3568 var fragType = records[recordIndex];
3569 var frags = records[recordIndex + 1];
3570 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003571 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3572 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3573 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3574 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3575 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3576 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3577 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3578 console.log("}; //");
3579 }
3580 }
3581 }
3582}
3583
3584var activeKey = 'a';
3585var pathKey = 'b';
3586var pathBackKey = 'B';
3587var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003588var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003589var addKey = 'd';
3590var deriviativesKey = 'f';
3591var angleKey = 'g';
3592var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003593var intersectionKey = 'i';
3594var intersectionBackKey = 'I';
3595var sequenceKey = 'j';
3596var midpointKey = 'k';
3597var logKey = 'l';
3598var logToConsoleKey = 'L';
3599var markKey = 'm';
3600var sortKey = 'o';
3601var opKey = 'p';
3602var opBackKey = 'P';
3603var computedKey = 'q';
3604var computedBackKey = 'Q';
3605var stepKey = 's';
3606var stepBackKey = 'S';
3607var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003608var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003609var curveTKey = 'u';
3610var controlLinesBackKey = 'V';
3611var controlLinesKey = 'v';
3612var ptsKey = 'x';
3613var xyKey = 'y';
3614var logCurvesKey = 'z';
3615var focusKey = '`';
3616var idKey = '.';
3617var retinaKey = '\\';
3618
3619function doKeyPress(evt) {
3620 var char = String.fromCharCode(evt.charCode);
3621 var focusWasOn = false;
3622 switch (char) {
3623 case '0':
3624 case '1':
3625 case '2':
3626 case '3':
3627 case '4':
3628 case '5':
3629 case '6':
3630 case '7':
3631 case '8':
3632 case '9':
3633 decimal_places = char - '0';
3634 redraw();
3635 break;
3636 case activeKey:
3637 draw_active ^= true;
3638 redraw();
3639 break;
3640 case addKey:
3641 draw_add ^= true;
3642 redraw();
3643 break;
3644 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003645 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003646 redraw();
3647 break;
3648 case angleBackKey:
3649 draw_angle = (draw_angle + 2) % 3;
3650 redraw();
3651 break;
3652 case centerKey:
3653 setScale(xmin, xmax, ymin, ymax);
3654 redraw();
3655 break;
caryclark624637c2015-05-11 07:21:27 -07003656 case coincidenceKey:
3657 draw_coincidence ^= true;
3658 redraw();
3659 break;
caryclarkdac1d172014-06-17 05:15:38 -07003660 case controlLinesBackKey:
3661 control_lines = (control_lines + 3) % 4;
3662 redraw();
3663 break;
3664 case controlLinesKey:
3665 control_lines = (control_lines + 1) % 4;
3666 redraw();
3667 break;
3668 case computedBackKey:
3669 draw_computed = (draw_computed + 5) % 6;
3670 redraw();
3671 break;
3672 case computedKey:
3673 draw_computed = (draw_computed + 1) % 6;
3674 redraw();
3675 break;
3676 case curveTKey:
3677 curve_t ^= true;
3678 if (curve_t) {
3679 draw_legend = true;
3680 }
3681 redraw();
3682 break;
3683 case deriviativesKey:
3684 draw_deriviatives = (draw_deriviatives + 1) % 3;
3685 redraw();
3686 break;
3687 case focusKey:
3688 focus_on_selection ^= true;
3689 setScale(xmin, xmax, ymin, ymax);
3690 redraw();
3691 break;
caryclarkdac1d172014-06-17 05:15:38 -07003692 case idKey:
3693 draw_id ^= true;
3694 redraw();
3695 break;
3696 case intersectionBackKey:
3697 draw_intersection = (draw_intersection + 3) % 4;
3698 redraw();
3699 break;
3700 case intersectionKey:
3701 draw_intersection = (draw_intersection + 1) % 4;
3702 redraw();
3703 break;
3704 case intersectTKey:
3705 draw_intersectT ^= true;
3706 redraw();
3707 break;
3708 case logCurvesKey:
3709 logCurves(tests[testIndex]);
3710 break;
3711 case logKey:
3712 draw_log ^= true;
3713 redraw();
3714 break;
3715 case logToConsoleKey:
3716 if (draw_log) {
3717 dumpLogToConsole();
3718 }
3719 break;
3720 case markKey:
3721 draw_mark ^= true;
3722 redraw();
3723 break;
3724 case midpointKey:
3725 draw_midpoint ^= true;
3726 redraw();
3727 break;
3728 case opKey:
3729 draw_op = (draw_op + 1) % 3;
3730 redraw();
3731 break;
3732 case opBackKey:
3733 draw_op = (draw_op + 2) % 3;
3734 redraw();
3735 break;
3736 case pathKey:
3737 draw_path = (draw_path + 1) % 4;
3738 redraw();
3739 break;
3740 case pathBackKey:
3741 draw_path = (draw_path + 3) % 4;
3742 redraw();
3743 break;
3744 case ptsKey:
3745 pt_labels = (pt_labels + 1) % 3;
3746 redraw();
3747 break;
3748 case retinaKey:
3749 retina_scale ^= true;
3750 drawTop();
3751 break;
3752 case sequenceKey:
3753 draw_sequence ^= true;
3754 redraw();
3755 break;
3756 case sortKey:
3757 draw_sort = (draw_sort + 1) % 3;
3758 drawTop();
3759 break;
3760 case stepKey:
3761 step_limit++;
3762 if (step_limit > stepMax) {
3763 step_limit = stepMax;
3764 }
3765 redraw();
3766 break;
3767 case stepBackKey:
3768 step_limit--;
3769 if (step_limit < 0) {
3770 step_limit = 0;
3771 }
3772 redraw();
3773 break;
caryclark03b03ca2015-04-23 09:13:37 -07003774 case topKey:
3775 draw_top ^= true;
3776 redraw();
3777 break;
caryclarkdac1d172014-06-17 05:15:38 -07003778 case xyKey:
3779 debug_xy = (debug_xy + 1) % 3;
3780 redraw();
3781 break;
3782 case '-':
3783 focusWasOn = focus_on_selection;
3784 if (focusWasOn) {
3785 focus_on_selection = false;
3786 scale /= 1.2;
3787 } else {
3788 scale /= 2;
3789 calcLeftTop();
3790 }
3791 redraw();
3792 focus_on_selection = focusWasOn;
3793 break;
3794 case '=':
3795 case '+':
3796 focusWasOn = focus_on_selection;
3797 if (focusWasOn) {
3798 focus_on_selection = false;
3799 scale *= 1.2;
3800 } else {
3801 scale *= 2;
3802 calcLeftTop();
3803 }
3804 redraw();
3805 focus_on_selection = focusWasOn;
3806 break;
3807 case '?':
3808 draw_hints ^= true;
3809 if (draw_hints && !draw_legend) {
3810 draw_legend = true;
3811 }
3812 redraw();
3813 break;
3814 case '/':
3815 draw_legend ^= true;
3816 redraw();
3817 break;
3818 }
3819}
3820
3821function doKeyDown(evt) {
3822 var char = evt.keyCode;
3823 var preventDefault = false;
3824 switch (char) {
3825 case 37: // left arrow
3826 if (evt.shiftKey) {
3827 testIndex -= 9;
3828 }
3829 if (--testIndex < 0)
3830 testIndex = tests.length - 1;
3831 drawTop();
3832 preventDefault = true;
3833 break;
3834 case 39: // right arrow
3835 if (evt.shiftKey) {
3836 testIndex += 9;
3837 }
3838 if (++testIndex >= tests.length)
3839 testIndex = 0;
3840 drawTop();
3841 preventDefault = true;
3842 break;
3843 }
3844 if (preventDefault) {
3845 evt.preventDefault();
3846 return false;
3847 }
3848 return true;
3849}
3850
3851(function() {
3852 var hidden = "hidden";
3853
3854 // Standards:
3855 if (hidden in document)
3856 document.addEventListener("visibilitychange", onchange);
3857 else if ((hidden = "mozHidden") in document)
3858 document.addEventListener("mozvisibilitychange", onchange);
3859 else if ((hidden = "webkitHidden") in document)
3860 document.addEventListener("webkitvisibilitychange", onchange);
3861 else if ((hidden = "msHidden") in document)
3862 document.addEventListener("msvisibilitychange", onchange);
3863 // IE 9 and lower:
3864 else if ('onfocusin' in document)
3865 document.onfocusin = document.onfocusout = onchange;
3866 // All others:
3867 else
3868 window.onpageshow = window.onpagehide
3869 = window.onfocus = window.onblur = onchange;
3870
3871 function onchange (evt) {
3872 var v = 'visible', h = 'hidden',
3873 evtMap = {
3874 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3875 };
3876
3877 evt = evt || window.event;
3878 if (evt.type in evtMap)
3879 document.body.className = evtMap[evt.type];
3880 else
3881 document.body.className = this[hidden] ? "hidden" : "visible";
3882 }
3883})();
3884
3885function calcXY() {
3886 var e = window.event;
3887 var tgt = e.target || e.srcElement;
3888 var left = tgt.offsetLeft;
3889 var top = tgt.offsetTop;
3890 mouseX = (e.clientX - left) / scale + srcLeft;
3891 mouseY = (e.clientY - top) / scale + srcTop;
3892}
3893
3894function calcLeftTop() {
3895 srcLeft = mouseX - screenWidth / 2 / scale;
3896 srcTop = mouseY - screenHeight / 2 / scale;
3897}
3898
3899var disableClick = false;
3900
3901function handleMouseClick() {
3902 if (disableClick) {
3903 return;
3904 }
3905 if (!curve_t || !ptInTControl()) {
3906 calcXY();
3907 calcLeftTop();
3908 }
3909 redraw();
3910// if (!curve_t || !ptInTControl()) {
3911// mouseX = screenWidth / 2 / scale + srcLeft;
3912// mouseY = screenHeight / 2 / scale + srcTop;
3913// }
3914}
3915
3916function handleMouseOver() {
3917 calcXY();
3918 if (debug_xy != 2) {
3919 return;
3920 }
3921 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3922 ctx.beginPath();
3923 ctx.rect(300,100,num.length * 6,10);
3924 ctx.fillStyle="white";
3925 ctx.fill();
3926 ctx.font = "normal 10px Arial";
3927 ctx.fillStyle="black";
3928 ctx.textAlign = "left";
3929 ctx.fillText(num, 300, 108);
3930}
3931
3932function start() {
3933 for (var i = 0; i < testDivs.length; ++i) {
3934 tests[i] = null;
3935 }
3936 testIndex = 0;
3937 drawTop();
3938 window.addEventListener('keypress', doKeyPress, true);
3939 window.addEventListener('keydown', doKeyDown, true);
3940 window.onresize = function() {
3941 drawTop();
3942 }
3943 /*
3944 window.onpagehide = function() {
3945 disableClick = true;
3946 }
3947 */
3948 window.onpageshow = function () {
3949 disableClick = false;
3950 }
3951}
3952
3953</script>
3954</head>
3955
3956<body onLoad="start();">
3957<canvas id="canvas" width="750" height="500"
3958 onmousemove="handleMouseOver()"
3959 onclick="handleMouseClick()"
3960 ></canvas >
3961</body>
3962</html>