blob: eece69b73b77ef88a747771a97b81d1fa5567fcb [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
3<div height="0" hidden="true">
caryclark630240d2014-09-19 06:33:31 -07004<div id="fuzz487a">
5 RunTestSet [fuzz487a]
caryclarkdac1d172014-06-17 05:15:38 -07006
caryclark630240d2014-09-19 06:33:31 -07007{{172.5,96}, {137.600006,96}},
8{{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}},
9{{107.500008,56.7999992}, {116.500008,23.0999985}},
10{{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}},
11{{97.0000076,20.4999981}, {97.0000076,55.4000015}},
12{{97.0000076,55.4000015}, {97.0000076,55.4000015}},
13{{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}},
14{{57.8000069,85.5}, {24.1000061,76.5}},
15{{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}},
16{{21.5000057,96}, {56.4000092,96}},
17{{56.4000092,96}, {56.4000092,96}},
18{{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}},
19{{228.900009,192}, {172.5,96}},
caryclark19eb3b22014-07-18 05:08:14 -070020op union
caryclark630240d2014-09-19 06:33:31 -070021{{172.5,96}, {137.600006,96}},
22{{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}},
23{{117.300003,60.9000015}, {134.800003,30.7000008}},
24{{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}},
25{{97.1000061,20.6000004}, {97.1000061,55.5}},
26{{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}},
27{{62.0000076,75.8000031}, {31.6000004,58.2999992}},
28{{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}},
29{{21.5,96}, {56.4000015,96}},
30{{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}},
31{{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}},
32{{43.3999977,156.700012}, {3.33333338e+029,119.400002}},
33{{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}},
34{{29.3999996,-10.8000002}, {33.2999992,-25.6000004}},
35{{33.2999992,-25.6000004}, {62,-17.9000015}},
36{{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}},
37{{161.199997,136}, {172.5,96}},
38debugShowCubicIntersection no self intersect {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}}
39debugShowCubicIntersection no self intersect {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}}
40debugShowCubicIntersection no self intersect {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}}
41debugShowCubicIntersection no self intersect {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}}
42debugShowCubicIntersection no self intersect {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}}
43debugShowCubicIntersection no self intersect {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}}
44debugShowCubicIntersection no self intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
45debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
46debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
47debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{172.5,96}, {137.600006,96}}
48debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
49debugShowCubicLineIntersection wtTs[0]=1 {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{117.300003,60.9000015}} wnTs[0]=0 {{117.300003,60.9000015}, {134.800003,30.7000008}}
50debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{137.600006,96}} wtTs[1]=1 {{117.300003,60.9000015}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
51debugShowCubicIntersection no intersect {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
52debugShowCubicLineIntersection wtTs[0]=0 {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{134.800003,30.7000008}} wnTs[0]=1 {{117.300003,60.9000015}, {134.800003,30.7000008}}
53debugShowLineIntersection wtTs[0]=0 {{117.300003,60.9000015}, {134.800003,30.7000008}} {{117.300003,60.9000015}} wtTs[1]=1 {{134.800003,30.7000008}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
54debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{117.300003,60.9000015}, {134.800003,30.7000008}}
55debugShowCubicLineIntersection wtTs[0]=1 {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{97.1000061,20.6000004}} wnTs[0]=0 {{97.1000061,20.6000004}, {97.1000061,55.5}}
56debugShowCubicLineIntersection wtTs[0]=0 {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{134.800003,30.7000008}} wtTs[1]=1 {{97.1000061,20.6000004}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
57debugShowCubicIntersection no intersect {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
58debugShowCubicLineIntersection wtTs[0]=0 {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}} {{97.1000061,55.5}} wnTs[0]=1 {{97.1000061,20.6000004}, {97.1000061,55.5}}
59debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{97.1000061,20.6000004}} wnTs[0]=0 {{97.1000061,20.6000004}, {97.1000061,55.5}}
60debugShowCubicLineIntersection wtTs[0]=0.13656589 {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{97.1000061,40.6604424}} wnTs[0]=0.574798 {{97.1000061,20.6000004}, {97.1000061,55.5}}
61debugShowCubicLineIntersection wtTs[0]=1 {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}} {{62.0000076,75.8000031}} wnTs[0]=0 {{62.0000076,75.8000031}, {31.6000004,58.2999992}}
62debugShowCubicLineIntersection wtTs[0]=0 {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}} {{97.1000061,55.5}} wtTs[1]=1 {{62.0000076,75.8000031}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
63debugShowCubicIntersection no intersect {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}} {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
64debugShowCubicLineIntersection wtTs[0]=0 {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{31.6000004,58.2999992}} wnTs[0]=1 {{62.0000076,75.8000031}, {31.6000004,58.2999992}}
65debugShowLineIntersection wtTs[0]=0 {{62.0000076,75.8000031}, {31.6000004,58.2999992}} {{62.0000076,75.8000031}} wtTs[1]=1 {{31.6000004,58.2999992}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
66debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{62.0000076,75.8000031}, {31.6000004,58.2999992}}
67debugShowCubicLineIntersection wtTs[0]=1 {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{21.5,96}} wnTs[0]=0 {{21.5,96}, {56.4000015,96}}
68debugShowCubicLineIntersection wtTs[0]=0 {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{31.6000004,58.2999992}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}}
69debugShowCubicLineIntersection wtTs[0]=0 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{56.4000015,96}} wnTs[0]=1 {{21.5,96}, {56.4000015,96}}
70debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{56.4000015,96}} wnTs[0]=1 {{21.5,96}, {56.4000015,96}}
71debugShowCubicIntersection wtTs[0]=1 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{76.6999969,131.100006}} wnTs[0]=0 {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}}
72debugShowCubicLineIntersection wtTs[0]=1 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{76.6999969,131.100006}} wnTs[0]=0 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}}
73debugShowCubicLineIntersection wtTs[0]=0 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{56.4000015,96}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}}
74debugShowCubicIntersection no intersect {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
75debugShowCubicLineIntersection wtTs[0]=0 {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}} {{76.6999969,131.100006}} wtTs[1]=1 {{43.3999977,156.700012}} wnTs[0]=0 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}} wnTs[1]=0
76debugShowCubicIntersection no intersect {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}} {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
77debugShowLineIntersection wtTs[0]=1 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}} {{3.33333338e+029,119.400002}} wnTs[0]=0 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}}
78debugShowCubicLineIntersection wtTs[0]=1 {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{161.199997,136}} wnTs[0]=0 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}}
79debugShowLineIntersection wtTs[0]=0 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}} {{161.199997,136}} wnTs[0]=0 {{161.199997,136}, {172.5,96}}
80debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{29.3999996,-10.8000002}} wnTs[0]=0 {{29.3999996,-10.8000002}, {33.2999992,-25.6000004}}
81debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}}
82debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{172.5,96}} wnTs[0]=1 {{161.199997,136}, {172.5,96}}
83debugShowLineIntersection wtTs[0]=1 {{29.3999996,-10.8000002}, {33.2999992,-25.6000004}} {{33.2999992,-25.6000004}} wnTs[0]=0 {{33.2999992,-25.6000004}, {62,-17.9000015}}
84debugShowCubicLineIntersection wtTs[0]=0 {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{62,-17.9000015}} wnTs[0]=1 {{33.2999992,-25.6000004}, {62,-17.9000015}}
85debugShowCubicLineIntersection wtTs[0]=1 {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{161.199997,136}} wnTs[0]=0 {{161.199997,136}, {172.5,96}}
86debugShowLineIntersection wtTs[0]=0 {{172.5,96}, {137.600006,96}} {{172.5,96}} wtTs[1]=1 {{137.600006,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}} wnTs[1]=1
87debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
88debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{172.5,96}, {137.600006,96}}
89debugShowLineIntersection wtTs[0]=1 {{228.900009,192}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
90debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
91debugShowCubicIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{137.600006,96}} wnTs[0]=0 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}}
92debugShowCubicIntersection no intersect {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}} {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
93debugShowCubicLineIntersection wtTs[0]=0.798977321 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{117.320122,60.8652802}} wnTs[0]=0.00114967 {{117.300003,60.9000015}, {134.800003,30.7000008}}
94debugShowCubicLineIntersection wtTs[0]=0.511418257 {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{116.491173,23.1330757}} wnTs[0]=0.999019 {{107.500008,56.7999992}, {116.500008,23.0999985}}
95debugShowCubicIntersection no intersect {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}} {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}}
96debugShowCubicLineIntersection no intersect {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}} {{97.1000061,20.6000004}, {97.1000061,55.5}}
97debugShowCubicIntersection no intersect {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}} {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}}
98debugShowCubicLineIntersection wtTs[0]=0.799679553 {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}} {{61.8468246,75.7118225}} wnTs[0]=0.00503891 {{62.0000076,75.8000031}, {31.6000004,58.2999992}}
99debugShowCubicLineIntersection no intersect {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{57.8000069,85.5}, {24.1000061,76.5}}
100debugShowCubicIntersection wtTs[0]=1 {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{21.5,96}} wnTs[0]=1 {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}}
101debugShowCubicLineIntersection no intersect {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{21.5000057,96}, {56.4000092,96}}
102debugShowCubicLineIntersection wtTs[0]=1 {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}} {{21.5000057,96}} wnTs[0]=1.63955e-007 {{21.5,96}, {56.4000015,96}}
103debugShowLineIntersection wtTs[0]=0 {{21.5000057,96}, {56.4000092,96}} {{21.5000057,96}} wtTs[1]=0.999999781 {{56.4000015,96}} wnTs[0]=1.63955e-007 {{21.5,96}, {56.4000015,96}} wnTs[1]=1
104debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{21.5,96}, {56.4000015,96}}
105debugShowCubicLineIntersection wtTs[0]=0 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{56.4000015,96}} wnTs[0]=1 {{21.5000057,96}, {56.4000092,96}}
106debugShowCubicIntersection wtTs[0]=0 {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}} {{56.4000015,96}} wnTs[0]=0 {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
107debugShowCubicIntersection wtTs[0]=0.267722282 {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}} {{64.540802,133.291794}} wnTs[0]=0.131302 {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
108debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{43.3999977,156.700012}, {3.33333338e+029,119.400002}}
109debugShowLineIntersection wtTs[0]=4.94283788e-028 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}} {{208.16127,156.700012}} wnTs[0]=0.367708 {{228.900009,192}, {172.5,96}}
110debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
111debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{137.600006,96}} wtTs[1]=1 {{107.500008,56.7999992}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
112debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{107.500008,56.7999992}} wnTs[0]=0 {{107.500008,56.7999992}, {116.500008,23.0999985}}
113debugShowCubicLineIntersection wtTs[0]=0 {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}} {{116.500008,23.0999985}} wtTs[1]=1 {{97.0000076,20.4999981}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
114debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{97.0000076,20.4999981}} wnTs[0]=0 {{97.0000076,20.4999981}, {97.0000076,55.4000015}}
115debugShowCubicLineIntersection wtTs[0]=0 {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}} {{97.0000076,55.4000015}} wtTs[1]=1 {{57.8000069,85.5}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} wnTs[1]=1
116debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{57.8000069,85.5}} wnTs[0]=0 {{57.8000069,85.5}, {24.1000061,76.5}}
117debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{56.4000092,96}} wnTs[0]=1 {{21.5000057,96}, {56.4000092,96}}
118debugShowCubicLineIntersection wtTs[0]=0 {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{56.4000092,96}} wnTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}}
119debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{172.5,96}} wnTs[0]=1 {{228.900009,192}, {172.5,96}}
120debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{172.5,96}, {137.600006,96}}
121debugShowCubicIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}}
122debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{107.500008,56.7999992}, {116.500008,23.0999985}}
123debugShowCubicIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}}
124debugShowCubicLineIntersection wtTs[0]=0.136112912 {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{97.0000076,40.4949226}} wnTs[0]=0.57292 {{97.0000076,20.4999981}, {97.0000076,55.4000015}}
125debugShowCubicIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}}
126debugShowCubicIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
127debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
128debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{161.199997,136}, {172.5,96}}
129debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=1 {{228.900009,192}, {172.5,96}}
130debugShowCubicIntersection no self intersect {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}}
131debugShowCubicIntersection no self intersect {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}}
132debugShowCubicIntersection no self intersect {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}}
133debugShowCubicIntersection no self intersect {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}}
134debugShowCubicIntersection no self intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
135debugShowCubicLineIntersection wtTs[0]=0 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
136debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{172.5,96}, {137.600006,96}}
137debugShowLineIntersection wtTs[0]=1 {{228.900009,192}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
138debugShowCubicLineIntersection wtTs[0]=1 {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{107.500008,56.7999992}} wnTs[0]=0 {{107.500008,56.7999992}, {116.500008,23.0999985}}
139debugShowCubicIntersection no intersect {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}} {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
140debugShowCubicLineIntersection wtTs[0]=0 {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}} {{116.500008,23.0999985}} wnTs[0]=1 {{107.500008,56.7999992}, {116.500008,23.0999985}}
141debugShowCubicLineIntersection wtTs[0]=1 {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}} {{97.0000076,20.4999981}} wnTs[0]=0 {{97.0000076,20.4999981}, {97.0000076,55.4000015}}
142debugShowCubicLineIntersection wtTs[0]=0 {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}} {{97.0000076,55.4000015}} wnTs[0]=1 {{97.0000076,20.4999981}, {97.0000076,55.4000015}}
143debugShowCubicLineIntersection wtTs[0]=1 {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}} {{57.8000069,85.5}} wnTs[0]=0 {{57.8000069,85.5}, {24.1000061,76.5}}
144debugShowCubicLineIntersection wtTs[0]=0 {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}} {{24.1000061,76.5}} wnTs[0]=1 {{57.8000069,85.5}, {24.1000061,76.5}}
145debugShowCubicLineIntersection wtTs[0]=1 {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}} {{21.5000057,96}} wnTs[0]=0 {{21.5000057,96}, {56.4000092,96}}
146debugShowCubicLineIntersection wtTs[0]=0 {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{56.4000092,96}} wnTs[0]=1 {{21.5000057,96}, {56.4000092,96}}
147debugShowCubicLineIntersection wtTs[0]=1 {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{228.900009,192}} wnTs[0]=0 {{228.900009,192}, {172.5,96}}
148SkOpSegment::debugShowTs - id=13 [o=12 t=0 117.300003,60.9000015 w=1 o=0] [o=1 t=0.00115 117.320122,60.8652802 w=1 o=0] [o=14 t=1 134.800003,30.7000008 w=1 o=0] operand
149SkOpSegment::debugShowTs o id=23 [o=22 t=0 3.33333338e+029,119.400002 w=1 o=0] [o=1,0,12,11,12,14,15,14,16,16,18,20,19,10,27,2,1,3,4,3,5,6,5,9,8,24 t=1 29.3999996,-10.8000002 w=1 o=0] operand
150SkOpSegment::addTPair addTPair this=13 0 other=23 0.999999881
151SkOpSegment::debugShowTs + id=13 [o=23,12 t=0 117.300003,60.9000015 w=1 o=0] [o=1 t=0.00115 117.320122,60.8652802 w=1 o=0] [o=14 t=1 134.800003,30.7000008 w=1 o=0] operand
152SkOpSegment::debugShowTs o id=23 [o=22 t=0 3.33333338e+029,119.400002 w=1 o=0] [o=13 t=1 117.300003,60.9000015 w=1 o=0] [o=1,0,12,11,12,14,15,14,16,16,18,20,19,10,27,2,1,3,4,3,5,6,5,9,8,24 t=1 29.3999996,-10.8000002 w=1 o=0] operand
153SkOpSegment::debugShowTs - id=17 [o=16 t=0 62.0000076,75.8000031 w=1 o=0] [o=5 t=0.00504 61.8468246,75.7118225 w=1 o=0] [o=18 t=1 31.6000004,58.2999992 w=1 o=0] operand
154SkOpSegment::debugShowTs o id=23 [o=22 t=0 3.33333338e+029,119.400002 w=1 o=0] [o=13 t=1 117.300003,60.9000015 w=1 o=0] [o=1,0,12,11,12,14,15,14,16,16,18,20,19,10,27,2,1,3,4,3,5,6,5,9,8,24 t=1 29.3999996,-10.8000002 w=1 o=0] operand
155SkOpSegment::addTPair addTPair this=17 0 other=23 0.999999881
156SkOpSegment::debugShowTs + id=17 [o=23,16 t=0 62.0000076,75.8000031 w=1 o=0] [o=5 t=0.00504 61.8468246,75.7118225 w=1 o=0] [o=18 t=1 31.6000004,58.2999992 w=1 o=0] operand
157SkOpSegment::debugShowTs o id=23 [o=22 t=0 3.33333338e+029,119.400002 w=1 o=0] [o=13,17 t=1 62.0000076,75.8000031 w=1 o=0] [o=1,0,12,11,12,14,15,14,16,16,18,20,19,10,27,2,1,3,4,3,5,6,5,9,8,24 t=1 29.3999996,-10.8000002 w=1 o=0] operand
158SkOpSegment::debugShowTs - id=11 [o=10,27 t=0 172.5,96 w=1 o=0] [o=1,23,12 t=1 137.600006,96 w=1 o=0] operand
159SkOpSegment::debugShowTs o id=0 [o=10,27 t=0 172.5,96 w=1 o=0] [o=1,23,12 t=1 137.600006,96 w=1 o=0]
160SkOpSegment::debugShowTs + id=11 [o=10,27 t=0 172.5,96 w=1 o=0] [o=1,23,12 t=1 137.600006,96 w=1 o=0] operand
161SkOpSegment::debugShowTs o id=0 [o=10,27 t=0 172.5,96 w=1 o=0] [o=1,23,12 t=1 137.600006,96 w=1 o=0]
162SkOpSegment::debugShowTs - id=19 [o=18 t=0 21.5,96 w=1 o=0] [o=7 t=1.64e-007 21.5000057,96 w=1 o=0] [o=23,20 t=1 56.4000015,96 w=1 o=0] operand
163SkOpSegment::debugShowTs o id=8 [o=7 t=0 21.5000057,96 w=1 o=0] [o=20 t=1 56.4000015,96 w=1 o=0] [o=9,23 t=1 56.4000092,96 w=1 o=0]
164SkOpSegment::addTPair addTPair this=19 1.63955463e-007 other=8 0
165SkOpSegment::addTPair addTPair this=8 0.999999781 other=19 1
166SkOpSegment::debugShowTs + id=19 [o=18 t=0 21.5,96 w=1 o=0] [o=8,7 t=1.64e-007 21.5000057,96 w=1 o=0] [o=8,23,20 t=1 56.4000015,96 w=1 o=0] operand
167SkOpSegment::debugShowTs o id=8 [o=19,7 t=0 21.5000057,96 w=1 o=0] [o=19,20 t=1 56.4000015,96 w=1 o=0] [o=9,23 t=1 56.4000092,96 w=1 o=0]
168SkOpContour::calcCoincidentWinding count=4
169
caryclarkdac1d172014-06-17 05:15:38 -0700170</div>
171
172</div>
173
174<script type="text/javascript">
175
176var testDivs = [
caryclark630240d2014-09-19 06:33:31 -0700177 fuzz487a,
caryclarkdac1d172014-06-17 05:15:38 -0700178];
179
180var decimal_places = 3; // make this 3 to show more precision
181
182var tests = [];
183var testLines = [];
184var testTitles = [];
185var testIndex = 0;
186var ctx;
187
188var xmin, xmax, focusXmin, focusXmax;
189var ymin, ymax, focusYmin, focusYmax;
190var scale;
191var mouseX, mouseY;
192var srcLeft, srcTop;
193var screenWidth, screenHeight;
194var drawnPts, drawnLines, drawnQuads, drawnCubics;
195var curveT = 0;
196
197var pt_labels = 2;
198var collect_bounds = false;
199var control_lines = 0;
200var curve_t = false;
201var debug_xy = 1;
202var focus_enabled = false;
203var focus_on_selection = false;
204var step_limit = 0;
205var draw_active = false;
206var draw_add = false;
207var draw_angle = 0;
208var draw_deriviatives = 0;
209var draw_hints = false;
210var draw_hodo = 0;
211var draw_id = false;
212var draw_intersection = 0;
213var draw_intersectT = false;
214var draw_legend = true;
215var draw_log = false;
216var draw_mark = false;
217var draw_midpoint = false;
218var draw_op = 0;
219var draw_sequence = false;
220var draw_sort = 0;
221var draw_path = 3;
222var draw_computed = 0;
223var retina_scale = !!window.devicePixelRatio;
224
225var activeCount = 0;
226var addCount = 0;
227var angleCount = 0;
228var opCount = 0;
229var sectCount = 0;
230var sortCount = 0;
231var markCount = 0;
232var activeMax = 0;
233var addMax = 0;
234var angleMax = 0;
235var sectMax = 0;
236var sectMax2 = 0;
237var sortMax = 0;
238var markMax = 0;
239var opMax = 0;
240var stepMax = 0;
241var lastIndex = 0;
242var hasPath = false;
243var hasComputedPath = false;
244
245var firstActiveSpan = -1;
246var logStart = -1;
247var logRange = 0;
248
249var SPAN_ID = 0;
250var SPAN_X1 = SPAN_ID + 1;
251var SPAN_Y1 = SPAN_X1 + 1;
252var SPAN_X2 = SPAN_Y1 + 1;
253var SPAN_Y2 = SPAN_X2 + 1;
254var SPAN_L_T = SPAN_Y2 + 1;
255var SPAN_L_TX = SPAN_L_T + 1;
256var SPAN_L_TY = SPAN_L_TX + 1;
257var SPAN_L_TEND = SPAN_L_TY + 1;
258var SPAN_L_OTHER = SPAN_L_TEND + 1;
259var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
260var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
261var SPAN_L_SUM = SPAN_L_OTHERI + 1;
262var SPAN_L_VAL = SPAN_L_SUM + 1;
263var SPAN_L_OPP = SPAN_L_VAL + 1;
264
265var SPAN_X3 = SPAN_Y2 + 1;
266var SPAN_Y3 = SPAN_X3 + 1;
267var SPAN_Q_T = SPAN_Y3 + 1;
268var SPAN_Q_TX = SPAN_Q_T + 1;
269var SPAN_Q_TY = SPAN_Q_TX + 1;
270var SPAN_Q_TEND = SPAN_Q_TY + 1;
271var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
272var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
273var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
274var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
275var SPAN_Q_VAL = SPAN_Q_SUM + 1;
276var SPAN_Q_OPP = SPAN_Q_VAL + 1;
277
278var SPAN_X4 = SPAN_Y3 + 1;
279var SPAN_Y4 = SPAN_X4 + 1;
280var SPAN_C_T = SPAN_Y4 + 1;
281var SPAN_C_TX = SPAN_C_T + 1;
282var SPAN_C_TY = SPAN_C_TX + 1;
283var SPAN_C_TEND = SPAN_C_TY + 1;
284var SPAN_C_OTHER = SPAN_C_TEND + 1;
285var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
286var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
287var SPAN_C_SUM = SPAN_C_OTHERI + 1;
288var SPAN_C_VAL = SPAN_C_SUM + 1;
289var SPAN_C_OPP = SPAN_C_VAL + 1;
290
291var ACTIVE_LINE_SPAN = 1;
292var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
293var ACTIVE_CUBIC_SPAN = ACTIVE_QUAD_SPAN + 1;
294
295var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
296var ADD_LINETO = ADD_MOVETO + 1;
297var ADD_QUADTO = ADD_LINETO + 1;
298var ADD_CUBICTO = ADD_QUADTO + 1;
299var ADD_CLOSE = ADD_CUBICTO + 1;
300var ADD_FILL = ADD_CLOSE + 1;
301
302var PATH_LINE = ADD_FILL + 1;
303var PATH_QUAD = PATH_LINE + 1;
304var PATH_CUBIC = PATH_QUAD + 1;
305
306var INTERSECT_LINE = PATH_CUBIC + 1;
307var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
308var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
309var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
310var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
311var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
312var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
313var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
314var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
315var INTERSECT_SELF_CUBIC = INTERSECT_QUAD_NO + 1;
316var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
317var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
318var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
319var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
320var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
321var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
322var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
323var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
324var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
325var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
326var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
327var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
328var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
329var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
330// FIXME: add cubic 5- 9
331var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
332
333var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
334var SORT_BINARY = SORT_UNARY + 1;
335
336var OP_DIFFERENCE = SORT_BINARY + 1;
337var OP_INTERSECT = OP_DIFFERENCE + 1;
338var OP_UNION = OP_INTERSECT + 1;
339var OP_XOR = OP_UNION + 1;
340
341var MARK_LINE = OP_XOR + 1;
342var MARK_QUAD = MARK_LINE + 1;
343var MARK_CUBIC = MARK_QUAD + 1;
344var MARK_DONE_LINE = MARK_CUBIC + 1;
345var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
346var MARK_DONE_CUBIC = MARK_DONE_QUAD + 1;
347var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
348var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
349var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_QUAD + 1;
350var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
351var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
352var MARK_SIMPLE_CUBIC = MARK_SIMPLE_QUAD + 1;
353var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
354var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
355var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_QUAD + 1;
356var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
357var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
358var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_QUAD + 1;
359var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
360
361var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
362var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
363
364var ANGLE_AFTER = COMPUTED_SET_2;
365var ANGLE_AFTER2 = ANGLE_AFTER + 1;
366
367var ACTIVE_OP = ANGLE_AFTER2 + 1;
368
369var FRAG_TYPE_LAST = ACTIVE_OP;
370
371var REC_TYPE_UNKNOWN = -1;
372var REC_TYPE_PATH = 0;
373var REC_TYPE_SECT = 1;
374var REC_TYPE_ACTIVE = 2;
375var REC_TYPE_ADD = 3;
376var REC_TYPE_SORT = 4;
377var REC_TYPE_OP = 5;
378var REC_TYPE_MARK = 6;
379var REC_TYPE_COMPUTED = 7;
380var REC_TYPE_COIN = 8;
381var REC_TYPE_ANGLE = 9;
382var REC_TYPE_ACTIVE_OP = 10;
383var REC_TYPE_LAST = REC_TYPE_ACTIVE_OP;
384
385function strs_to_nums(strs) {
386 var result = [];
387 for (var idx = 1; idx < strs.length; ++idx) {
388 var str = strs[idx];
389 var num = parseFloat(str);
390 if (isNaN(num)) {
391 result.push(str);
392 } else {
393 result.push(num);
394 }
395 }
396 return result;
397}
398
399function filter_str_by(id, str, regex, array) {
400 if (regex.test(str)) {
401 var strs = regex.exec(str);
402 var result = strs_to_nums(strs);
403 array.push(id);
404 array.push(result);
405 return true;
406 }
407 return false;
408}
409
410function construct_regexp2(pattern) {
411 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
412 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
413 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
414 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
415 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
416 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
417 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
418 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
419 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
420 escape = escape.replace(/PATH/g, "pathB?");
421 escape = escape.replace(/IDX/g, "(\\d+)");
422 escape = escape.replace(/NUM/g, "(-?\\d+)");
423 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
424 return new RegExp(escape, 'i');
425}
426
427function construct_regexp2c(pattern) {
428 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
429 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
430 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}");
431 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}");
432 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{P_VAL\\}, \\{P_VAL\\}\\}");
433 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
434 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
435 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?,(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
436 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
437 escape = escape.replace(/OPER/g, "[a-z]+");
438 escape = escape.replace(/PATH/g, "pathB?");
439 escape = escape.replace(/T_F/g, "([TF])");
440 escape = escape.replace(/IDX/g, "(\\d+)");
441 escape = escape.replace(/NUM/g, "(-?\\d+)");
442 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
443 return new RegExp(escape, 'i');
444}
445
446function match_regexp(str, lineNo, array, id, pattern) {
447 var regex = construct_regexp2(pattern);
448 if (filter_str_by(id, str, regex, array)) {
449 return true;
450 }
451 regex = construct_regexp2c(pattern);
452 return filter_str_by(id, str, regex, array);
453}
454
455function endsWith(str, suffix) {
456 return str.indexOf(suffix, str.length - suffix.length) !== -1;
457}
458
459function parse_all(test) {
460 var lines = test.match(/[^\r\n]+/g);
461 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
462 var record = [];
463 var recType = REC_TYPE_UNKNOWN;
464 var lastLineNo;
465 var moveX, moveY;
466 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
467 var line = lines[lineNo];
468 if (line.length == 0) {
469 continue;
470 }
471 var opStart = "SkOpSegment::";
472 if (line.lastIndexOf(opStart, 0) === 0) {
473 line = line.substr(opStart.length);
474 }
475 var angleStart = "SkOpAngle::";
476 if (line.lastIndexOf(angleStart, 0) === 0) {
477 line = line.substr(angleStart.length);
478 }
479 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
480 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
481 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
482 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
483 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
484 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
485 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
486 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
487 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
488 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
489 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
490 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
491 : line.lastIndexOf("{{", 0) === 0 ? REC_TYPE_PATH
492 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
493 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
494 : REC_TYPE_UNKNOWN;
495 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
496 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
497 if (recType != REC_TYPE_UNKNOWN) {
498 records.push(recType);
499 records.push(lastLineNo);
500 records.push(record);
501 }
502 record = [];
503 recType = type;
504 lastLineNo = lineNo;
505 }
506 var found = false;
507 switch (recType) {
508 case REC_TYPE_ACTIVE:
509 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
510" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM"
511 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
512" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM"
513 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
514" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=NUM"
515 );
516 break;
517 case REC_TYPE_ACTIVE_OP:
518 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
519" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
520 );
521 break;
522 case REC_TYPE_ADD:
523 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
524 moveX = record[1][0];
525 moveY = record[1][1];
526 found = true;
527 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
528 record[1].unshift(moveY);
529 record[1].unshift(moveX);
530 moveX = record[1][2];
531 moveY = record[1][3];
532 found = true;
533 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
534 record[1].unshift(moveY);
535 record[1].unshift(moveX);
536 moveX = record[1][4];
537 moveY = record[1][5];
538 found = true;
539 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
540 record[1].unshift(moveY);
541 record[1].unshift(moveX);
542 moveX = record[1][6];
543 moveY = record[1][7];
544 found = true;
545 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
546 found = true;
547 } else {
548 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
549 }
550 break;
551 case REC_TYPE_ANGLE:
552 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
553"id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL < id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL < id=IDX IDX/IDX tStart=T_VAL tEnd=T_VAL T_F IDX");
554 if (found) {
555 break;
556 }
557 found = match_regexp(line, lineNo, record, ANGLE_AFTER2, "after " +
558"[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");
559 break;
560 case REC_TYPE_COIN:
561 found = true;
562 break;
563 case REC_TYPE_COMPUTED:
564 found = line == "computed quadratics given"
565 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
566 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
567 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
568 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
569 );
570 break;
571 case REC_TYPE_PATH:
572 found = match_regexp(line, lineNo, record, PATH_LINE, "LINE_VAL"
573 ) || match_regexp(line, lineNo, record, PATH_QUAD, "QUAD_VAL"
574 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "CUBIC_VAL"
575 );
576 break;
577 case REC_TYPE_SECT:
578 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
579" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
580 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
581" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
582 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
583" no intersect LINE_VAL LINE_VAL"
584 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
585" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
586 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
587" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
588 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
589" no intersect QUAD_VAL LINE_VAL"
590 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
591" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
592 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
593" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
594 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
595" no intersect QUAD_VAL QUAD_VAL"
596 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
597" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
598 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
599" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
600 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
601" 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"
602 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
603" no intersect CUBIC_VAL LINE_VAL"
604 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
605" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
606 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
607" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
608 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
609" 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"
610 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
611" 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"
612 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
613" no intersect CUBIC_VAL QUAD_VAL"
614 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
615" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
616 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
617" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
618 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
619" 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"
620 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
621" 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"
622 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
623" no intersect CUBIC_VAL CUBIC_VAL"
624 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
625" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
626 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
627" no self intersect CUBIC_VAL"
628 );
629 break;
630 case REC_TYPE_SORT:
631 var hasDone = / done/.test(line);
632 var hasUnorderable = / unorderable/.test(line);
633 var hasSmall = / small/.test(line);
634 var hasTiny = / tiny/.test(line);
635 var hasOperand = / operand/.test(line);
636 var hasStop = / stop/.test(line);
637 line.replace(/[ a-z]+$/, "");
638 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
639" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
640 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
641" [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"
642 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
643" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
644 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
645" [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"
646 );
647 if (found) {
648 record[1].push(hasDone);
649 record[1].push(hasUnorderable);
650 record[1].push(hasSmall);
651 record[1].push(hasTiny);
652 record[1].push(hasOperand);
653 record[1].push(hasStop);
654 }
655 break;
656 case REC_TYPE_MARK:
657 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
658" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
659 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
660" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
661 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
662" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
663 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDoneBinary" +
664" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
665 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDoneBinary" +
666" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
667 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDoneBinary" +
668" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=NUM oppSum=OPT windSum=OPT windValue=IDX"
669 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_LINE, "markUnsortable" +
670" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
671 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_QUAD, "markUnsortable" +
672" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
673 ) || match_regexp(line, lineNo, record, MARK_UNSORTABLE_CUBIC, "markUnsortable" +
674" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
675 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
676" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
677 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
678" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
679 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
680" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
681 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_LINE, "markDone" +
682" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
683 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_QUAD, "markDone" +
684" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
685 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_DONE_CUBIC, "markDone" +
686" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
687 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_LINE, "markDoneUnary" +
688" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
689 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_QUAD, "markDoneUnary" +
690" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
691 ) || match_regexp(line, lineNo, record, MARK_DONE_UNARY_CUBIC, "markDoneUnary" +
692" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
693 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
694" last id=IDX windSum=OPT small=IDX");
695 break;
696 case REC_TYPE_OP:
697 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
698 || line.lastIndexOf("operator<", 0) === 0) {
699 found = true;
700 break;
701 }
702 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op difference"
703 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
704 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
705 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
706 );
707 break;
708 case REC_TYPE_UNKNOWN:
709 found = true;
710 break;
711 }
712 if (!found) {
713 console.log(line + " [" + lineNo + "] of type " + type + " not found");
714 }
715 }
716 if (recType != REC_TYPE_UNKNOWN) {
717 records.push(recType);
718 records.push(lastLineNo);
719 records.push(record);
720 }
721 if (records.length >= 1) {
722 tests[testIndex] = records;
723 testLines[testIndex] = lines;
724 }
725}
726
727function init(test) {
728 var canvas = document.getElementById('canvas');
729 if (!canvas.getContext) return;
730 ctx = canvas.getContext('2d');
731 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
732 var unscaledWidth = window.innerWidth - 20;
733 var unscaledHeight = window.innerHeight - 20;
734 screenWidth = unscaledWidth;
735 screenHeight = unscaledHeight;
736 canvas.width = unscaledWidth * resScale;
737 canvas.height = unscaledHeight * resScale;
738 canvas.style.width = unscaledWidth + 'px';
739 canvas.style.height = unscaledHeight + 'px';
740 if (resScale != 1) {
741 ctx.scale(resScale, resScale);
742 }
743 xmin = Infinity;
744 xmax = -Infinity;
745 ymin = Infinity;
746 ymax = -Infinity;
747 hasPath = hasComputedPath = false;
748 firstActiveSpan = -1;
749 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
750 var recType = test[tIndex];
751 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
752 console.log("unknown rec type: " + recType);
753 throw "stop execution";
754 }
755 var records = test[tIndex + 2];
756 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
757 var fragType = records[recordIndex];
758 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
759 console.log("unknown in range frag type: " + fragType);
760 throw "stop execution";
761 }
762 var frags = records[recordIndex + 1];
763 var first = 0;
764 var last = -1;
765 var first2 = 0;
766 var last2 = 0;
767 switch (recType) {
768 case REC_TYPE_COMPUTED:
769 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
770 break;
771 }
772 hasComputedPath = true;
773 case REC_TYPE_PATH:
774 switch (fragType) {
775 case PATH_LINE:
776 last = 4;
777 break;
778 case PATH_QUAD:
779 last = 6;
780 break;
781 case PATH_CUBIC:
782 last = 8;
783 break;
784 default:
785 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
786 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
787 throw "stop execution";
788 }
789 if (recType == REC_TYPE_PATH) {
790 hasPath = true;
791 }
792 break;
793 case REC_TYPE_ACTIVE:
794 if (firstActiveSpan < 0) {
795 firstActiveSpan = tIndex;
796 }
797 first = 1;
798 switch (fragType) {
799 case ACTIVE_LINE_SPAN:
800 last = 5;
801 break;
802 case ACTIVE_QUAD_SPAN:
803 last = 7;
804 break;
805 case ACTIVE_CUBIC_SPAN:
806 last = 9;
807 break;
808 default:
809 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
810 throw "stop execution";
811 }
812 break;
813 case REC_TYPE_ADD:
814 switch (fragType) {
815 case ADD_MOVETO:
816 break;
817 case ADD_LINETO:
818 last = 4;
819 break;
820 case ADD_QUADTO:
821 last = 6;
822 break;
823 case ADD_CUBICTO:
824 last = 8;
825 break;
826 case ADD_CLOSE:
827 case ADD_FILL:
828 break;
829 default:
830 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
831 throw "stop execution";
832 }
833 break;
834 case REC_TYPE_SECT:
835 switch (fragType) {
836 case INTERSECT_LINE:
837 first = 1; last = 5; first2 = 8; last2 = 12;
838 break;
839 case INTERSECT_LINE_2:
840 first = 1; last = 5; first2 = 11; last2 = 15;
841 break;
842 case INTERSECT_LINE_NO:
843 first = 0; last = 4; first2 = 4; last2 = 8;
844 break;
845 case INTERSECT_QUAD_LINE:
846 first = 1; last = 7; first2 = 10; last2 = 14;
847 break;
848 case INTERSECT_QUAD_LINE_2:
849 first = 1; last = 7; first2 = 13; last2 = 17;
850 break;
851 case INTERSECT_QUAD_LINE_NO:
852 first = 0; last = 6; first2 = 6; last2 = 10;
853 break;
854 case INTERSECT_QUAD:
855 first = 1; last = 7; first2 = 10; last2 = 16;
856 break;
857 case INTERSECT_QUAD_2:
858 first = 1; last = 7; first2 = 13; last2 = 19;
859 break;
860 case INTERSECT_QUAD_NO:
861 first = 0; last = 6; first2 = 6; last2 = 12;
862 break;
863 case INTERSECT_SELF_CUBIC:
864 first = 1; last = 9;
865 break;
866 case INTERSECT_SELF_CUBIC_NO:
867 first = 0; last = 8;
868 break;
869 case INTERSECT_CUBIC_LINE:
870 first = 1; last = 9; first2 = 12; last2 = 16;
871 break;
872 case INTERSECT_CUBIC_LINE_2:
873 first = 1; last = 9; first2 = 15; last2 = 19;
874 break;
875 case INTERSECT_CUBIC_LINE_3:
876 first = 1; last = 9; first2 = 18; last2 = 22;
877 break;
878 case INTERSECT_CUBIC_LINE_NO:
879 first = 0; last = 8; first2 = 8; last2 = 12;
880 break;
881 case INTERSECT_CUBIC_QUAD:
882 first = 1; last = 9; first2 = 12; last2 = 18;
883 break;
884 case INTERSECT_CUBIC_QUAD_2:
885 first = 1; last = 9; first2 = 15; last2 = 21;
886 break;
887 case INTERSECT_CUBIC_QUAD_3:
888 first = 1; last = 9; first2 = 18; last2 = 24;
889 break;
890 case INTERSECT_CUBIC_QUAD_4:
891 first = 1; last = 9; first2 = 21; last2 = 27;
892 break;
893 case INTERSECT_CUBIC_QUAD_NO:
894 first = 0; last = 8; first2 = 8; last2 = 14;
895 break;
896 case INTERSECT_CUBIC:
897 first = 1; last = 9; first2 = 12; last2 = 20;
898 break;
899 case INTERSECT_CUBIC_2:
900 first = 1; last = 9; first2 = 15; last2 = 23;
901 break;
902 case INTERSECT_CUBIC_3:
903 first = 1; last = 9; first2 = 18; last2 = 26;
904 break;
905 case INTERSECT_CUBIC_4:
906 first = 1; last = 9; first2 = 21; last2 = 29;
907 break;
908 case INTERSECT_CUBIC_NO:
909 first = 0; last = 8; first2 = 8; last2 = 16;
910 break;
911 default:
912 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
913 throw "stop execution";
914 }
915 break;
916 default:
917 continue;
918 }
919 for (var idx = first; idx < last; idx += 2) {
920 xmin = Math.min(xmin, frags[idx]);
921 xmax = Math.max(xmax, frags[idx]);
922 ymin = Math.min(ymin, frags[idx + 1]);
923 ymax = Math.max(ymax, frags[idx + 1]);
924 }
925 for (var idx = first2; idx < last2; idx += 2) {
926 xmin = Math.min(xmin, frags[idx]);
927 xmax = Math.max(xmax, frags[idx]);
928 ymin = Math.min(ymin, frags[idx + 1]);
929 ymax = Math.max(ymax, frags[idx + 1]);
930 }
931 }
932 }
933 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
934 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
935 var recType = test[tIndex];
936 var records = test[tIndex + 2];
937 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
938 var fragType = records[recordIndex];
939 var frags = records[recordIndex + 1];
940 switch (recType) {
941 case REC_TYPE_ACTIVE_OP:
942 if (!draw_op) {
943 break;
944 }
945 {
946 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
947 curve_extremes(curve, angleBounds);
948 }
949 break;
950 case REC_TYPE_ANGLE:
951 if (!draw_angle) {
952 break;
953 }
954 if (fragType == ANGLE_AFTER) {
955 var curve = curvePartialByID(test, frags[0], frags[3], frags[4]);
956 curve_extremes(curve, angleBounds);
957 curve = curvePartialByID(test, frags[5], frags[8], frags[9]);
958 curve_extremes(curve, angleBounds);
959 curve = curvePartialByID(test, frags[10], frags[13], frags[14]);
960 } else if (fragType == ANGLE_AFTER2) {
961 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
962 curve_extremes(curve, angleBounds);
963 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
964 curve_extremes(curve, angleBounds);
965 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
966 }
967 break;
968 case REC_TYPE_SORT:
969 if (!draw_sort) {
970 break;
971 }
972 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
973 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
974 curve_extremes(curve, angleBounds);
975 }
976 break;
977 }
978 }
979 }
980 xmin = Math.min(xmin, angleBounds[0]);
981 ymin = Math.min(ymin, angleBounds[1]);
982 xmax = Math.max(xmax, angleBounds[2]);
983 ymax = Math.max(ymax, angleBounds[3]);
984 setScale(xmin, xmax, ymin, ymax);
985 if (hasPath == false && hasComputedPath == true && !draw_computed) {
986 draw_computed = 3; // show both quadratics and cubics
987 }
988 if (hasPath == true && hasComputedPath == false && draw_computed) {
989 draw_computed = 0;
990 }
991}
992
993function curveByID(test, id) {
994 var tIndex = firstActiveSpan;
995 if (tIndex < 0) {
996 return [];
997 }
998 while (tIndex < test.length) {
999 var recType = test[tIndex];
1000 if (recType != REC_TYPE_ACTIVE) {
1001 return [];
1002 }
1003 var records = test[tIndex + 2];
1004 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1005 var fragType = records[recordIndex];
1006 var frags = records[recordIndex + 1];
1007 if (frags[0] == id) {
1008 switch (fragType) {
1009 case ACTIVE_LINE_SPAN:
1010 return [frags[1], frags[2], frags[3], frags[4]];
1011 case ACTIVE_QUAD_SPAN:
1012 return [frags[1], frags[2], frags[3], frags[4],
1013 frags[5], frags[6]];
1014 case ACTIVE_CUBIC_SPAN:
1015 return [frags[1], frags[2], frags[3], frags[4],
1016 frags[5], frags[6], frags[7], frags[8]];
1017 }
1018 }
1019 }
1020 tIndex += 3;
1021 }
1022 return [];
1023}
1024
1025function curvePartialByID(test, id, t0, t1) {
1026 var tIndex = firstActiveSpan;
1027 if (tIndex < 0) {
1028 return [];
1029 }
1030 while (tIndex < test.length) {
1031 var recType = test[tIndex];
1032 if (recType != REC_TYPE_ACTIVE) {
1033 return [];
1034 }
1035 var records = test[tIndex + 2];
1036 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1037 var fragType = records[recordIndex];
1038 var frags = records[recordIndex + 1];
1039 if (frags[0] == id) {
1040 switch (fragType) {
1041 case ACTIVE_LINE_SPAN:
1042 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
1043 case ACTIVE_QUAD_SPAN:
1044 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1045 frags[5], frags[6], t0, t1);
1046 case ACTIVE_CUBIC_SPAN:
1047 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1048 frags[5], frags[6], frags[7], frags[8], t0, t1);
1049 }
1050 }
1051 }
1052 tIndex += 3;
1053 }
1054 return [];
1055}
1056
1057function idByCurve(test, frag, type) {
1058 var tIndex = firstActiveSpan;
1059 if (tIndex < 0) {
1060 return -1;
1061 }
1062 while (tIndex < test.length) {
1063 var recType = test[tIndex];
1064 if (recType != REC_TYPE_ACTIVE) {
1065 return -1;
1066 }
1067 var records = test[tIndex + 2];
1068 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1069 var fragType = records[recordIndex];
1070 var frags = records[recordIndex + 1];
1071 switch (fragType) {
1072 case ACTIVE_LINE_SPAN:
1073 if (type != PATH_LINE) {
1074 continue;
1075 }
1076 if (frag[0] != frags[1] || frag[1] != frags[2]
1077 || frag[2] != frags[3] || frag[3] != frags[4]) {
1078 continue;
1079 }
1080 return frags[0];
1081 case ACTIVE_QUAD_SPAN:
1082 if (type != PATH_QUAD) {
1083 continue;
1084 }
1085 if (frag[0] != frags[1] || frag[1] != frags[2]
1086 || frag[2] != frags[3] || frag[3] != frags[4]
1087 || frag[4] != frags[5] || frag[5] != frags[6]) {
1088 continue;
1089 }
1090 return frags[0];
1091 case ACTIVE_CUBIC_SPAN:
1092 if (type != PATH_CUBIC) {
1093 continue;
1094 }
1095 if (frag[0] != frags[1] || frag[1] != frags[2]
1096 || frag[2] != frags[3] || frag[3] != frags[4]
1097 || frag[4] != frags[5] || frag[5] != frags[6]
1098 || frag[6] != frags[7] || frag[7] != frags[8]) {
1099 continue;
1100 }
1101 return frags[0];
1102 }
1103 }
1104 ++tIndex;
1105 }
1106 return -1;
1107}
1108
1109function curve_extremes(curve, bounds) {
1110 for (var index = 0; index < curve.length; index += 2) {
1111 var x = curve[index];
1112 var y = curve[index + 1];
1113 bounds[0] = Math.min(bounds[0], x);
1114 bounds[1] = Math.min(bounds[1], y);
1115 bounds[2] = Math.max(bounds[2], x);
1116 bounds[3] = Math.max(bounds[3], y);
1117 }
1118}
1119
1120function setScale(x0, x1, y0, y1) {
1121 var srcWidth = x1 - x0;
1122 var srcHeight = y1 - y0;
1123 var usableWidth = screenWidth;
1124 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1125 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1126 usableWidth -= (xDigits + yDigits) * 10;
1127 usableWidth -= decimal_places * 10;
1128 if (draw_legend) {
1129 usableWidth -= 40;
1130 }
1131 var hscale = usableWidth / srcWidth;
1132 var vscale = screenHeight / srcHeight;
1133 scale = Math.min(hscale, vscale);
1134 var invScale = 1 / scale;
1135 var sxmin = x0 - invScale * 5;
1136 var symin = y0 - invScale * 10;
1137 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1138 var symax = y1 + invScale * 10;
1139 srcWidth = sxmax - sxmin;
1140 srcHeight = symax - symin;
1141 hscale = usableWidth / srcWidth;
1142 vscale = screenHeight / srcHeight;
1143 scale = Math.min(hscale, vscale);
1144 srcLeft = sxmin;
1145 srcTop = symin;
1146}
1147
1148function drawArc(curve, op, from, to) {
1149 var type = PATH_LINE + (curve.length / 2 - 2);
1150 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1151 var dy = pt.y - curve[1];
1152 var dx = pt.x - curve[0];
1153 var dist = Math.sqrt(dy * dy + dx * dx);
1154 var _dist = dist * scale;
1155 var angle = Math.atan2(dy, dx);
1156 var _px = (curve[0] - srcLeft) * scale;
1157 var _py = (curve[1] - srcTop) * scale;
1158 var divisor = 4;
1159 var endDist;
1160 do {
1161 var ends = [];
1162 for (var index = -1; index <= 1; index += 2) {
1163 var px = Math.cos(index * Math.PI / divisor);
1164 var py = Math.sin(index * Math.PI / divisor);
1165 ends.push(px);
1166 ends.push(py);
1167 }
1168 var endDx = (ends[2] - ends[0]) * scale * dist;
1169 var endDy = (ends[3] - ends[1]) * scale * dist;
1170 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1171 if (endDist < 100) {
1172 break;
1173 }
1174 divisor *= 2;
1175 } while (true);
1176 if (endDist < 30) {
1177 return;
1178 }
1179 if (op) {
1180 divisor *= 2;
1181 }
1182 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1183 ctx.beginPath();
1184 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1185 ctx.stroke();
1186 var saveAlign = ctx.textAlign;
1187 var saveStyle = ctx.fillStyle;
1188 var saveFont = ctx.font;
1189 ctx.textAlign = "center";
1190 ctx.fillStyle = "black";
1191 ctx.font = "normal 24px Arial";
1192 divisor *= 0.8;
1193 for (var index = -1; index <= 1; index += 2) {
1194 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1195 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1196 var _px = (px - srcLeft) * scale;
1197 var _py = (py - srcTop) * scale;
1198 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1199 }
1200 ctx.textAlign = saveAlign;
1201 ctx.fillStyle = saveStyle;
1202 ctx.font = saveFont;
1203}
1204
1205function drawPoint(px, py, end) {
1206 for (var pts = 0; pts < drawnPts.length; pts += 2) {
1207 var x = drawnPts[pts];
1208 var y = drawnPts[pts + 1];
1209 if (px == x && py == y) {
1210 return;
1211 }
1212 }
1213 drawnPts.push(px);
1214 drawnPts.push(py);
1215 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1216 var _px = (px - srcLeft) * scale;
1217 var _py = (py - srcTop) * scale;
1218 ctx.beginPath();
1219 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1220 ctx.closePath();
1221 if (end) {
1222 ctx.fill();
1223 } else {
1224 ctx.stroke();
1225 }
1226 if (debug_xy) {
1227 ctx.textAlign = "left";
1228 ctx.fillText(label, _px + 5, _py);
1229 }
1230}
1231
1232function drawPoints(ptArray, curveType, drawControls) {
1233 var count = (curveType - PATH_LINE + 2) * 2;
1234 for (var idx = 0; idx < count; idx += 2) {
1235 if (!drawControls && idx != 0 && idx != count - 2) {
1236 continue;
1237 }
1238 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1239 }
1240}
1241
1242function drawControlLines(curve, curveType, drawEnd) {
1243 if (curveType == PATH_LINE) {
1244 return;
1245 }
1246 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1247 drawLine(curve[0], curve[1], curve[2], curve[3]);
1248 drawLine(curve[2], curve[3], curve[4], curve[5]);
1249 if (curveType == PATH_CUBIC) {
1250 drawLine(curve[4], curve[5], curve[6], curve[7]);
1251 if (drawEnd > 1) {
1252 drawLine(curve[6], curve[7], curve[0], curve[1]);
1253 if (drawEnd > 2) {
1254 drawLine(curve[0], curve[1], curve[4], curve[5]);
1255 drawLine(curve[6], curve[7], curve[2], curve[3]);
1256 }
1257 }
1258 } else if (drawEnd > 1) {
1259 drawLine(curve[4], curve[5], curve[0], curve[1]);
1260 }
1261}
1262
1263function pointAtT(curve, curveType, t) {
1264 var xy = {};
1265 switch (curveType) {
1266 case PATH_LINE:
1267 var a = 1 - t;
1268 var b = t;
1269 xy.x = a * curve[0] + b * curve[2];
1270 xy.y = a * curve[1] + b * curve[3];
1271 break;
1272 case PATH_QUAD:
1273 var one_t = 1 - t;
1274 var a = one_t * one_t;
1275 var b = 2 * one_t * t;
1276 var c = t * t;
1277 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1278 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1279 break;
1280 case PATH_CUBIC:
1281 var one_t = 1 - t;
1282 var one_t2 = one_t * one_t;
1283 var a = one_t2 * one_t;
1284 var b = 3 * one_t2 * t;
1285 var t2 = t * t;
1286 var c = 3 * one_t * t2;
1287 var d = t2 * t;
1288 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1289 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1290 break;
1291 }
1292 return xy;
1293}
1294
1295function drawPointAtT(curve, curveType) {
1296 var x, y;
1297 var xy = pointAtT(curve, curveType, curveT);
1298 drawPoint(xy.x, xy.y, true);
1299 if (!draw_intersectT) {
1300 return;
1301 }
1302 ctx.fillStyle = "red";
1303 drawTAtPointUp(xy.x, xy.y, curveT);
1304}
1305
1306function drawTAtPointUp(px, py, t) {
1307 var label = t.toFixed(decimal_places);
1308 var _px = (px - srcLeft)* scale;
1309 var _py = (py - srcTop) * scale;
1310 ctx.fillText(label, _px + 5, _py - 10);
1311}
1312
1313function drawTAtPointDown(px, py, t) {
1314 var label = t.toFixed(decimal_places);
1315 var _px = (px - srcLeft)* scale;
1316 var _py = (py - srcTop) * scale;
1317 ctx.fillText(label, _px + 5, _py + 10);
1318}
1319
1320function alreadyDrawnLine(x1, y1, x2, y2) {
1321 if (collect_bounds) {
1322 if (focus_enabled) {
1323 focusXmin = Math.min(focusXmin, x1, x2);
1324 focusYmin = Math.min(focusYmin, y1, y2);
1325 focusXmax = Math.max(focusXmax, x1, x2);
1326 focusYmax = Math.max(focusYmax, y1, y2);
1327 }
1328 return true;
1329 }
1330 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1331 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1332 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1333 return true;
1334 }
1335 }
1336 drawnLines.push(x1);
1337 drawnLines.push(y1);
1338 drawnLines.push(x2);
1339 drawnLines.push(y2);
1340 return false;
1341}
1342
1343function drawLine(x1, y1, x2, y2) {
1344 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1345 return;
1346 }
1347 ctx.beginPath();
1348 ctx.moveTo((x1 - srcLeft) * scale,
1349 (y1 - srcTop) * scale);
1350 ctx.lineTo((x2 - srcLeft) * scale,
1351 (y2 - srcTop) * scale);
1352 ctx.stroke();
1353}
1354
1355function linePartial(x1, y1, x2, y2, t1, t2) {
1356 var dx = x1 - x2;
1357 var dy = y1 - y2;
1358 var array = [
1359 x1 - t1 * dx,
1360 y1 - t1 * dy,
1361 x1 - t2 * dx,
1362 y1 - t2 * dy
1363 ];
1364 return array;
1365}
1366
1367function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1368 var a = linePartial(x1, y1, x2, y2, t1, t2);
1369 var ax = a[0];
1370 var ay = a[1];
1371 var bx = a[2];
1372 var by = a[3];
1373 if (alreadyDrawnLine(ax, ay, bx, by)) {
1374 return;
1375 }
1376 ctx.beginPath();
1377 ctx.moveTo((ax - srcLeft) * scale,
1378 (ay - srcTop) * scale);
1379 ctx.lineTo((bx - srcLeft) * scale,
1380 (by - srcTop) * scale);
1381 ctx.stroke();
1382}
1383
1384function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1385 if (collect_bounds) {
1386 if (focus_enabled) {
1387 focusXmin = Math.min(focusXmin, x1, x2, x3);
1388 focusYmin = Math.min(focusYmin, y1, y2, y3);
1389 focusXmax = Math.max(focusXmax, x1, x2, x3);
1390 focusYmax = Math.max(focusYmax, y1, y2, y3);
1391 }
1392 return true;
1393 }
1394 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1395 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1396 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1397 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1398 return true;
1399 }
1400 }
1401 drawnQuads.push(x1);
1402 drawnQuads.push(y1);
1403 drawnQuads.push(x2);
1404 drawnQuads.push(y2);
1405 drawnQuads.push(x3);
1406 drawnQuads.push(y3);
1407 return false;
1408}
1409
1410function drawQuad(x1, y1, x2, y2, x3, y3) {
1411 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1412 return;
1413 }
1414 ctx.beginPath();
1415 ctx.moveTo((x1 - srcLeft) * scale,
1416 (y1 - srcTop) * scale);
1417 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1418 (y2 - srcTop) * scale,
1419 (x3 - srcLeft) * scale,
1420 (y3 - srcTop) * scale);
1421 ctx.stroke();
1422}
1423
1424function interp(A, B, t) {
1425 return A + (B - A) * t;
1426}
1427
1428function interp_quad_coords(x1, x2, x3, t)
1429{
1430 var ab = interp(x1, x2, t);
1431 var bc = interp(x2, x3, t);
1432 var abc = interp(ab, bc, t);
1433 return abc;
1434}
1435
1436function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1437 var ax = interp_quad_coords(x1, x2, x3, t1);
1438 var ay = interp_quad_coords(y1, y2, y3, t1);
1439 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1440 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1441 var cx = interp_quad_coords(x1, x2, x3, t2);
1442 var cy = interp_quad_coords(y1, y2, y3, t2);
1443 var bx = 2*dx - (ax + cx)/2;
1444 var by = 2*dy - (ay + cy)/2;
1445 var array = [
1446 ax, ay, bx, by, cx, cy
1447 ];
1448 return array;
1449}
1450
1451function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1452 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1453 var ax = a[0];
1454 var ay = a[1];
1455 var bx = a[2];
1456 var by = a[3];
1457 var cx = a[4];
1458 var cy = a[5];
1459 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1460 return;
1461 }
1462 ctx.beginPath();
1463 ctx.moveTo((ax - srcLeft) * scale,
1464 (ay - srcTop) * scale);
1465 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1466 (by - srcTop) * scale,
1467 (cx - srcLeft) * scale,
1468 (cy - srcTop) * scale);
1469 ctx.stroke();
1470}
1471
1472function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1473 if (collect_bounds) {
1474 if (focus_enabled) {
1475 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1476 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1477 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1478 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1479 }
1480 return true;
1481 }
1482 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1483 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
1484 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1485 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1486 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1487 return true;
1488 }
1489 }
1490 drawnCubics.push(x1);
1491 drawnCubics.push(y1);
1492 drawnCubics.push(x2);
1493 drawnCubics.push(y2);
1494 drawnCubics.push(x3);
1495 drawnCubics.push(y3);
1496 drawnCubics.push(x4);
1497 drawnCubics.push(y4);
1498 return false;
1499}
1500
1501function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1502 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1503 return;
1504 }
1505 ctx.beginPath();
1506 ctx.moveTo((x1 - srcLeft) * scale,
1507 (y1 - srcTop) * scale);
1508 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1509 (y2 - srcTop) * scale,
1510 (x3 - srcLeft) * scale,
1511 (y3 - srcTop) * scale,
1512 (x4 - srcLeft) * scale,
1513 (y4 - srcTop) * scale);
1514 ctx.stroke();
1515}
1516
1517function interp_cubic_coords(x1, x2, x3, x4, t)
1518{
1519 var ab = interp(x1, x2, t);
1520 var bc = interp(x2, x3, t);
1521 var cd = interp(x3, x4, t);
1522 var abc = interp(ab, bc, t);
1523 var bcd = interp(bc, cd, t);
1524 var abcd = interp(abc, bcd, t);
1525 return abcd;
1526}
1527
1528function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1529 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1530 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1531 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1532 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1533 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1534 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1535 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1536 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1537 var mx = ex * 27 - ax * 8 - dx;
1538 var my = ey * 27 - ay * 8 - dy;
1539 var nx = fx * 27 - ax - dx * 8;
1540 var ny = fy * 27 - ay - dy * 8;
1541 var bx = (mx * 2 - nx) / 18;
1542 var by = (my * 2 - ny) / 18;
1543 var cx = (nx * 2 - mx) / 18;
1544 var cy = (ny * 2 - my) / 18;
1545 var array = [
1546 ax, ay, bx, by, cx, cy, dx, dy
1547 ];
1548 return array;
1549}
1550
1551function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1552 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
1553 var ax = a[0];
1554 var ay = a[1];
1555 var bx = a[2];
1556 var by = a[3];
1557 var cx = a[4];
1558 var cy = a[5];
1559 var dx = a[6];
1560 var dy = a[7];
1561 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
1562 return;
1563 }
1564 ctx.beginPath();
1565 ctx.moveTo((ax - srcLeft) * scale,
1566 (ay - srcTop) * scale);
1567 ctx.bezierCurveTo((bx - srcLeft) * scale,
1568 (by - srcTop) * scale,
1569 (cx - srcLeft) * scale,
1570 (cy - srcTop) * scale,
1571 (dx - srcLeft) * scale,
1572 (dy - srcTop) * scale);
1573 ctx.stroke();
1574}
1575
1576function drawCurve(c) {
1577 switch (c.length) {
1578 case 4:
1579 drawLine(c[0], c[1], c[2], c[3]);
1580 break;
1581 case 6:
1582 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1583 break;
1584 case 8:
1585 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1586 break;
1587 }
1588}
1589
1590function boundsWidth(pts) {
1591 var min = pts[0];
1592 var max = pts[0];
1593 for (var idx = 2; idx < pts.length; idx += 2) {
1594 min = Math.min(min, pts[idx]);
1595 max = Math.max(max, pts[idx]);
1596 }
1597 return max - min;
1598}
1599
1600function boundsHeight(pts) {
1601 var min = pts[1];
1602 var max = pts[1];
1603 for (var idx = 3; idx < pts.length; idx += 2) {
1604 min = Math.min(min, pts[idx]);
1605 max = Math.max(max, pts[idx]);
1606 }
1607 return max - min;
1608}
1609
1610function tangent(pts) {
1611 var dx = pts[2] - pts[0];
1612 var dy = pts[3] - pts[1];
1613 if (dx == 0 && dy == 0 && pts.length > 4) {
1614 dx = pts[4] - pts[0];
1615 dy = pts[5] - pts[1];
1616 if (dx == 0 && dy == 0 && pts.length > 6) {
1617 dx = pts[6] - pts[0];
1618 dy = pts[7] - pts[1];
1619 }
1620 }
1621 return Math.atan2(-dy, dx);
1622}
1623
1624function hodograph(cubic) {
1625 var hodo = [];
1626 hodo[0] = 3 * (cubic[2] - cubic[0]);
1627 hodo[1] = 3 * (cubic[3] - cubic[1]);
1628 hodo[2] = 3 * (cubic[4] - cubic[2]);
1629 hodo[3] = 3 * (cubic[5] - cubic[3]);
1630 hodo[4] = 3 * (cubic[6] - cubic[4]);
1631 hodo[5] = 3 * (cubic[7] - cubic[5]);
1632 return hodo;
1633}
1634
1635function hodograph2(cubic) {
1636 var quad = hodograph(cubic);
1637 var hodo = [];
1638 hodo[0] = 2 * (quad[2] - quad[0]);
1639 hodo[1] = 2 * (quad[3] - quad[1]);
1640 hodo[2] = 2 * (quad[4] - quad[2]);
1641 hodo[3] = 2 * (quad[5] - quad[3]);
1642 return hodo;
1643}
1644
1645function quadraticRootsReal(A, B, C, s) {
1646 if (A == 0) {
1647 if (B == 0) {
1648 s[0] = 0;
1649 return C == 0;
1650 }
1651 s[0] = -C / B;
1652 return 1;
1653 }
1654 /* normal form: x^2 + px + q = 0 */
1655 var p = B / (2 * A);
1656 var q = C / A;
1657 var p2 = p * p;
1658 if (p2 < q) {
1659 return 0;
1660 }
1661 var sqrt_D = 0;
1662 if (p2 > q) {
1663 sqrt_D = sqrt(p2 - q);
1664 }
1665 s[0] = sqrt_D - p;
1666 s[1] = -sqrt_D - p;
1667 return 1 + s[0] != s[1];
1668}
1669
1670function add_valid_ts(s, realRoots, t) {
1671 var foundRoots = 0;
1672 for (var index = 0; index < realRoots; ++index) {
1673 var tValue = s[index];
1674 if (tValue >= 0 && tValue <= 1) {
1675 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
1676 if (t[idx2] != tValue) {
1677 t[foundRoots++] = tValue;
1678 }
1679 }
1680 }
1681 }
1682 return foundRoots;
1683}
1684
1685function quadraticRootsValidT(a, b, c, t) {
1686 var s = [];
1687 var realRoots = quadraticRootsReal(A, B, C, s);
1688 var foundRoots = add_valid_ts(s, realRoots, t);
1689 return foundRoots != 0;
1690}
1691
1692function find_cubic_inflections(cubic, tValues) {
1693 var Ax = src[2] - src[0];
1694 var Ay = src[3] - src[1];
1695 var Bx = src[4] - 2 * src[2] + src[0];
1696 var By = src[5] - 2 * src[3] + src[1];
1697 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
1698 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
1699 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
1700 Ax * By - Ay * Bx, tValues);
1701}
1702
1703function dxy_at_t(curve, type, t) {
1704 var dxy = {};
1705 if (type == PATH_QUAD) {
1706 var a = t - 1;
1707 var b = 1 - 2 * t;
1708 var c = t;
1709 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
1710 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
1711 } else if (type == PATH_CUBIC) {
1712 var one_t = 1 - t;
1713 var a = curve[0];
1714 var b = curve[2];
1715 var c = curve[4];
1716 var d = curve[6];
1717 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
1718 a = curve[1];
1719 b = curve[3];
1720 c = curve[5];
1721 d = curve[7];
1722 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
1723 }
1724 return dxy;
1725}
1726
1727function drawLabel(num, px, py) {
1728 ctx.beginPath();
1729 ctx.arc(px, py, 8, 0, Math.PI*2, true);
1730 ctx.closePath();
1731 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
1732 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
1733 ctx.stroke();
1734 ctx.fillStyle = "black";
1735 ctx.font = "normal 10px Arial";
1736 // ctx.rotate(0.001);
1737 ctx.fillText(num, px - 2, py + 3);
1738 // ctx.rotate(-0.001);
1739}
1740
1741function drawLabelX(ymin, num, loc) {
1742 var px = (loc - srcLeft) * scale;
1743 var py = (ymin - srcTop) * scale - 20;
1744 drawLabel(num, px, py);
1745}
1746
1747function drawLabelY(xmin, num, loc) {
1748 var px = (xmin - srcLeft) * scale - 20;
1749 var py = (loc - srcTop) * scale;
1750 drawLabel(num, px, py);
1751}
1752
1753function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
1754 ctx.beginPath();
1755 ctx.moveTo(hx, hy - 100);
1756 ctx.lineTo(hx, hy);
1757 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
1758 ctx.stroke();
1759 ctx.beginPath();
1760 ctx.moveTo(hx, hy);
1761 ctx.lineTo(hx, hy + 100);
1762 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
1763 ctx.stroke();
1764 ctx.beginPath();
1765 ctx.moveTo(hx - 100, hy);
1766 ctx.lineTo(hx, hy);
1767 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
1768 ctx.stroke();
1769 ctx.beginPath();
1770 ctx.moveTo(hx, hy);
1771 ctx.lineTo(hx + 100, hy);
1772 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
1773 ctx.stroke();
1774}
1775
1776function scalexy(x, y, mag) {
1777 var length = Math.sqrt(x * x + y * y);
1778 return mag / length;
1779}
1780
1781function drawArrow(x, y, dx, dy) {
1782 var dscale = scalexy(dx, dy, 1 / scale * 100);
1783 dx *= dscale;
1784 dy *= dscale;
1785 ctx.beginPath();
1786 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
1787 x += dx;
1788 y += dy;
1789 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
1790 dx /= 10;
1791 dy /= 10;
1792 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
1793 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
1794 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
1795 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
1796 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
1797 ctx.stroke();
1798}
1799
1800function x_at_t(curve, t) {
1801 var one_t = 1 - t;
1802 if (curve.length == 4) {
1803 return one_t * curve[0] + t * curve[2];
1804 }
1805 var one_t2 = one_t * one_t;
1806 var t2 = t * t;
1807 if (curve.length == 6) {
1808 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
1809 }
1810 var a = one_t2 * one_t;
1811 var b = 3 * one_t2 * t;
1812 var c = 3 * one_t * t2;
1813 var d = t2 * t;
1814 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1815}
1816
1817function y_at_t(curve, t) {
1818 var one_t = 1 - t;
1819 if (curve.length == 4) {
1820 return one_t * curve[1] + t * curve[3];
1821 }
1822 var one_t2 = one_t * one_t;
1823 var t2 = t * t;
1824 if (curve.length == 6) {
1825 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
1826 }
1827 var a = one_t2 * one_t;
1828 var b = 3 * one_t2 * t;
1829 var c = 3 * one_t * t2;
1830 var d = t2 * t;
1831 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1832}
1833
1834function drawOrder(curve, label) {
1835 var px = x_at_t(curve, 0.75);
1836 var py = y_at_t(curve, 0.75);
1837 var _px = (px - srcLeft) * scale;
1838 var _py = (py - srcTop) * scale;
1839 ctx.beginPath();
1840 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
1841 ctx.closePath();
1842 ctx.fillStyle = "white";
1843 ctx.fill();
1844 if (label == 'L') {
1845 ctx.strokeStyle = "rgba(255,0,0, 1)";
1846 ctx.fillStyle = "rgba(255,0,0, 1)";
1847 } else {
1848 ctx.strokeStyle = "rgba(0,0,255, 1)";
1849 ctx.fillStyle = "rgba(0,0,255, 1)";
1850 }
1851 ctx.stroke();
1852 ctx.font = "normal 16px Arial";
1853 ctx.textAlign = "center";
1854 ctx.fillText(label, _px, _py + 5);
1855 ctx.font = "normal 10px Arial";
1856}
1857
1858function drawID(curve, id) {
1859 var px = x_at_t(curve, 0.5);
1860 var py = y_at_t(curve, 0.5);
1861 var _px = (px - srcLeft) * scale;
1862 var _py = (py - srcTop) * scale;
1863 draw_id_at(id, _px, _py);
1864}
1865
1866function draw_id_at(id, _px, _py) {
1867 ctx.beginPath();
1868 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
1869 ctx.closePath();
1870 ctx.fillStyle = "white";
1871 ctx.fill();
1872 ctx.strokeStyle = "rgba(127,127,0, 1)";
1873 ctx.fillStyle = "rgba(127,127,0, 1)";
1874 ctx.stroke();
1875 ctx.font = "normal 16px Arial";
1876 ctx.textAlign = "center";
1877 ctx.fillText(id, _px, _py + 5);
1878 ctx.font = "normal 10px Arial";
1879}
1880
1881function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
1882 var curve = [x1, y1, x2, y2];
1883 drawCurvePartialID(id, curve, t1, t2);
1884}
1885
1886function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
1887 var curve = [x1, y1, x2, y2, x3, y3];
1888 drawCurvePartialID(id, curve, t1, t2);
1889}
1890
1891function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1892 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
1893 drawCurvePartialID(id, curve, t1, t2);
1894}
1895
1896function drawCurvePartialID(id, curve, t1, t2) {
1897 var px = x_at_t(curve, (t1 + t2) / 2);
1898 var py = y_at_t(curve, (t1 + t2) / 2);
1899 var _px = (px - srcLeft) * scale;
1900 var _py = (py - srcTop) * scale;
1901 draw_id_at(id, _px, _py);
1902}
1903
1904function drawCurveSpecials(test, curve, type) {
1905 if (pt_labels) {
1906 drawPoints(curve, type, pt_labels == 2);
1907 }
1908 if (control_lines != 0) {
1909 drawControlLines(curve, type, control_lines);
1910 }
1911 if (curve_t) {
1912 drawPointAtT(curve, type);
1913 }
1914 if (draw_midpoint) {
1915 var mid = pointAtT(curve, type, 0.5);
1916 drawPoint(mid.x, mid.y, true);
1917 }
1918 if (draw_id) {
1919 var id = idByCurve(test, curve, type);
1920 if (id >= 0) {
1921 drawID(curve, id);
1922 }
1923 }
1924 if (type == PATH_LINE) {
1925 return;
1926 }
1927 if (draw_deriviatives > 0) {
1928 var d = dxy_at_t(curve, type, 0);
1929 drawArrow(curve[0], curve[1], d.x, d.y);
1930 if (draw_deriviatives == 2) {
1931 d = dxy_at_t(curve, type, 1);
1932 if (type == PATH_CUBIC) {
1933 drawArrow(curve[6], curve[7], d.x, d.y);
1934 } else {
1935 drawArrow(curve[4], curve[5], d.x, d.y);
1936 }
1937 }
1938 if (draw_midpoint) {
1939 var mid = pointAtT(curve, type, 0.5);
1940 d = dxy_at_t(curve, type, 0.5);
1941 drawArrow(mid.x, mid.y, d.x, d.y);
1942 }
1943 }
1944 if (type != PATH_CUBIC) {
1945 return;
1946 }
1947 if (draw_hodo == 1 || draw_hodo == 2) {
1948 var hodo = hodograph(curve);
1949 var hMinX = Math.min(0, hodo[0], hodo[2], hodo[4]);
1950 var hMinY = Math.min(0, hodo[1], hodo[3], hodo[5]);
1951 var hMaxX = Math.max(0, hodo[0], hodo[2], hodo[4]);
1952 var hMaxY = Math.max(0, hodo[1], hodo[3], hodo[5]);
1953 var hScaleX = hMaxX - hMinX > 0 ? screenWidth / (hMaxX - hMinX) : 1;
1954 var hScaleY = hMaxY - hMinY > 0 ? screenHeight / (hMaxY - hMinY) : 1;
1955 var hUnit = Math.min(hScaleX, hScaleY);
1956 hUnit /= 2;
1957 var hx = xoffset - hMinX * hUnit;
1958 var hy = yoffset - hMinY * hUnit;
1959 ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
1960 ctx.quadraticCurveTo(
1961 hx + hodo[2] * hUnit, hy + hodo[3] * hUnit,
1962 hx + hodo[4] * hUnit, hy + hodo[5] * hUnit);
1963 ctx.strokeStyle = "red";
1964 ctx.stroke();
1965 if (draw_hodo == 1) {
1966 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
1967 }
1968 }
1969 if (draw_hodo == 3) {
1970 var hodo = hodograph2(curve);
1971 var hMinX = Math.min(0, hodo[0], hodo[2]);
1972 var hMinY = Math.min(0, hodo[1], hodo[3]);
1973 var hMaxX = Math.max(0, hodo[0], hodo[2]);
1974 var hMaxY = Math.max(0, hodo[1], hodo[3]);
1975 var hScaleX = hMaxX - hMinX > 0 ? screenWidth / (hMaxX - hMinX) : 1;
1976 var hScaleY = hMaxY - hMinY > 0 ? screenHeight / (hMaxY - hMinY) : 1;
1977 var hUnit = Math.min(hScaleX, hScaleY);
1978 hUnit /= 2;
1979 var hx = xoffset - hMinX * hUnit;
1980 var hy = yoffset - hMinY * hUnit;
1981 ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
1982 ctx.lineTo(hx + hodo[2] * hUnit, hy + hodo[3] * hUnit);
1983 ctx.strokeStyle = "red";
1984 ctx.stroke();
1985 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
1986 }
1987 if (draw_sequence) {
1988 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
1989 for (var i = 0; i < 8; i+= 2) {
1990 drawLabelX(ymin, i >> 1, curve[i]);
1991 }
1992 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
1993 for (var i = 1; i < 8; i+= 2) {
1994 drawLabelY(xmin, i >> 1, curve[i]);
1995 }
1996 }
1997}
1998
1999function logCurves(test) {
2000 for (curves in test) {
2001 var curve = test[curves];
2002 dumpCurve(curve);
2003 }
2004}
2005
2006function curveToString(curve) {
2007 var str = "{{";
2008 for (i = 0; i < curve.length; i += 2) {
2009 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2010 if (i < curve.length - 2) {
2011 str += "}, {";
2012 }
2013 }
2014 str += "}}";
2015 return str;
2016}
2017
2018function dumpCurve(curve) {
2019 console.log(curveToString(curve));
2020}
2021
2022function draw(test, lines, title) {
2023 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2024 ctx.font = "normal 50px Arial";
2025 ctx.textAlign = "left";
2026 ctx.fillText(title, 50, 50);
2027 ctx.font = "normal 10px Arial";
2028 ctx.lineWidth = "1.001"; "0.999";
2029 var secondPath = test.length;
2030 var closeCount = 0;
2031 logStart = -1;
2032 logRange = 0;
2033 // find last active rec type at this step
2034 var curType = test[0];
2035 var curStep = 0;
2036 var hasOp = false;
2037 var lastActive = 0;
2038 var lastAdd = 0;
2039 var lastSect = 0;
2040 var lastSort = 0;
2041 var lastMark = 0;
2042 activeCount = 0;
2043 addCount = 0;
2044 angleCount = 0;
2045 opCount = 0;
2046 sectCount = 0;
2047 sortCount = 0;
2048 markCount = 0;
2049 activeMax = 0;
2050 addMax = 0;
2051 angleMax = 0;
2052 opMax = 0;
2053 sectMax = 0;
2054 sectMax2 = 0;
2055 sortMax = 0;
2056 markMax = 0;
2057 lastIndex = test.length - 3;
2058 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2059 var recType = test[tIndex];
2060 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2061 console.log("unknown rec type: " + recType);
2062 throw "stop execution";
2063 }
2064 // if (curType == recType && curType != REC_TYPE_ADD) {
2065 // continue;
2066 // }
2067 var inStepRange = step_limit == 0 || curStep < step_limit;
2068 curType = recType;
2069 if (recType == REC_TYPE_OP) {
2070 hasOp = true;
2071 continue;
2072 }
2073 if (recType == REC_TYPE_UNKNOWN) {
2074 // these types do not advance step
2075 continue;
2076 }
2077 var bumpStep = false;
2078 var records = test[tIndex + 2];
2079 var fragType = records[0];
2080 if (recType == REC_TYPE_ADD) {
2081 if (records.length != 2) {
2082 console.log("expect only two elements: " + records.length);
2083 throw "stop execution";
2084 }
2085 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2086 continue;
2087 }
2088 ++addMax;
2089 if (!draw_add || !inStepRange) {
2090 continue;
2091 }
2092 lastAdd = tIndex;
2093 ++addCount;
2094 bumpStep = true;
2095 }
2096 if (recType == REC_TYPE_PATH && hasOp) {
2097 secondPath = tIndex;
2098 }
2099 if (recType == REC_TYPE_ACTIVE) {
2100 ++activeMax;
2101 if (!draw_active || !inStepRange) {
2102 continue;
2103 }
2104 lastActive = tIndex;
2105 ++activeCount;
2106 bumpStep = true;
2107 }
2108 if (recType == REC_TYPE_ACTIVE_OP) {
2109 ++opMax;
2110 if (!draw_op || !inStepRange) {
2111 continue;
2112 }
2113 lastOp = tIndex;
2114 ++opCount;
2115 bumpStep = true;
2116 }
2117 if (recType == REC_TYPE_ANGLE) {
2118 ++angleMax;
2119 if (!draw_angle || !inStepRange) {
2120 continue;
2121 }
2122 lastAngle = tIndex;
2123 ++angleCount;
2124 bumpStep = true;
2125 }
2126 if (recType == REC_TYPE_SECT) {
2127 if (records.length != 2) {
2128 console.log("expect only two elements: " + records.length);
2129 throw "stop execution";
2130 }
2131 ++sectMax;
2132 var sectBump = 1;
2133 switch (fragType) {
2134 case INTERSECT_LINE:
2135 case INTERSECT_QUAD_LINE:
2136 case INTERSECT_QUAD:
2137 case INTERSECT_SELF_CUBIC:
2138 case INTERSECT_CUBIC_LINE:
2139 case INTERSECT_CUBIC_QUAD:
2140 case INTERSECT_CUBIC:
2141 sectBump = 1;
2142 break;
2143 case INTERSECT_LINE_2:
2144 case INTERSECT_QUAD_LINE_2:
2145 case INTERSECT_QUAD_2:
2146 case INTERSECT_CUBIC_LINE_2:
2147 case INTERSECT_CUBIC_QUAD_2:
2148 case INTERSECT_CUBIC_2:
2149 sectBump = 2;
2150 break;
2151 case INTERSECT_LINE_NO:
2152 case INTERSECT_QUAD_LINE_NO:
2153 case INTERSECT_QUAD_NO:
2154 case INTERSECT_SELF_CUBIC_NO:
2155 case INTERSECT_CUBIC_LINE_NO:
2156 case INTERSECT_CUBIC_QUAD_NO:
2157 case INTERSECT_CUBIC_NO:
2158 sectBump = 0;
2159 break;
2160 case INTERSECT_CUBIC_LINE_3:
2161 case INTERSECT_CUBIC_QUAD_3:
2162 case INTERSECT_CUBIC_3:
2163 sectBump = 3;
2164 break;
2165 case INTERSECT_CUBIC_QUAD_4:
2166 case INTERSECT_CUBIC_4:
2167 sectBump = 4;
2168 break;
2169 default:
2170 console.log("missing case " + records.length);
2171 throw "stop execution";
2172 }
2173 sectMax2 += sectBump;
2174 if (draw_intersection <= 1 || !inStepRange) {
2175 continue;
2176 }
2177 lastSect = tIndex;
2178 sectCount += sectBump;
2179 bumpStep = true;
2180 }
2181 if (recType == REC_TYPE_SORT) {
2182 ++sortMax;
2183 if (!draw_sort || !inStepRange) {
2184 continue;
2185 }
2186 lastSort = tIndex;
2187 ++sortCount;
2188 bumpStep = true;
2189 }
2190 if (recType == REC_TYPE_MARK) {
2191 ++markMax;
2192 if (!draw_mark || !inStepRange) {
2193 continue;
2194 }
2195 lastMark = tIndex;
2196 ++markCount;
2197 bumpStep = true;
2198 }
2199 if (bumpStep) {
2200 lastIndex = tIndex;
2201 logStart = test[tIndex + 1];
2202 logRange = records.length / 2;
2203 ++curStep;
2204 }
2205 }
2206 stepMax = (draw_add ? addMax : 0)
2207 + (draw_active ? activeMax : 0)
2208 + (draw_op ? opMax : 0)
2209 + (draw_angle ? angleMax : 0)
2210 + (draw_sort ? sortMax : 0)
2211 + (draw_mark ? markMax : 0)
2212 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2213 if (stepMax == 0) {
2214 stepMax = addMax + activeMax + angleMax + opMax + sortMax + markMax;
2215 }
2216 drawnPts = [];
2217 drawnLines = [];
2218 drawnQuads = [];
2219 drawnCubics = [];
2220 focusXmin = focusYmin = Infinity;
2221 focusXmax = focusYmax = -Infinity;
2222 var pathIndex = 0;
2223 var opLetter = 'S';
2224 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2225 var recType = test[tIndex];
2226 var records = test[tIndex + 2];
2227 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2228 var fragType = records[recordIndex];
2229 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2230 console.log("unknown in range frag type: " + fragType);
2231 throw "stop execution";
2232 }
2233 var frags = records[recordIndex + 1];
2234 focus_enabled = false;
2235 switch (recType) {
2236 case REC_TYPE_COMPUTED:
2237 if (draw_computed == 0) {
2238 continue;
2239 }
2240 ctx.lineWidth = 1;
2241 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2242 ctx.fillStyle = "blue";
2243 var drawThis = false;
2244 switch (fragType) {
2245 case PATH_QUAD:
2246 if ((draw_computed & 5) == 1 || ((draw_computed & 4) != 0
2247 && (draw_computed & 1) == pathIndex)) {
2248 drawQuad(frags[0], frags[1], frags[2], frags[3],
2249 frags[4], frags[5]);
2250 drawThis = true;
2251 }
2252 break;
2253 case PATH_CUBIC:
2254 if ((draw_computed & 6) == 2 || ((draw_computed & 4) != 0
2255 && (draw_computed & 1) != pathIndex)) {
2256 drawCubic(frags[0], frags[1], frags[2], frags[3],
2257 frags[4], frags[5], frags[6], frags[7]);
2258 drawThis = true;
2259 }
2260 ++pathIndex;
2261 break;
2262 case COMPUTED_SET_1:
2263 pathIndex = 0;
2264 break;
2265 case COMPUTED_SET_2:
2266 pathIndex = 1;
2267 break;
2268 default:
2269 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2270 throw "stop execution";
2271 }
2272 if (!drawThis || collect_bounds) {
2273 break;
2274 }
2275 drawCurveSpecials(test, frags, fragType);
2276 break;
2277 case REC_TYPE_PATH:
2278 if (!draw_path) {
2279 continue;
2280 }
2281 var firstPath = tIndex < secondPath;
2282 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2283 continue;
2284 }
2285 ctx.lineWidth = 1;
2286 ctx.strokeStyle = firstPath ? "black" : "red";
2287 ctx.fillStyle = "blue";
2288 switch (fragType) {
2289 case PATH_LINE:
2290 drawLine(frags[0], frags[1], frags[2], frags[3]);
2291 break;
2292 case PATH_QUAD:
2293 drawQuad(frags[0], frags[1], frags[2], frags[3],
2294 frags[4], frags[5]);
2295 break;
2296 case PATH_CUBIC:
2297 drawCubic(frags[0], frags[1], frags[2], frags[3],
2298 frags[4], frags[5], frags[6], frags[7]);
2299 break;
2300 default:
2301 console.log("unknown REC_TYPE_PATH frag type: " + fragType);
2302 throw "stop execution";
2303 }
2304 if (collect_bounds) {
2305 break;
2306 }
2307 drawCurveSpecials(test, frags, fragType);
2308 break;
2309 case REC_TYPE_OP:
2310 switch (fragType) {
2311 case OP_INTERSECT: opLetter = 'I'; break;
2312 case OP_DIFFERENCE: opLetter = 'D'; break;
2313 case OP_UNION: opLetter = 'U'; break;
2314 case OP_XOR: opLetter = 'X'; break;
2315 default:
2316 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2317 throw "stop execution";
2318 }
2319 break;
2320 case REC_TYPE_ACTIVE:
2321 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2322 continue;
2323 }
2324 var x1 = frags[SPAN_X1];
2325 var y1 = frags[SPAN_Y1];
2326 var x2 = frags[SPAN_X2];
2327 var y2 = frags[SPAN_Y2];
2328 var x3, y3, x3, y4, t1, t2;
2329 ctx.lineWidth = 3;
2330 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2331 focus_enabled = true;
2332 switch (fragType) {
2333 case ACTIVE_LINE_SPAN:
2334 t1 = frags[SPAN_L_T];
2335 t2 = frags[SPAN_L_TEND];
2336 drawLinePartial(x1, y1, x2, y2, t1, t2);
2337 if (draw_id) {
2338 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
2339 }
2340 break;
2341 case ACTIVE_QUAD_SPAN:
2342 x3 = frags[SPAN_X3];
2343 y3 = frags[SPAN_Y3];
2344 t1 = frags[SPAN_Q_T];
2345 t2 = frags[SPAN_Q_TEND];
2346 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
2347 if (draw_id) {
2348 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
2349 }
2350 break;
2351 case ACTIVE_CUBIC_SPAN:
2352 x3 = frags[SPAN_X3];
2353 y3 = frags[SPAN_Y3];
2354 x4 = frags[SPAN_X4];
2355 y4 = frags[SPAN_Y4];
2356 t1 = frags[SPAN_C_T];
2357 t2 = frags[SPAN_C_TEND];
2358 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2359 if (draw_id) {
2360 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2361 }
2362 break;
2363 default:
2364 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2365 throw "stop execution";
2366 }
2367 break;
2368 case REC_TYPE_ACTIVE_OP:
2369 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2370 continue;
2371 }
2372 focus_enabled = true;
2373 ctx.lineWidth = 3;
2374 var activeSpan = frags[7] == "1";
2375 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2376 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2377 drawCurve(curve);
2378 if (draw_op > 1) {
2379 drawArc(curve, false, frags[3], frags[4]);
2380 drawArc(curve, true, frags[5], frags[6]);
2381 }
2382 break;
2383 case REC_TYPE_ADD:
2384 if (!draw_add) {
2385 continue;
2386 }
2387 ctx.lineWidth = 3;
2388 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2389 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2390 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2391 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2392 : "rgba(127,0,127, 0.3)";
2393 focus_enabled = true;
2394 switch (fragType) {
2395 case ADD_MOVETO:
2396 break;
2397 case ADD_LINETO:
2398 if (step_limit == 0 || tIndex >= lastAdd) {
2399 drawLine(frags[0], frags[1], frags[2], frags[3]);
2400 }
2401 break;
2402 case ADD_QUADTO:
2403 if (step_limit == 0 || tIndex >= lastAdd) {
2404 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2405 }
2406 break;
2407 case ADD_CUBICTO:
2408 if (step_limit == 0 || tIndex >= lastAdd) {
2409 drawCubic(frags[0], frags[1], frags[2], frags[3],
2410 frags[4], frags[5], frags[6], frags[7]);
2411 }
2412 break;
2413 case ADD_CLOSE:
2414 ++closeCount;
2415 break;
2416 case ADD_FILL:
2417 break;
2418 default:
2419 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2420 throw "stop execution";
2421 }
2422 break;
2423 case REC_TYPE_ANGLE:
2424 if (!draw_angle || (step_limit > 0 && tIndex < lastAngle)) {
2425 continue;
2426 }
2427 if (fragType != ANGLE_AFTER && fragType != ANGLE_AFTER2) {
2428 continue;
2429 }
2430 focus_enabled = true;
2431 ctx.lineWidth = 3;
2432 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
2433 var leftCurve, midCurve, rightCurve;
2434 if (fragType == ANGLE_AFTER) {
2435 leftCurve = curvePartialByID(test, frags[0], frags[3], frags[4]);
2436 midCurve = curvePartialByID(test, frags[5], frags[8], frags[9]);
2437 rightCurve = curvePartialByID(test, frags[10], frags[13], frags[14]);
2438 } else {
2439 leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2440 midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2441 rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
2442 }
2443 drawCurve(leftCurve);
2444 drawCurve(rightCurve);
2445 var inBetween = frags[fragType == ANGLE_AFTER ? 15 : 18] == "T";
2446 ctx.strokeStyle = inBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
2447 drawCurve(midCurve);
2448 if (draw_angle > 1) {
2449 drawOrder(leftCurve, 'L');
2450 drawOrder(rightCurve, 'R');
2451 }
2452 break;
2453 case REC_TYPE_SECT:
2454 if (!draw_intersection) {
2455 continue;
2456 }
2457 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
2458 continue;
2459 }
2460 // draw_intersection == 1 : show all
2461 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
2462 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
2463 ctx.lineWidth = 1;
2464 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2465 ctx.fillStyle = "blue";
2466 focus_enabled = true;
2467 var f = [];
2468 var c1s;
2469 var c1l;
2470 var c2s;
2471 var c2l;
2472 switch (fragType) {
2473 case INTERSECT_LINE:
2474 f.push(5, 6, 0, 7);
2475 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
2476 break;
2477 case INTERSECT_LINE_2:
2478 f.push(5, 6, 0, 10);
2479 f.push(8, 9, 7, 15);
2480 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
2481 break;
2482 case INTERSECT_LINE_NO:
2483 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2484 break;
2485 case INTERSECT_QUAD_LINE:
2486 f.push(7, 8, 0, 9);
2487 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
2488 break;
2489 case INTERSECT_QUAD_LINE_2:
2490 f.push(7, 8, 0, 12);
2491 f.push(10, 11, 9, 17);
2492 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
2493 break;
2494 case INTERSECT_QUAD_LINE_NO:
2495 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2496 break;
2497 case INTERSECT_QUAD:
2498 f.push(7, 8, 0, 9);
2499 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
2500 break;
2501 case INTERSECT_QUAD_2:
2502 f.push(7, 8, 0, 12);
2503 f.push(10, 11, 9, 19);
2504 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
2505 break;
2506 case INTERSECT_QUAD_NO:
2507 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2508 break;
2509 case INTERSECT_SELF_CUBIC:
2510 f.push(9, 10, 0, 11);
2511 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
2512 break;
2513 case INTERSECT_SELF_CUBIC_NO:
2514 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
2515 break;
2516 case INTERSECT_CUBIC_LINE:
2517 f.push(9, 10, 0, 11);
2518 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
2519 break;
2520 case INTERSECT_CUBIC_LINE_2:
2521 f.push(9, 10, 0, 14);
2522 f.push(12, 13, 11, 19);
2523 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
2524 break;
2525 case INTERSECT_CUBIC_LINE_3:
2526 f.push(9, 10, 0, 17);
2527 f.push(12, 13, 11, 22);
2528 f.push(15, 16, 14, 23);
2529 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
2530 break;
2531 case INTERSECT_CUBIC_QUAD_NO:
2532 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
2533 break;
2534 case INTERSECT_CUBIC_QUAD:
2535 f.push(9, 10, 0, 11);
2536 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
2537 break;
2538 case INTERSECT_CUBIC_QUAD_2:
2539 f.push(9, 10, 0, 14);
2540 f.push(12, 13, 11, 21);
2541 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
2542 break;
2543 case INTERSECT_CUBIC_QUAD_3:
2544 f.push(9, 10, 0, 17);
2545 f.push(12, 13, 11, 24);
2546 f.push(15, 16, 14, 25);
2547 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
2548 break;
2549 case INTERSECT_CUBIC_QUAD_4:
2550 f.push(9, 10, 0, 20);
2551 f.push(12, 13, 11, 27);
2552 f.push(15, 16, 14, 28);
2553 f.push(18, 19, 17, 29);
2554 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
2555 break;
2556 case INTERSECT_CUBIC_LINE_NO:
2557 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
2558 break;
2559 case INTERSECT_CUBIC:
2560 f.push(9, 10, 0, 11);
2561 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
2562 break;
2563 case INTERSECT_CUBIC_2:
2564 f.push(9, 10, 0, 14);
2565 f.push(12, 13, 11, 23);
2566 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
2567 break;
2568 case INTERSECT_CUBIC_3:
2569 f.push(9, 10, 0, 17);
2570 f.push(12, 13, 11, 26);
2571 f.push(15, 16, 14, 27);
2572 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
2573 break;
2574 case INTERSECT_CUBIC_4:
2575 f.push(9, 10, 0, 20);
2576 f.push(12, 13, 11, 29);
2577 f.push(15, 16, 14, 30);
2578 f.push(18, 19, 17, 31);
2579 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
2580 break;
2581 case INTERSECT_CUBIC_NO:
2582 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
2583 break;
2584 default:
2585 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
2586 throw "stop execution";
2587 }
2588 if (draw_intersection != 1) {
2589 var id = -1;
2590 var curve;
2591 switch (c1l) {
2592 case 4:
2593 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
2594 if (draw_id) {
2595 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
2596 id = idByCurve(test, curve, PATH_LINE);
2597 }
2598 break;
2599 case 6:
2600 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
2601 frags[c1s + 4], frags[c1s + 5]);
2602 if (draw_id) {
2603 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
2604 frags[c1s + 4], frags[c1s + 5]];
2605 id = idByCurve(test, curve, PATH_QUAD);
2606 }
2607 break;
2608 case 8:
2609 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
2610 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
2611 if (draw_id) {
2612 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
2613 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
2614 id = idByCurve(test, curve, PATH_CUBIC);
2615 }
2616 break;
2617 }
2618 if (id >= 0) {
2619 drawID(curve, id);
2620 }
2621 id = -1;
2622 switch (c2l) {
2623 case 0:
2624 break;
2625 case 4:
2626 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
2627 if (draw_id) {
2628 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
2629 id = idByCurve(test, curve, PATH_LINE);
2630 }
2631 break;
2632 case 6:
2633 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
2634 frags[c2s + 4], frags[c2s + 5]);
2635 if (draw_id) {
2636 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
2637 frags[c2s + 4], frags[c2s + 5]];
2638 id = idByCurve(test, curve, PATH_QUAD);
2639 }
2640 break;
2641 case 8:
2642 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
2643 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
2644 if (draw_id) {
2645 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
2646 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
2647 id = idByCurve(test, curve, PATH_CUBIC);
2648 }
2649 break;
2650 }
2651 if (id >= 0) {
2652 drawID(curve, id);
2653 }
2654 }
2655 if (collect_bounds) {
2656 break;
2657 }
2658 for (var idx = 0; idx < f.length; idx += 4) {
2659 if (draw_intersection != 3 || idx == lastSect - tIndex) {
2660 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
2661 }
2662 }
2663 if (!draw_intersectT) {
2664 break;
2665 }
2666 ctx.fillStyle = "red";
2667 for (var idx = 0; idx < f.length; idx += 4) {
2668 if (draw_intersection != 3 || idx == lastSect - tIndex) {
2669 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
2670 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
2671 }
2672 }
2673 break;
2674 case REC_TYPE_SORT:
2675 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
2676 continue;
2677 }
2678 ctx.lineWidth = 3;
2679 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
2680 focus_enabled = true;
2681 switch (fragType) {
2682 case SORT_UNARY:
2683 case SORT_BINARY:
2684 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
2685 drawCurve(curve);
2686 break;
2687 default:
2688 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
2689 throw "stop execution";
2690 }
2691 break;
2692 case REC_TYPE_MARK:
2693 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
2694 continue;
2695 }
2696 ctx.lineWidth = 3;
2697 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
2698 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
2699 focus_enabled = true;
2700 switch (fragType) {
2701 case MARK_LINE:
2702 case MARK_DONE_LINE:
2703 case MARK_UNSORTABLE_LINE:
2704 case MARK_SIMPLE_LINE:
2705 case MARK_SIMPLE_DONE_LINE:
2706 case MARK_DONE_UNARY_LINE:
2707 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
2708 frags[5], frags[9]);
2709 if (draw_id) {
2710 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
2711 frags[5], frags[9]);
2712 }
2713 break;
2714 case MARK_QUAD:
2715 case MARK_DONE_QUAD:
2716 case MARK_UNSORTABLE_QUAD:
2717 case MARK_SIMPLE_QUAD:
2718 case MARK_SIMPLE_DONE_QUAD:
2719 case MARK_DONE_UNARY_QUAD:
2720 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
2721 frags[5], frags[6], frags[7], frags[11]);
2722 if (draw_id) {
2723 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
2724 frags[5], frags[6], frags[7], frags[11]);
2725 }
2726 break;
2727 case MARK_CUBIC:
2728 case MARK_DONE_CUBIC:
2729 case MARK_UNSORTABLE_CUBIC:
2730 case MARK_SIMPLE_CUBIC:
2731 case MARK_SIMPLE_DONE_CUBIC:
2732 case MARK_DONE_UNARY_CUBIC:
2733 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
2734 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
2735 if (draw_id) {
2736 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
2737 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
2738 }
2739 break;
2740 case MARK_ANGLE_LAST:
2741 // FIXME: ignored for now
2742 break;
2743 default:
2744 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
2745 throw "stop execution";
2746 }
2747 break;
2748 default:
2749 continue;
2750 }
2751 }
2752 switch (recType) {
2753 case REC_TYPE_SORT:
2754 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
2755 break;
2756 }
2757 var angles = []; // use tangent lines to describe arcs
2758 var windFrom = [];
2759 var windTo = [];
2760 var opp = [];
2761 var minXY = Number.MAX_VALUE;
2762 var partial;
2763 focus_enabled = true;
2764 var someUnsortable = false;
2765 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2766 var fragType = records[recordIndex];
2767 var frags = records[recordIndex + 1];
2768 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
2769 (fragType == SORT_BINARY && frags[16]);
2770 someUnsortable |= unsortable;
2771 switch (fragType) {
2772 case SORT_UNARY:
2773 case SORT_BINARY:
2774 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
2775 break;
2776 default:
2777 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
2778 throw "stop execution";
2779 }
2780 var dx = boundsWidth(partial);
2781 var dy = boundsHeight(partial);
2782 minXY = Math.min(minXY, dx * dx + dy * dy);
2783 if (collect_bounds) {
2784 continue;
2785 }
2786 angles.push(tangent(partial));
2787 var from = frags[12];
2788 var to = frags[12];
2789 var sgn = frags[10];
2790 if (sgn < 0) {
2791 from -= frags[11];
2792 } else if (sgn > 0) {
2793 to -= frags[11];
2794 }
2795 windFrom.push(from + (unsortable ? "!" : ""));
2796 windTo.push(to + (unsortable ? "!" : ""));
2797 opp.push(fragType == SORT_BINARY);
2798 if (draw_sort == 1) {
2799 drawOrder(partial, frags[12]);
2800 } else {
2801 drawOrder(partial, (recordIndex / 2) + 1);
2802 }
2803 }
2804 var radius = Math.sqrt(minXY) / 2 * scale;
2805 radius = Math.min(50, radius);
2806 var scaledRadius = radius / scale;
2807 var centerX = partial[0];
2808 var centerY = partial[1];
2809 if (collect_bounds) {
2810 if (focus_enabled) {
2811 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
2812 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
2813 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
2814 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
2815 }
2816 break;
2817 }
2818 break;
2819 default:
2820 break;
2821 }
2822 }
2823 if (collect_bounds) {
2824 return;
2825 }
2826 if (draw_log && logStart >= 0) {
2827 ctx.font = "normal 10px Arial";
2828 ctx.textAlign = "left";
2829 ctx.beginPath();
2830 var top = screenHeight - 20 - (logRange + 2) * 10;
2831 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
2832 ctx.fillStyle = "white";
2833 ctx.fill();
2834 ctx.fillStyle = "rgba(0,0,0, 0.5)";
2835 if (logStart > 0) {
2836 ctx.fillText(lines[logStart - 1], 50, top + 8);
2837 }
2838 ctx.fillStyle = "black";
2839 for (var idx = 0; idx < logRange; ++idx) {
2840 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
2841 }
2842 ctx.fillStyle = "rgba(0,0,0, 0.5)";
2843 if (logStart + logRange < lines.length) {
2844 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
2845 }
2846 }
2847 if (draw_legend) {
2848 var pos = 0;
2849 var drawSomething = draw_add | draw_active | draw_sort | draw_mark;
2850 // drawBox(pos++, "yellow", "black", opLetter, true, '');
2851 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
2852 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
2853 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
2854 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
2855 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
2856 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
2857 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
2858 drawBox(pos++, "black", "white",
2859 (new Array('P', 'P1', 'P2', 'P'))[draw_path], draw_path != 0, pathKey);
2860 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
2861 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
2862 draw_computed != 0, computedKey);
2863 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
2864 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
2865 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
2866 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
2867 if (curve_t) {
2868 drawCurveTControl();
2869 }
2870 ctx.font = "normal 20px Arial";
2871 ctx.fillStyle = "rgba(0,0,0, 0.3)";
2872 ctx.textAlign = "right";
2873 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
2874 }
2875 if (draw_hints) {
2876 ctx.font = "normal 10px Arial";
2877 ctx.fillStyle = "rgba(0,0,0, 0.5)";
2878 ctx.textAlign = "right";
2879 var y = 4;
2880 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
2881 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
2882 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
2883 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
2884 ctx.fillText("hodo : " + hodoKey, screenWidth - 10, pos * 50 + y++ * 10);
2885 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
2886 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
2887 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
2888 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
2889 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
2890 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
2891 }
2892}
2893
2894function drawBox(y, backC, foreC, str, enable, label) {
2895 ctx.beginPath();
2896 ctx.fillStyle = backC;
2897 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
2898 ctx.fill();
2899 ctx.font = "normal 16px Arial";
2900 ctx.fillStyle = foreC;
2901 ctx.textAlign = "center";
2902 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
2903 if (!enable) {
2904 ctx.fillStyle = "rgba(255,255,255, 0.5)";
2905 ctx.fill();
2906 }
2907 if (label != '') {
2908 ctx.font = "normal 9px Arial";
2909 ctx.fillStyle = "black";
2910 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
2911 }
2912}
2913
2914function drawCurveTControl() {
2915 ctx.lineWidth = 2;
2916 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
2917 ctx.beginPath();
2918 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
2919 ctx.stroke();
2920 var ty = 40 + curveT * (screenHeight - 80);
2921 ctx.beginPath();
2922 ctx.moveTo(screenWidth - 80, ty);
2923 ctx.lineTo(screenWidth - 85, ty - 5);
2924 ctx.lineTo(screenWidth - 85, ty + 5);
2925 ctx.lineTo(screenWidth - 80, ty);
2926 ctx.fillStyle = "rgba(0,0,0, 0.6)";
2927 ctx.fill();
2928 var num = curveT.toFixed(decimal_places);
2929 ctx.font = "normal 10px Arial";
2930 ctx.textAlign = "left";
2931 ctx.fillText(num, screenWidth - 78, ty);
2932}
2933
2934function ptInTControl() {
2935 var e = window.event;
2936 var tgt = e.target || e.srcElement;
2937 var left = tgt.offsetLeft;
2938 var top = tgt.offsetTop;
2939 var x = (e.clientX - left);
2940 var y = (e.clientY - top);
2941 if (x < screenWidth - 80 || x > screenWidth - 50) {
2942 return false;
2943 }
2944 if (y < 40 || y > screenHeight - 80) {
2945 return false;
2946 }
2947 curveT = (y - 40) / (screenHeight - 120);
2948 if (curveT < 0 || curveT > 1) {
2949 throw "stop execution";
2950 }
2951 return true;
2952}
2953
2954function drawTop() {
2955 if (tests[testIndex] == null) {
2956 var str = testDivs[testIndex].textContent;
2957 parse_all(str);
2958 var title = testDivs[testIndex].id.toString();
2959 testTitles[testIndex] = title;
2960 }
2961 init(tests[testIndex]);
2962 redraw();
2963}
2964
2965function redraw() {
2966 if (focus_on_selection) {
2967 collect_bounds = true;
2968 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
2969 collect_bounds = false;
2970 if (focusXmin < focusXmax && focusYmin < focusYmax) {
2971 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
2972 }
2973 }
2974 ctx.beginPath();
2975 ctx.fillStyle = "white";
2976 ctx.rect(0, 0, screenWidth, screenHeight);
2977 ctx.fill();
2978 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
2979}
2980
2981function dumpCurvePartial(test, id, t0, t1) {
2982 var curve = curveByID(test, id);
2983 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
2984 console.log("id=" + id + " " + name + "=" + curveToString(curve)
2985 + " t0=" + t0 + " t1=" + t1
2986 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
2987}
2988
2989function dumpAngleTest(test, id, t0, t1) {
2990 var curve = curveByID(test, id);
2991 console.log(" { {" + curveToString(curve) + "}, "
2992 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
2993}
2994
2995function dumpLogToConsole() {
2996 if (logStart < 0) {
2997 return;
2998 }
2999 var test = tests[testIndex];
3000 var recType = REC_TYPE_UNKNOWN;
3001 var records;
3002 for (var index = 0; index < test.length; index += 3) {
3003 var lastLineNo = test[index + 1];
3004 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3005 recType = test[index];
3006 records = test[index + 2];
3007 break;
3008 }
3009 }
3010 if (recType == REC_TYPE_UNKNOWN) {
3011 return;
3012 }
3013 var lines = testLines[testIndex];
3014 for (var idx = 0; idx < logRange; ++idx) {
3015 var line = lines[logStart + idx];
3016 console.log(line);
3017 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3018 var fragType = records[recordIndex];
3019 var frags = records[recordIndex + 1];
3020 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
3021 dumpCurvePartial(test, frags[0], frags[3], frags[4]);
3022 dumpCurvePartial(test, frags[5], frags[8], frags[9]);
3023 dumpCurvePartial(test, frags[10], frags[13], frags[14]);
3024 console.log("\nstatic IntersectData intersectDataSet[] = {");
3025 dumpAngleTest(test, frags[0], frags[3], frags[4]);
3026 dumpAngleTest(test, frags[5], frags[8], frags[9]);
3027 dumpAngleTest(test, frags[10], frags[13], frags[14]);
3028 console.log("};");
3029 } else if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER2) {
3030 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3031 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3032 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3033 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3034 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3035 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3036 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3037 console.log("}; //");
3038 }
3039 }
3040 }
3041}
3042
3043var activeKey = 'a';
3044var pathKey = 'b';
3045var pathBackKey = 'B';
3046var centerKey = 'c';
3047var addKey = 'd';
3048var deriviativesKey = 'f';
3049var angleKey = 'g';
3050var angleBackKey = 'G';
3051var hodoKey = 'h';
3052var intersectionKey = 'i';
3053var intersectionBackKey = 'I';
3054var sequenceKey = 'j';
3055var midpointKey = 'k';
3056var logKey = 'l';
3057var logToConsoleKey = 'L';
3058var markKey = 'm';
3059var sortKey = 'o';
3060var opKey = 'p';
3061var opBackKey = 'P';
3062var computedKey = 'q';
3063var computedBackKey = 'Q';
3064var stepKey = 's';
3065var stepBackKey = 'S';
3066var intersectTKey = 't';
3067var curveTKey = 'u';
3068var controlLinesBackKey = 'V';
3069var controlLinesKey = 'v';
3070var ptsKey = 'x';
3071var xyKey = 'y';
3072var logCurvesKey = 'z';
3073var focusKey = '`';
3074var idKey = '.';
3075var retinaKey = '\\';
3076
3077function doKeyPress(evt) {
3078 var char = String.fromCharCode(evt.charCode);
3079 var focusWasOn = false;
3080 switch (char) {
3081 case '0':
3082 case '1':
3083 case '2':
3084 case '3':
3085 case '4':
3086 case '5':
3087 case '6':
3088 case '7':
3089 case '8':
3090 case '9':
3091 decimal_places = char - '0';
3092 redraw();
3093 break;
3094 case activeKey:
3095 draw_active ^= true;
3096 redraw();
3097 break;
3098 case addKey:
3099 draw_add ^= true;
3100 redraw();
3101 break;
3102 case angleKey:
3103 draw_angle = (draw_angle + 1) % 3;
3104 redraw();
3105 break;
3106 case angleBackKey:
3107 draw_angle = (draw_angle + 2) % 3;
3108 redraw();
3109 break;
3110 case centerKey:
3111 setScale(xmin, xmax, ymin, ymax);
3112 redraw();
3113 break;
3114 case controlLinesBackKey:
3115 control_lines = (control_lines + 3) % 4;
3116 redraw();
3117 break;
3118 case controlLinesKey:
3119 control_lines = (control_lines + 1) % 4;
3120 redraw();
3121 break;
3122 case computedBackKey:
3123 draw_computed = (draw_computed + 5) % 6;
3124 redraw();
3125 break;
3126 case computedKey:
3127 draw_computed = (draw_computed + 1) % 6;
3128 redraw();
3129 break;
3130 case curveTKey:
3131 curve_t ^= true;
3132 if (curve_t) {
3133 draw_legend = true;
3134 }
3135 redraw();
3136 break;
3137 case deriviativesKey:
3138 draw_deriviatives = (draw_deriviatives + 1) % 3;
3139 redraw();
3140 break;
3141 case focusKey:
3142 focus_on_selection ^= true;
3143 setScale(xmin, xmax, ymin, ymax);
3144 redraw();
3145 break;
3146 case hodoKey:
3147 draw_hodo = (draw_hodo + 1) % 4;
3148 redraw();
3149 break;
3150 case idKey:
3151 draw_id ^= true;
3152 redraw();
3153 break;
3154 case intersectionBackKey:
3155 draw_intersection = (draw_intersection + 3) % 4;
3156 redraw();
3157 break;
3158 case intersectionKey:
3159 draw_intersection = (draw_intersection + 1) % 4;
3160 redraw();
3161 break;
3162 case intersectTKey:
3163 draw_intersectT ^= true;
3164 redraw();
3165 break;
3166 case logCurvesKey:
3167 logCurves(tests[testIndex]);
3168 break;
3169 case logKey:
3170 draw_log ^= true;
3171 redraw();
3172 break;
3173 case logToConsoleKey:
3174 if (draw_log) {
3175 dumpLogToConsole();
3176 }
3177 break;
3178 case markKey:
3179 draw_mark ^= true;
3180 redraw();
3181 break;
3182 case midpointKey:
3183 draw_midpoint ^= true;
3184 redraw();
3185 break;
3186 case opKey:
3187 draw_op = (draw_op + 1) % 3;
3188 redraw();
3189 break;
3190 case opBackKey:
3191 draw_op = (draw_op + 2) % 3;
3192 redraw();
3193 break;
3194 case pathKey:
3195 draw_path = (draw_path + 1) % 4;
3196 redraw();
3197 break;
3198 case pathBackKey:
3199 draw_path = (draw_path + 3) % 4;
3200 redraw();
3201 break;
3202 case ptsKey:
3203 pt_labels = (pt_labels + 1) % 3;
3204 redraw();
3205 break;
3206 case retinaKey:
3207 retina_scale ^= true;
3208 drawTop();
3209 break;
3210 case sequenceKey:
3211 draw_sequence ^= true;
3212 redraw();
3213 break;
3214 case sortKey:
3215 draw_sort = (draw_sort + 1) % 3;
3216 drawTop();
3217 break;
3218 case stepKey:
3219 step_limit++;
3220 if (step_limit > stepMax) {
3221 step_limit = stepMax;
3222 }
3223 redraw();
3224 break;
3225 case stepBackKey:
3226 step_limit--;
3227 if (step_limit < 0) {
3228 step_limit = 0;
3229 }
3230 redraw();
3231 break;
3232 case xyKey:
3233 debug_xy = (debug_xy + 1) % 3;
3234 redraw();
3235 break;
3236 case '-':
3237 focusWasOn = focus_on_selection;
3238 if (focusWasOn) {
3239 focus_on_selection = false;
3240 scale /= 1.2;
3241 } else {
3242 scale /= 2;
3243 calcLeftTop();
3244 }
3245 redraw();
3246 focus_on_selection = focusWasOn;
3247 break;
3248 case '=':
3249 case '+':
3250 focusWasOn = focus_on_selection;
3251 if (focusWasOn) {
3252 focus_on_selection = false;
3253 scale *= 1.2;
3254 } else {
3255 scale *= 2;
3256 calcLeftTop();
3257 }
3258 redraw();
3259 focus_on_selection = focusWasOn;
3260 break;
3261 case '?':
3262 draw_hints ^= true;
3263 if (draw_hints && !draw_legend) {
3264 draw_legend = true;
3265 }
3266 redraw();
3267 break;
3268 case '/':
3269 draw_legend ^= true;
3270 redraw();
3271 break;
3272 }
3273}
3274
3275function doKeyDown(evt) {
3276 var char = evt.keyCode;
3277 var preventDefault = false;
3278 switch (char) {
3279 case 37: // left arrow
3280 if (evt.shiftKey) {
3281 testIndex -= 9;
3282 }
3283 if (--testIndex < 0)
3284 testIndex = tests.length - 1;
3285 drawTop();
3286 preventDefault = true;
3287 break;
3288 case 39: // right arrow
3289 if (evt.shiftKey) {
3290 testIndex += 9;
3291 }
3292 if (++testIndex >= tests.length)
3293 testIndex = 0;
3294 drawTop();
3295 preventDefault = true;
3296 break;
3297 }
3298 if (preventDefault) {
3299 evt.preventDefault();
3300 return false;
3301 }
3302 return true;
3303}
3304
3305(function() {
3306 var hidden = "hidden";
3307
3308 // Standards:
3309 if (hidden in document)
3310 document.addEventListener("visibilitychange", onchange);
3311 else if ((hidden = "mozHidden") in document)
3312 document.addEventListener("mozvisibilitychange", onchange);
3313 else if ((hidden = "webkitHidden") in document)
3314 document.addEventListener("webkitvisibilitychange", onchange);
3315 else if ((hidden = "msHidden") in document)
3316 document.addEventListener("msvisibilitychange", onchange);
3317 // IE 9 and lower:
3318 else if ('onfocusin' in document)
3319 document.onfocusin = document.onfocusout = onchange;
3320 // All others:
3321 else
3322 window.onpageshow = window.onpagehide
3323 = window.onfocus = window.onblur = onchange;
3324
3325 function onchange (evt) {
3326 var v = 'visible', h = 'hidden',
3327 evtMap = {
3328 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3329 };
3330
3331 evt = evt || window.event;
3332 if (evt.type in evtMap)
3333 document.body.className = evtMap[evt.type];
3334 else
3335 document.body.className = this[hidden] ? "hidden" : "visible";
3336 }
3337})();
3338
3339function calcXY() {
3340 var e = window.event;
3341 var tgt = e.target || e.srcElement;
3342 var left = tgt.offsetLeft;
3343 var top = tgt.offsetTop;
3344 mouseX = (e.clientX - left) / scale + srcLeft;
3345 mouseY = (e.clientY - top) / scale + srcTop;
3346}
3347
3348function calcLeftTop() {
3349 srcLeft = mouseX - screenWidth / 2 / scale;
3350 srcTop = mouseY - screenHeight / 2 / scale;
3351}
3352
3353var disableClick = false;
3354
3355function handleMouseClick() {
3356 if (disableClick) {
3357 return;
3358 }
3359 if (!curve_t || !ptInTControl()) {
3360 calcXY();
3361 calcLeftTop();
3362 }
3363 redraw();
3364// if (!curve_t || !ptInTControl()) {
3365// mouseX = screenWidth / 2 / scale + srcLeft;
3366// mouseY = screenHeight / 2 / scale + srcTop;
3367// }
3368}
3369
3370function handleMouseOver() {
3371 calcXY();
3372 if (debug_xy != 2) {
3373 return;
3374 }
3375 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3376 ctx.beginPath();
3377 ctx.rect(300,100,num.length * 6,10);
3378 ctx.fillStyle="white";
3379 ctx.fill();
3380 ctx.font = "normal 10px Arial";
3381 ctx.fillStyle="black";
3382 ctx.textAlign = "left";
3383 ctx.fillText(num, 300, 108);
3384}
3385
3386function start() {
3387 for (var i = 0; i < testDivs.length; ++i) {
3388 tests[i] = null;
3389 }
3390 testIndex = 0;
3391 drawTop();
3392 window.addEventListener('keypress', doKeyPress, true);
3393 window.addEventListener('keydown', doKeyDown, true);
3394 window.onresize = function() {
3395 drawTop();
3396 }
3397 /*
3398 window.onpagehide = function() {
3399 disableClick = true;
3400 }
3401 */
3402 window.onpageshow = function () {
3403 disableClick = false;
3404 }
3405}
3406
3407</script>
3408</head>
3409
3410<body onLoad="start();">
3411<canvas id="canvas" width="750" height="500"
3412 onmousemove="handleMouseOver()"
3413 onclick="handleMouseClick()"
3414 ></canvas >
3415</body>
3416</html>