3 <div height="0" hidden="true">
7 {{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}},
21 {{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}},
38 debugShowCubicIntersection no self intersect {{137.600006,96}, {137.600006,81}, {129.400009,67.9000015}, {117.300003,60.9000015}}
39 debugShowCubicIntersection no self intersect {{134.800003,30.7000008}, {123.700005,24.3000011}, {110.800003,20.6000004}, {97.1000061,20.6000004}}
40 debugShowCubicIntersection no self intersect {{97.1000061,55.5}, {82.1000061,55.5}, {69.0000076,63.7000008}, {62.0000076,75.8000031}}
41 debugShowCubicIntersection no self intersect {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}}
42 debugShowCubicIntersection no self intersect {{56.4000015,96}, {56.4000015,111}, {64.5999985,124.099998}, {76.6999969,131.100006}}
43 debugShowCubicIntersection no self intersect {{76.6999969,131.100006}, {60.6999969,131.100006}, {47.2999954,141.900009}, {43.3999977,156.700012}}
44 debugShowCubicIntersection no self intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}}
45 debugShowCubicLineIntersection 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}}
46 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
47 debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{172.5,96}, {137.600006,96}}
48 debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
49 debugShowCubicLineIntersection 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}}
50 debugShowCubicLineIntersection 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
51 debugShowCubicIntersection 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}}
52 debugShowCubicLineIntersection 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}}
53 debugShowLineIntersection 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
54 debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{117.300003,60.9000015}, {134.800003,30.7000008}}
55 debugShowCubicLineIntersection 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}}
56 debugShowCubicLineIntersection 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
57 debugShowCubicIntersection 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}}
58 debugShowCubicLineIntersection 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}}
59 debugShowLineIntersection 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}}
60 debugShowCubicLineIntersection 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}}
61 debugShowCubicLineIntersection 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}}
62 debugShowCubicLineIntersection 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
63 debugShowCubicIntersection 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}}
64 debugShowCubicLineIntersection 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}}
65 debugShowLineIntersection 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
66 debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{62.0000076,75.8000031}, {31.6000004,58.2999992}}
67 debugShowCubicLineIntersection 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}}
68 debugShowCubicLineIntersection 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}}
69 debugShowCubicLineIntersection 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}}
70 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{56.4000015,96}} wnTs[0]=1 {{21.5,96}, {56.4000015,96}}
71 debugShowCubicIntersection 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}}
72 debugShowCubicLineIntersection 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}}
73 debugShowCubicLineIntersection 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}}
74 debugShowCubicIntersection 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}}
75 debugShowCubicLineIntersection 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
76 debugShowCubicIntersection 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}}
77 debugShowLineIntersection 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}}
78 debugShowCubicLineIntersection 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}}
79 debugShowLineIntersection wtTs[0]=0 {{43.3999977,156.700012}, {3.33333338e+029,119.400002}} {{161.199997,136}} wnTs[0]=0 {{161.199997,136}, {172.5,96}}
80 debugShowLineIntersection 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}}
81 debugShowCubicLineIntersection 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}}
82 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{172.5,96}} wnTs[0]=1 {{161.199997,136}, {172.5,96}}
83 debugShowLineIntersection 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}}
84 debugShowCubicLineIntersection 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}}
85 debugShowCubicLineIntersection 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}}
86 debugShowLineIntersection 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
87 debugShowCubicLineIntersection 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}}
88 debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{172.5,96}, {137.600006,96}}
89 debugShowLineIntersection wtTs[0]=1 {{228.900009,192}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
90 debugShowCubicLineIntersection 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}}
91 debugShowCubicIntersection 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}}
92 debugShowCubicIntersection 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}}
93 debugShowCubicLineIntersection 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}}
94 debugShowCubicLineIntersection 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}}
95 debugShowCubicIntersection 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}}
96 debugShowCubicLineIntersection 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}}
97 debugShowCubicIntersection 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}}
98 debugShowCubicLineIntersection 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}}
99 debugShowCubicLineIntersection 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}}
100 debugShowCubicIntersection 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}}
101 debugShowCubicLineIntersection no intersect {{31.6000004,58.2999992}, {25.2000008,69.4000015}, {21.5,82.3000031}, {21.5,96}} {{21.5000057,96}, {56.4000092,96}}
102 debugShowCubicLineIntersection 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}}
103 debugShowLineIntersection 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
104 debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{21.5,96}, {56.4000015,96}}
105 debugShowCubicLineIntersection 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}}
106 debugShowCubicIntersection 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}}
107 debugShowCubicIntersection 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}}
108 debugShowCubicLineIntersection 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}}
109 debugShowLineIntersection 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}}
110 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{137.600006,96}} wnTs[0]=1 {{172.5,96}, {137.600006,96}}
111 debugShowCubicLineIntersection 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
112 debugShowLineIntersection 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}}
113 debugShowCubicLineIntersection 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
114 debugShowLineIntersection 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}}
115 debugShowCubicLineIntersection 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
116 debugShowLineIntersection 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}}
117 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{56.4000092,96}} wnTs[0]=1 {{21.5000057,96}, {56.4000092,96}}
118 debugShowCubicLineIntersection 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}}
119 debugShowLineIntersection wtTs[0]=1 {{3.33333338e+029,119.400002}, {29.3999996,-10.8000002}} {{172.5,96}} wnTs[0]=1 {{228.900009,192}, {172.5,96}}
120 debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{172.5,96}, {137.600006,96}}
121 debugShowCubicIntersection 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}}
122 debugShowCubicLineIntersection no intersect {{62,-17.9000015}, {160.399994,147.300003}, {161.199997,141.699997}, {161.199997,136}} {{107.500008,56.7999992}, {116.500008,23.0999985}}
123 debugShowCubicIntersection 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}}
124 debugShowCubicLineIntersection 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}}
125 debugShowCubicIntersection 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}}
126 debugShowCubicIntersection 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}}
127 debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
128 debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{161.199997,136}, {172.5,96}}
129 debugShowLineIntersection wtTs[0]=1 {{161.199997,136}, {172.5,96}} {{172.5,96}} wnTs[0]=1 {{228.900009,192}, {172.5,96}}
130 debugShowCubicIntersection no self intersect {{137.600006,96}, {137.600006,77.1999969}, {124.800003,61.4000015}, {107.500008,56.7999992}}
131 debugShowCubicIntersection no self intersect {{116.500008,23.0999985}, {110.200005,21.3999977}, {103.600006,20.4999981}, {97.0000076,20.4999981}}
132 debugShowCubicIntersection no self intersect {{97.0000076,55.4000015}, {78.2000122,55.4000015}, {62.4000092,68.2000046}, {57.8000069,85.5}}
133 debugShowCubicIntersection no self intersect {{24.1000061,76.5}, {22.4000053,82.8000031}, {21.5000057,89.4000015}, {21.5000057,96}}
134 debugShowCubicIntersection no self intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}}
135 debugShowCubicLineIntersection 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}}
136 debugShowCubicLineIntersection no intersect {{56.4000092,96}, {56.4000092,205.199997}, {228.900009,198.699997}, {228.900009,192}} {{172.5,96}, {137.600006,96}}
137 debugShowLineIntersection wtTs[0]=1 {{228.900009,192}, {172.5,96}} {{172.5,96}} wnTs[0]=0 {{172.5,96}, {137.600006,96}}
138 debugShowCubicLineIntersection 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}}
139 debugShowCubicIntersection 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}}
140 debugShowCubicLineIntersection 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}}
141 debugShowCubicLineIntersection 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}}
142 debugShowCubicLineIntersection 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}}
143 debugShowCubicLineIntersection 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}}
144 debugShowCubicLineIntersection 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}}
145 debugShowCubicLineIntersection 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}}
146 debugShowCubicLineIntersection 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}}
147 debugShowCubicLineIntersection 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}}
148 SkOpSegment::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
149 SkOpSegment::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
150 SkOpSegment::addTPair addTPair this=13 0 other=23 0.999999881
151 SkOpSegment::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
152 SkOpSegment::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
153 SkOpSegment::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
154 SkOpSegment::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
155 SkOpSegment::addTPair addTPair this=17 0 other=23 0.999999881
156 SkOpSegment::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
157 SkOpSegment::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
158 SkOpSegment::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
159 SkOpSegment::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]
160 SkOpSegment::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
161 SkOpSegment::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]
162 SkOpSegment::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
163 SkOpSegment::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]
164 SkOpSegment::addTPair addTPair this=19 1.63955463e-007 other=8 0
165 SkOpSegment::addTPair addTPair this=8 0.999999781 other=19 1
166 SkOpSegment::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
167 SkOpSegment::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]
168 SkOpContour::calcCoincidentWinding count=4
174 <script type="text/javascript">
180 var decimal_places = 3; // make this 3 to show more precision
188 var xmin, xmax, focusXmin, focusXmax;
189 var ymin, ymax, focusYmin, focusYmax;
193 var screenWidth, screenHeight;
194 var drawnPts, drawnLines, drawnQuads, drawnCubics;
198 var collect_bounds = false;
199 var control_lines = 0;
202 var focus_enabled = false;
203 var focus_on_selection = false;
205 var draw_active = false;
206 var draw_add = false;
208 var draw_deriviatives = 0;
209 var draw_hints = false;
212 var draw_intersection = 0;
213 var draw_intersectT = false;
214 var draw_legend = true;
215 var draw_log = false;
216 var draw_mark = false;
217 var draw_midpoint = false;
219 var draw_sequence = false;
222 var draw_computed = 0;
223 var retina_scale = !!window.devicePixelRatio;
243 var hasComputedPath = false;
245 var firstActiveSpan = -1;
250 var SPAN_X1 = SPAN_ID + 1;
251 var SPAN_Y1 = SPAN_X1 + 1;
252 var SPAN_X2 = SPAN_Y1 + 1;
253 var SPAN_Y2 = SPAN_X2 + 1;
254 var SPAN_L_T = SPAN_Y2 + 1;
255 var SPAN_L_TX = SPAN_L_T + 1;
256 var SPAN_L_TY = SPAN_L_TX + 1;
257 var SPAN_L_TEND = SPAN_L_TY + 1;
258 var SPAN_L_OTHER = SPAN_L_TEND + 1;
259 var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
260 var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
261 var SPAN_L_SUM = SPAN_L_OTHERI + 1;
262 var SPAN_L_VAL = SPAN_L_SUM + 1;
263 var SPAN_L_OPP = SPAN_L_VAL + 1;
265 var SPAN_X3 = SPAN_Y2 + 1;
266 var SPAN_Y3 = SPAN_X3 + 1;
267 var SPAN_Q_T = SPAN_Y3 + 1;
268 var SPAN_Q_TX = SPAN_Q_T + 1;
269 var SPAN_Q_TY = SPAN_Q_TX + 1;
270 var SPAN_Q_TEND = SPAN_Q_TY + 1;
271 var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
272 var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
273 var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
274 var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
275 var SPAN_Q_VAL = SPAN_Q_SUM + 1;
276 var SPAN_Q_OPP = SPAN_Q_VAL + 1;
278 var SPAN_X4 = SPAN_Y3 + 1;
279 var SPAN_Y4 = SPAN_X4 + 1;
280 var SPAN_C_T = SPAN_Y4 + 1;
281 var SPAN_C_TX = SPAN_C_T + 1;
282 var SPAN_C_TY = SPAN_C_TX + 1;
283 var SPAN_C_TEND = SPAN_C_TY + 1;
284 var SPAN_C_OTHER = SPAN_C_TEND + 1;
285 var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
286 var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
287 var SPAN_C_SUM = SPAN_C_OTHERI + 1;
288 var SPAN_C_VAL = SPAN_C_SUM + 1;
289 var SPAN_C_OPP = SPAN_C_VAL + 1;
291 var ACTIVE_LINE_SPAN = 1;
292 var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
293 var ACTIVE_CUBIC_SPAN = ACTIVE_QUAD_SPAN + 1;
295 var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
296 var ADD_LINETO = ADD_MOVETO + 1;
297 var ADD_QUADTO = ADD_LINETO + 1;
298 var ADD_CUBICTO = ADD_QUADTO + 1;
299 var ADD_CLOSE = ADD_CUBICTO + 1;
300 var ADD_FILL = ADD_CLOSE + 1;
302 var PATH_LINE = ADD_FILL + 1;
303 var PATH_QUAD = PATH_LINE + 1;
304 var PATH_CUBIC = PATH_QUAD + 1;
306 var INTERSECT_LINE = PATH_CUBIC + 1;
307 var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
308 var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
309 var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
310 var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
311 var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
312 var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
313 var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
314 var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
315 var INTERSECT_SELF_CUBIC = INTERSECT_QUAD_NO + 1;
316 var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
317 var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
318 var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
319 var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
320 var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
321 var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
322 var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
323 var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
324 var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
325 var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
326 var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
327 var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
328 var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
329 var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
330 // FIXME: add cubic 5- 9
331 var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
333 var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
334 var SORT_BINARY = SORT_UNARY + 1;
336 var OP_DIFFERENCE = SORT_BINARY + 1;
337 var OP_INTERSECT = OP_DIFFERENCE + 1;
338 var OP_UNION = OP_INTERSECT + 1;
339 var OP_XOR = OP_UNION + 1;
341 var MARK_LINE = OP_XOR + 1;
342 var MARK_QUAD = MARK_LINE + 1;
343 var MARK_CUBIC = MARK_QUAD + 1;
344 var MARK_DONE_LINE = MARK_CUBIC + 1;
345 var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
346 var MARK_DONE_CUBIC = MARK_DONE_QUAD + 1;
347 var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
348 var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
349 var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_QUAD + 1;
350 var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
351 var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
352 var MARK_SIMPLE_CUBIC = MARK_SIMPLE_QUAD + 1;
353 var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
354 var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
355 var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_QUAD + 1;
356 var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
357 var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
358 var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_QUAD + 1;
359 var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
361 var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
362 var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
364 var ANGLE_AFTER = COMPUTED_SET_2;
365 var ANGLE_AFTER2 = ANGLE_AFTER + 1;
367 var ACTIVE_OP = ANGLE_AFTER2 + 1;
369 var FRAG_TYPE_LAST = ACTIVE_OP;
371 var REC_TYPE_UNKNOWN = -1;
372 var REC_TYPE_PATH = 0;
373 var REC_TYPE_SECT = 1;
374 var REC_TYPE_ACTIVE = 2;
375 var REC_TYPE_ADD = 3;
376 var REC_TYPE_SORT = 4;
378 var REC_TYPE_MARK = 6;
379 var REC_TYPE_COMPUTED = 7;
380 var REC_TYPE_COIN = 8;
381 var REC_TYPE_ANGLE = 9;
382 var REC_TYPE_ACTIVE_OP = 10;
383 var REC_TYPE_LAST = REC_TYPE_ACTIVE_OP;
385 function strs_to_nums(strs) {
387 for (var idx = 1; idx < strs.length; ++idx) {
389 var num = parseFloat(str);
399 function 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);
410 function 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');
427 function 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');
446 function match_regexp(str, lineNo, array, id, pattern) {
447 var regex = construct_regexp2(pattern);
448 if (filter_str_by(id, str, regex, array)) {
451 regex = construct_regexp2c(pattern);
452 return filter_str_by(id, str, regex, array);
455 function endsWith(str, suffix) {
456 return str.indexOf(suffix, str.length - suffix.length) !== -1;
459 function 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
463 var recType = REC_TYPE_UNKNOWN;
466 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
467 var line = lines[lineNo];
468 if (line.length == 0) {
471 var opStart = "SkOpSegment::";
472 if (line.lastIndexOf(opStart, 0) === 0) {
473 line = line.substr(opStart.length);
475 var angleStart = "SkOpAngle::";
476 if (line.lastIndexOf(angleStart, 0) === 0) {
477 line = line.substr(angleStart.length);
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
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);
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"
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"
523 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
524 moveX = record[1][0];
525 moveY = record[1][1];
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];
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];
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];
545 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
548 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
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");
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");
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,"
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"
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"
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"
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);
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");
697 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
698 || line.lastIndexOf("operator<", 0) === 0) {
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"
708 case REC_TYPE_UNKNOWN:
713 console.log(line + " [" + lineNo + "] of type " + type + " not found");
716 if (recType != REC_TYPE_UNKNOWN) {
717 records.push(recType);
718 records.push(lastLineNo);
719 records.push(record);
721 if (records.length >= 1) {
722 tests[testIndex] = records;
723 testLines[testIndex] = lines;
727 function 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';
741 ctx.scale(resScale, resScale);
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";
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";
762 var frags = records[recordIndex + 1];
768 case REC_TYPE_COMPUTED:
769 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
772 hasComputedPath = true;
785 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
786 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
787 throw "stop execution";
789 if (recType == REC_TYPE_PATH) {
793 case REC_TYPE_ACTIVE:
794 if (firstActiveSpan < 0) {
795 firstActiveSpan = tIndex;
799 case ACTIVE_LINE_SPAN:
802 case ACTIVE_QUAD_SPAN:
805 case ACTIVE_CUBIC_SPAN:
809 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
810 throw "stop execution";
830 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
831 throw "stop execution";
837 first = 1; last = 5; first2 = 8; last2 = 12;
839 case INTERSECT_LINE_2:
840 first = 1; last = 5; first2 = 11; last2 = 15;
842 case INTERSECT_LINE_NO:
843 first = 0; last = 4; first2 = 4; last2 = 8;
845 case INTERSECT_QUAD_LINE:
846 first = 1; last = 7; first2 = 10; last2 = 14;
848 case INTERSECT_QUAD_LINE_2:
849 first = 1; last = 7; first2 = 13; last2 = 17;
851 case INTERSECT_QUAD_LINE_NO:
852 first = 0; last = 6; first2 = 6; last2 = 10;
855 first = 1; last = 7; first2 = 10; last2 = 16;
857 case INTERSECT_QUAD_2:
858 first = 1; last = 7; first2 = 13; last2 = 19;
860 case INTERSECT_QUAD_NO:
861 first = 0; last = 6; first2 = 6; last2 = 12;
863 case INTERSECT_SELF_CUBIC:
866 case INTERSECT_SELF_CUBIC_NO:
869 case INTERSECT_CUBIC_LINE:
870 first = 1; last = 9; first2 = 12; last2 = 16;
872 case INTERSECT_CUBIC_LINE_2:
873 first = 1; last = 9; first2 = 15; last2 = 19;
875 case INTERSECT_CUBIC_LINE_3:
876 first = 1; last = 9; first2 = 18; last2 = 22;
878 case INTERSECT_CUBIC_LINE_NO:
879 first = 0; last = 8; first2 = 8; last2 = 12;
881 case INTERSECT_CUBIC_QUAD:
882 first = 1; last = 9; first2 = 12; last2 = 18;
884 case INTERSECT_CUBIC_QUAD_2:
885 first = 1; last = 9; first2 = 15; last2 = 21;
887 case INTERSECT_CUBIC_QUAD_3:
888 first = 1; last = 9; first2 = 18; last2 = 24;
890 case INTERSECT_CUBIC_QUAD_4:
891 first = 1; last = 9; first2 = 21; last2 = 27;
893 case INTERSECT_CUBIC_QUAD_NO:
894 first = 0; last = 8; first2 = 8; last2 = 14;
896 case INTERSECT_CUBIC:
897 first = 1; last = 9; first2 = 12; last2 = 20;
899 case INTERSECT_CUBIC_2:
900 first = 1; last = 9; first2 = 15; last2 = 23;
902 case INTERSECT_CUBIC_3:
903 first = 1; last = 9; first2 = 18; last2 = 26;
905 case INTERSECT_CUBIC_4:
906 first = 1; last = 9; first2 = 21; last2 = 29;
908 case INTERSECT_CUBIC_NO:
909 first = 0; last = 8; first2 = 8; last2 = 16;
912 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
913 throw "stop execution";
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]);
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]);
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];
941 case REC_TYPE_ACTIVE_OP:
946 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
947 curve_extremes(curve, angleBounds);
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]);
972 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
973 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
974 curve_extremes(curve, angleBounds);
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
988 if (hasPath == true && hasComputedPath == false && draw_computed) {
993 function curveByID(test, id) {
994 var tIndex = firstActiveSpan;
998 while (tIndex < test.length) {
999 var recType = test[tIndex];
1000 if (recType != REC_TYPE_ACTIVE) {
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) {
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]];
1025 function curvePartialByID(test, id, t0, t1) {
1026 var tIndex = firstActiveSpan;
1030 while (tIndex < test.length) {
1031 var recType = test[tIndex];
1032 if (recType != REC_TYPE_ACTIVE) {
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) {
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);
1057 function idByCurve(test, frag, type) {
1058 var tIndex = firstActiveSpan;
1062 while (tIndex < test.length) {
1063 var recType = test[tIndex];
1064 if (recType != REC_TYPE_ACTIVE) {
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];
1072 case ACTIVE_LINE_SPAN:
1073 if (type != PATH_LINE) {
1076 if (frag[0] != frags[1] || frag[1] != frags[2]
1077 || frag[2] != frags[3] || frag[3] != frags[4]) {
1081 case ACTIVE_QUAD_SPAN:
1082 if (type != PATH_QUAD) {
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]) {
1091 case ACTIVE_CUBIC_SPAN:
1092 if (type != PATH_CUBIC) {
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]) {
1109 function 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);
1120 function 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;
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);
1148 function 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;
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);
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) {
1182 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1184 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
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";
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);
1200 ctx.textAlign = saveAlign;
1201 ctx.fillStyle = saveStyle;
1202 ctx.font = saveFont;
1205 function 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) {
1215 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1216 var _px = (px - srcLeft) * scale;
1217 var _py = (py - srcTop) * scale;
1219 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1227 ctx.textAlign = "left";
1228 ctx.fillText(label, _px + 5, _py);
1232 function 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) {
1238 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1242 function drawControlLines(curve, curveType, drawEnd) {
1243 if (curveType == PATH_LINE) {
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]);
1252 drawLine(curve[6], curve[7], curve[0], curve[1]);
1254 drawLine(curve[0], curve[1], curve[4], curve[5]);
1255 drawLine(curve[6], curve[7], curve[2], curve[3]);
1258 } else if (drawEnd > 1) {
1259 drawLine(curve[4], curve[5], curve[0], curve[1]);
1263 function pointAtT(curve, curveType, t) {
1265 switch (curveType) {
1269 xy.x = a * curve[0] + b * curve[2];
1270 xy.y = a * curve[1] + b * curve[3];
1274 var a = one_t * one_t;
1275 var b = 2 * one_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];
1282 var one_t2 = one_t * one_t;
1283 var a = one_t2 * one_t;
1284 var b = 3 * one_t2 * t;
1286 var c = 3 * one_t * t2;
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];
1295 function drawPointAtT(curve, curveType) {
1297 var xy = pointAtT(curve, curveType, curveT);
1298 drawPoint(xy.x, xy.y, true);
1299 if (!draw_intersectT) {
1302 ctx.fillStyle = "red";
1303 drawTAtPointUp(xy.x, xy.y, curveT);
1306 function 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);
1313 function 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);
1320 function 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);
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]) {
1336 drawnLines.push(x1);
1337 drawnLines.push(y1);
1338 drawnLines.push(x2);
1339 drawnLines.push(y2);
1343 function drawLine(x1, y1, x2, y2) {
1344 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1348 ctx.moveTo((x1 - srcLeft) * scale,
1349 (y1 - srcTop) * scale);
1350 ctx.lineTo((x2 - srcLeft) * scale,
1351 (y2 - srcTop) * scale);
1355 function linePartial(x1, y1, x2, y2, t1, t2) {
1367 function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1368 var a = linePartial(x1, y1, x2, y2, t1, t2);
1373 if (alreadyDrawnLine(ax, ay, bx, by)) {
1377 ctx.moveTo((ax - srcLeft) * scale,
1378 (ay - srcTop) * scale);
1379 ctx.lineTo((bx - srcLeft) * scale,
1380 (by - srcTop) * scale);
1384 function 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);
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]) {
1401 drawnQuads.push(x1);
1402 drawnQuads.push(y1);
1403 drawnQuads.push(x2);
1404 drawnQuads.push(y2);
1405 drawnQuads.push(x3);
1406 drawnQuads.push(y3);
1410 function drawQuad(x1, y1, x2, y2, x3, y3) {
1411 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
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);
1424 function interp(A, B, t) {
1425 return A + (B - A) * t;
1428 function interp_quad_coords(x1, x2, x3, t)
1430 var ab = interp(x1, x2, t);
1431 var bc = interp(x2, x3, t);
1432 var abc = interp(ab, bc, t);
1436 function 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;
1446 ax, ay, bx, by, cx, cy
1451 function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1452 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1459 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
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);
1472 function 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);
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]) {
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);
1501 function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1502 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
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);
1517 function interp_cubic_coords(x1, x2, x3, x4, t)
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);
1528 function 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;
1546 ax, ay, bx, by, cx, cy, dx, dy
1551 function 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);
1561 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
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);
1576 function drawCurve(c) {
1579 drawLine(c[0], c[1], c[2], c[3]);
1582 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1585 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1590 function boundsWidth(pts) {
1593 for (var idx = 2; idx < pts.length; idx += 2) {
1594 min = Math.min(min, pts[idx]);
1595 max = Math.max(max, pts[idx]);
1600 function boundsHeight(pts) {
1603 for (var idx = 3; idx < pts.length; idx += 2) {
1604 min = Math.min(min, pts[idx]);
1605 max = Math.max(max, pts[idx]);
1610 function 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];
1621 return Math.atan2(-dy, dx);
1624 function hodograph(cubic) {
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]);
1635 function hodograph2(cubic) {
1636 var quad = hodograph(cubic);
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]);
1645 function quadraticRootsReal(A, B, C, s) {
1654 /* normal form: x^2 + px + q = 0 */
1655 var p = B / (2 * A);
1663 sqrt_D = sqrt(p2 - q);
1667 return 1 + s[0] != s[1];
1670 function add_valid_ts(s, realRoots, t) {
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;
1685 function quadraticRootsValidT(a, b, c, t) {
1687 var realRoots = quadraticRootsReal(A, B, C, s);
1688 var foundRoots = add_valid_ts(s, realRoots, t);
1689 return foundRoots != 0;
1692 function 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);
1703 function dxy_at_t(curve, type, t) {
1705 if (type == PATH_QUAD) {
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) {
1717 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
1722 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
1727 function drawLabel(num, px, py) {
1729 ctx.arc(px, py, 8, 0, Math.PI*2, true);
1731 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
1732 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
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);
1741 function drawLabelX(ymin, num, loc) {
1742 var px = (loc - srcLeft) * scale;
1743 var py = (ymin - srcTop) * scale - 20;
1744 drawLabel(num, px, py);
1747 function drawLabelY(xmin, num, loc) {
1748 var px = (xmin - srcLeft) * scale - 20;
1749 var py = (loc - srcTop) * scale;
1750 drawLabel(num, px, py);
1753 function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
1755 ctx.moveTo(hx, hy - 100);
1757 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
1761 ctx.lineTo(hx, hy + 100);
1762 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
1765 ctx.moveTo(hx - 100, hy);
1767 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
1771 ctx.lineTo(hx + 100, hy);
1772 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
1776 function scalexy(x, y, mag) {
1777 var length = Math.sqrt(x * x + y * y);
1778 return mag / length;
1781 function drawArrow(x, y, dx, dy) {
1782 var dscale = scalexy(dx, dy, 1 / scale * 100);
1786 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
1789 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
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)";
1800 function x_at_t(curve, t) {
1802 if (curve.length == 4) {
1803 return one_t * curve[0] + t * curve[2];
1805 var one_t2 = one_t * one_t;
1807 if (curve.length == 6) {
1808 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
1810 var a = one_t2 * one_t;
1811 var b = 3 * one_t2 * t;
1812 var c = 3 * one_t * t2;
1814 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1817 function y_at_t(curve, t) {
1819 if (curve.length == 4) {
1820 return one_t * curve[1] + t * curve[3];
1822 var one_t2 = one_t * one_t;
1824 if (curve.length == 6) {
1825 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
1827 var a = one_t2 * one_t;
1828 var b = 3 * one_t2 * t;
1829 var c = 3 * one_t * t2;
1831 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1834 function 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;
1840 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
1842 ctx.fillStyle = "white";
1845 ctx.strokeStyle = "rgba(255,0,0, 1)";
1846 ctx.fillStyle = "rgba(255,0,0, 1)";
1848 ctx.strokeStyle = "rgba(0,0,255, 1)";
1849 ctx.fillStyle = "rgba(0,0,255, 1)";
1852 ctx.font = "normal 16px Arial";
1853 ctx.textAlign = "center";
1854 ctx.fillText(label, _px, _py + 5);
1855 ctx.font = "normal 10px Arial";
1858 function 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);
1866 function draw_id_at(id, _px, _py) {
1868 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
1870 ctx.fillStyle = "white";
1872 ctx.strokeStyle = "rgba(127,127,0, 1)";
1873 ctx.fillStyle = "rgba(127,127,0, 1)";
1875 ctx.font = "normal 16px Arial";
1876 ctx.textAlign = "center";
1877 ctx.fillText(id, _px, _py + 5);
1878 ctx.font = "normal 10px Arial";
1881 function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
1882 var curve = [x1, y1, x2, y2];
1883 drawCurvePartialID(id, curve, t1, t2);
1886 function 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);
1891 function 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);
1896 function 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);
1904 function drawCurveSpecials(test, curve, type) {
1906 drawPoints(curve, type, pt_labels == 2);
1908 if (control_lines != 0) {
1909 drawControlLines(curve, type, control_lines);
1912 drawPointAtT(curve, type);
1914 if (draw_midpoint) {
1915 var mid = pointAtT(curve, type, 0.5);
1916 drawPoint(mid.x, mid.y, true);
1919 var id = idByCurve(test, curve, type);
1924 if (type == PATH_LINE) {
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);
1935 drawArrow(curve[4], curve[5], d.x, d.y);
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);
1944 if (type != PATH_CUBIC) {
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);
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";
1965 if (draw_hodo == 1) {
1966 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
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);
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";
1985 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
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]);
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]);
1999 function logCurves(test) {
2000 for (curves in test) {
2001 var curve = test[curves];
2006 function curveToString(curve) {
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) {
2018 function dumpCurve(curve) {
2019 console.log(curveToString(curve));
2022 function 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;
2033 // find last active rec type at this step
2034 var curType = test[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";
2064 // if (curType == recType && curType != REC_TYPE_ADD) {
2067 var inStepRange = step_limit == 0 || curStep < step_limit;
2069 if (recType == REC_TYPE_OP) {
2073 if (recType == REC_TYPE_UNKNOWN) {
2074 // these types do not advance step
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";
2085 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2089 if (!draw_add || !inStepRange) {
2096 if (recType == REC_TYPE_PATH && hasOp) {
2097 secondPath = tIndex;
2099 if (recType == REC_TYPE_ACTIVE) {
2101 if (!draw_active || !inStepRange) {
2104 lastActive = tIndex;
2108 if (recType == REC_TYPE_ACTIVE_OP) {
2110 if (!draw_op || !inStepRange) {
2117 if (recType == REC_TYPE_ANGLE) {
2119 if (!draw_angle || !inStepRange) {
2126 if (recType == REC_TYPE_SECT) {
2127 if (records.length != 2) {
2128 console.log("expect only two elements: " + records.length);
2129 throw "stop execution";
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:
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:
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:
2160 case INTERSECT_CUBIC_LINE_3:
2161 case INTERSECT_CUBIC_QUAD_3:
2162 case INTERSECT_CUBIC_3:
2165 case INTERSECT_CUBIC_QUAD_4:
2166 case INTERSECT_CUBIC_4:
2170 console.log("missing case " + records.length);
2171 throw "stop execution";
2173 sectMax2 += sectBump;
2174 if (draw_intersection <= 1 || !inStepRange) {
2178 sectCount += sectBump;
2181 if (recType == REC_TYPE_SORT) {
2183 if (!draw_sort || !inStepRange) {
2190 if (recType == REC_TYPE_MARK) {
2192 if (!draw_mark || !inStepRange) {
2201 logStart = test[tIndex + 1];
2202 logRange = records.length / 2;
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);
2214 stepMax = addMax + activeMax + angleMax + opMax + sortMax + markMax;
2220 focusXmin = focusYmin = Infinity;
2221 focusXmax = focusYmax = -Infinity;
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";
2233 var frags = records[recordIndex + 1];
2234 focus_enabled = false;
2236 case REC_TYPE_COMPUTED:
2237 if (draw_computed == 0) {
2241 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2242 ctx.fillStyle = "blue";
2243 var drawThis = false;
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]);
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]);
2262 case COMPUTED_SET_1:
2265 case COMPUTED_SET_2:
2269 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2270 throw "stop execution";
2272 if (!drawThis || collect_bounds) {
2275 drawCurveSpecials(test, frags, fragType);
2281 var firstPath = tIndex < secondPath;
2282 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2286 ctx.strokeStyle = firstPath ? "black" : "red";
2287 ctx.fillStyle = "blue";
2290 drawLine(frags[0], frags[1], frags[2], frags[3]);
2293 drawQuad(frags[0], frags[1], frags[2], frags[3],
2294 frags[4], frags[5]);
2297 drawCubic(frags[0], frags[1], frags[2], frags[3],
2298 frags[4], frags[5], frags[6], frags[7]);
2301 console.log("unknown REC_TYPE_PATH frag type: " + fragType);
2302 throw "stop execution";
2304 if (collect_bounds) {
2307 drawCurveSpecials(test, frags, 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;
2316 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2317 throw "stop execution";
2320 case REC_TYPE_ACTIVE:
2321 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
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;
2330 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2331 focus_enabled = true;
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);
2338 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
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);
2348 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
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);
2360 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2364 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2365 throw "stop execution";
2368 case REC_TYPE_ACTIVE_OP:
2369 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2372 focus_enabled = true;
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]);
2379 drawArc(curve, false, frags[3], frags[4]);
2380 drawArc(curve, true, frags[5], frags[6]);
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;
2398 if (step_limit == 0 || tIndex >= lastAdd) {
2399 drawLine(frags[0], frags[1], frags[2], frags[3]);
2403 if (step_limit == 0 || tIndex >= lastAdd) {
2404 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
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]);
2419 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2420 throw "stop execution";
2423 case REC_TYPE_ANGLE:
2424 if (!draw_angle || (step_limit > 0 && tIndex < lastAngle)) {
2427 if (fragType != ANGLE_AFTER && fragType != ANGLE_AFTER2) {
2430 focus_enabled = true;
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]);
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]);
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');
2454 if (!draw_intersection) {
2457 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
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
2464 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2465 ctx.fillStyle = "blue";
2466 focus_enabled = true;
2473 case INTERSECT_LINE:
2475 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
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;
2482 case INTERSECT_LINE_NO:
2483 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2485 case INTERSECT_QUAD_LINE:
2487 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
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;
2494 case INTERSECT_QUAD_LINE_NO:
2495 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2497 case INTERSECT_QUAD:
2499 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
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;
2506 case INTERSECT_QUAD_NO:
2507 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2509 case INTERSECT_SELF_CUBIC:
2510 f.push(9, 10, 0, 11);
2511 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
2513 case INTERSECT_SELF_CUBIC_NO:
2514 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
2516 case INTERSECT_CUBIC_LINE:
2517 f.push(9, 10, 0, 11);
2518 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
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;
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;
2531 case INTERSECT_CUBIC_QUAD_NO:
2532 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
2534 case INTERSECT_CUBIC_QUAD:
2535 f.push(9, 10, 0, 11);
2536 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
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;
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;
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;
2556 case INTERSECT_CUBIC_LINE_NO:
2557 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
2559 case INTERSECT_CUBIC:
2560 f.push(9, 10, 0, 11);
2561 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
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;
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;
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;
2581 case INTERSECT_CUBIC_NO:
2582 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
2585 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
2586 throw "stop execution";
2588 if (draw_intersection != 1) {
2593 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
2595 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
2596 id = idByCurve(test, curve, PATH_LINE);
2600 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
2601 frags[c1s + 4], frags[c1s + 5]);
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);
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]);
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);
2626 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
2628 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
2629 id = idByCurve(test, curve, PATH_LINE);
2633 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
2634 frags[c2s + 4], frags[c2s + 5]);
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);
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]);
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);
2655 if (collect_bounds) {
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);
2663 if (!draw_intersectT) {
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]]);
2675 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
2679 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
2680 focus_enabled = true;
2684 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
2688 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
2689 throw "stop execution";
2693 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
2697 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
2698 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
2699 focus_enabled = true;
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]);
2710 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
2711 frags[5], frags[9]);
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]);
2723 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
2724 frags[5], frags[6], frags[7], frags[11]);
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]);
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]);
2740 case MARK_ANGLE_LAST:
2741 // FIXME: ignored for now
2744 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
2745 throw "stop execution";
2754 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
2757 var angles = []; // use tangent lines to describe arcs
2761 var minXY = Number.MAX_VALUE;
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;
2774 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
2777 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
2778 throw "stop execution";
2780 var dx = boundsWidth(partial);
2781 var dy = boundsHeight(partial);
2782 minXY = Math.min(minXY, dx * dx + dy * dy);
2783 if (collect_bounds) {
2786 angles.push(tangent(partial));
2787 var from = frags[12];
2789 var sgn = frags[10];
2792 } else if (sgn > 0) {
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]);
2801 drawOrder(partial, (recordIndex / 2) + 1);
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);
2823 if (collect_bounds) {
2826 if (draw_log && logStart >= 0) {
2827 ctx.font = "normal 10px Arial";
2828 ctx.textAlign = "left";
2830 var top = screenHeight - 20 - (logRange + 2) * 10;
2831 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
2832 ctx.fillStyle = "white";
2834 ctx.fillStyle = "rgba(0,0,0, 0.5)";
2836 ctx.fillText(lines[logStart - 1], 50, top + 8);
2838 ctx.fillStyle = "black";
2839 for (var idx = 0; idx < logRange; ++idx) {
2840 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
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);
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, '');
2868 drawCurveTControl();
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);
2876 ctx.font = "normal 10px Arial";
2877 ctx.fillStyle = "rgba(0,0,0, 0.5)";
2878 ctx.textAlign = "right";
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);
2894 function drawBox(y, backC, foreC, str, enable, label) {
2896 ctx.fillStyle = backC;
2897 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
2899 ctx.font = "normal 16px Arial";
2900 ctx.fillStyle = foreC;
2901 ctx.textAlign = "center";
2902 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
2904 ctx.fillStyle = "rgba(255,255,255, 0.5)";
2908 ctx.font = "normal 9px Arial";
2909 ctx.fillStyle = "black";
2910 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
2914 function drawCurveTControl() {
2916 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
2918 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
2920 var ty = 40 + curveT * (screenHeight - 80);
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)";
2928 var num = curveT.toFixed(decimal_places);
2929 ctx.font = "normal 10px Arial";
2930 ctx.textAlign = "left";
2931 ctx.fillText(num, screenWidth - 78, ty);
2934 function 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) {
2944 if (y < 40 || y > screenHeight - 80) {
2947 curveT = (y - 40) / (screenHeight - 120);
2948 if (curveT < 0 || curveT > 1) {
2949 throw "stop execution";
2954 function drawTop() {
2955 if (tests[testIndex] == null) {
2956 var str = testDivs[testIndex].textContent;
2958 var title = testDivs[testIndex].id.toString();
2959 testTitles[testIndex] = title;
2961 init(tests[testIndex]);
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);
2975 ctx.fillStyle = "white";
2976 ctx.rect(0, 0, screenWidth, screenHeight);
2978 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
2981 function 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)));
2989 function dumpAngleTest(test, id, t0, t1) {
2990 var curve = curveByID(test, id);
2991 console.log(" { {" + curveToString(curve) + "}, "
2992 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
2995 function dumpLogToConsole() {
2999 var test = tests[testIndex];
3000 var recType = REC_TYPE_UNKNOWN;
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];
3010 if (recType == REC_TYPE_UNKNOWN) {
3013 var lines = testLines[testIndex];
3014 for (var idx = 0; idx < logRange; ++idx) {
3015 var line = lines[logStart + idx];
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]);
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("}; //");
3043 var activeKey = 'a';
3045 var pathBackKey = 'B';
3046 var centerKey = 'c';
3048 var deriviativesKey = 'f';
3050 var angleBackKey = 'G';
3052 var intersectionKey = 'i';
3053 var intersectionBackKey = 'I';
3054 var sequenceKey = 'j';
3055 var midpointKey = 'k';
3057 var logToConsoleKey = 'L';
3061 var opBackKey = 'P';
3062 var computedKey = 'q';
3063 var computedBackKey = 'Q';
3065 var stepBackKey = 'S';
3066 var intersectTKey = 't';
3067 var curveTKey = 'u';
3068 var controlLinesBackKey = 'V';
3069 var controlLinesKey = 'v';
3072 var logCurvesKey = 'z';
3075 var retinaKey = '\\';
3077 function doKeyPress(evt) {
3078 var char = String.fromCharCode(evt.charCode);
3079 var focusWasOn = false;
3091 decimal_places = char - '0';
3095 draw_active ^= true;
3103 draw_angle = (draw_angle + 1) % 3;
3107 draw_angle = (draw_angle + 2) % 3;
3111 setScale(xmin, xmax, ymin, ymax);
3114 case controlLinesBackKey:
3115 control_lines = (control_lines + 3) % 4;
3118 case controlLinesKey:
3119 control_lines = (control_lines + 1) % 4;
3122 case computedBackKey:
3123 draw_computed = (draw_computed + 5) % 6;
3127 draw_computed = (draw_computed + 1) % 6;
3137 case deriviativesKey:
3138 draw_deriviatives = (draw_deriviatives + 1) % 3;
3142 focus_on_selection ^= true;
3143 setScale(xmin, xmax, ymin, ymax);
3147 draw_hodo = (draw_hodo + 1) % 4;
3154 case intersectionBackKey:
3155 draw_intersection = (draw_intersection + 3) % 4;
3158 case intersectionKey:
3159 draw_intersection = (draw_intersection + 1) % 4;
3163 draw_intersectT ^= true;
3167 logCurves(tests[testIndex]);
3173 case logToConsoleKey:
3183 draw_midpoint ^= true;
3187 draw_op = (draw_op + 1) % 3;
3191 draw_op = (draw_op + 2) % 3;
3195 draw_path = (draw_path + 1) % 4;
3199 draw_path = (draw_path + 3) % 4;
3203 pt_labels = (pt_labels + 1) % 3;
3207 retina_scale ^= true;
3211 draw_sequence ^= true;
3215 draw_sort = (draw_sort + 1) % 3;
3220 if (step_limit > stepMax) {
3221 step_limit = stepMax;
3227 if (step_limit < 0) {
3233 debug_xy = (debug_xy + 1) % 3;
3237 focusWasOn = focus_on_selection;
3239 focus_on_selection = false;
3246 focus_on_selection = focusWasOn;
3250 focusWasOn = focus_on_selection;
3252 focus_on_selection = false;
3259 focus_on_selection = focusWasOn;
3263 if (draw_hints && !draw_legend) {
3269 draw_legend ^= true;
3275 function doKeyDown(evt) {
3276 var char = evt.keyCode;
3277 var preventDefault = false;
3279 case 37: // left arrow
3283 if (--testIndex < 0)
3284 testIndex = tests.length - 1;
3286 preventDefault = true;
3288 case 39: // right arrow
3292 if (++testIndex >= tests.length)
3295 preventDefault = true;
3298 if (preventDefault) {
3299 evt.preventDefault();
3306 var hidden = "hidden";
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);
3318 else if ('onfocusin' in document)
3319 document.onfocusin = document.onfocusout = onchange;
3322 window.onpageshow = window.onpagehide
3323 = window.onfocus = window.onblur = onchange;
3325 function onchange (evt) {
3326 var v = 'visible', h = 'hidden',
3328 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3331 evt = evt || window.event;
3332 if (evt.type in evtMap)
3333 document.body.className = evtMap[evt.type];
3335 document.body.className = this[hidden] ? "hidden" : "visible";
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;
3348 function calcLeftTop() {
3349 srcLeft = mouseX - screenWidth / 2 / scale;
3350 srcTop = mouseY - screenHeight / 2 / scale;
3353 var disableClick = false;
3355 function handleMouseClick() {
3359 if (!curve_t || !ptInTControl()) {
3364 // if (!curve_t || !ptInTControl()) {
3365 // mouseX = screenWidth / 2 / scale + srcLeft;
3366 // mouseY = screenHeight / 2 / scale + srcTop;
3370 function handleMouseOver() {
3372 if (debug_xy != 2) {
3375 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3377 ctx.rect(300,100,num.length * 6,10);
3378 ctx.fillStyle="white";
3380 ctx.font = "normal 10px Arial";
3381 ctx.fillStyle="black";
3382 ctx.textAlign = "left";
3383 ctx.fillText(num, 300, 108);
3387 for (var i = 0; i < testDivs.length; ++i) {
3392 window.addEventListener('keypress', doKeyPress, true);
3393 window.addEventListener('keydown', doKeyDown, true);
3394 window.onresize = function() {
3398 window.onpagehide = function() {
3399 disableClick = true;
3402 window.onpageshow = function () {
3403 disableClick = false;
3410 <body onLoad="start();">
3411 <canvas id="canvas" width="750" height="500"
3412 onmousemove="handleMouseOver()"
3413 onclick="handleMouseClick()"