blob: 4517ceb505afb60f646173927a32f8bda3f39096 [file] [log] [blame]
caryclarkdac1d172014-06-17 05:15:38 -07001<html>
2<head>
3<div height="0" hidden="true">
caryclarkdac1d172014-06-17 05:15:38 -07004
caryclark4e1a4c92015-05-18 12:56:57 -07005<div id="builder3838_3" >
6seg=1 {{{40, 10}, {60, 10}}}
7seg=2 {{{60, 10}, {60, 30}}}
8seg=3 {{{60, 30}, {40, 30}}}
9seg=4 {{{40, 30}, {40, 10}}}
10seg=5 {{{41, 11}, {41, 29}}}
11seg=6 {{{41, 29}, {59, 29}}}
12seg=7 {{{59, 29}, {59, 11}}}
13seg=8 {{{59, 11}, {41, 11}}}
14debugShowLineIntersection wtTs[0]=0 {{{60,10}, {60,30}}} {{60,10}} wnTs[0]=1 {{{40,10}, {60,10}}}
15debugShowLineIntersection wtTs[0]=1 {{{40,30}, {40,10}}} {{40,10}} wnTs[0]=0 {{{40,10}, {60,10}}}
16debugShowLineIntersection wtTs[0]=0 {{{60,30}, {40,30}}} {{60,30}} wnTs[0]=1 {{{60,10}, {60,30}}}
17debugShowLineIntersection wtTs[0]=0 {{{40,30}, {40,10}}} {{40,30}} wnTs[0]=1 {{{60,30}, {40,30}}}
18debugShowLineIntersection wtTs[0]=0 {{{41,29}, {59,29}}} {{41,29}} wnTs[0]=1 {{{41,11}, {41,29}}}
19debugShowLineIntersection wtTs[0]=1 {{{59,11}, {41,11}}} {{41,11}} wnTs[0]=0 {{{41,11}, {41,29}}}
20debugShowLineIntersection wtTs[0]=0 {{{59,29}, {59,11}}} {{59,29}} wnTs[0]=1 {{{41,29}, {59,29}}}
21debugShowLineIntersection wtTs[0]=0 {{{59,11}, {41,11}}} {{59,11}} wnTs[0]=1 {{{59,29}, {59,11}}}
22SkOpSegment::debugShowActiveSpans id=1 (40,10 60,10) t=0 (40,10) tEnd=1 windSum=? windValue=1
23SkOpSegment::debugShowActiveSpans id=2 (60,10 60,30) t=0 (60,10) tEnd=1 windSum=? windValue=1
24SkOpSegment::debugShowActiveSpans id=3 (60,30 40,30) t=0 (60,30) tEnd=1 windSum=? windValue=1
25SkOpSegment::debugShowActiveSpans id=4 (40,30 40,10) t=0 (40,30) tEnd=1 windSum=? windValue=1
26SkOpSegment::debugShowActiveSpans id=5 (41,11 41,29) t=0 (41,11) tEnd=1 windSum=? windValue=1
27SkOpSegment::debugShowActiveSpans id=6 (41,29 59,29) t=0 (41,29) tEnd=1 windSum=? windValue=1
28SkOpSegment::debugShowActiveSpans id=7 (59,29 59,11) t=0 (59,29) tEnd=1 windSum=? windValue=1
29SkOpSegment::debugShowActiveSpans id=8 (59,11 41,11) t=0 (59,11) tEnd=1 windSum=? windValue=1
30SkOpSpan::sortableTop dir=kTop seg=1 t=0.5 pt=(50,10)
31SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=1 seg=1 {{{40, 10}, {60, 10}}} t=0.5 pt=(50,10) slope=(20,0)
32SkOpSegment::markWinding id=1 (40,10 60,10) t=0 [1] (40,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
33SkOpSegment::markWinding id=2 (60,10 60,30) t=0 [3] (60,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
34SkOpSegment::markWinding id=3 (60,30 40,30) t=0 [5] (60,30) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
35SkOpSegment::markWinding id=4 (40,30 40,10) t=0 [7] (40,30) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
36SkOpSegment::markWinding id=1 (40,10 60,10) t=0 [1] (40,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
37SkOpSegment::findNextWinding simple
38SkOpSegment::markDone id=1 (40,10 60,10) t=0 [1] (40,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
39bridgeWinding current id=1 from=(60,10) to=(40,10)
40SkOpSegment::findNextWinding simple
41SkOpSegment::markDone id=4 (40,30 40,10) t=0 [7] (40,30) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
42bridgeWinding current id=4 from=(40,10) to=(40,30)
43path.moveTo(60,10);
44path.lineTo(40,10);
45SkOpSegment::findNextWinding simple
46SkOpSegment::markDone id=3 (60,30 40,30) t=0 [5] (60,30) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
47bridgeWinding current id=3 from=(40,30) to=(60,30)
48path.lineTo(40,30);
49SkOpSegment::findNextWinding simple
50SkOpSegment::markDone id=2 (60,10 60,30) t=0 [3] (60,10) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
51bridgeWinding current id=2 from=(60,30) to=(60,10)
52path.lineTo(60,30);
53path.lineTo(60,10);
54path.close();
55SkOpSegment::debugShowActiveSpans id=5 (41,11 41,29) t=0 (41,11) tEnd=1 windSum=? windValue=1
56SkOpSegment::debugShowActiveSpans id=6 (41,29 59,29) t=0 (41,29) tEnd=1 windSum=? windValue=1
57SkOpSegment::debugShowActiveSpans id=7 (59,29 59,11) t=0 (59,29) tEnd=1 windSum=? windValue=1
58SkOpSegment::debugShowActiveSpans id=8 (59,11 41,11) t=0 (59,11) tEnd=1 windSum=? windValue=1
59SkOpSpan::sortableTop dir=kLeft seg=5 t=0.5 pt=(41,20)
60SkOpSpan::sortableTop [0] valid=1 operand=0 span=7 ccw=1 seg=4 {{{40, 30}, {40, 10}}} t=0.5 pt=(40,20) slope=(0,-20)
61SkOpSpan::sortableTop [1] valid=1 operand=0 span=9 ccw=0 seg=5 {{{41, 11}, {41, 29}}} t=0.5 pt=(41,20) slope=(0,18)
62SkOpSegment::markWinding id=5 (41,11 41,29) t=0 [9] (41,11) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
63SkOpSegment::markWinding id=6 (41,29 59,29) t=0 [11] (41,29) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
64SkOpSegment::markWinding id=7 (59,29 59,11) t=0 [13] (59,29) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
65SkOpSegment::markWinding id=8 (59,11 41,11) t=0 [15] (59,11) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
66SkOpSegment::markWinding id=5 (41,11 41,29) t=0 [9] (41,11) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
67SkOpSegment::findNextWinding simple
68SkOpSegment::markDone id=5 (41,11 41,29) t=0 [9] (41,11) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
69bridgeWinding current id=5 from=(41,29) to=(41,11)
70SkOpSegment::findNextWinding simple
71SkOpSegment::markDone id=8 (59,11 41,11) t=0 [15] (59,11) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
72bridgeWinding current id=8 from=(41,11) to=(59,11)
73path.moveTo(41,29);
74path.lineTo(41,11);
75SkOpSegment::findNextWinding simple
76SkOpSegment::markDone id=7 (59,29 59,11) t=0 [13] (59,29) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
77bridgeWinding current id=7 from=(59,11) to=(59,29)
78path.lineTo(59,11);
79SkOpSegment::findNextWinding simple
80SkOpSegment::markDone id=6 (41,29 59,29) t=0 [11] (41,29) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
81bridgeWinding current id=6 from=(59,29) to=(41,29)
82path.lineTo(59,29);
83path.lineTo(41,29);
84path.close();
85SkOpSpan::sortableTop dir=kTop seg=1 t=0.5 pt=(50,10)
86SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=0 seg=1 {{{60, 10}, {40, 10}}} t=0.5 pt=(50,10) slope=(-20,0)
caryclarkdac1d172014-06-17 05:15:38 -070087</div>
caryclark54359292015-03-26 07:52:43 -070088
caryclarkdac1d172014-06-17 05:15:38 -070089</div>
90
91<script type="text/javascript">
92
93var testDivs = [
caryclark4e1a4c92015-05-18 12:56:57 -070094 builder3838_3,
caryclarkdac1d172014-06-17 05:15:38 -070095];
96
97var decimal_places = 3; // make this 3 to show more precision
98
99var tests = [];
100var testLines = [];
101var testTitles = [];
102var testIndex = 0;
103var ctx;
104
105var xmin, xmax, focusXmin, focusXmax;
106var ymin, ymax, focusYmin, focusYmax;
107var scale;
108var mouseX, mouseY;
109var srcLeft, srcTop;
110var screenWidth, screenHeight;
caryclark1049f122015-04-20 08:31:59 -0700111var drawnPts, drawnLines, drawnQuads, drawnConics, drawnCubics;
caryclarkdac1d172014-06-17 05:15:38 -0700112var curveT = 0;
113
114var pt_labels = 2;
115var collect_bounds = false;
116var control_lines = 0;
117var curve_t = false;
118var debug_xy = 1;
119var focus_enabled = false;
120var focus_on_selection = false;
121var step_limit = 0;
122var draw_active = false;
123var draw_add = false;
124var draw_angle = 0;
caryclark624637c2015-05-11 07:21:27 -0700125var draw_coincidence = false;
caryclarkdac1d172014-06-17 05:15:38 -0700126var draw_deriviatives = 0;
127var draw_hints = false;
caryclarkdac1d172014-06-17 05:15:38 -0700128var draw_id = false;
129var draw_intersection = 0;
130var draw_intersectT = false;
131var draw_legend = true;
132var draw_log = false;
133var draw_mark = false;
134var draw_midpoint = false;
135var draw_op = 0;
136var draw_sequence = false;
137var draw_sort = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700138var draw_top = false;
caryclarkdac1d172014-06-17 05:15:38 -0700139var draw_path = 3;
140var draw_computed = 0;
141var retina_scale = !!window.devicePixelRatio;
142
143var activeCount = 0;
144var addCount = 0;
145var angleCount = 0;
caryclark624637c2015-05-11 07:21:27 -0700146var coinCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700147var opCount = 0;
148var sectCount = 0;
149var sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700150var topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700151var markCount = 0;
152var activeMax = 0;
153var addMax = 0;
154var angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -0700155var coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700156var sectMax = 0;
157var sectMax2 = 0;
158var sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -0700159var topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700160var markMax = 0;
161var opMax = 0;
162var stepMax = 0;
163var lastIndex = 0;
164var hasPath = false;
165var hasComputedPath = false;
caryclark54359292015-03-26 07:52:43 -0700166var angleBetween = false;
167var afterIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -0700168
169var firstActiveSpan = -1;
170var logStart = -1;
171var logRange = 0;
172
173var SPAN_ID = 0;
174var SPAN_X1 = SPAN_ID + 1;
175var SPAN_Y1 = SPAN_X1 + 1;
176var SPAN_X2 = SPAN_Y1 + 1;
177var SPAN_Y2 = SPAN_X2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700178
caryclarkdac1d172014-06-17 05:15:38 -0700179var SPAN_L_T = SPAN_Y2 + 1;
180var SPAN_L_TX = SPAN_L_T + 1;
181var SPAN_L_TY = SPAN_L_TX + 1;
182var SPAN_L_TEND = SPAN_L_TY + 1;
183var SPAN_L_OTHER = SPAN_L_TEND + 1;
184var SPAN_L_OTHERT = SPAN_L_OTHER + 1;
185var SPAN_L_OTHERI = SPAN_L_OTHERT + 1;
186var SPAN_L_SUM = SPAN_L_OTHERI + 1;
187var SPAN_L_VAL = SPAN_L_SUM + 1;
188var SPAN_L_OPP = SPAN_L_VAL + 1;
189
190var SPAN_X3 = SPAN_Y2 + 1;
191var SPAN_Y3 = SPAN_X3 + 1;
caryclark1049f122015-04-20 08:31:59 -0700192
caryclarkdac1d172014-06-17 05:15:38 -0700193var SPAN_Q_T = SPAN_Y3 + 1;
194var SPAN_Q_TX = SPAN_Q_T + 1;
195var SPAN_Q_TY = SPAN_Q_TX + 1;
196var SPAN_Q_TEND = SPAN_Q_TY + 1;
197var SPAN_Q_OTHER = SPAN_Q_TEND + 1;
198var SPAN_Q_OTHERT = SPAN_Q_OTHER + 1;
199var SPAN_Q_OTHERI = SPAN_Q_OTHERT + 1;
200var SPAN_Q_SUM = SPAN_Q_OTHERI + 1;
201var SPAN_Q_VAL = SPAN_Q_SUM + 1;
202var SPAN_Q_OPP = SPAN_Q_VAL + 1;
203
caryclark1049f122015-04-20 08:31:59 -0700204var SPAN_K_W = SPAN_Y3 + 1;
205var SPAN_K_T = SPAN_K_W + 1;
206var SPAN_K_TX = SPAN_K_T + 1;
207var SPAN_K_TY = SPAN_K_TX + 1;
208var SPAN_K_TEND = SPAN_K_TY + 1;
209var SPAN_K_OTHER = SPAN_K_TEND + 1;
210var SPAN_K_OTHERT = SPAN_K_OTHER + 1;
211var SPAN_K_OTHERI = SPAN_K_OTHERT + 1;
212var SPAN_K_SUM = SPAN_K_OTHERI + 1;
213var SPAN_K_VAL = SPAN_K_SUM + 1;
214var SPAN_K_OPP = SPAN_K_VAL + 1;
215
caryclarkdac1d172014-06-17 05:15:38 -0700216var SPAN_X4 = SPAN_Y3 + 1;
217var SPAN_Y4 = SPAN_X4 + 1;
caryclark1049f122015-04-20 08:31:59 -0700218
caryclarkdac1d172014-06-17 05:15:38 -0700219var SPAN_C_T = SPAN_Y4 + 1;
220var SPAN_C_TX = SPAN_C_T + 1;
221var SPAN_C_TY = SPAN_C_TX + 1;
222var SPAN_C_TEND = SPAN_C_TY + 1;
223var SPAN_C_OTHER = SPAN_C_TEND + 1;
224var SPAN_C_OTHERT = SPAN_C_OTHER + 1;
225var SPAN_C_OTHERI = SPAN_C_OTHERT + 1;
226var SPAN_C_SUM = SPAN_C_OTHERI + 1;
227var SPAN_C_VAL = SPAN_C_SUM + 1;
228var SPAN_C_OPP = SPAN_C_VAL + 1;
229
230var ACTIVE_LINE_SPAN = 1;
231var ACTIVE_QUAD_SPAN = ACTIVE_LINE_SPAN + 1;
caryclark1049f122015-04-20 08:31:59 -0700232var ACTIVE_CONIC_SPAN = ACTIVE_QUAD_SPAN + 1;
233var ACTIVE_CUBIC_SPAN = ACTIVE_CONIC_SPAN + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700234
235var ADD_MOVETO = ACTIVE_CUBIC_SPAN + 1;
236var ADD_LINETO = ADD_MOVETO + 1;
237var ADD_QUADTO = ADD_LINETO + 1;
caryclark1049f122015-04-20 08:31:59 -0700238var ADD_CONICTO = ADD_QUADTO + 1;
239var ADD_CUBICTO = ADD_CONICTO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700240var ADD_CLOSE = ADD_CUBICTO + 1;
241var ADD_FILL = ADD_CLOSE + 1;
242
243var PATH_LINE = ADD_FILL + 1;
244var PATH_QUAD = PATH_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700245var PATH_CONIC = PATH_QUAD + 1;
246var PATH_CUBIC = PATH_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700247
248var INTERSECT_LINE = PATH_CUBIC + 1;
249var INTERSECT_LINE_2 = INTERSECT_LINE + 1;
250var INTERSECT_LINE_NO = INTERSECT_LINE_2 + 1;
251var INTERSECT_QUAD_LINE = INTERSECT_LINE_NO + 1;
252var INTERSECT_QUAD_LINE_2 = INTERSECT_QUAD_LINE + 1;
253var INTERSECT_QUAD_LINE_NO = INTERSECT_QUAD_LINE_2 + 1;
254var INTERSECT_QUAD = INTERSECT_QUAD_LINE_NO + 1;
255var INTERSECT_QUAD_2 = INTERSECT_QUAD + 1;
256var INTERSECT_QUAD_NO = INTERSECT_QUAD_2 + 1;
caryclark1049f122015-04-20 08:31:59 -0700257var INTERSECT_CONIC_LINE = INTERSECT_QUAD_NO + 1;
258var INTERSECT_CONIC_LINE_2 = INTERSECT_CONIC_LINE + 1;
259var INTERSECT_CONIC_LINE_NO = INTERSECT_CONIC_LINE_2 + 1;
260var INTERSECT_CONIC = INTERSECT_CONIC_LINE_NO + 1;
261var INTERSECT_CONIC_2 = INTERSECT_CONIC + 1;
262var INTERSECT_CONIC_NO = INTERSECT_CONIC_2 + 1;
263var INTERSECT_SELF_CUBIC = INTERSECT_CONIC_NO + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700264var INTERSECT_SELF_CUBIC_NO = INTERSECT_SELF_CUBIC + 1;
265var INTERSECT_CUBIC_LINE = INTERSECT_SELF_CUBIC_NO + 1;
266var INTERSECT_CUBIC_LINE_2 = INTERSECT_CUBIC_LINE + 1;
267var INTERSECT_CUBIC_LINE_3 = INTERSECT_CUBIC_LINE_2 + 1;
268var INTERSECT_CUBIC_LINE_NO = INTERSECT_CUBIC_LINE_3 + 1;
269var INTERSECT_CUBIC_QUAD = INTERSECT_CUBIC_LINE_NO + 1;
270var INTERSECT_CUBIC_QUAD_2 = INTERSECT_CUBIC_QUAD + 1;
271var INTERSECT_CUBIC_QUAD_3 = INTERSECT_CUBIC_QUAD_2 + 1;
272var INTERSECT_CUBIC_QUAD_4 = INTERSECT_CUBIC_QUAD_3 + 1;
273var INTERSECT_CUBIC_QUAD_NO = INTERSECT_CUBIC_QUAD_4 + 1;
274var INTERSECT_CUBIC = INTERSECT_CUBIC_QUAD_NO + 1;
275var INTERSECT_CUBIC_2 = INTERSECT_CUBIC + 1;
276var INTERSECT_CUBIC_3 = INTERSECT_CUBIC_2 + 1;
277var INTERSECT_CUBIC_4 = INTERSECT_CUBIC_3 + 1;
278// FIXME: add cubic 5- 9
279var INTERSECT_CUBIC_NO = INTERSECT_CUBIC_4 + 1;
280
281var SORT_UNARY = INTERSECT_CUBIC_NO + 1;
282var SORT_BINARY = SORT_UNARY + 1;
283
284var OP_DIFFERENCE = SORT_BINARY + 1;
285var OP_INTERSECT = OP_DIFFERENCE + 1;
286var OP_UNION = OP_INTERSECT + 1;
287var OP_XOR = OP_UNION + 1;
288
289var MARK_LINE = OP_XOR + 1;
290var MARK_QUAD = MARK_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700291var MARK_CONIC = MARK_QUAD + 1;
292var MARK_CUBIC = MARK_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700293var MARK_DONE_LINE = MARK_CUBIC + 1;
294var MARK_DONE_QUAD = MARK_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700295var MARK_DONE_CONIC = MARK_DONE_QUAD + 1;
296var MARK_DONE_CUBIC = MARK_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700297var MARK_UNSORTABLE_LINE = MARK_DONE_CUBIC + 1;
298var MARK_UNSORTABLE_QUAD = MARK_UNSORTABLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700299var MARK_UNSORTABLE_CONIC = MARK_UNSORTABLE_QUAD + 1;
300var MARK_UNSORTABLE_CUBIC = MARK_UNSORTABLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700301var MARK_SIMPLE_LINE = MARK_UNSORTABLE_CUBIC + 1;
302var MARK_SIMPLE_QUAD = MARK_SIMPLE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700303var MARK_SIMPLE_CONIC = MARK_SIMPLE_QUAD + 1;
304var MARK_SIMPLE_CUBIC = MARK_SIMPLE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700305var MARK_SIMPLE_DONE_LINE = MARK_SIMPLE_CUBIC + 1;
306var MARK_SIMPLE_DONE_QUAD = MARK_SIMPLE_DONE_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700307var MARK_SIMPLE_DONE_CONIC = MARK_SIMPLE_DONE_QUAD + 1;
308var MARK_SIMPLE_DONE_CUBIC = MARK_SIMPLE_DONE_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700309var MARK_DONE_UNARY_LINE = MARK_SIMPLE_DONE_CUBIC + 1;
310var MARK_DONE_UNARY_QUAD = MARK_DONE_UNARY_LINE + 1;
caryclark1049f122015-04-20 08:31:59 -0700311var MARK_DONE_UNARY_CONIC = MARK_DONE_UNARY_QUAD + 1;
312var MARK_DONE_UNARY_CUBIC = MARK_DONE_UNARY_CONIC + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700313var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
314
315var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
316var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
317
caryclark624637c2015-05-11 07:21:27 -0700318var ANGLE_AFTER = COMPUTED_SET_2 + 1;
caryclark54359292015-03-26 07:52:43 -0700319var ANGLE_AFTERPART = ANGLE_AFTER + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700320
caryclark54359292015-03-26 07:52:43 -0700321var ACTIVE_OP = ANGLE_AFTERPART + 1;
caryclarkdac1d172014-06-17 05:15:38 -0700322
caryclark624637c2015-05-11 07:21:27 -0700323var COIN_MAIN_SPAN = ACTIVE_OP + 1;
324var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
325
326var FRAG_TYPE_LAST = COIN_OPP_SPAN;
caryclarkdac1d172014-06-17 05:15:38 -0700327
328var REC_TYPE_UNKNOWN = -1;
329var REC_TYPE_PATH = 0;
caryclark54359292015-03-26 07:52:43 -0700330var REC_TYPE_PATH2 = 1;
331var REC_TYPE_SECT = 2;
332var REC_TYPE_ACTIVE = 3;
333var REC_TYPE_ADD = 4;
334var REC_TYPE_SORT = 5;
335var REC_TYPE_OP = 6;
336var REC_TYPE_MARK = 7;
337var REC_TYPE_COMPUTED = 8;
338var REC_TYPE_COIN = 9;
339var REC_TYPE_ANGLE = 10;
340var REC_TYPE_ACTIVE_OP = 11;
341var REC_TYPE_AFTERPART = 12;
caryclark03b03ca2015-04-23 09:13:37 -0700342var REC_TYPE_TOP = 13;
caryclark624637c2015-05-11 07:21:27 -0700343var REC_TYPE_COINCIDENCE = 14;
344var REC_TYPE_LAST = REC_TYPE_COINCIDENCE;
caryclarkdac1d172014-06-17 05:15:38 -0700345
346function strs_to_nums(strs) {
347 var result = [];
348 for (var idx = 1; idx < strs.length; ++idx) {
349 var str = strs[idx];
350 var num = parseFloat(str);
351 if (isNaN(num)) {
352 result.push(str);
353 } else {
354 result.push(num);
355 }
356 }
357 return result;
358}
359
360function filter_str_by(id, str, regex, array) {
361 if (regex.test(str)) {
362 var strs = regex.exec(str);
363 var result = strs_to_nums(strs);
364 array.push(id);
365 array.push(result);
366 return true;
367 }
368 return false;
369}
370
371function construct_regexp2(pattern) {
372 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
373 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
374 escape = escape.replace(/CUBIC_VAL/g, "\\(P_VAL P_VAL P_VAL P_VAL\\)");
caryclark1049f122015-04-20 08:31:59 -0700375 escape = escape.replace(/CONIC_VAL/g, "\\(P_VAL P_VAL P_VAL W_VAL\\)");
caryclarkdac1d172014-06-17 05:15:38 -0700376 escape = escape.replace(/QUAD_VAL/g, "\\(P_VAL P_VAL P_VAL\\)");
377 escape = escape.replace(/LINE_VAL/g, "\\(P_VAL P_VAL\\)");
378 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700379 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700380 escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
381 escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
382 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700383 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700384 escape = escape.replace(/PATH/g, "pathB?");
caryclark1049f122015-04-20 08:31:59 -0700385 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700386 escape = escape.replace(/NUM/g, "(-?\\d+)");
387 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
388 return new RegExp(escape, 'i');
389}
390
391function construct_regexp2c(pattern) {
392 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
393 escape = escape.replace(/UNSORTABLE/g, "\\*\\*\\* UNSORTABLE \\*\\*\\*");
caryclark54359292015-03-26 07:52:43 -0700394 escape = escape.replace(/CUBIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclark1049f122015-04-20 08:31:59 -0700395 escape = escape.replace(/CONIC_VAL/g, "(?:\\$\\d = )?\\{\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}, W_VAL\\}");
caryclark54359292015-03-26 07:52:43 -0700396 escape = escape.replace(/QUAD_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
397 escape = escape.replace(/LINE_VAL/g, "(?:\\$\\d = )?\\{\\{\\{P_VAL\\}, \\{P_VAL\\}\\}\\}");
caryclarkdac1d172014-06-17 05:15:38 -0700398 escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
caryclark54359292015-03-26 07:52:43 -0700399 escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
caryclarkdac1d172014-06-17 05:15:38 -0700400 escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
caryclark54359292015-03-26 07:52:43 -0700401 escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700402 escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
caryclark1049f122015-04-20 08:31:59 -0700403 escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
caryclarkdac1d172014-06-17 05:15:38 -0700404 escape = escape.replace(/OPER/g, "[a-z]+");
405 escape = escape.replace(/PATH/g, "pathB?");
406 escape = escape.replace(/T_F/g, "([TF])");
caryclark1049f122015-04-20 08:31:59 -0700407 escape = escape.replace(/IDX/g, "(-?\\d+)");
caryclarkdac1d172014-06-17 05:15:38 -0700408 escape = escape.replace(/NUM/g, "(-?\\d+)");
409 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
410 return new RegExp(escape, 'i');
411}
412
413function match_regexp(str, lineNo, array, id, pattern) {
414 var regex = construct_regexp2(pattern);
415 if (filter_str_by(id, str, regex, array)) {
416 return true;
417 }
418 regex = construct_regexp2c(pattern);
419 return filter_str_by(id, str, regex, array);
420}
421
422function endsWith(str, suffix) {
423 return str.indexOf(suffix, str.length - suffix.length) !== -1;
424}
425
426function parse_all(test) {
427 var lines = test.match(/[^\r\n]+/g);
428 var records = []; // a rec can be the original paths, a set of intersections, a set of active spans, a sort, or a path add
429 var record = [];
430 var recType = REC_TYPE_UNKNOWN;
431 var lastLineNo;
432 var moveX, moveY;
433 for (var lineNo = 0; lineNo < lines.length; ++lineNo) {
434 var line = lines[lineNo];
435 if (line.length == 0) {
436 continue;
437 }
438 var opStart = "SkOpSegment::";
439 if (line.lastIndexOf(opStart, 0) === 0) {
440 line = line.substr(opStart.length);
441 }
442 var angleStart = "SkOpAngle::";
443 if (line.lastIndexOf(angleStart, 0) === 0) {
444 line = line.substr(angleStart.length);
445 }
caryclark624637c2015-05-11 07:21:27 -0700446 var coinStart = "SkOpCoincidence::";
447 if (line.lastIndexOf(coinStart, 0) === 0) {
448 line = line.substr(coinStart.length);
449 }
caryclark54359292015-03-26 07:52:43 -0700450 var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
caryclark624637c2015-05-11 07:21:27 -0700451 : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
caryclark54359292015-03-26 07:52:43 -0700452 : line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
caryclarkdac1d172014-06-17 05:15:38 -0700453 : line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
caryclark54359292015-03-26 07:52:43 -0700454 : line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
caryclarkdac1d172014-06-17 05:15:38 -0700455 : line.lastIndexOf("debugShow", 0) === 0 ? REC_TYPE_SECT
456 : line.lastIndexOf("activeOp", 0) === 0 ? REC_TYPE_ACTIVE_OP
457 : line.lastIndexOf("computed", 0) === 0 ? REC_TYPE_COMPUTED
458 : line.lastIndexOf("debugOne", 0) === 0 ? REC_TYPE_SORT
459 : line.lastIndexOf("dumpOne", 0) === 0 ? REC_TYPE_SORT
caryclark03b03ca2015-04-23 09:13:37 -0700460 : line.lastIndexOf("findTop", 0) === 0 ? REC_TYPE_TOP
caryclarkdac1d172014-06-17 05:15:38 -0700461 : line.lastIndexOf("pathB.", 0) === 0 ? REC_TYPE_ADD
462 : line.lastIndexOf("path.", 0) === 0 ? REC_TYPE_ADD
463 : line.lastIndexOf("after", 0) === 0 ? REC_TYPE_ANGLE
464 : line.lastIndexOf("mark", 0) === 0 ? REC_TYPE_MARK
465 : line.lastIndexOf(" {{", 0) === 0 ? REC_TYPE_COMPUTED
caryclark54359292015-03-26 07:52:43 -0700466 : line.lastIndexOf("seg=", 0) === 0 ? REC_TYPE_PATH
caryclarkdac1d172014-06-17 05:15:38 -0700467 : line.lastIndexOf("op", 0) === 0 ? REC_TYPE_OP
468 : line.lastIndexOf("$", 0) === 0 ? REC_TYPE_PATH
469 : REC_TYPE_UNKNOWN;
470 if (recType != type || recType == REC_TYPE_ADD || recType == REC_TYPE_SECT
471 || recType == REC_TYPE_ACTIVE_OP || recType == REC_TYPE_ANGLE) {
472 if (recType != REC_TYPE_UNKNOWN) {
473 records.push(recType);
474 records.push(lastLineNo);
475 records.push(record);
476 }
477 record = [];
478 recType = type;
479 lastLineNo = lineNo;
480 }
481 var found = false;
482 switch (recType) {
483 case REC_TYPE_ACTIVE:
484 found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700485" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700486 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700487" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700488 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700489" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700490 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
caryclark624637c2015-05-11 07:21:27 -0700491" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
492 ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
493" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
494 ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
495" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
496 ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
497" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
498 ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
499" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
caryclarkdac1d172014-06-17 05:15:38 -0700500 );
501 break;
502 case REC_TYPE_ACTIVE_OP:
503 found = match_regexp(line, lineNo, record, ACTIVE_OP, "activeOp" +
504" id=IDX t=T_VAL tEnd=T_VAL op=OPER miFrom=NUM miTo=NUM suFrom=NUM suTo=NUM result=IDX"
505 );
506 break;
507 case REC_TYPE_ADD:
508 if (match_regexp(line, lineNo, record, ADD_MOVETO, "PATH.moveTo(P_VAL);")) {
509 moveX = record[1][0];
510 moveY = record[1][1];
511 found = true;
512 } else if (match_regexp(line, lineNo, record, ADD_LINETO, "PATH.lineTo(P_VAL);")) {
513 record[1].unshift(moveY);
514 record[1].unshift(moveX);
515 moveX = record[1][2];
516 moveY = record[1][3];
517 found = true;
518 } else if (match_regexp(line, lineNo, record, ADD_QUADTO, "PATH.quadTo(P_VAL, P_VAL);")) {
519 record[1].unshift(moveY);
520 record[1].unshift(moveX);
521 moveX = record[1][4];
522 moveY = record[1][5];
523 found = true;
caryclark1049f122015-04-20 08:31:59 -0700524 } else if (match_regexp(line, lineNo, record, ADD_CONICTO, "PATH.conicTo(P_VAL, P_VAL, T_VAL);")) {
525 record[1].unshift(moveY);
526 record[1].unshift(moveX);
527 moveX = record[1][4];
528 moveY = record[1][5];
529 found = true;
caryclarkdac1d172014-06-17 05:15:38 -0700530 } else if (match_regexp(line, lineNo, record, ADD_CUBICTO, "PATH.cubicTo(P_VAL, P_VAL, P_VAL);")) {
531 record[1].unshift(moveY);
532 record[1].unshift(moveX);
533 moveX = record[1][6];
534 moveY = record[1][7];
535 found = true;
536 } else if (match_regexp(line, lineNo, record, ADD_FILL, "PATH.setFillType(FILL_TYPE);")) {
537 found = true;
538 } else {
539 found = match_regexp(line, lineNo, record, ADD_CLOSE, "PATH.close();");
540 }
541 break;
caryclark54359292015-03-26 07:52:43 -0700542 case REC_TYPE_AFTERPART:
543 found = match_regexp(line, lineNo, record, PATH_LINE, "afterPart LINE_VAL")
544 || match_regexp(line, lineNo, record, PATH_QUAD, "afterPart QUAD_VAL")
caryclark1049f122015-04-20 08:31:59 -0700545 || match_regexp(line, lineNo, record, PATH_CONIC, "afterPart CONIC_VAL")
caryclark54359292015-03-26 07:52:43 -0700546 || match_regexp(line, lineNo, record, PATH_CUBIC, "afterPart CUBIC_VAL")
547 break;
caryclarkdac1d172014-06-17 05:15:38 -0700548 case REC_TYPE_ANGLE:
549 found = match_regexp(line, lineNo, record, ANGLE_AFTER, "after " +
caryclarkdac1d172014-06-17 05:15:38 -0700550"[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");
551 break;
552 case REC_TYPE_COIN:
553 found = true;
554 break;
caryclark624637c2015-05-11 07:21:27 -0700555 case REC_TYPE_COINCIDENCE:
556 found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
557" + id=IDX t=T_VAL tEnd=T_VAL"
558 ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
559" - id=IDX t=T_VAL tEnd=T_VAL"
560 );
561 break;
caryclarkdac1d172014-06-17 05:15:38 -0700562 case REC_TYPE_COMPUTED:
563 found = line == "computed quadratics given"
564 || match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
565 ) || match_regexp(line, lineNo, record, COMPUTED_SET_2, "computed quadratics set 2"
566 ) || match_regexp(line, lineNo, record, PATH_QUAD, " QUAD_VAL,"
caryclark1049f122015-04-20 08:31:59 -0700567 ) || match_regexp(line, lineNo, record, PATH_CONIC, " CONIC_VAL,"
caryclarkdac1d172014-06-17 05:15:38 -0700568 ) || match_regexp(line, lineNo, record, PATH_CUBIC, " CUBIC_VAL,"
569 );
570 break;
571 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700572 found = match_regexp(line, lineNo, record, PATH_LINE, "seg=IDX LINE_VAL"
573 ) || match_regexp(line, lineNo, record, PATH_QUAD, "seg=IDX QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700574 ) || match_regexp(line, lineNo, record, PATH_CONIC, "seg=IDX CONIC_VAL"
caryclark54359292015-03-26 07:52:43 -0700575 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "seg=IDX CUBIC_VAL"
576 );
577 break;
578 case REC_TYPE_PATH2:
579 found = match_regexp(line, lineNo, record, PATH_LINE, "((SkOpSegment*) PTR_VAL) [IDX] {LINE_VAL}"
580 ) || match_regexp(line, lineNo, record, PATH_QUAD, "((SkOpSegment*) PTR_VAL) [IDX] {QUAD_VAL}"
caryclark1049f122015-04-20 08:31:59 -0700581 ) || match_regexp(line, lineNo, record, PATH_CONIC, "((SkOpSegment*) PTR_VAL) [IDX] {CONIC_VAL}"
caryclark54359292015-03-26 07:52:43 -0700582 ) || match_regexp(line, lineNo, record, PATH_CUBIC, "((SkOpSegment*) PTR_VAL) [IDX] {CUBIC_VAL}"
caryclarkdac1d172014-06-17 05:15:38 -0700583 );
584 break;
585 case REC_TYPE_SECT:
586 found = match_regexp(line, lineNo, record, INTERSECT_LINE, "debugShowLineIntersection" +
587" wtTs[0]=T_VAL LINE_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
588 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_2, "debugShowLineIntersection" +
589" wtTs[0]=T_VAL LINE_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
590 ) || match_regexp(line, lineNo, record, INTERSECT_LINE_NO, "debugShowLineIntersection" +
591" no intersect LINE_VAL LINE_VAL"
592 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE, "debugShowQuadLineIntersection" +
593" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
594 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_2, "debugShowQuadLineIntersection" +
595" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
596 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_LINE_NO, "debugShowQuadLineIntersection" +
597" no intersect QUAD_VAL LINE_VAL"
598 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD, "debugShowQuadIntersection" +
599" wtTs[0]=T_VAL QUAD_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
600 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_2, "debugShowQuadIntersection" +
601" wtTs[0]=T_VAL QUAD_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
602 ) || match_regexp(line, lineNo, record, INTERSECT_QUAD_NO, "debugShowQuadIntersection" +
603" no intersect QUAD_VAL QUAD_VAL"
caryclark1049f122015-04-20 08:31:59 -0700604 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE, "debugShowConicLineIntersection" +
605" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
606 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_2, "debugShowConicLineIntersection" +
607" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
608 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_LINE_NO, "debugShowConicLineIntersection" +
609" no intersect CONIC_VAL LINE_VAL"
610 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC, "debugShowConicIntersection" +
611" wtTs[0]=T_VAL CONIC_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL"
612 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_2, "debugShowConicIntersection" +
613" wtTs[0]=T_VAL CONIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CONIC_VAL wnTs[1]=T_VAL"
614 ) || match_regexp(line, lineNo, record, INTERSECT_CONIC_NO, "debugShowConicIntersection" +
615" no intersect CONIC_VAL CONIC_VAL"
caryclarkdac1d172014-06-17 05:15:38 -0700616 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE, "debugShowCubicLineIntersection" +
617" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL"
618 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_2, "debugShowCubicLineIntersection" +
619" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL LINE_VAL wnTs[1]=T_VAL"
620 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_3, "debugShowCubicLineIntersection" +
621" 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"
622 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_LINE_NO, "debugShowCubicLineIntersection" +
623" no intersect CUBIC_VAL LINE_VAL"
624 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD, "debugShowCubicQuadIntersection" +
625" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL"
626 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_2, "debugShowCubicQuadIntersection" +
627" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL QUAD_VAL wnTs[1]=T_VAL"
628 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_3, "debugShowCubicQuadIntersection" +
629" 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"
630 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_4, "debugShowCubicQuadIntersection" +
631" 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"
632 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_QUAD_NO, "debugShowCubicQuadIntersection" +
633" no intersect CUBIC_VAL QUAD_VAL"
634 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC, "debugShowCubicIntersection" +
635" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL"
636 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_2, "debugShowCubicIntersection" +
637" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL PT_VAL wnTs[0]=T_VAL CUBIC_VAL wnTs[1]=T_VAL"
638 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_3, "debugShowCubicIntersection" +
639" 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"
640 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_4, "debugShowCubicIntersection" +
641" 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"
642 ) || match_regexp(line, lineNo, record, INTERSECT_CUBIC_NO, "debugShowCubicIntersection" +
643" no intersect CUBIC_VAL CUBIC_VAL"
644 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC, "debugShowCubicIntersection" +
645" wtTs[0]=T_VAL CUBIC_VAL PT_VAL wtTs[1]=T_VAL"
646 ) || match_regexp(line, lineNo, record, INTERSECT_SELF_CUBIC_NO, "debugShowCubicIntersection" +
647" no self intersect CUBIC_VAL"
648 );
649 break;
650 case REC_TYPE_SORT:
651 var hasDone = / done/.test(line);
652 var hasUnorderable = / unorderable/.test(line);
653 var hasSmall = / small/.test(line);
654 var hasTiny = / tiny/.test(line);
655 var hasOperand = / operand/.test(line);
656 var hasStop = / stop/.test(line);
657 line.replace(/[ a-z]+$/, "");
658 found = match_regexp(line, lineNo, record, SORT_UNARY, "debugOne" +
659" [IDX/IDX] next=IDX/IDX sect=IDX/IDX s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
660 ) || match_regexp(line, lineNo, record, SORT_BINARY, "debugOne" +
661" [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"
662 ) || match_regexp(line, lineNo, record, SORT_UNARY, "dumpOne" +
663" [IDX/IDX] next=IDX/IDX sect=NUM/NUM s=T_VAL [IDX] e=T_VAL [IDX] sgn=NUM windVal=IDX windSum=OPT"
664 ) || match_regexp(line, lineNo, record, SORT_BINARY, "dumpOne" +
665" [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"
666 );
667 if (found) {
668 record[1].push(hasDone);
669 record[1].push(hasUnorderable);
670 record[1].push(hasSmall);
671 record[1].push(hasTiny);
672 record[1].push(hasOperand);
673 record[1].push(hasStop);
674 }
675 break;
caryclark03b03ca2015-04-23 09:13:37 -0700676 case REC_TYPE_TOP:
677 found = match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
678" id=IDX s=T_VAL e=T_VAL cw=NUM swap=NUM inflections=NUM monotonic=NUM"
679 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
680" id=IDX s=T_VAL e=T_VAL (-) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
681 ) || match_regexp(line, lineNo, record, ACTIVE_OP, "findTop" +
682" id=IDX s=T_VAL e=T_VAL (+) cw=NUM swap=NUM inflections=NUM monotonic=NUM"
683 );
684 break;
caryclarkdac1d172014-06-17 05:15:38 -0700685 case REC_TYPE_MARK:
686 found = match_regexp(line, lineNo, record, MARK_LINE, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700687" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700688 ) || match_regexp(line, lineNo, record, MARK_QUAD, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700689" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700690 ) || match_regexp(line, lineNo, record, MARK_CONIC, "markWinding" +
691" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700692 ) || match_regexp(line, lineNo, record, MARK_CUBIC, "markWinding" +
caryclark54359292015-03-26 07:52:43 -0700693" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX"
694 ) || match_regexp(line, lineNo, record, MARK_DONE_LINE, "markDone" +
695" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
696 ) || match_regexp(line, lineNo, record, MARK_DONE_QUAD, "markDone" +
697" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclark1049f122015-04-20 08:31:59 -0700698 ) || match_regexp(line, lineNo, record, MARK_DONE_CONIC, "markDone" +
699" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclark54359292015-03-26 07:52:43 -0700700 ) || match_regexp(line, lineNo, record, MARK_DONE_CUBIC, "markDone" +
701" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=OPT newOppSum=OPT oppSum=OPT windSum=OPT windValue=IDX oppValue=OPT"
caryclarkdac1d172014-06-17 05:15:38 -0700702 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_LINE, "markWinding" +
703" id=IDX LINE_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
704 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_QUAD, "markWinding" +
705" id=IDX QUAD_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclark1049f122015-04-20 08:31:59 -0700706 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CONIC, "markWinding" +
707" id=IDX CONIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700708 ) || match_regexp(line, lineNo, record, MARK_SIMPLE_CUBIC, "markWinding" +
709" id=IDX CUBIC_VAL t=T_VAL [IDX] PT_VAL tEnd=T_VAL newWindSum=NUM windSum=OPT windValue=IDX"
caryclarkdac1d172014-06-17 05:15:38 -0700710 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
caryclark1049f122015-04-20 08:31:59 -0700711" last segment=IDX span=IDX"
caryclark54359292015-03-26 07:52:43 -0700712 ) || match_regexp(line, lineNo, record, MARK_ANGLE_LAST, "markAngle" +
713" last segment=IDX span=IDX windSum=OPT");
caryclarkdac1d172014-06-17 05:15:38 -0700714 break;
715 case REC_TYPE_OP:
716 if (line.lastIndexOf("oppSign oppSign=", 0) === 0
717 || line.lastIndexOf("operator<", 0) === 0) {
718 found = true;
719 break;
720 }
caryclark54359292015-03-26 07:52:43 -0700721 found = match_regexp(line, lineNo, record, OP_DIFFERENCE, "op diff"
caryclarkdac1d172014-06-17 05:15:38 -0700722 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op intersect"
caryclark54359292015-03-26 07:52:43 -0700723 ) || match_regexp(line, lineNo, record, OP_INTERSECT, "op sect"
caryclarkdac1d172014-06-17 05:15:38 -0700724 ) || match_regexp(line, lineNo, record, OP_UNION, "op union"
725 ) || match_regexp(line, lineNo, record, OP_XOR, "op xor"
726 );
727 break;
728 case REC_TYPE_UNKNOWN:
729 found = true;
730 break;
731 }
732 if (!found) {
733 console.log(line + " [" + lineNo + "] of type " + type + " not found");
734 }
735 }
736 if (recType != REC_TYPE_UNKNOWN) {
737 records.push(recType);
738 records.push(lastLineNo);
739 records.push(record);
740 }
741 if (records.length >= 1) {
742 tests[testIndex] = records;
743 testLines[testIndex] = lines;
744 }
745}
746
747function init(test) {
748 var canvas = document.getElementById('canvas');
749 if (!canvas.getContext) return;
750 ctx = canvas.getContext('2d');
751 var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1;
752 var unscaledWidth = window.innerWidth - 20;
753 var unscaledHeight = window.innerHeight - 20;
754 screenWidth = unscaledWidth;
755 screenHeight = unscaledHeight;
756 canvas.width = unscaledWidth * resScale;
757 canvas.height = unscaledHeight * resScale;
758 canvas.style.width = unscaledWidth + 'px';
759 canvas.style.height = unscaledHeight + 'px';
760 if (resScale != 1) {
761 ctx.scale(resScale, resScale);
762 }
763 xmin = Infinity;
764 xmax = -Infinity;
765 ymin = Infinity;
766 ymax = -Infinity;
767 hasPath = hasComputedPath = false;
768 firstActiveSpan = -1;
769 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
770 var recType = test[tIndex];
771 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
772 console.log("unknown rec type: " + recType);
773 throw "stop execution";
774 }
775 var records = test[tIndex + 2];
776 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
777 var fragType = records[recordIndex];
778 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
779 console.log("unknown in range frag type: " + fragType);
780 throw "stop execution";
781 }
782 var frags = records[recordIndex + 1];
783 var first = 0;
784 var last = -1;
785 var first2 = 0;
786 var last2 = 0;
787 switch (recType) {
788 case REC_TYPE_COMPUTED:
789 if (fragType == COMPUTED_SET_1 || fragType == COMPUTED_SET_2) {
790 break;
791 }
792 hasComputedPath = true;
793 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -0700794 first = 1;
caryclarkdac1d172014-06-17 05:15:38 -0700795 switch (fragType) {
796 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -0700797 last = 5;
caryclarkdac1d172014-06-17 05:15:38 -0700798 break;
caryclark1049f122015-04-20 08:31:59 -0700799 case PATH_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -0700800 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -0700801 last = 7;
caryclarkdac1d172014-06-17 05:15:38 -0700802 break;
803 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -0700804 last = 9;
caryclarkdac1d172014-06-17 05:15:38 -0700805 break;
806 default:
807 console.log("unknown " + (recType == REC_TYPE_PATH ? "REC_TYPE_PATH"
808 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
809 throw "stop execution";
810 }
811 if (recType == REC_TYPE_PATH) {
812 hasPath = true;
813 }
814 break;
caryclark54359292015-03-26 07:52:43 -0700815 case REC_TYPE_PATH2:
816 first = 1;
817 switch (fragType) {
818 case PATH_LINE:
819 last = 5;
820 break;
caryclark1049f122015-04-20 08:31:59 -0700821 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700822 case PATH_QUAD:
823 last = 7;
824 break;
825 case PATH_CUBIC:
826 last = 9;
827 break;
828 default:
829 console.log("unknown " + (recType == REC_TYPE_PATH2 ? "REC_TYPE_PATH2"
830 : "REC_TYPE_COMPUTED") + " frag type:" + fragType);
831 throw "stop execution";
832 }
833 if (recType == REC_TYPE_PATH2) {
834 hasPath = true;
835 }
836 break;
caryclarkdac1d172014-06-17 05:15:38 -0700837 case REC_TYPE_ACTIVE:
838 if (firstActiveSpan < 0) {
839 firstActiveSpan = tIndex;
840 }
841 first = 1;
842 switch (fragType) {
843 case ACTIVE_LINE_SPAN:
844 last = 5;
845 break;
caryclark1049f122015-04-20 08:31:59 -0700846 case ACTIVE_CONIC_SPAN:
caryclarkdac1d172014-06-17 05:15:38 -0700847 case ACTIVE_QUAD_SPAN:
848 last = 7;
849 break;
850 case ACTIVE_CUBIC_SPAN:
851 last = 9;
852 break;
853 default:
854 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
855 throw "stop execution";
856 }
857 break;
858 case REC_TYPE_ADD:
859 switch (fragType) {
860 case ADD_MOVETO:
861 break;
862 case ADD_LINETO:
863 last = 4;
864 break;
caryclark1049f122015-04-20 08:31:59 -0700865 case ADD_CONICTO:
caryclarkdac1d172014-06-17 05:15:38 -0700866 case ADD_QUADTO:
867 last = 6;
868 break;
869 case ADD_CUBICTO:
870 last = 8;
871 break;
872 case ADD_CLOSE:
873 case ADD_FILL:
874 break;
875 default:
876 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
877 throw "stop execution";
878 }
879 break;
caryclark54359292015-03-26 07:52:43 -0700880 case REC_TYPE_AFTERPART:
881 switch (fragType) {
882 case PATH_LINE:
883 last = 4;
884 break;
caryclark1049f122015-04-20 08:31:59 -0700885 case PATH_CONIC:
caryclark54359292015-03-26 07:52:43 -0700886 case PATH_QUAD:
887 last = 6;
888 break;
889 case PATH_CUBIC:
890 last = 8;
891 break;
892 default:
893 console.log("unknown REC_TYPE_ACTIVEPART frag type: " + fragType);
894 throw "stop execution";
895 }
896 break;
caryclarkdac1d172014-06-17 05:15:38 -0700897 case REC_TYPE_SECT:
898 switch (fragType) {
899 case INTERSECT_LINE:
900 first = 1; last = 5; first2 = 8; last2 = 12;
901 break;
902 case INTERSECT_LINE_2:
903 first = 1; last = 5; first2 = 11; last2 = 15;
904 break;
905 case INTERSECT_LINE_NO:
906 first = 0; last = 4; first2 = 4; last2 = 8;
907 break;
caryclark1049f122015-04-20 08:31:59 -0700908 case INTERSECT_CONIC_LINE:
909 first = 1; last = 7; first2 = 11; last2 = 15;
910 break;
caryclarkdac1d172014-06-17 05:15:38 -0700911 case INTERSECT_QUAD_LINE:
912 first = 1; last = 7; first2 = 10; last2 = 14;
913 break;
caryclark1049f122015-04-20 08:31:59 -0700914 case INTERSECT_CONIC_LINE_2:
915 first = 1; last = 7; first2 = 14; last2 = 18;
916 break;
caryclarkdac1d172014-06-17 05:15:38 -0700917 case INTERSECT_QUAD_LINE_2:
918 first = 1; last = 7; first2 = 13; last2 = 17;
919 break;
caryclark1049f122015-04-20 08:31:59 -0700920 case INTERSECT_CONIC_LINE_NO:
921 first = 0; last = 6; first2 = 7; last2 = 11;
922 break;
caryclarkdac1d172014-06-17 05:15:38 -0700923 case INTERSECT_QUAD_LINE_NO:
924 first = 0; last = 6; first2 = 6; last2 = 10;
925 break;
caryclark1049f122015-04-20 08:31:59 -0700926 case INTERSECT_CONIC:
927 first = 1; last = 7; first2 = 11; last2 = 17;
928 break;
caryclarkdac1d172014-06-17 05:15:38 -0700929 case INTERSECT_QUAD:
930 first = 1; last = 7; first2 = 10; last2 = 16;
931 break;
caryclark1049f122015-04-20 08:31:59 -0700932 case INTERSECT_CONIC_2:
933 first = 1; last = 7; first2 = 14; last2 = 20;
934 break;
caryclarkdac1d172014-06-17 05:15:38 -0700935 case INTERSECT_QUAD_2:
936 first = 1; last = 7; first2 = 13; last2 = 19;
937 break;
caryclark1049f122015-04-20 08:31:59 -0700938 case INTERSECT_CONIC_NO:
939 first = 0; last = 6; first2 = 7; last2 = 13;
940 break;
caryclarkdac1d172014-06-17 05:15:38 -0700941 case INTERSECT_QUAD_NO:
942 first = 0; last = 6; first2 = 6; last2 = 12;
943 break;
944 case INTERSECT_SELF_CUBIC:
945 first = 1; last = 9;
946 break;
947 case INTERSECT_SELF_CUBIC_NO:
948 first = 0; last = 8;
949 break;
950 case INTERSECT_CUBIC_LINE:
951 first = 1; last = 9; first2 = 12; last2 = 16;
952 break;
953 case INTERSECT_CUBIC_LINE_2:
954 first = 1; last = 9; first2 = 15; last2 = 19;
955 break;
956 case INTERSECT_CUBIC_LINE_3:
957 first = 1; last = 9; first2 = 18; last2 = 22;
958 break;
959 case INTERSECT_CUBIC_LINE_NO:
960 first = 0; last = 8; first2 = 8; last2 = 12;
961 break;
962 case INTERSECT_CUBIC_QUAD:
963 first = 1; last = 9; first2 = 12; last2 = 18;
964 break;
965 case INTERSECT_CUBIC_QUAD_2:
966 first = 1; last = 9; first2 = 15; last2 = 21;
967 break;
968 case INTERSECT_CUBIC_QUAD_3:
969 first = 1; last = 9; first2 = 18; last2 = 24;
970 break;
971 case INTERSECT_CUBIC_QUAD_4:
972 first = 1; last = 9; first2 = 21; last2 = 27;
973 break;
974 case INTERSECT_CUBIC_QUAD_NO:
975 first = 0; last = 8; first2 = 8; last2 = 14;
976 break;
977 case INTERSECT_CUBIC:
978 first = 1; last = 9; first2 = 12; last2 = 20;
979 break;
980 case INTERSECT_CUBIC_2:
981 first = 1; last = 9; first2 = 15; last2 = 23;
982 break;
983 case INTERSECT_CUBIC_3:
984 first = 1; last = 9; first2 = 18; last2 = 26;
985 break;
986 case INTERSECT_CUBIC_4:
987 first = 1; last = 9; first2 = 21; last2 = 29;
988 break;
989 case INTERSECT_CUBIC_NO:
990 first = 0; last = 8; first2 = 8; last2 = 16;
991 break;
992 default:
993 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
994 throw "stop execution";
995 }
996 break;
997 default:
998 continue;
999 }
1000 for (var idx = first; idx < last; idx += 2) {
1001 xmin = Math.min(xmin, frags[idx]);
1002 xmax = Math.max(xmax, frags[idx]);
1003 ymin = Math.min(ymin, frags[idx + 1]);
1004 ymax = Math.max(ymax, frags[idx + 1]);
1005 }
1006 for (var idx = first2; idx < last2; idx += 2) {
1007 xmin = Math.min(xmin, frags[idx]);
1008 xmax = Math.max(xmax, frags[idx]);
1009 ymin = Math.min(ymin, frags[idx + 1]);
1010 ymax = Math.max(ymax, frags[idx + 1]);
1011 }
1012 }
1013 }
1014 var angleBounds = [Infinity, Infinity, -Infinity, -Infinity];
1015 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
1016 var recType = test[tIndex];
1017 var records = test[tIndex + 2];
1018 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1019 var fragType = records[recordIndex];
1020 var frags = records[recordIndex + 1];
1021 switch (recType) {
1022 case REC_TYPE_ACTIVE_OP:
1023 if (!draw_op) {
1024 break;
1025 }
1026 {
1027 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1028 curve_extremes(curve, angleBounds);
1029 }
1030 break;
1031 case REC_TYPE_ANGLE:
1032 if (!draw_angle) {
1033 break;
1034 }
caryclark54359292015-03-26 07:52:43 -07001035 {
caryclarkdac1d172014-06-17 05:15:38 -07001036 var curve = curvePartialByID(test, frags[0], frags[4], frags[5]);
1037 curve_extremes(curve, angleBounds);
1038 curve = curvePartialByID(test, frags[6], frags[10], frags[11]);
1039 curve_extremes(curve, angleBounds);
1040 curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
1041 }
1042 break;
caryclark624637c2015-05-11 07:21:27 -07001043 case REC_TYPE_COINCIDENCE:
1044 if (!draw_coincidence) {
1045 break;
1046 }
1047 {
1048 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1049 curve_extremes(curve, angleBounds);
1050 }
1051 break;
caryclarkdac1d172014-06-17 05:15:38 -07001052 case REC_TYPE_SORT:
1053 if (!draw_sort) {
1054 break;
1055 }
1056 if (fragType == SORT_UNARY || fragType == SORT_BINARY) {
1057 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
1058 curve_extremes(curve, angleBounds);
1059 }
1060 break;
caryclark03b03ca2015-04-23 09:13:37 -07001061 case REC_TYPE_TOP:
1062 if (!draw_top) {
1063 break;
1064 }
1065 {
1066 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
1067 curve_extremes(curve, angleBounds);
1068 }
1069 break;
caryclarkdac1d172014-06-17 05:15:38 -07001070 }
1071 }
1072 }
1073 xmin = Math.min(xmin, angleBounds[0]);
1074 ymin = Math.min(ymin, angleBounds[1]);
1075 xmax = Math.max(xmax, angleBounds[2]);
1076 ymax = Math.max(ymax, angleBounds[3]);
1077 setScale(xmin, xmax, ymin, ymax);
1078 if (hasPath == false && hasComputedPath == true && !draw_computed) {
caryclark1049f122015-04-20 08:31:59 -07001079 draw_computed = 7; // show quadratics, conics, and cubics
caryclarkdac1d172014-06-17 05:15:38 -07001080 }
1081 if (hasPath == true && hasComputedPath == false && draw_computed) {
1082 draw_computed = 0;
1083 }
1084}
1085
1086function curveByID(test, id) {
caryclark54359292015-03-26 07:52:43 -07001087 var tIndex = -3;
1088 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001089 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001090 if (recType == REC_TYPE_OP) {
1091 continue;
1092 }
1093 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001094 return [];
1095 }
1096 var records = test[tIndex + 2];
1097 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1098 var fragType = records[recordIndex];
1099 var frags = records[recordIndex + 1];
1100 if (frags[0] == id) {
1101 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001102 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001103 return [frags[1], frags[2], frags[3], frags[4]];
caryclark54359292015-03-26 07:52:43 -07001104 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001105 return [frags[1], frags[2], frags[3], frags[4],
1106 frags[5], frags[6]];
caryclark1049f122015-04-20 08:31:59 -07001107 case PATH_CONIC:
1108 return [frags[1], frags[2], frags[3], frags[4],
1109 frags[5], frags[6], frags[7]];
caryclark54359292015-03-26 07:52:43 -07001110 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001111 return [frags[1], frags[2], frags[3], frags[4],
1112 frags[5], frags[6], frags[7], frags[8]];
1113 }
1114 }
1115 }
caryclarkdac1d172014-06-17 05:15:38 -07001116 }
1117 return [];
1118}
1119
1120function curvePartialByID(test, id, t0, t1) {
caryclark54359292015-03-26 07:52:43 -07001121 var tIndex = -3;
1122 while ((tIndex += 3) < test.length) {
caryclarkdac1d172014-06-17 05:15:38 -07001123 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001124 if (recType == REC_TYPE_OP) {
1125 continue;
1126 }
1127 if (recType != REC_TYPE_PATH) {
caryclarkdac1d172014-06-17 05:15:38 -07001128 return [];
1129 }
1130 var records = test[tIndex + 2];
1131 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1132 var fragType = records[recordIndex];
1133 var frags = records[recordIndex + 1];
1134 if (frags[0] == id) {
1135 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001136 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001137 return linePartial(frags[1], frags[2], frags[3], frags[4], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001138 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001139 return quadPartial(frags[1], frags[2], frags[3], frags[4],
1140 frags[5], frags[6], t0, t1);
caryclark1049f122015-04-20 08:31:59 -07001141 case PATH_CONIC:
1142 return conicPartial(frags[1], frags[2], frags[3], frags[4],
1143 frags[5], frags[6], frags[7], t0, t1);
caryclark54359292015-03-26 07:52:43 -07001144 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001145 return cubicPartial(frags[1], frags[2], frags[3], frags[4],
1146 frags[5], frags[6], frags[7], frags[8], t0, t1);
1147 }
1148 }
1149 }
caryclarkdac1d172014-06-17 05:15:38 -07001150 }
1151 return [];
1152}
1153
1154function idByCurve(test, frag, type) {
caryclark54359292015-03-26 07:52:43 -07001155 var tIndex = 0;
caryclarkdac1d172014-06-17 05:15:38 -07001156 while (tIndex < test.length) {
1157 var recType = test[tIndex];
caryclark54359292015-03-26 07:52:43 -07001158 if (recType != REC_TYPE_PATH) {
1159 ++tIndex;
1160 continue;
caryclarkdac1d172014-06-17 05:15:38 -07001161 }
1162 var records = test[tIndex + 2];
1163 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
1164 var fragType = records[recordIndex];
1165 var frags = records[recordIndex + 1];
caryclark54359292015-03-26 07:52:43 -07001166 if (frag.length != frags.length - 1) {
1167 continue;
1168 }
caryclarkdac1d172014-06-17 05:15:38 -07001169 switch (fragType) {
caryclark54359292015-03-26 07:52:43 -07001170 case PATH_LINE:
caryclarkdac1d172014-06-17 05:15:38 -07001171 if (frag[0] != frags[1] || frag[1] != frags[2]
1172 || frag[2] != frags[3] || frag[3] != frags[4]) {
1173 continue;
1174 }
1175 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001176 case PATH_QUAD:
caryclarkdac1d172014-06-17 05:15:38 -07001177 if (frag[0] != frags[1] || frag[1] != frags[2]
1178 || frag[2] != frags[3] || frag[3] != frags[4]
1179 || frag[4] != frags[5] || frag[5] != frags[6]) {
1180 continue;
1181 }
1182 return frags[0];
caryclark1049f122015-04-20 08:31:59 -07001183 case PATH_CONIC:
1184 if (frag[0] != frags[1] || frag[1] != frags[2]
1185 || frag[2] != frags[3] || frag[3] != frags[4]
1186 || frag[4] != frags[5] || frag[5] != frags[6]
1187 || frag[6] != frags[7]) {
1188 continue;
1189 }
1190 return frags[0];
caryclark54359292015-03-26 07:52:43 -07001191 case PATH_CUBIC:
caryclarkdac1d172014-06-17 05:15:38 -07001192 if (frag[0] != frags[1] || frag[1] != frags[2]
1193 || frag[2] != frags[3] || frag[3] != frags[4]
1194 || frag[4] != frags[5] || frag[5] != frags[6]
1195 || frag[6] != frags[7] || frag[7] != frags[8]) {
1196 continue;
1197 }
1198 return frags[0];
1199 }
1200 }
1201 ++tIndex;
1202 }
1203 return -1;
1204}
1205
1206function curve_extremes(curve, bounds) {
caryclark1049f122015-04-20 08:31:59 -07001207 var length = curve.length == 7 ? 6 : curve.length;
caryclarkdac1d172014-06-17 05:15:38 -07001208 for (var index = 0; index < curve.length; index += 2) {
1209 var x = curve[index];
1210 var y = curve[index + 1];
1211 bounds[0] = Math.min(bounds[0], x);
1212 bounds[1] = Math.min(bounds[1], y);
1213 bounds[2] = Math.max(bounds[2], x);
1214 bounds[3] = Math.max(bounds[3], y);
1215 }
1216}
1217
1218function setScale(x0, x1, y0, y1) {
1219 var srcWidth = x1 - x0;
1220 var srcHeight = y1 - y0;
1221 var usableWidth = screenWidth;
1222 var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10));
1223 var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10));
1224 usableWidth -= (xDigits + yDigits) * 10;
1225 usableWidth -= decimal_places * 10;
1226 if (draw_legend) {
1227 usableWidth -= 40;
1228 }
1229 var hscale = usableWidth / srcWidth;
1230 var vscale = screenHeight / srcHeight;
1231 scale = Math.min(hscale, vscale);
1232 var invScale = 1 / scale;
1233 var sxmin = x0 - invScale * 5;
1234 var symin = y0 - invScale * 10;
1235 var sxmax = x1 + invScale * (6 * decimal_places + 10);
1236 var symax = y1 + invScale * 10;
1237 srcWidth = sxmax - sxmin;
1238 srcHeight = symax - symin;
1239 hscale = usableWidth / srcWidth;
1240 vscale = screenHeight / srcHeight;
1241 scale = Math.min(hscale, vscale);
1242 srcLeft = sxmin;
1243 srcTop = symin;
1244}
1245
1246function drawArc(curve, op, from, to) {
1247 var type = PATH_LINE + (curve.length / 2 - 2);
1248 var pt = pointAtT(curve, type, op ? 0.4 : 0.6);
1249 var dy = pt.y - curve[1];
1250 var dx = pt.x - curve[0];
1251 var dist = Math.sqrt(dy * dy + dx * dx);
1252 var _dist = dist * scale;
1253 var angle = Math.atan2(dy, dx);
1254 var _px = (curve[0] - srcLeft) * scale;
1255 var _py = (curve[1] - srcTop) * scale;
1256 var divisor = 4;
1257 var endDist;
1258 do {
1259 var ends = [];
1260 for (var index = -1; index <= 1; index += 2) {
1261 var px = Math.cos(index * Math.PI / divisor);
1262 var py = Math.sin(index * Math.PI / divisor);
1263 ends.push(px);
1264 ends.push(py);
1265 }
1266 var endDx = (ends[2] - ends[0]) * scale * dist;
1267 var endDy = (ends[3] - ends[1]) * scale * dist;
1268 endDist = Math.sqrt(endDx * endDx + endDy * endDy);
1269 if (endDist < 100) {
1270 break;
1271 }
1272 divisor *= 2;
1273 } while (true);
1274 if (endDist < 30) {
1275 return;
1276 }
1277 if (op) {
1278 divisor *= 2;
1279 }
1280 ctx.strokeStyle = op ? "rgba(210,0,45, 0.4)" : "rgba(90,90,90, 0.5)";
1281 ctx.beginPath();
1282 ctx.arc(_px, _py, _dist, angle - Math.PI / divisor, angle + Math.PI / divisor, false);
1283 ctx.stroke();
1284 var saveAlign = ctx.textAlign;
1285 var saveStyle = ctx.fillStyle;
1286 var saveFont = ctx.font;
1287 ctx.textAlign = "center";
1288 ctx.fillStyle = "black";
1289 ctx.font = "normal 24px Arial";
1290 divisor *= 0.8;
1291 for (var index = -1; index <= 1; index += 2) {
1292 var px = curve[0] + Math.cos(angle + index * Math.PI / divisor) * dist;
1293 var py = curve[1] + Math.sin(angle + index * Math.PI / divisor) * dist;
1294 var _px = (px - srcLeft) * scale;
1295 var _py = (py - srcTop) * scale;
1296 ctx.fillText(index < 0 ? to.toString() : from.toString(), _px, _py + 8);
1297 }
1298 ctx.textAlign = saveAlign;
1299 ctx.fillStyle = saveStyle;
1300 ctx.font = saveFont;
1301}
1302
1303function drawPoint(px, py, end) {
caryclark1049f122015-04-20 08:31:59 -07001304 var length = drawnPts.length == 7 ? 6 : drawnPts.length;
1305 for (var pts = 0; pts < length; pts += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001306 var x = drawnPts[pts];
1307 var y = drawnPts[pts + 1];
1308 if (px == x && py == y) {
1309 return;
1310 }
1311 }
1312 drawnPts.push(px);
1313 drawnPts.push(py);
1314 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
1315 var _px = (px - srcLeft) * scale;
1316 var _py = (py - srcTop) * scale;
1317 ctx.beginPath();
1318 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
1319 ctx.closePath();
1320 if (end) {
1321 ctx.fill();
1322 } else {
1323 ctx.stroke();
1324 }
1325 if (debug_xy) {
1326 ctx.textAlign = "left";
1327 ctx.fillText(label, _px + 5, _py);
1328 }
1329}
1330
caryclark1049f122015-04-20 08:31:59 -07001331function coordCount(curveType) {
1332 switch (curveType) {
1333 case PATH_LINE:
1334 return 4;
1335 case PATH_QUAD:
1336 return 6;
1337 case PATH_CONIC:
1338 return 6;
1339 case PATH_CUBIC:
1340 return 8;
1341 }
1342 return -1;
1343}
1344
caryclarkdac1d172014-06-17 05:15:38 -07001345function drawPoints(ptArray, curveType, drawControls) {
caryclark1049f122015-04-20 08:31:59 -07001346 var count = coordCount(curveType);
caryclarkdac1d172014-06-17 05:15:38 -07001347 for (var idx = 0; idx < count; idx += 2) {
1348 if (!drawControls && idx != 0 && idx != count - 2) {
1349 continue;
1350 }
1351 drawPoint(ptArray[idx], ptArray[idx + 1], idx == 0 || idx == count - 2);
1352 }
1353}
1354
1355function drawControlLines(curve, curveType, drawEnd) {
1356 if (curveType == PATH_LINE) {
1357 return;
1358 }
1359 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
1360 drawLine(curve[0], curve[1], curve[2], curve[3]);
1361 drawLine(curve[2], curve[3], curve[4], curve[5]);
1362 if (curveType == PATH_CUBIC) {
1363 drawLine(curve[4], curve[5], curve[6], curve[7]);
1364 if (drawEnd > 1) {
1365 drawLine(curve[6], curve[7], curve[0], curve[1]);
1366 if (drawEnd > 2) {
1367 drawLine(curve[0], curve[1], curve[4], curve[5]);
1368 drawLine(curve[6], curve[7], curve[2], curve[3]);
1369 }
1370 }
1371 } else if (drawEnd > 1) {
1372 drawLine(curve[4], curve[5], curve[0], curve[1]);
1373 }
1374}
1375
1376function pointAtT(curve, curveType, t) {
1377 var xy = {};
1378 switch (curveType) {
1379 case PATH_LINE:
1380 var a = 1 - t;
1381 var b = t;
1382 xy.x = a * curve[0] + b * curve[2];
1383 xy.y = a * curve[1] + b * curve[3];
1384 break;
1385 case PATH_QUAD:
1386 var one_t = 1 - t;
1387 var a = one_t * one_t;
1388 var b = 2 * one_t * t;
1389 var c = t * t;
1390 xy.x = a * curve[0] + b * curve[2] + c * curve[4];
1391 xy.y = a * curve[1] + b * curve[3] + c * curve[5];
1392 break;
caryclark1049f122015-04-20 08:31:59 -07001393 case PATH_CONIC:
1394 var one_t = 1 - t;
1395 var a = one_t * one_t;
1396 var b = 2 * one_t * t;
1397 var c = t * t;
1398 xy.x = a * curve[0] + b * curve[2] * curve[6] + c * curve[4];
1399 xy.y = a * curve[1] + b * curve[3] * curve[6] + c * curve[5];
1400 var d = a + b * curve[6] + c;
1401 xy.x /= d;
1402 xy.y /= d;
1403 break;
caryclarkdac1d172014-06-17 05:15:38 -07001404 case PATH_CUBIC:
1405 var one_t = 1 - t;
1406 var one_t2 = one_t * one_t;
1407 var a = one_t2 * one_t;
1408 var b = 3 * one_t2 * t;
1409 var t2 = t * t;
1410 var c = 3 * one_t * t2;
1411 var d = t2 * t;
1412 xy.x = a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
1413 xy.y = a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
1414 break;
1415 }
1416 return xy;
1417}
1418
1419function drawPointAtT(curve, curveType) {
1420 var x, y;
1421 var xy = pointAtT(curve, curveType, curveT);
1422 drawPoint(xy.x, xy.y, true);
1423 if (!draw_intersectT) {
1424 return;
1425 }
1426 ctx.fillStyle = "red";
1427 drawTAtPointUp(xy.x, xy.y, curveT);
1428}
1429
1430function drawTAtPointUp(px, py, t) {
1431 var label = t.toFixed(decimal_places);
1432 var _px = (px - srcLeft)* scale;
1433 var _py = (py - srcTop) * scale;
1434 ctx.fillText(label, _px + 5, _py - 10);
1435}
1436
1437function drawTAtPointDown(px, py, t) {
1438 var label = t.toFixed(decimal_places);
1439 var _px = (px - srcLeft)* scale;
1440 var _py = (py - srcTop) * scale;
1441 ctx.fillText(label, _px + 5, _py + 10);
1442}
1443
1444function alreadyDrawnLine(x1, y1, x2, y2) {
1445 if (collect_bounds) {
1446 if (focus_enabled) {
1447 focusXmin = Math.min(focusXmin, x1, x2);
1448 focusYmin = Math.min(focusYmin, y1, y2);
1449 focusXmax = Math.max(focusXmax, x1, x2);
1450 focusYmax = Math.max(focusYmax, y1, y2);
1451 }
1452 return true;
1453 }
1454 for (var pts = 0; pts < drawnLines.length; pts += 4) {
1455 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]
1456 && x2 == drawnLines[pts + 2] && y2 == drawnLines[pts + 3]) {
1457 return true;
1458 }
1459 }
1460 drawnLines.push(x1);
1461 drawnLines.push(y1);
1462 drawnLines.push(x2);
1463 drawnLines.push(y2);
1464 return false;
1465}
1466
1467function drawLine(x1, y1, x2, y2) {
1468 if (alreadyDrawnLine(x1, y1, x2, y2)) {
1469 return;
1470 }
1471 ctx.beginPath();
1472 ctx.moveTo((x1 - srcLeft) * scale,
1473 (y1 - srcTop) * scale);
1474 ctx.lineTo((x2 - srcLeft) * scale,
1475 (y2 - srcTop) * scale);
1476 ctx.stroke();
1477}
1478
1479function linePartial(x1, y1, x2, y2, t1, t2) {
1480 var dx = x1 - x2;
1481 var dy = y1 - y2;
1482 var array = [
1483 x1 - t1 * dx,
1484 y1 - t1 * dy,
1485 x1 - t2 * dx,
1486 y1 - t2 * dy
1487 ];
1488 return array;
1489}
1490
1491function drawLinePartial(x1, y1, x2, y2, t1, t2) {
1492 var a = linePartial(x1, y1, x2, y2, t1, t2);
1493 var ax = a[0];
1494 var ay = a[1];
1495 var bx = a[2];
1496 var by = a[3];
1497 if (alreadyDrawnLine(ax, ay, bx, by)) {
1498 return;
1499 }
1500 ctx.beginPath();
1501 ctx.moveTo((ax - srcLeft) * scale,
1502 (ay - srcTop) * scale);
1503 ctx.lineTo((bx - srcLeft) * scale,
1504 (by - srcTop) * scale);
1505 ctx.stroke();
1506}
1507
1508function alreadyDrawnQuad(x1, y1, x2, y2, x3, y3) {
1509 if (collect_bounds) {
1510 if (focus_enabled) {
1511 focusXmin = Math.min(focusXmin, x1, x2, x3);
1512 focusYmin = Math.min(focusYmin, y1, y2, y3);
1513 focusXmax = Math.max(focusXmax, x1, x2, x3);
1514 focusYmax = Math.max(focusYmax, y1, y2, y3);
1515 }
1516 return true;
1517 }
1518 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
1519 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]
1520 && x2 == drawnQuads[pts + 2] && y2 == drawnQuads[pts + 3]
1521 && x3 == drawnQuads[pts + 4] && y3 == drawnQuads[pts + 5]) {
1522 return true;
1523 }
1524 }
1525 drawnQuads.push(x1);
1526 drawnQuads.push(y1);
1527 drawnQuads.push(x2);
1528 drawnQuads.push(y2);
1529 drawnQuads.push(x3);
1530 drawnQuads.push(y3);
1531 return false;
1532}
1533
1534function drawQuad(x1, y1, x2, y2, x3, y3) {
1535 if (alreadyDrawnQuad(x1, y1, x2, y2, x3, y3)) {
1536 return;
1537 }
1538 ctx.beginPath();
1539 ctx.moveTo((x1 - srcLeft) * scale,
1540 (y1 - srcTop) * scale);
1541 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
1542 (y2 - srcTop) * scale,
1543 (x3 - srcLeft) * scale,
1544 (y3 - srcTop) * scale);
1545 ctx.stroke();
1546}
1547
1548function interp(A, B, t) {
1549 return A + (B - A) * t;
1550}
1551
1552function interp_quad_coords(x1, x2, x3, t)
1553{
1554 var ab = interp(x1, x2, t);
1555 var bc = interp(x2, x3, t);
1556 var abc = interp(ab, bc, t);
1557 return abc;
1558}
1559
1560function quadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1561 var ax = interp_quad_coords(x1, x2, x3, t1);
1562 var ay = interp_quad_coords(y1, y2, y3, t1);
1563 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
1564 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
1565 var cx = interp_quad_coords(x1, x2, x3, t2);
1566 var cy = interp_quad_coords(y1, y2, y3, t2);
1567 var bx = 2*dx - (ax + cx)/2;
1568 var by = 2*dy - (ay + cy)/2;
1569 var array = [
1570 ax, ay, bx, by, cx, cy
1571 ];
1572 return array;
1573}
1574
1575function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
1576 var a = quadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
1577 var ax = a[0];
1578 var ay = a[1];
1579 var bx = a[2];
1580 var by = a[3];
1581 var cx = a[4];
1582 var cy = a[5];
1583 if (alreadyDrawnQuad(ax, ay, bx, by, cx, cy)) {
1584 return;
1585 }
1586 ctx.beginPath();
1587 ctx.moveTo((ax - srcLeft) * scale,
1588 (ay - srcTop) * scale);
1589 ctx.quadraticCurveTo((bx - srcLeft) * scale,
1590 (by - srcTop) * scale,
1591 (cx - srcLeft) * scale,
1592 (cy - srcTop) * scale);
1593 ctx.stroke();
1594}
1595
caryclark1049f122015-04-20 08:31:59 -07001596function alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w) {
1597 if (collect_bounds) {
1598 if (focus_enabled) {
1599 focusXmin = Math.min(focusXmin, x1, x2, x3);
1600 focusYmin = Math.min(focusYmin, y1, y2, y3);
1601 focusXmax = Math.max(focusXmax, x1, x2, x3);
1602 focusYmax = Math.max(focusYmax, y1, y2, y3);
1603 }
1604 return true;
1605 }
1606 for (var pts = 0; pts < drawnConics.length; pts += 8) {
1607 if (x1 == drawnConics[pts] && y1 == drawnCubics[pts + 1]
1608 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1609 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1610 && w == drawnCubics[pts + 6]) {
1611 return true;
1612 }
1613 }
1614 drawnConics.push(x1);
1615 drawnConics.push(y1);
1616 drawnConics.push(x2);
1617 drawnConics.push(y2);
1618 drawnConics.push(x3);
1619 drawnConics.push(y3);
1620 drawnCubics.push(w);
1621 return false;
1622}
1623
1624var kMaxConicToQuadPOW2 = 5;
1625
1626function computeQuadPOW2(curve, tol) {
1627 var a = curve[6] - 1;
1628 var k = a / (4 * (2 + a));
1629 var x = k * (curve[0] - 2 * curve[2] + curve[4]);
1630 var y = k * (curve[1] - 2 * curve[3] + curve[5]);
1631
1632 var error = Math.sqrt(x * x + y * y);
1633 var pow2;
1634 for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1635 if (error <= tol) {
1636 break;
1637 }
1638 error *= 0.25;
1639 }
1640 return pow2;
1641}
1642
1643function subdivide_w_value(w) {
1644 return Math.sqrt(0.5 + w * 0.5);
1645}
1646
1647function chop(curve, part1, part2) {
1648 var w = curve[6];
1649 var scale = 1 / (1 + w);
1650 part1[0] = curve[0];
1651 part1[1] = curve[1];
1652 part1[2] = (curve[0] + curve[2] * w) * scale;
1653 part1[3] = (curve[1] + curve[3] * w) * scale;
1654 part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5;
1655 part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5;
1656 part2[2] = (curve[2] * w + curve[4]) * scale;
1657 part2[3] = (curve[3] * w + curve[5]) * scale;
1658 part2[4] = curve[4];
1659 part2[5] = curve[5];
1660 part1[6] = part2[6] = subdivide_w_value(w);
1661}
1662
1663function subdivide(curve, level, pts) {
1664 if (0 == level) {
1665 pts.push(curve[2]);
1666 pts.push(curve[3]);
1667 pts.push(curve[4]);
1668 pts.push(curve[5]);
1669 } else {
1670 var part1 = [], part2 = [];
1671 chop(curve, part1, part2);
1672 --level;
1673 subdivide(part1, level, pts);
1674 subdivide(part2, level, pts);
1675 }
1676}
1677
1678function chopIntoQuadsPOW2(curve, pow2, pts) {
1679 subdivide(curve, pow2, pts);
1680 return 1 << pow2;
1681}
1682
1683function drawConicWithQuads(x1, y1, x2, y2, x3, y3, w) {
1684 if (alreadyDrawnConic(x1, y1, x2, y2, x3, y3, w)) {
1685 return;
1686 }
1687 ctx.beginPath();
1688 ctx.moveTo((x1 - srcLeft) * scale,
1689 (y1 - srcTop) * scale);
1690 var tol = 1 / scale;
1691 var curve = [x1, y1, x2, y2, x3, y3, w];
1692 var pow2 = computeQuadPOW2(curve, tol);
1693 var pts = [];
1694 chopIntoQuadsPOW2(curve, pow2, pts);
1695 for (var i = 0; i < pts.length; i += 4) {
1696 ctx.quadraticCurveTo(
1697 (pts[i + 0] - srcLeft) * scale, (pts[i + 1] - srcTop) * scale,
1698 (pts[i + 2] - srcLeft) * scale, (pts[i + 3] - srcTop) * scale);
1699 }
1700 ctx.stroke();
1701}
1702
1703function conic_eval_numerator(x1, x2, x3, w, t) {
1704 var src2w = x2 * w;
1705 var C = x1;
1706 var A = x3 - 2 * src2w + C;
1707 var B = 2 * (src2w - C);
1708 return (A * t + B) * t + C;
1709}
1710
1711
1712function conic_eval_denominator(w, t) {
1713 var B = 2 * (w - 1);
1714 var C = 1;
1715 var A = -B;
1716 return (A * t + B) * t + C;
1717}
1718
1719function conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1720 var ax = conic_eval_numerator(x1, x2, x3, w, t1);
1721 var ay = conic_eval_numerator(y1, y2, y3, w, t1);
1722 var az = conic_eval_denominator(w, t1);
1723 var midT = (t1 + t2) / 2;
1724 var dx = conic_eval_numerator(x1, x2, x3, w, midT);
1725 var dy = conic_eval_numerator(y1, y2, y3, w, midT);
1726 var dz = conic_eval_denominator(w, midT);
1727 var cx = conic_eval_numerator(x1, x2, x3, w, t2);
1728 var cy = conic_eval_numerator(y1, y2, y3, w, t2);
1729 var cz = conic_eval_denominator(w, t2);
1730 var bx = 2 * dx - (ax + cx) / 2;
1731 var by = 2 * dy - (ay + cy) / 2;
1732 var bz = 2 * dz - (az + cz) / 2;
1733 var dt = t2 - t1;
1734 var dt_1 = 1 - dt;
1735 var partW = (1 + dt * (w - 1)) / Math.sqrt(dt * dt + 2 * dt * dt_1 * w + dt_1 * dt_1);
1736 var array = [
1737 ax / az, ay / az, bx / bz, by / bz, cx / cz, cy / cz, partW
1738 ];
1739 return array;
1740}
1741
1742function drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2) {
1743 var a = conicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
1744 var ax = a[0];
1745 var ay = a[1];
1746 var bx = a[2];
1747 var by = a[3];
1748 var cx = a[4];
1749 var cy = a[5];
1750 var w_ = a[6];
1751 drawConicWithQuads(ax, ay, bx, by, cx, cy, w_);
1752}
1753
caryclarkdac1d172014-06-17 05:15:38 -07001754function alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1755 if (collect_bounds) {
1756 if (focus_enabled) {
1757 focusXmin = Math.min(focusXmin, x1, x2, x3, x4);
1758 focusYmin = Math.min(focusYmin, y1, y2, y3, y4);
1759 focusXmax = Math.max(focusXmax, x1, x2, x3, x4);
1760 focusYmax = Math.max(focusYmax, y1, y2, y3, y4);
1761 }
1762 return true;
1763 }
1764 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
1765 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]
1766 && x2 == drawnCubics[pts + 2] && y2 == drawnCubics[pts + 3]
1767 && x3 == drawnCubics[pts + 4] && y3 == drawnCubics[pts + 5]
1768 && x4 == drawnCubics[pts + 6] && y4 == drawnCubics[pts + 7]) {
1769 return true;
1770 }
1771 }
1772 drawnCubics.push(x1);
1773 drawnCubics.push(y1);
1774 drawnCubics.push(x2);
1775 drawnCubics.push(y2);
1776 drawnCubics.push(x3);
1777 drawnCubics.push(y3);
1778 drawnCubics.push(x4);
1779 drawnCubics.push(y4);
1780 return false;
1781}
1782
1783function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
1784 if (alreadyDrawnCubic(x1, y1, x2, y2, x3, y3, x4, y4)) {
1785 return;
1786 }
1787 ctx.beginPath();
1788 ctx.moveTo((x1 - srcLeft) * scale,
1789 (y1 - srcTop) * scale);
1790 ctx.bezierCurveTo((x2 - srcLeft) * scale,
1791 (y2 - srcTop) * scale,
1792 (x3 - srcLeft) * scale,
1793 (y3 - srcTop) * scale,
1794 (x4 - srcLeft) * scale,
1795 (y4 - srcTop) * scale);
1796 ctx.stroke();
1797}
1798
1799function interp_cubic_coords(x1, x2, x3, x4, t)
1800{
1801 var ab = interp(x1, x2, t);
1802 var bc = interp(x2, x3, t);
1803 var cd = interp(x3, x4, t);
1804 var abc = interp(ab, bc, t);
1805 var bcd = interp(bc, cd, t);
1806 var abcd = interp(abc, bcd, t);
1807 return abcd;
1808}
1809
1810function cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1811 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
1812 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
1813 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
1814 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
1815 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
1816 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
1817 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
1818 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
1819 var mx = ex * 27 - ax * 8 - dx;
1820 var my = ey * 27 - ay * 8 - dy;
1821 var nx = fx * 27 - ax - dx * 8;
1822 var ny = fy * 27 - ay - dy * 8;
1823 var bx = (mx * 2 - nx) / 18;
1824 var by = (my * 2 - ny) / 18;
1825 var cx = (nx * 2 - mx) / 18;
1826 var cy = (ny * 2 - my) / 18;
1827 var array = [
1828 ax, ay, bx, by, cx, cy, dx, dy
1829 ];
1830 return array;
1831}
1832
1833function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
1834 var a = cubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
1835 var ax = a[0];
1836 var ay = a[1];
1837 var bx = a[2];
1838 var by = a[3];
1839 var cx = a[4];
1840 var cy = a[5];
1841 var dx = a[6];
1842 var dy = a[7];
1843 if (alreadyDrawnCubic(ax, ay, bx, by, cx, cy, dx, dy)) {
1844 return;
1845 }
1846 ctx.beginPath();
1847 ctx.moveTo((ax - srcLeft) * scale,
1848 (ay - srcTop) * scale);
1849 ctx.bezierCurveTo((bx - srcLeft) * scale,
1850 (by - srcTop) * scale,
1851 (cx - srcLeft) * scale,
1852 (cy - srcTop) * scale,
1853 (dx - srcLeft) * scale,
1854 (dy - srcTop) * scale);
1855 ctx.stroke();
1856}
1857
1858function drawCurve(c) {
1859 switch (c.length) {
1860 case 4:
1861 drawLine(c[0], c[1], c[2], c[3]);
1862 break;
1863 case 6:
1864 drawQuad(c[0], c[1], c[2], c[3], c[4], c[5]);
1865 break;
caryclark1049f122015-04-20 08:31:59 -07001866 case 7:
1867 drawConicWithQuads(c[0], c[1], c[2], c[3], c[4], c[5], c[6]);
1868 break;
caryclarkdac1d172014-06-17 05:15:38 -07001869 case 8:
1870 drawCubic(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1871 break;
1872 }
1873}
1874
1875function boundsWidth(pts) {
1876 var min = pts[0];
1877 var max = pts[0];
caryclark1049f122015-04-20 08:31:59 -07001878 var length = pts.length == 7 ? 6 : pts.length;
1879 for (var idx = 2; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001880 min = Math.min(min, pts[idx]);
1881 max = Math.max(max, pts[idx]);
1882 }
1883 return max - min;
1884}
1885
1886function boundsHeight(pts) {
1887 var min = pts[1];
1888 var max = pts[1];
caryclark1049f122015-04-20 08:31:59 -07001889 var length = pts.length == 7 ? 6 : pts.length;
1890 for (var idx = 3; idx < length; idx += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07001891 min = Math.min(min, pts[idx]);
1892 max = Math.max(max, pts[idx]);
1893 }
1894 return max - min;
1895}
1896
1897function tangent(pts) {
1898 var dx = pts[2] - pts[0];
1899 var dy = pts[3] - pts[1];
1900 if (dx == 0 && dy == 0 && pts.length > 4) {
1901 dx = pts[4] - pts[0];
1902 dy = pts[5] - pts[1];
caryclark1049f122015-04-20 08:31:59 -07001903 if (dx == 0 && dy == 0 && pts.length == 8) {
caryclarkdac1d172014-06-17 05:15:38 -07001904 dx = pts[6] - pts[0];
1905 dy = pts[7] - pts[1];
1906 }
1907 }
1908 return Math.atan2(-dy, dx);
1909}
1910
1911function hodograph(cubic) {
1912 var hodo = [];
1913 hodo[0] = 3 * (cubic[2] - cubic[0]);
1914 hodo[1] = 3 * (cubic[3] - cubic[1]);
1915 hodo[2] = 3 * (cubic[4] - cubic[2]);
1916 hodo[3] = 3 * (cubic[5] - cubic[3]);
1917 hodo[4] = 3 * (cubic[6] - cubic[4]);
1918 hodo[5] = 3 * (cubic[7] - cubic[5]);
1919 return hodo;
1920}
1921
1922function hodograph2(cubic) {
1923 var quad = hodograph(cubic);
1924 var hodo = [];
1925 hodo[0] = 2 * (quad[2] - quad[0]);
1926 hodo[1] = 2 * (quad[3] - quad[1]);
1927 hodo[2] = 2 * (quad[4] - quad[2]);
1928 hodo[3] = 2 * (quad[5] - quad[3]);
1929 return hodo;
1930}
1931
1932function quadraticRootsReal(A, B, C, s) {
1933 if (A == 0) {
1934 if (B == 0) {
1935 s[0] = 0;
1936 return C == 0;
1937 }
1938 s[0] = -C / B;
1939 return 1;
1940 }
1941 /* normal form: x^2 + px + q = 0 */
1942 var p = B / (2 * A);
1943 var q = C / A;
1944 var p2 = p * p;
1945 if (p2 < q) {
1946 return 0;
1947 }
1948 var sqrt_D = 0;
1949 if (p2 > q) {
1950 sqrt_D = sqrt(p2 - q);
1951 }
1952 s[0] = sqrt_D - p;
1953 s[1] = -sqrt_D - p;
1954 return 1 + s[0] != s[1];
1955}
1956
1957function add_valid_ts(s, realRoots, t) {
1958 var foundRoots = 0;
1959 for (var index = 0; index < realRoots; ++index) {
1960 var tValue = s[index];
1961 if (tValue >= 0 && tValue <= 1) {
1962 for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
1963 if (t[idx2] != tValue) {
1964 t[foundRoots++] = tValue;
1965 }
1966 }
1967 }
1968 }
1969 return foundRoots;
1970}
1971
1972function quadraticRootsValidT(a, b, c, t) {
1973 var s = [];
1974 var realRoots = quadraticRootsReal(A, B, C, s);
1975 var foundRoots = add_valid_ts(s, realRoots, t);
1976 return foundRoots != 0;
1977}
1978
1979function find_cubic_inflections(cubic, tValues) {
1980 var Ax = src[2] - src[0];
1981 var Ay = src[3] - src[1];
1982 var Bx = src[4] - 2 * src[2] + src[0];
1983 var By = src[5] - 2 * src[3] + src[1];
1984 var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
1985 var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
1986 return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
1987 Ax * By - Ay * Bx, tValues);
1988}
1989
1990function dxy_at_t(curve, type, t) {
1991 var dxy = {};
1992 if (type == PATH_QUAD) {
1993 var a = t - 1;
1994 var b = 1 - 2 * t;
1995 var c = t;
1996 dxy.x = a * curve[0] + b * curve[2] + c * curve[4];
1997 dxy.y = a * curve[1] + b * curve[3] + c * curve[5];
caryclark1049f122015-04-20 08:31:59 -07001998 } else if (type == PATH_CONIC) {
1999 var p20x = curve[4] - curve[0];
2000 var p20y = curve[5] - curve[1];
2001 var p10xw = (curve[2] - curve[0]) * curve[6];
2002 var p10yw = (curve[3] - curve[1]) * curve[6];
2003 var coeff0x = curve[6] * p20x - p20x;
2004 var coeff0y = curve[6] * p20y - p20y;
2005 var coeff1x = p20x - 2 * p10xw;
2006 var coeff1y = p20y - 2 * p10yw;
2007 dxy.x = t * (t * coeff0x + coeff1x) + p10xw;
2008 dxy.y = t * (t * coeff0y + coeff1y) + p10yw;
caryclarkdac1d172014-06-17 05:15:38 -07002009 } else if (type == PATH_CUBIC) {
2010 var one_t = 1 - t;
2011 var a = curve[0];
2012 var b = curve[2];
2013 var c = curve[4];
2014 var d = curve[6];
2015 dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2016 a = curve[1];
2017 b = curve[3];
2018 c = curve[5];
2019 d = curve[7];
2020 dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
2021 }
2022 return dxy;
2023}
2024
2025function drawLabel(num, px, py) {
2026 ctx.beginPath();
2027 ctx.arc(px, py, 8, 0, Math.PI*2, true);
2028 ctx.closePath();
2029 ctx.strokeStyle = "rgba(0,0,0, 0.4)";
2030 ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
2031 ctx.stroke();
2032 ctx.fillStyle = "black";
2033 ctx.font = "normal 10px Arial";
2034 // ctx.rotate(0.001);
2035 ctx.fillText(num, px - 2, py + 3);
2036 // ctx.rotate(-0.001);
2037}
2038
2039function drawLabelX(ymin, num, loc) {
2040 var px = (loc - srcLeft) * scale;
2041 var py = (ymin - srcTop) * scale - 20;
2042 drawLabel(num, px, py);
2043}
2044
2045function drawLabelY(xmin, num, loc) {
2046 var px = (xmin - srcLeft) * scale - 20;
2047 var py = (loc - srcTop) * scale;
2048 drawLabel(num, px, py);
2049}
2050
2051function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
2052 ctx.beginPath();
2053 ctx.moveTo(hx, hy - 100);
2054 ctx.lineTo(hx, hy);
2055 ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
2056 ctx.stroke();
2057 ctx.beginPath();
2058 ctx.moveTo(hx, hy);
2059 ctx.lineTo(hx, hy + 100);
2060 ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
2061 ctx.stroke();
2062 ctx.beginPath();
2063 ctx.moveTo(hx - 100, hy);
2064 ctx.lineTo(hx, hy);
2065 ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
2066 ctx.stroke();
2067 ctx.beginPath();
2068 ctx.moveTo(hx, hy);
2069 ctx.lineTo(hx + 100, hy);
2070 ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
2071 ctx.stroke();
2072}
2073
2074function scalexy(x, y, mag) {
2075 var length = Math.sqrt(x * x + y * y);
2076 return mag / length;
2077}
2078
caryclark03b03ca2015-04-23 09:13:37 -07002079function drawArrow(x, y, dx, dy, s) {
2080 var dscale = scalexy(dx, dy, 1 / scale * 100 * s);
caryclarkdac1d172014-06-17 05:15:38 -07002081 dx *= dscale;
2082 dy *= dscale;
2083 ctx.beginPath();
2084 ctx.moveTo((x - srcLeft) * scale, (y - srcTop) * scale);
2085 x += dx;
2086 y += dy;
2087 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2088 dx /= 10;
2089 dy /= 10;
2090 ctx.lineTo((x - dy - srcLeft) * scale, (y + dx - srcTop) * scale);
2091 ctx.lineTo((x + dx * 2 - srcLeft) * scale, (y + dy * 2 - srcTop) * scale);
2092 ctx.lineTo((x + dy - srcLeft) * scale, (y - dx - srcTop) * scale);
2093 ctx.lineTo((x - srcLeft) * scale, (y - srcTop) * scale);
2094 ctx.strokeStyle = "rgba(0,75,0, 0.4)";
2095 ctx.stroke();
2096}
2097
2098function x_at_t(curve, t) {
2099 var one_t = 1 - t;
2100 if (curve.length == 4) {
2101 return one_t * curve[0] + t * curve[2];
2102 }
2103 var one_t2 = one_t * one_t;
2104 var t2 = t * t;
2105 if (curve.length == 6) {
2106 return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4];
2107 }
caryclark1049f122015-04-20 08:31:59 -07002108 if (curve.length == 7) {
2109 return (one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] + t2 * curve[4])
2110 / (one_t2 +2 * one_t * t * curve[6] + t2);
2111 }
caryclarkdac1d172014-06-17 05:15:38 -07002112 var a = one_t2 * one_t;
2113 var b = 3 * one_t2 * t;
2114 var c = 3 * one_t * t2;
2115 var d = t2 * t;
2116 return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6];
2117}
2118
2119function y_at_t(curve, t) {
2120 var one_t = 1 - t;
2121 if (curve.length == 4) {
2122 return one_t * curve[1] + t * curve[3];
2123 }
2124 var one_t2 = one_t * one_t;
2125 var t2 = t * t;
2126 if (curve.length == 6) {
2127 return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5];
2128 }
caryclark1049f122015-04-20 08:31:59 -07002129 if (curve.length == 7) {
2130 return (one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] + t2 * curve[5])
2131 / (one_t2 +2 * one_t * t * curve[6] + t2);
2132 }
caryclarkdac1d172014-06-17 05:15:38 -07002133 var a = one_t2 * one_t;
2134 var b = 3 * one_t2 * t;
2135 var c = 3 * one_t * t2;
2136 var d = t2 * t;
2137 return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
2138}
2139
2140function drawOrder(curve, label) {
2141 var px = x_at_t(curve, 0.75);
2142 var py = y_at_t(curve, 0.75);
2143 var _px = (px - srcLeft) * scale;
2144 var _py = (py - srcTop) * scale;
2145 ctx.beginPath();
2146 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2147 ctx.closePath();
2148 ctx.fillStyle = "white";
2149 ctx.fill();
2150 if (label == 'L') {
2151 ctx.strokeStyle = "rgba(255,0,0, 1)";
2152 ctx.fillStyle = "rgba(255,0,0, 1)";
2153 } else {
2154 ctx.strokeStyle = "rgba(0,0,255, 1)";
2155 ctx.fillStyle = "rgba(0,0,255, 1)";
2156 }
2157 ctx.stroke();
2158 ctx.font = "normal 16px Arial";
2159 ctx.textAlign = "center";
2160 ctx.fillText(label, _px, _py + 5);
2161 ctx.font = "normal 10px Arial";
2162}
2163
2164function drawID(curve, id) {
2165 var px = x_at_t(curve, 0.5);
2166 var py = y_at_t(curve, 0.5);
2167 var _px = (px - srcLeft) * scale;
2168 var _py = (py - srcTop) * scale;
2169 draw_id_at(id, _px, _py);
2170}
2171
2172function draw_id_at(id, _px, _py) {
2173 ctx.beginPath();
2174 ctx.arc(_px, _py, 15, 0, Math.PI * 2, true);
2175 ctx.closePath();
2176 ctx.fillStyle = "white";
2177 ctx.fill();
2178 ctx.strokeStyle = "rgba(127,127,0, 1)";
2179 ctx.fillStyle = "rgba(127,127,0, 1)";
2180 ctx.stroke();
2181 ctx.font = "normal 16px Arial";
2182 ctx.textAlign = "center";
2183 ctx.fillText(id, _px, _py + 5);
2184 ctx.font = "normal 10px Arial";
2185}
2186
2187function drawLinePartialID(id, x1, y1, x2, y2, t1, t2) {
2188 var curve = [x1, y1, x2, y2];
2189 drawCurvePartialID(id, curve, t1, t2);
2190}
2191
2192function drawQuadPartialID(id, x1, y1, x2, y2, x3, y3, t1, t2) {
2193 var curve = [x1, y1, x2, y2, x3, y3];
2194 drawCurvePartialID(id, curve, t1, t2);
2195}
2196
caryclark1049f122015-04-20 08:31:59 -07002197function drawConicPartialID(id, x1, y1, x2, y2, x3, y3, w, t1, t2) {
2198 var curve = [x1, y1, x2, y2, x3, y3, w];
2199 drawCurvePartialID(id, curve, t1, t2);
2200}
2201
caryclarkdac1d172014-06-17 05:15:38 -07002202function drawCubicPartialID(id, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
2203 var curve = [x1, y1, x2, y2, x3, y3, x4, y4];
2204 drawCurvePartialID(id, curve, t1, t2);
2205}
2206
2207function drawCurvePartialID(id, curve, t1, t2) {
2208 var px = x_at_t(curve, (t1 + t2) / 2);
2209 var py = y_at_t(curve, (t1 + t2) / 2);
2210 var _px = (px - srcLeft) * scale;
2211 var _py = (py - srcTop) * scale;
2212 draw_id_at(id, _px, _py);
2213}
2214
2215function drawCurveSpecials(test, curve, type) {
2216 if (pt_labels) {
2217 drawPoints(curve, type, pt_labels == 2);
2218 }
2219 if (control_lines != 0) {
2220 drawControlLines(curve, type, control_lines);
2221 }
2222 if (curve_t) {
2223 drawPointAtT(curve, type);
2224 }
2225 if (draw_midpoint) {
2226 var mid = pointAtT(curve, type, 0.5);
2227 drawPoint(mid.x, mid.y, true);
2228 }
2229 if (draw_id) {
2230 var id = idByCurve(test, curve, type);
2231 if (id >= 0) {
2232 drawID(curve, id);
2233 }
2234 }
2235 if (type == PATH_LINE) {
2236 return;
2237 }
2238 if (draw_deriviatives > 0) {
2239 var d = dxy_at_t(curve, type, 0);
caryclark03b03ca2015-04-23 09:13:37 -07002240 drawArrow(curve[0], curve[1], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002241 if (draw_deriviatives == 2) {
2242 d = dxy_at_t(curve, type, 1);
2243 if (type == PATH_CUBIC) {
caryclark03b03ca2015-04-23 09:13:37 -07002244 drawArrow(curve[6], curve[7], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002245 } else {
caryclark03b03ca2015-04-23 09:13:37 -07002246 drawArrow(curve[4], curve[5], d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002247 }
2248 }
2249 if (draw_midpoint) {
2250 var mid = pointAtT(curve, type, 0.5);
2251 d = dxy_at_t(curve, type, 0.5);
caryclark03b03ca2015-04-23 09:13:37 -07002252 drawArrow(mid.x, mid.y, d.x, d.y, 1);
caryclarkdac1d172014-06-17 05:15:38 -07002253 }
2254 }
2255 if (type != PATH_CUBIC) {
2256 return;
2257 }
caryclarkdac1d172014-06-17 05:15:38 -07002258 if (draw_sequence) {
2259 var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
2260 for (var i = 0; i < 8; i+= 2) {
2261 drawLabelX(ymin, i >> 1, curve[i]);
2262 }
2263 var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
2264 for (var i = 1; i < 8; i+= 2) {
2265 drawLabelY(xmin, i >> 1, curve[i]);
2266 }
2267 }
2268}
2269
2270function logCurves(test) {
2271 for (curves in test) {
2272 var curve = test[curves];
2273 dumpCurve(curve);
2274 }
2275}
2276
2277function curveToString(curve) {
2278 var str = "{{";
caryclark1049f122015-04-20 08:31:59 -07002279 var length = curve.length == 7 ? 6 : curve.length;
2280 if (curve.length == 7) {
2281 str += "{";
2282 }
2283 for (i = 0; i < length; i += 2) {
caryclarkdac1d172014-06-17 05:15:38 -07002284 str += curve[i].toFixed(decimal_places) + "," + curve[i + 1].toFixed(decimal_places);
2285 if (i < curve.length - 2) {
2286 str += "}, {";
2287 }
2288 }
caryclark1049f122015-04-20 08:31:59 -07002289 str += "}";
2290 if (curve.length == 7) {
2291 str += "}, " + curve[6].toFixed(decimal_places);
2292 }
2293 str += "}";
caryclarkdac1d172014-06-17 05:15:38 -07002294 return str;
2295}
2296
2297function dumpCurve(curve) {
2298 console.log(curveToString(curve));
2299}
2300
2301function draw(test, lines, title) {
2302 ctx.fillStyle = "rgba(0,0,0, 0.1)";
2303 ctx.font = "normal 50px Arial";
2304 ctx.textAlign = "left";
2305 ctx.fillText(title, 50, 50);
2306 ctx.font = "normal 10px Arial";
2307 ctx.lineWidth = "1.001"; "0.999";
2308 var secondPath = test.length;
2309 var closeCount = 0;
2310 logStart = -1;
2311 logRange = 0;
2312 // find last active rec type at this step
2313 var curType = test[0];
2314 var curStep = 0;
2315 var hasOp = false;
2316 var lastActive = 0;
2317 var lastAdd = 0;
caryclark624637c2015-05-11 07:21:27 -07002318 var lastCoin = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002319 var lastSect = 0;
2320 var lastSort = 0;
2321 var lastMark = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002322 var lastTop = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002323 activeCount = 0;
2324 addCount = 0;
2325 angleCount = 0;
2326 opCount = 0;
2327 sectCount = 0;
2328 sortCount = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002329 topCount = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002330 markCount = 0;
2331 activeMax = 0;
2332 addMax = 0;
2333 angleMax = 0;
caryclark624637c2015-05-11 07:21:27 -07002334 coinMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002335 opMax = 0;
2336 sectMax = 0;
2337 sectMax2 = 0;
2338 sortMax = 0;
caryclark03b03ca2015-04-23 09:13:37 -07002339 topMax = 0;
caryclarkdac1d172014-06-17 05:15:38 -07002340 markMax = 0;
2341 lastIndex = test.length - 3;
2342 for (var tIndex = 0; tIndex < test.length; tIndex += 3) {
2343 var recType = test[tIndex];
2344 if (!typeof recType == 'number' || recType < REC_TYPE_UNKNOWN || recType > REC_TYPE_LAST) {
2345 console.log("unknown rec type: " + recType);
2346 throw "stop execution";
2347 }
2348 // if (curType == recType && curType != REC_TYPE_ADD) {
2349 // continue;
2350 // }
2351 var inStepRange = step_limit == 0 || curStep < step_limit;
2352 curType = recType;
2353 if (recType == REC_TYPE_OP) {
2354 hasOp = true;
2355 continue;
2356 }
2357 if (recType == REC_TYPE_UNKNOWN) {
2358 // these types do not advance step
2359 continue;
2360 }
2361 var bumpStep = false;
2362 var records = test[tIndex + 2];
2363 var fragType = records[0];
2364 if (recType == REC_TYPE_ADD) {
2365 if (records.length != 2) {
2366 console.log("expect only two elements: " + records.length);
2367 throw "stop execution";
2368 }
2369 if (fragType == ADD_MOVETO || fragType == ADD_CLOSE) {
2370 continue;
2371 }
2372 ++addMax;
2373 if (!draw_add || !inStepRange) {
2374 continue;
2375 }
2376 lastAdd = tIndex;
2377 ++addCount;
2378 bumpStep = true;
2379 }
2380 if (recType == REC_TYPE_PATH && hasOp) {
2381 secondPath = tIndex;
2382 }
caryclark54359292015-03-26 07:52:43 -07002383 if (recType == REC_TYPE_PATH2 && hasOp) {
2384 secondPath = tIndex;
2385 }
caryclarkdac1d172014-06-17 05:15:38 -07002386 if (recType == REC_TYPE_ACTIVE) {
2387 ++activeMax;
2388 if (!draw_active || !inStepRange) {
2389 continue;
2390 }
2391 lastActive = tIndex;
2392 ++activeCount;
2393 bumpStep = true;
2394 }
2395 if (recType == REC_TYPE_ACTIVE_OP) {
2396 ++opMax;
2397 if (!draw_op || !inStepRange) {
2398 continue;
2399 }
2400 lastOp = tIndex;
2401 ++opCount;
2402 bumpStep = true;
2403 }
caryclark54359292015-03-26 07:52:43 -07002404 if (recType == REC_TYPE_AFTERPART) {
2405 if (draw_angle != 3 || !inStepRange) {
2406 continue;
2407 }
2408 lastAngle = tIndex;
2409 ++angleCount;
2410 bumpStep = true;
2411 }
caryclarkdac1d172014-06-17 05:15:38 -07002412 if (recType == REC_TYPE_ANGLE) {
2413 ++angleMax;
caryclark54359292015-03-26 07:52:43 -07002414 if (draw_angle == 0 || draw_angle == 3 || !inStepRange) {
caryclarkdac1d172014-06-17 05:15:38 -07002415 continue;
2416 }
2417 lastAngle = tIndex;
2418 ++angleCount;
2419 bumpStep = true;
2420 }
caryclark624637c2015-05-11 07:21:27 -07002421 if (recType == REC_TYPE_COINCIDENCE) {
2422 ++coinMax;
2423 if (!draw_coincidence || !inStepRange) {
2424 continue;
2425 }
2426 lastCoin = tIndex;
2427 ++coinCount;
2428 bumpStep = true;
2429 }
caryclarkdac1d172014-06-17 05:15:38 -07002430 if (recType == REC_TYPE_SECT) {
2431 if (records.length != 2) {
2432 console.log("expect only two elements: " + records.length);
2433 throw "stop execution";
2434 }
2435 ++sectMax;
2436 var sectBump = 1;
2437 switch (fragType) {
2438 case INTERSECT_LINE:
2439 case INTERSECT_QUAD_LINE:
2440 case INTERSECT_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002441 case INTERSECT_CONIC_LINE:
2442 case INTERSECT_CONIC:
caryclarkdac1d172014-06-17 05:15:38 -07002443 case INTERSECT_SELF_CUBIC:
2444 case INTERSECT_CUBIC_LINE:
2445 case INTERSECT_CUBIC_QUAD:
2446 case INTERSECT_CUBIC:
2447 sectBump = 1;
2448 break;
2449 case INTERSECT_LINE_2:
2450 case INTERSECT_QUAD_LINE_2:
2451 case INTERSECT_QUAD_2:
caryclark1049f122015-04-20 08:31:59 -07002452 case INTERSECT_CONIC_LINE_2:
2453 case INTERSECT_CONIC_2:
caryclarkdac1d172014-06-17 05:15:38 -07002454 case INTERSECT_CUBIC_LINE_2:
2455 case INTERSECT_CUBIC_QUAD_2:
2456 case INTERSECT_CUBIC_2:
2457 sectBump = 2;
2458 break;
2459 case INTERSECT_LINE_NO:
2460 case INTERSECT_QUAD_LINE_NO:
2461 case INTERSECT_QUAD_NO:
caryclark1049f122015-04-20 08:31:59 -07002462 case INTERSECT_CONIC_LINE_NO:
2463 case INTERSECT_CONIC_NO:
caryclarkdac1d172014-06-17 05:15:38 -07002464 case INTERSECT_SELF_CUBIC_NO:
2465 case INTERSECT_CUBIC_LINE_NO:
2466 case INTERSECT_CUBIC_QUAD_NO:
2467 case INTERSECT_CUBIC_NO:
2468 sectBump = 0;
2469 break;
2470 case INTERSECT_CUBIC_LINE_3:
2471 case INTERSECT_CUBIC_QUAD_3:
2472 case INTERSECT_CUBIC_3:
2473 sectBump = 3;
2474 break;
2475 case INTERSECT_CUBIC_QUAD_4:
2476 case INTERSECT_CUBIC_4:
2477 sectBump = 4;
2478 break;
2479 default:
2480 console.log("missing case " + records.length);
2481 throw "stop execution";
2482 }
2483 sectMax2 += sectBump;
2484 if (draw_intersection <= 1 || !inStepRange) {
2485 continue;
2486 }
2487 lastSect = tIndex;
2488 sectCount += sectBump;
2489 bumpStep = true;
2490 }
2491 if (recType == REC_TYPE_SORT) {
2492 ++sortMax;
2493 if (!draw_sort || !inStepRange) {
2494 continue;
2495 }
2496 lastSort = tIndex;
2497 ++sortCount;
2498 bumpStep = true;
2499 }
caryclark03b03ca2015-04-23 09:13:37 -07002500 if (recType == REC_TYPE_TOP) {
2501 ++topMax;
2502 if (!draw_top || !inStepRange) {
2503 continue;
2504 }
2505 lastTop = tIndex;
2506 ++topCount;
2507 bumpStep = true;
2508 }
caryclarkdac1d172014-06-17 05:15:38 -07002509 if (recType == REC_TYPE_MARK) {
2510 ++markMax;
2511 if (!draw_mark || !inStepRange) {
2512 continue;
2513 }
2514 lastMark = tIndex;
2515 ++markCount;
2516 bumpStep = true;
2517 }
2518 if (bumpStep) {
2519 lastIndex = tIndex;
2520 logStart = test[tIndex + 1];
2521 logRange = records.length / 2;
2522 ++curStep;
2523 }
2524 }
2525 stepMax = (draw_add ? addMax : 0)
2526 + (draw_active ? activeMax : 0)
reed0dc4dd62015-03-24 13:55:33 -07002527 + (draw_angle ? angleMax : 0)
caryclark624637c2015-05-11 07:21:27 -07002528 + (draw_coincidence ? coinMax : 0)
caryclark54359292015-03-26 07:52:43 -07002529 + (draw_op ? opMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002530 + (draw_sort ? sortMax : 0)
caryclark03b03ca2015-04-23 09:13:37 -07002531 + (draw_top ? topMax : 0)
caryclarkdac1d172014-06-17 05:15:38 -07002532 + (draw_mark ? markMax : 0)
2533 + (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
2534 if (stepMax == 0) {
caryclark624637c2015-05-11 07:21:27 -07002535 stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
caryclarkdac1d172014-06-17 05:15:38 -07002536 }
2537 drawnPts = [];
2538 drawnLines = [];
2539 drawnQuads = [];
caryclark1049f122015-04-20 08:31:59 -07002540 drawnConics = [];
caryclarkdac1d172014-06-17 05:15:38 -07002541 drawnCubics = [];
2542 focusXmin = focusYmin = Infinity;
2543 focusXmax = focusYmax = -Infinity;
2544 var pathIndex = 0;
2545 var opLetter = 'S';
2546 for (var tIndex = lastIndex; tIndex >= 0; tIndex -= 3) {
2547 var recType = test[tIndex];
2548 var records = test[tIndex + 2];
2549 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
2550 var fragType = records[recordIndex];
2551 if (!typeof fragType == 'number' || fragType < 1 || fragType > FRAG_TYPE_LAST) {
2552 console.log("unknown in range frag type: " + fragType);
2553 throw "stop execution";
2554 }
2555 var frags = records[recordIndex + 1];
2556 focus_enabled = false;
2557 switch (recType) {
2558 case REC_TYPE_COMPUTED:
2559 if (draw_computed == 0) {
2560 continue;
2561 }
2562 ctx.lineWidth = 1;
2563 ctx.strokeStyle = pathIndex == 0 ? "black" : "red";
2564 ctx.fillStyle = "blue";
2565 var drawThis = false;
2566 switch (fragType) {
2567 case PATH_QUAD:
caryclark1049f122015-04-20 08:31:59 -07002568 if ((draw_computed & 0x9) == 1 || ((draw_computed & 8) != 0
2569 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002570 drawQuad(frags[0], frags[1], frags[2], frags[3],
2571 frags[4], frags[5]);
2572 drawThis = true;
2573 }
2574 break;
caryclark1049f122015-04-20 08:31:59 -07002575 case PATH_CONIC:
2576 if ((draw_computed & 0xA) == 2 || ((draw_computed & 8) != 0
2577 && (draw_computed & 7) == pathIndex)) {
2578 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2579 frags[4], frags[5], frags[6]);
2580 drawThis = true;
2581 }
2582 break;
caryclarkdac1d172014-06-17 05:15:38 -07002583 case PATH_CUBIC:
caryclark1049f122015-04-20 08:31:59 -07002584 if ((draw_computed & 0xC) == 4 || ((draw_computed & 8) != 0
2585 && (draw_computed & 7) == pathIndex)) {
caryclarkdac1d172014-06-17 05:15:38 -07002586 drawCubic(frags[0], frags[1], frags[2], frags[3],
2587 frags[4], frags[5], frags[6], frags[7]);
2588 drawThis = true;
2589 }
2590 ++pathIndex;
2591 break;
2592 case COMPUTED_SET_1:
2593 pathIndex = 0;
2594 break;
2595 case COMPUTED_SET_2:
2596 pathIndex = 1;
2597 break;
2598 default:
2599 console.log("unknown REC_TYPE_COMPUTED frag type: " + fragType);
2600 throw "stop execution";
2601 }
2602 if (!drawThis || collect_bounds) {
2603 break;
2604 }
2605 drawCurveSpecials(test, frags, fragType);
2606 break;
2607 case REC_TYPE_PATH:
caryclark54359292015-03-26 07:52:43 -07002608 case REC_TYPE_PATH2:
caryclarkdac1d172014-06-17 05:15:38 -07002609 if (!draw_path) {
2610 continue;
2611 }
2612 var firstPath = tIndex < secondPath;
2613 if ((draw_path & (firstPath ? 1 : 2)) == 0) {
2614 continue;
2615 }
2616 ctx.lineWidth = 1;
2617 ctx.strokeStyle = firstPath ? "black" : "red";
2618 ctx.fillStyle = "blue";
caryclark54359292015-03-26 07:52:43 -07002619 var frags2 = [];
caryclarkdac1d172014-06-17 05:15:38 -07002620 switch (fragType) {
2621 case PATH_LINE:
caryclark54359292015-03-26 07:52:43 -07002622 for (var i = 0; i < 4; ++ i) { frags2[i] = frags[i + 1]; }
2623 drawLine(frags2[0], frags2[1], frags2[2], frags2[3]);
caryclarkdac1d172014-06-17 05:15:38 -07002624 break;
2625 case PATH_QUAD:
caryclark54359292015-03-26 07:52:43 -07002626 for (var i = 0; i < 6; ++ i) { frags2[i] = frags[i + 1]; }
2627 drawQuad(frags2[0], frags2[1], frags2[2], frags2[3],
2628 frags2[4], frags2[5]);
caryclarkdac1d172014-06-17 05:15:38 -07002629 break;
caryclark1049f122015-04-20 08:31:59 -07002630 case PATH_CONIC:
2631 for (var i = 0; i < 7; ++ i) { frags2[i] = frags[i + 1]; }
2632 drawConicWithQuads(frags2[0], frags2[1], frags2[2], frags2[3],
2633 frags2[4], frags2[5], frags2[6]);
2634 break;
caryclarkdac1d172014-06-17 05:15:38 -07002635 case PATH_CUBIC:
caryclark54359292015-03-26 07:52:43 -07002636 for (var i = 0; i < 8; ++ i) { frags2[i] = frags[i + 1]; }
2637 drawCubic(frags2[0], frags2[1], frags2[2], frags2[3],
2638 frags2[4], frags2[5], frags2[6], frags2[7]);
caryclarkdac1d172014-06-17 05:15:38 -07002639 break;
2640 default:
caryclark54359292015-03-26 07:52:43 -07002641 console.log("unknown REC_TYPE_PATH2 frag type: " + fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002642 throw "stop execution";
2643 }
2644 if (collect_bounds) {
2645 break;
2646 }
caryclark54359292015-03-26 07:52:43 -07002647 drawCurveSpecials(test, frags2, fragType);
caryclarkdac1d172014-06-17 05:15:38 -07002648 break;
2649 case REC_TYPE_OP:
2650 switch (fragType) {
2651 case OP_INTERSECT: opLetter = 'I'; break;
2652 case OP_DIFFERENCE: opLetter = 'D'; break;
2653 case OP_UNION: opLetter = 'U'; break;
2654 case OP_XOR: opLetter = 'X'; break;
2655 default:
2656 console.log("unknown REC_TYPE_OP frag type: " + fragType);
2657 throw "stop execution";
2658 }
2659 break;
2660 case REC_TYPE_ACTIVE:
2661 if (!draw_active || (step_limit > 0 && tIndex < lastActive)) {
2662 continue;
2663 }
2664 var x1 = frags[SPAN_X1];
2665 var y1 = frags[SPAN_Y1];
2666 var x2 = frags[SPAN_X2];
2667 var y2 = frags[SPAN_Y2];
caryclark1049f122015-04-20 08:31:59 -07002668 var x3, y3, x3, y4, t1, t2, w;
caryclarkdac1d172014-06-17 05:15:38 -07002669 ctx.lineWidth = 3;
2670 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2671 focus_enabled = true;
2672 switch (fragType) {
2673 case ACTIVE_LINE_SPAN:
2674 t1 = frags[SPAN_L_T];
2675 t2 = frags[SPAN_L_TEND];
2676 drawLinePartial(x1, y1, x2, y2, t1, t2);
2677 if (draw_id) {
2678 drawLinePartialID(frags[0], x1, y1, x2, y2, t1, t2);
2679 }
2680 break;
2681 case ACTIVE_QUAD_SPAN:
2682 x3 = frags[SPAN_X3];
2683 y3 = frags[SPAN_Y3];
2684 t1 = frags[SPAN_Q_T];
2685 t2 = frags[SPAN_Q_TEND];
2686 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
2687 if (draw_id) {
2688 drawQuadPartialID(frags[0], x1, y1, x2, y2, x3, y3, t1, t2);
2689 }
2690 break;
caryclark1049f122015-04-20 08:31:59 -07002691 case ACTIVE_CONIC_SPAN:
2692 x3 = frags[SPAN_X3];
2693 y3 = frags[SPAN_Y3];
2694 t1 = frags[SPAN_K_T];
2695 t2 = frags[SPAN_K_TEND];
2696 w = frags[SPAN_K_W];
2697 drawConicPartial(x1, y1, x2, y2, x3, y3, w, t1, t2);
2698 if (draw_id) {
2699 drawConicPartialID(frags[0], x1, y1, x2, y2, x3, y3, w, t1, t2);
2700 }
2701 break;
caryclarkdac1d172014-06-17 05:15:38 -07002702 case ACTIVE_CUBIC_SPAN:
2703 x3 = frags[SPAN_X3];
2704 y3 = frags[SPAN_Y3];
2705 x4 = frags[SPAN_X4];
2706 y4 = frags[SPAN_Y4];
2707 t1 = frags[SPAN_C_T];
2708 t2 = frags[SPAN_C_TEND];
2709 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2710 if (draw_id) {
2711 drawCubicPartialID(frags[0], x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
2712 }
2713 break;
2714 default:
2715 console.log("unknown REC_TYPE_ACTIVE frag type: " + fragType);
2716 throw "stop execution";
2717 }
2718 break;
2719 case REC_TYPE_ACTIVE_OP:
2720 if (!draw_op || (step_limit > 0 && tIndex < lastOp)) {
2721 continue;
2722 }
2723 focus_enabled = true;
2724 ctx.lineWidth = 3;
2725 var activeSpan = frags[7] == "1";
2726 ctx.strokeStyle = activeSpan ? "rgba(45,160,0, 0.3)" : "rgba(255,45,0, 0.5)";
2727 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2728 drawCurve(curve);
2729 if (draw_op > 1) {
2730 drawArc(curve, false, frags[3], frags[4]);
2731 drawArc(curve, true, frags[5], frags[6]);
2732 }
2733 break;
2734 case REC_TYPE_ADD:
2735 if (!draw_add) {
2736 continue;
2737 }
2738 ctx.lineWidth = 3;
2739 ctx.strokeStyle = closeCount == 0 ? "rgba(0,0,255, 0.3)"
2740 : closeCount == 1 ? "rgba(0,127,0, 0.3)"
2741 : closeCount == 2 ? "rgba(0,127,127, 0.3)"
2742 : closeCount == 3 ? "rgba(127,127,0, 0.3)"
2743 : "rgba(127,0,127, 0.3)";
2744 focus_enabled = true;
2745 switch (fragType) {
2746 case ADD_MOVETO:
2747 break;
2748 case ADD_LINETO:
2749 if (step_limit == 0 || tIndex >= lastAdd) {
2750 drawLine(frags[0], frags[1], frags[2], frags[3]);
2751 }
2752 break;
2753 case ADD_QUADTO:
2754 if (step_limit == 0 || tIndex >= lastAdd) {
2755 drawQuad(frags[0], frags[1], frags[2], frags[3], frags[4], frags[5]);
2756 }
2757 break;
caryclark1049f122015-04-20 08:31:59 -07002758 case ADD_CONICTO:
2759 if (step_limit == 0 || tIndex >= lastAdd) {
2760 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2761 frags[4], frags[5], frags[6]);
2762 }
2763 break;
caryclarkdac1d172014-06-17 05:15:38 -07002764 case ADD_CUBICTO:
2765 if (step_limit == 0 || tIndex >= lastAdd) {
2766 drawCubic(frags[0], frags[1], frags[2], frags[3],
2767 frags[4], frags[5], frags[6], frags[7]);
2768 }
2769 break;
2770 case ADD_CLOSE:
2771 ++closeCount;
2772 break;
2773 case ADD_FILL:
2774 break;
2775 default:
2776 console.log("unknown REC_TYPE_ADD frag type: " + fragType);
2777 throw "stop execution";
2778 }
2779 break;
2780 case REC_TYPE_ANGLE:
caryclark54359292015-03-26 07:52:43 -07002781 angleBetween = frags[18] == "T";
2782 afterIndex = 0;
2783 if (draw_angle == 0 || draw_angle == 3 || (step_limit > 0 && tIndex < lastAngle)) {
caryclarkdac1d172014-06-17 05:15:38 -07002784 continue;
2785 }
2786 focus_enabled = true;
2787 ctx.lineWidth = 3;
2788 ctx.strokeStyle = "rgba(127,45,127, 0.3)";
caryclark54359292015-03-26 07:52:43 -07002789 var leftCurve = curvePartialByID(test, frags[0], frags[4], frags[5]);
2790 var midCurve = curvePartialByID(test, frags[6], frags[10], frags[11]);
2791 var rightCurve = curvePartialByID(test, frags[12], frags[16], frags[17]);
caryclarkdac1d172014-06-17 05:15:38 -07002792 drawCurve(leftCurve);
2793 drawCurve(rightCurve);
caryclark54359292015-03-26 07:52:43 -07002794 ctx.strokeStyle = angleBetween ? "rgba(0,160,45, 0.3)" : "rgba(255,0,45, 0.5)";
caryclarkdac1d172014-06-17 05:15:38 -07002795 drawCurve(midCurve);
2796 if (draw_angle > 1) {
2797 drawOrder(leftCurve, 'L');
2798 drawOrder(rightCurve, 'R');
2799 }
2800 break;
caryclark54359292015-03-26 07:52:43 -07002801 case REC_TYPE_AFTERPART:
2802 if (draw_angle != 3 || (step_limit > 0 && tIndex < lastAngle)) {
2803 continue;
2804 }
2805 ctx.strokeStyle = afterIndex == 0 ? "rgba(255,0,0, 1.0)"
2806 : (afterIndex == 1) == angleBetween ? "rgba(0,128,0, 1.0)"
2807 : "rgba(0,0,255, 1.0)";
2808 switch (fragType) {
2809 case PATH_LINE:
2810 drawLine(frags[0], frags[1], frags[2], frags[3]);
2811 break;
2812 case PATH_QUAD:
2813 drawQuad(frags[0], frags[1], frags[2], frags[3],
2814 frags[4], frags[5]);
2815 break;
caryclark1049f122015-04-20 08:31:59 -07002816 case PATH_CONIC:
2817 drawConicWithQuads(frags[0], frags[1], frags[2], frags[3],
2818 frags[4], frags[5], frags[6]);
2819 break;
caryclark54359292015-03-26 07:52:43 -07002820 case PATH_CUBIC:
2821 drawCubic(frags[0], frags[1], frags[2], frags[3],
caryclark1049f122015-04-20 08:31:59 -07002822 frags[4], frags[5], frags[6], frags[7]);
caryclark54359292015-03-26 07:52:43 -07002823 break;
2824 default:
2825 console.log("unknown REC_TYPE_AFTERPART frag type: " + fragType);
2826 throw "stop execution";
2827 }
2828 ++afterIndex;
2829 break;
caryclark624637c2015-05-11 07:21:27 -07002830 case REC_TYPE_COINCIDENCE:
2831 if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
2832 continue;
2833 }
2834 focus_enabled = true;
2835 ctx.lineWidth = 3;
2836 ctx.strokeStyle = "rgba(127,45,63, 0.3)";
2837 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
2838 drawCurve(curve);
2839 break;
caryclarkdac1d172014-06-17 05:15:38 -07002840 case REC_TYPE_SECT:
2841 if (!draw_intersection) {
2842 continue;
2843 }
2844 if (draw_intersection != 1 && (step_limit > 0 && tIndex < lastSect)) {
2845 continue;
2846 }
2847 // draw_intersection == 1 : show all
2848 // draw_intersection == 2 : step == 0 ? show all : show intersection line #step
2849 // draw_intersection == 3 : step == 0 ? show all : show intersection #step
2850 ctx.lineWidth = 1;
2851 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
2852 ctx.fillStyle = "blue";
2853 focus_enabled = true;
2854 var f = [];
2855 var c1s;
2856 var c1l;
2857 var c2s;
2858 var c2l;
2859 switch (fragType) {
2860 case INTERSECT_LINE:
2861 f.push(5, 6, 0, 7);
2862 c1s = 1; c1l = 4; c2s = 8; c2l = 4;
2863 break;
2864 case INTERSECT_LINE_2:
2865 f.push(5, 6, 0, 10);
2866 f.push(8, 9, 7, 15);
2867 c1s = 1; c1l = 4; c2s = 11; c2l = 4;
2868 break;
2869 case INTERSECT_LINE_NO:
2870 c1s = 0; c1l = 4; c2s = 4; c2l = 4;
2871 break;
2872 case INTERSECT_QUAD_LINE:
2873 f.push(7, 8, 0, 9);
2874 c1s = 1; c1l = 6; c2s = 10; c2l = 4;
2875 break;
2876 case INTERSECT_QUAD_LINE_2:
2877 f.push(7, 8, 0, 12);
2878 f.push(10, 11, 9, 17);
2879 c1s = 1; c1l = 6; c2s = 13; c2l = 4;
2880 break;
2881 case INTERSECT_QUAD_LINE_NO:
2882 c1s = 0; c1l = 6; c2s = 6; c2l = 4;
2883 break;
2884 case INTERSECT_QUAD:
2885 f.push(7, 8, 0, 9);
2886 c1s = 1; c1l = 6; c2s = 10; c2l = 6;
2887 break;
2888 case INTERSECT_QUAD_2:
2889 f.push(7, 8, 0, 12);
2890 f.push(10, 11, 9, 19);
2891 c1s = 1; c1l = 6; c2s = 13; c2l = 6;
2892 break;
2893 case INTERSECT_QUAD_NO:
2894 c1s = 0; c1l = 6; c2s = 6; c2l = 6;
2895 break;
caryclark1049f122015-04-20 08:31:59 -07002896 case INTERSECT_CONIC_LINE:
2897 f.push(8, 9, 0, 10);
2898 c1s = 1; c1l = 7; c2s = 11; c2l = 4;
2899 break;
2900 case INTERSECT_CONIC_LINE_2:
2901 f.push(8, 9, 0, 12);
2902 f.push(11, 12, 10, 18);
2903 c1s = 1; c1l = 7; c2s = 14; c2l = 4;
2904 break;
2905 case INTERSECT_CONIC_LINE_NO:
2906 c1s = 0; c1l = 7; c2s = 7; c2l = 4;
2907 break;
2908 case INTERSECT_CONIC:
2909 f.push(8, 9, 0, 10);
2910 c1s = 1; c1l = 7; c2s = 11; c2l = 7;
2911 break;
2912 case INTERSECT_CONIC_2:
2913 f.push(8, 9, 0, 13);
2914 f.push(11, 12, 10, 21);
2915 c1s = 1; c1l = 7; c2s = 14; c2l = 7;
2916 break;
2917 case INTERSECT_CONIC_NO:
2918 c1s = 0; c1l = 7; c2s = 7; c2l = 7;
2919 break;
caryclarkdac1d172014-06-17 05:15:38 -07002920 case INTERSECT_SELF_CUBIC:
2921 f.push(9, 10, 0, 11);
2922 c1s = 1; c1l = 8; c2s = 0; c2l = 0;
2923 break;
2924 case INTERSECT_SELF_CUBIC_NO:
2925 c1s = 0; c1l = 8; c2s = 0; c2l = 0;
2926 break;
2927 case INTERSECT_CUBIC_LINE:
2928 f.push(9, 10, 0, 11);
2929 c1s = 1; c1l = 8; c2s = 12; c2l = 4;
2930 break;
2931 case INTERSECT_CUBIC_LINE_2:
2932 f.push(9, 10, 0, 14);
2933 f.push(12, 13, 11, 19);
2934 c1s = 1; c1l = 8; c2s = 15; c2l = 4;
2935 break;
2936 case INTERSECT_CUBIC_LINE_3:
2937 f.push(9, 10, 0, 17);
2938 f.push(12, 13, 11, 22);
2939 f.push(15, 16, 14, 23);
2940 c1s = 1; c1l = 8; c2s = 18; c2l = 4;
2941 break;
2942 case INTERSECT_CUBIC_QUAD_NO:
2943 c1s = 0; c1l = 8; c2s = 8; c2l = 6;
2944 break;
2945 case INTERSECT_CUBIC_QUAD:
2946 f.push(9, 10, 0, 11);
2947 c1s = 1; c1l = 8; c2s = 12; c2l = 6;
2948 break;
2949 case INTERSECT_CUBIC_QUAD_2:
2950 f.push(9, 10, 0, 14);
2951 f.push(12, 13, 11, 21);
2952 c1s = 1; c1l = 8; c2s = 15; c2l = 6;
2953 break;
2954 case INTERSECT_CUBIC_QUAD_3:
2955 f.push(9, 10, 0, 17);
2956 f.push(12, 13, 11, 24);
2957 f.push(15, 16, 14, 25);
2958 c1s = 1; c1l = 8; c2s = 18; c2l = 6;
2959 break;
2960 case INTERSECT_CUBIC_QUAD_4:
2961 f.push(9, 10, 0, 20);
2962 f.push(12, 13, 11, 27);
2963 f.push(15, 16, 14, 28);
2964 f.push(18, 19, 17, 29);
2965 c1s = 1; c1l = 8; c2s = 21; c2l = 6;
2966 break;
2967 case INTERSECT_CUBIC_LINE_NO:
2968 c1s = 0; c1l = 8; c2s = 8; c2l = 4;
2969 break;
2970 case INTERSECT_CUBIC:
2971 f.push(9, 10, 0, 11);
2972 c1s = 1; c1l = 8; c2s = 12; c2l = 8;
2973 break;
2974 case INTERSECT_CUBIC_2:
2975 f.push(9, 10, 0, 14);
2976 f.push(12, 13, 11, 23);
2977 c1s = 1; c1l = 8; c2s = 15; c2l = 8;
2978 break;
2979 case INTERSECT_CUBIC_3:
2980 f.push(9, 10, 0, 17);
2981 f.push(12, 13, 11, 26);
2982 f.push(15, 16, 14, 27);
2983 c1s = 1; c1l = 8; c2s = 18; c2l = 8;
2984 break;
2985 case INTERSECT_CUBIC_4:
2986 f.push(9, 10, 0, 20);
2987 f.push(12, 13, 11, 29);
2988 f.push(15, 16, 14, 30);
2989 f.push(18, 19, 17, 31);
2990 c1s = 1; c1l = 8; c2s = 21; c2l = 8;
2991 break;
2992 case INTERSECT_CUBIC_NO:
2993 c1s = 0; c1l = 8; c2s = 8; c2l = 8;
2994 break;
2995 default:
2996 console.log("unknown REC_TYPE_SECT frag type: " + fragType);
2997 throw "stop execution";
2998 }
2999 if (draw_intersection != 1) {
3000 var id = -1;
3001 var curve;
3002 switch (c1l) {
3003 case 4:
3004 drawLine(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]);
3005 if (draw_id) {
3006 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3]];
3007 id = idByCurve(test, curve, PATH_LINE);
3008 }
3009 break;
3010 case 6:
3011 drawQuad(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3012 frags[c1s + 4], frags[c1s + 5]);
3013 if (draw_id) {
3014 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3015 frags[c1s + 4], frags[c1s + 5]];
3016 id = idByCurve(test, curve, PATH_QUAD);
3017 }
3018 break;
caryclark1049f122015-04-20 08:31:59 -07003019 case 7:
3020 drawConicWithQuads(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3021 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]);
3022 if (draw_id) {
3023 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3024 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6]];
3025 id = idByCurve(test, curve, PATH_CONIC);
3026 }
3027 break;
caryclarkdac1d172014-06-17 05:15:38 -07003028 case 8:
3029 drawCubic(frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3030 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]);
3031 if (draw_id) {
3032 curve = [frags[c1s], frags[c1s + 1], frags[c1s + 2], frags[c1s + 3],
3033 frags[c1s + 4], frags[c1s + 5], frags[c1s + 6], frags[c1s + 7]];
3034 id = idByCurve(test, curve, PATH_CUBIC);
3035 }
3036 break;
3037 }
3038 if (id >= 0) {
3039 drawID(curve, id);
3040 }
3041 id = -1;
3042 switch (c2l) {
3043 case 0:
3044 break;
3045 case 4:
3046 drawLine(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]);
3047 if (draw_id) {
3048 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3]];
3049 id = idByCurve(test, curve, PATH_LINE);
3050 }
3051 break;
3052 case 6:
3053 drawQuad(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3054 frags[c2s + 4], frags[c2s + 5]);
3055 if (draw_id) {
3056 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3057 frags[c2s + 4], frags[c2s + 5]];
3058 id = idByCurve(test, curve, PATH_QUAD);
3059 }
3060 break;
caryclark1049f122015-04-20 08:31:59 -07003061 case 7:
3062 drawConicWithQuads(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3063 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]);
3064 if (draw_id) {
3065 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3066 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6]];
3067 id = idByCurve(test, curve, PATH_CONIC);
3068 }
3069 break;
caryclarkdac1d172014-06-17 05:15:38 -07003070 case 8:
3071 drawCubic(frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3072 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]);
3073 if (draw_id) {
3074 curve = [frags[c2s], frags[c2s + 1], frags[c2s + 2], frags[c2s + 3],
3075 frags[c2s + 4], frags[c2s + 5], frags[c2s + 6], frags[c2s + 7]];
3076 id = idByCurve(test, curve, PATH_CUBIC);
3077 }
3078 break;
3079 }
3080 if (id >= 0) {
3081 drawID(curve, id);
3082 }
3083 }
3084 if (collect_bounds) {
3085 break;
3086 }
caryclark54359292015-03-26 07:52:43 -07003087 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3088 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003089 drawPoint(frags[f[idx]], frags[f[idx + 1]], true);
3090 }
3091 }
3092 if (!draw_intersectT) {
3093 break;
3094 }
3095 ctx.fillStyle = "red";
caryclark54359292015-03-26 07:52:43 -07003096 if (draw_intersection != 3 || step_limit == 0 || tIndex >= lastSect) {
3097 for (var idx = 0; idx < f.length; idx += 4) {
caryclarkdac1d172014-06-17 05:15:38 -07003098 drawTAtPointUp(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 2]]);
3099 drawTAtPointDown(frags[f[idx]], frags[f[idx + 1]], frags[f[idx + 3]]);
3100 }
3101 }
3102 break;
3103 case REC_TYPE_SORT:
3104 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3105 continue;
3106 }
3107 ctx.lineWidth = 3;
3108 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3109 focus_enabled = true;
3110 switch (fragType) {
3111 case SORT_UNARY:
3112 case SORT_BINARY:
3113 var curve = curvePartialByID(test, frags[0], frags[6], frags[8]);
3114 drawCurve(curve);
3115 break;
3116 default:
3117 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3118 throw "stop execution";
3119 }
3120 break;
caryclark03b03ca2015-04-23 09:13:37 -07003121 case REC_TYPE_TOP:
3122 if (!draw_top || (step_limit > 0 && tIndex < lastTop)) {
3123 continue;
3124 }
3125 ctx.lineWidth = 3;
3126 ctx.strokeStyle = "rgba(127,127,0, 0.5)";
3127 focus_enabled = true;
3128 {
3129 var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
3130 drawCurve(curve);
3131 var type = PATH_LINE + (curve.length / 2 - 2);
3132 var mid = pointAtT(curve, type, 0.5);
3133 var d = dxy_at_t(curve, type, 0.5);
3134 drawArrow(mid.x, mid.y, d.x, d.y, 0.3);
3135 }
3136 break;
caryclarkdac1d172014-06-17 05:15:38 -07003137 case REC_TYPE_MARK:
3138 if (!draw_mark || (step_limit > 0 && tIndex < lastMark)) {
3139 continue;
3140 }
3141 ctx.lineWidth = 3;
3142 ctx.strokeStyle = fragType >= MARK_DONE_LINE ?
3143 "rgba(127,0,127, 0.5)" : "rgba(127,127,0, 0.5)";
3144 focus_enabled = true;
3145 switch (fragType) {
3146 case MARK_LINE:
3147 case MARK_DONE_LINE:
3148 case MARK_UNSORTABLE_LINE:
3149 case MARK_SIMPLE_LINE:
3150 case MARK_SIMPLE_DONE_LINE:
3151 case MARK_DONE_UNARY_LINE:
3152 drawLinePartial(frags[1], frags[2], frags[3], frags[4],
3153 frags[5], frags[9]);
3154 if (draw_id) {
3155 drawLinePartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3156 frags[5], frags[9]);
3157 }
3158 break;
3159 case MARK_QUAD:
3160 case MARK_DONE_QUAD:
3161 case MARK_UNSORTABLE_QUAD:
3162 case MARK_SIMPLE_QUAD:
3163 case MARK_SIMPLE_DONE_QUAD:
3164 case MARK_DONE_UNARY_QUAD:
3165 drawQuadPartial(frags[1], frags[2], frags[3], frags[4],
3166 frags[5], frags[6], frags[7], frags[11]);
3167 if (draw_id) {
3168 drawQuadPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3169 frags[5], frags[6], frags[7], frags[11]);
3170 }
3171 break;
3172 case MARK_CUBIC:
3173 case MARK_DONE_CUBIC:
3174 case MARK_UNSORTABLE_CUBIC:
3175 case MARK_SIMPLE_CUBIC:
3176 case MARK_SIMPLE_DONE_CUBIC:
3177 case MARK_DONE_UNARY_CUBIC:
3178 drawCubicPartial(frags[1], frags[2], frags[3], frags[4],
3179 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3180 if (draw_id) {
3181 drawCubicPartialID(frags[0], frags[1], frags[2], frags[3], frags[4],
3182 frags[5], frags[6], frags[7], frags[8], frags[9], frags[13]);
3183 }
3184 break;
3185 case MARK_ANGLE_LAST:
3186 // FIXME: ignored for now
3187 break;
3188 default:
3189 console.log("unknown REC_TYPE_MARK frag type: " + fragType);
3190 throw "stop execution";
3191 }
3192 break;
3193 default:
3194 continue;
3195 }
3196 }
3197 switch (recType) {
3198 case REC_TYPE_SORT:
3199 if (!draw_sort || (step_limit > 0 && tIndex < lastSort)) {
3200 break;
3201 }
3202 var angles = []; // use tangent lines to describe arcs
3203 var windFrom = [];
3204 var windTo = [];
3205 var opp = [];
3206 var minXY = Number.MAX_VALUE;
3207 var partial;
3208 focus_enabled = true;
3209 var someUnsortable = false;
3210 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3211 var fragType = records[recordIndex];
3212 var frags = records[recordIndex + 1];
3213 var unsortable = (fragType == SORT_UNARY && frags[14]) ||
3214 (fragType == SORT_BINARY && frags[16]);
3215 someUnsortable |= unsortable;
3216 switch (fragType) {
3217 case SORT_UNARY:
3218 case SORT_BINARY:
3219 partial = curvePartialByID(test, frags[0], frags[6], frags[8]);
3220 break;
3221 default:
3222 console.log("unknown REC_TYPE_SORT frag type: " + fragType);
3223 throw "stop execution";
3224 }
3225 var dx = boundsWidth(partial);
3226 var dy = boundsHeight(partial);
3227 minXY = Math.min(minXY, dx * dx + dy * dy);
3228 if (collect_bounds) {
3229 continue;
3230 }
3231 angles.push(tangent(partial));
3232 var from = frags[12];
3233 var to = frags[12];
3234 var sgn = frags[10];
3235 if (sgn < 0) {
3236 from -= frags[11];
3237 } else if (sgn > 0) {
3238 to -= frags[11];
3239 }
3240 windFrom.push(from + (unsortable ? "!" : ""));
3241 windTo.push(to + (unsortable ? "!" : ""));
3242 opp.push(fragType == SORT_BINARY);
3243 if (draw_sort == 1) {
3244 drawOrder(partial, frags[12]);
3245 } else {
3246 drawOrder(partial, (recordIndex / 2) + 1);
3247 }
3248 }
3249 var radius = Math.sqrt(minXY) / 2 * scale;
3250 radius = Math.min(50, radius);
3251 var scaledRadius = radius / scale;
3252 var centerX = partial[0];
3253 var centerY = partial[1];
3254 if (collect_bounds) {
3255 if (focus_enabled) {
3256 focusXmin = Math.min(focusXmin, centerX - scaledRadius);
3257 focusYmin = Math.min(focusYmin, centerY - scaledRadius);
3258 focusXmax = Math.max(focusXmax, centerX + scaledRadius);
3259 focusYmax = Math.max(focusYmax, centerY + scaledRadius);
3260 }
3261 break;
3262 }
3263 break;
3264 default:
3265 break;
3266 }
3267 }
3268 if (collect_bounds) {
3269 return;
3270 }
3271 if (draw_log && logStart >= 0) {
3272 ctx.font = "normal 10px Arial";
3273 ctx.textAlign = "left";
3274 ctx.beginPath();
3275 var top = screenHeight - 20 - (logRange + 2) * 10;
3276 ctx.rect(50, top, screenWidth - 100, (logRange + 2) * 10);
3277 ctx.fillStyle = "white";
3278 ctx.fill();
3279 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3280 if (logStart > 0) {
3281 ctx.fillText(lines[logStart - 1], 50, top + 8);
3282 }
3283 ctx.fillStyle = "black";
3284 for (var idx = 0; idx < logRange; ++idx) {
3285 ctx.fillText(lines[logStart + idx], 50, top + 18 + 10 * idx);
3286 }
3287 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3288 if (logStart + logRange < lines.length) {
3289 ctx.fillText(lines[logStart + logRange], 50, top + 18 + 10 * logRange);
3290 }
3291 }
3292 if (draw_legend) {
3293 var pos = 0;
caryclark624637c2015-05-11 07:21:27 -07003294 var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
caryclarkdac1d172014-06-17 05:15:38 -07003295 // drawBox(pos++, "yellow", "black", opLetter, true, '');
3296 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
3297 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
3298 drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
3299 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
caryclark624637c2015-05-11 07:21:27 -07003300 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
caryclarkdac1d172014-06-17 05:15:38 -07003301 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
3302 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
caryclark03b03ca2015-04-23 09:13:37 -07003303 drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
caryclarkdac1d172014-06-17 05:15:38 -07003304 drawBox(pos++, "rgba(127,0,127, 0.3)", "black", draw_mark ? markCount : markMax, draw_mark, markKey);
3305 drawBox(pos++, "black", "white",
3306 (new Array('P', 'P1', 'P2', 'P'))[draw_path], draw_path != 0, pathKey);
3307 drawBox(pos++, "rgba(0,63,0, 0.7)", "white",
3308 (new Array('Q', 'Q', 'C', 'QC', 'Qc', 'Cq'))[draw_computed],
3309 draw_computed != 0, computedKey);
3310 drawBox(pos++, "green", "black", step_limit, drawSomething, '');
3311 drawBox(pos++, "green", "black", stepMax, drawSomething, '');
3312 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", lastIndex, drawSomething & draw_log, '');
3313 drawBox(pos++, "rgba(255,0,0, 0.6)", "black", test.length - 1, drawSomething & draw_log, '');
3314 if (curve_t) {
3315 drawCurveTControl();
3316 }
3317 ctx.font = "normal 20px Arial";
3318 ctx.fillStyle = "rgba(0,0,0, 0.3)";
3319 ctx.textAlign = "right";
3320 ctx.fillText(scale.toFixed(decimal_places) + 'x' , screenWidth - 10, screenHeight - 5);
3321 }
3322 if (draw_hints) {
3323 ctx.font = "normal 10px Arial";
3324 ctx.fillStyle = "rgba(0,0,0, 0.5)";
3325 ctx.textAlign = "right";
3326 var y = 4;
3327 ctx.fillText("control lines : " + controlLinesKey, ctx.screenWidthwidth - 10, pos * 50 + y++ * 10);
3328 ctx.fillText("curve t : " + curveTKey, screenWidth - 10, pos * 50 + y++ * 10);
3329 ctx.fillText("deriviatives : " + deriviativesKey, screenWidth - 10, pos * 50 + y++ * 10);
3330 ctx.fillText("intersect t : " + intersectTKey, screenWidth - 10, pos * 50 + y++ * 10);
caryclarkdac1d172014-06-17 05:15:38 -07003331 ctx.fillText("log : " + logKey, screenWidth - 10, pos * 50 + y++ * 10);
3332 ctx.fillText("log curve : " + logCurvesKey, screenWidth - 10, pos * 50 + y++ * 10);
3333 ctx.fillText("mid point : " + midpointKey, screenWidth - 10, pos * 50 + y++ * 10);
3334 ctx.fillText("points : " + ptsKey, screenWidth - 10, pos * 50 + y++ * 10);
3335 ctx.fillText("sequence : " + sequenceKey, screenWidth - 10, pos * 50 + y++ * 10);
3336 ctx.fillText("xy : " + xyKey, screenWidth - 10, pos * 50 + y++ * 10);
3337 }
3338}
3339
3340function drawBox(y, backC, foreC, str, enable, label) {
3341 ctx.beginPath();
3342 ctx.fillStyle = backC;
3343 ctx.rect(screenWidth - 40, y * 50 + 10, 40, 30);
3344 ctx.fill();
3345 ctx.font = "normal 16px Arial";
3346 ctx.fillStyle = foreC;
3347 ctx.textAlign = "center";
3348 ctx.fillText(str, screenWidth - 20, y * 50 + 32);
3349 if (!enable) {
3350 ctx.fillStyle = "rgba(255,255,255, 0.5)";
3351 ctx.fill();
3352 }
3353 if (label != '') {
3354 ctx.font = "normal 9px Arial";
3355 ctx.fillStyle = "black";
3356 ctx.fillText(label, screenWidth - 47, y * 50 + 40);
3357 }
3358}
3359
3360function drawCurveTControl() {
3361 ctx.lineWidth = 2;
3362 ctx.strokeStyle = "rgba(0,0,0, 0.3)";
3363 ctx.beginPath();
3364 ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80);
3365 ctx.stroke();
3366 var ty = 40 + curveT * (screenHeight - 80);
3367 ctx.beginPath();
3368 ctx.moveTo(screenWidth - 80, ty);
3369 ctx.lineTo(screenWidth - 85, ty - 5);
3370 ctx.lineTo(screenWidth - 85, ty + 5);
3371 ctx.lineTo(screenWidth - 80, ty);
3372 ctx.fillStyle = "rgba(0,0,0, 0.6)";
3373 ctx.fill();
3374 var num = curveT.toFixed(decimal_places);
3375 ctx.font = "normal 10px Arial";
3376 ctx.textAlign = "left";
3377 ctx.fillText(num, screenWidth - 78, ty);
3378}
3379
3380function ptInTControl() {
3381 var e = window.event;
3382 var tgt = e.target || e.srcElement;
3383 var left = tgt.offsetLeft;
3384 var top = tgt.offsetTop;
3385 var x = (e.clientX - left);
3386 var y = (e.clientY - top);
3387 if (x < screenWidth - 80 || x > screenWidth - 50) {
3388 return false;
3389 }
3390 if (y < 40 || y > screenHeight - 80) {
3391 return false;
3392 }
3393 curveT = (y - 40) / (screenHeight - 120);
3394 if (curveT < 0 || curveT > 1) {
3395 throw "stop execution";
3396 }
3397 return true;
3398}
3399
3400function drawTop() {
3401 if (tests[testIndex] == null) {
3402 var str = testDivs[testIndex].textContent;
3403 parse_all(str);
3404 var title = testDivs[testIndex].id.toString();
3405 testTitles[testIndex] = title;
3406 }
3407 init(tests[testIndex]);
3408 redraw();
3409}
3410
3411function redraw() {
3412 if (focus_on_selection) {
3413 collect_bounds = true;
3414 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3415 collect_bounds = false;
3416 if (focusXmin < focusXmax && focusYmin < focusYmax) {
3417 setScale(focusXmin, focusXmax, focusYmin, focusYmax);
3418 }
3419 }
3420 ctx.beginPath();
3421 ctx.fillStyle = "white";
3422 ctx.rect(0, 0, screenWidth, screenHeight);
3423 ctx.fill();
3424 draw(tests[testIndex], testLines[testIndex], testTitles[testIndex]);
3425}
3426
3427function dumpCurvePartial(test, id, t0, t1) {
3428 var curve = curveByID(test, id);
3429 var name = ["line", "quad", "cubic"][curve.length / 2 - 2];
3430 console.log("id=" + id + " " + name + "=" + curveToString(curve)
3431 + " t0=" + t0 + " t1=" + t1
3432 + " partial=" + curveToString(curvePartialByID(test, id, t0, t1)));
3433}
3434
3435function dumpAngleTest(test, id, t0, t1) {
3436 var curve = curveByID(test, id);
3437 console.log(" { {" + curveToString(curve) + "}, "
3438 + curve.length / 2 + ", " + t0 + ", " + t1 + ", {} }, //");
3439}
3440
3441function dumpLogToConsole() {
3442 if (logStart < 0) {
3443 return;
3444 }
3445 var test = tests[testIndex];
3446 var recType = REC_TYPE_UNKNOWN;
3447 var records;
3448 for (var index = 0; index < test.length; index += 3) {
3449 var lastLineNo = test[index + 1];
3450 if (lastLineNo >= logStart && lastLineNo < logStart + logRange) {
3451 recType = test[index];
3452 records = test[index + 2];
3453 break;
3454 }
3455 }
3456 if (recType == REC_TYPE_UNKNOWN) {
3457 return;
3458 }
3459 var lines = testLines[testIndex];
3460 for (var idx = 0; idx < logRange; ++idx) {
3461 var line = lines[logStart + idx];
3462 console.log(line);
3463 for (var recordIndex = 0; recordIndex < records.length; recordIndex += 2) {
3464 var fragType = records[recordIndex];
3465 var frags = records[recordIndex + 1];
3466 if (recType == REC_TYPE_ANGLE && fragType == ANGLE_AFTER) {
caryclarkdac1d172014-06-17 05:15:38 -07003467 dumpCurvePartial(test, frags[0], frags[4], frags[5]);
3468 dumpCurvePartial(test, frags[6], frags[10], frags[11]);
3469 dumpCurvePartial(test, frags[12], frags[16], frags[17]);
3470 console.log("\nstatic IntersectData intersectDataSet[] = { //");
3471 dumpAngleTest(test, frags[0], frags[4], frags[5]);
3472 dumpAngleTest(test, frags[6], frags[10], frags[11]);
3473 dumpAngleTest(test, frags[12], frags[16], frags[17]);
3474 console.log("}; //");
3475 }
3476 }
3477 }
3478}
3479
3480var activeKey = 'a';
3481var pathKey = 'b';
3482var pathBackKey = 'B';
3483var centerKey = 'c';
caryclark624637c2015-05-11 07:21:27 -07003484var coincidenceKey = 'C';
caryclarkdac1d172014-06-17 05:15:38 -07003485var addKey = 'd';
3486var deriviativesKey = 'f';
3487var angleKey = 'g';
3488var angleBackKey = 'G';
caryclarkdac1d172014-06-17 05:15:38 -07003489var intersectionKey = 'i';
3490var intersectionBackKey = 'I';
3491var sequenceKey = 'j';
3492var midpointKey = 'k';
3493var logKey = 'l';
3494var logToConsoleKey = 'L';
3495var markKey = 'm';
3496var sortKey = 'o';
3497var opKey = 'p';
3498var opBackKey = 'P';
3499var computedKey = 'q';
3500var computedBackKey = 'Q';
3501var stepKey = 's';
3502var stepBackKey = 'S';
3503var intersectTKey = 't';
caryclark03b03ca2015-04-23 09:13:37 -07003504var topKey = 'T';
caryclarkdac1d172014-06-17 05:15:38 -07003505var curveTKey = 'u';
3506var controlLinesBackKey = 'V';
3507var controlLinesKey = 'v';
3508var ptsKey = 'x';
3509var xyKey = 'y';
3510var logCurvesKey = 'z';
3511var focusKey = '`';
3512var idKey = '.';
3513var retinaKey = '\\';
3514
3515function doKeyPress(evt) {
3516 var char = String.fromCharCode(evt.charCode);
3517 var focusWasOn = false;
3518 switch (char) {
3519 case '0':
3520 case '1':
3521 case '2':
3522 case '3':
3523 case '4':
3524 case '5':
3525 case '6':
3526 case '7':
3527 case '8':
3528 case '9':
3529 decimal_places = char - '0';
3530 redraw();
3531 break;
3532 case activeKey:
3533 draw_active ^= true;
3534 redraw();
3535 break;
3536 case addKey:
3537 draw_add ^= true;
3538 redraw();
3539 break;
3540 case angleKey:
caryclark54359292015-03-26 07:52:43 -07003541 draw_angle = (draw_angle + 1) % 4;
caryclarkdac1d172014-06-17 05:15:38 -07003542 redraw();
3543 break;
3544 case angleBackKey:
3545 draw_angle = (draw_angle + 2) % 3;
3546 redraw();
3547 break;
3548 case centerKey:
3549 setScale(xmin, xmax, ymin, ymax);
3550 redraw();
3551 break;
caryclark624637c2015-05-11 07:21:27 -07003552 case coincidenceKey:
3553 draw_coincidence ^= true;
3554 redraw();
3555 break;
caryclarkdac1d172014-06-17 05:15:38 -07003556 case controlLinesBackKey:
3557 control_lines = (control_lines + 3) % 4;
3558 redraw();
3559 break;
3560 case controlLinesKey:
3561 control_lines = (control_lines + 1) % 4;
3562 redraw();
3563 break;
3564 case computedBackKey:
3565 draw_computed = (draw_computed + 5) % 6;
3566 redraw();
3567 break;
3568 case computedKey:
3569 draw_computed = (draw_computed + 1) % 6;
3570 redraw();
3571 break;
3572 case curveTKey:
3573 curve_t ^= true;
3574 if (curve_t) {
3575 draw_legend = true;
3576 }
3577 redraw();
3578 break;
3579 case deriviativesKey:
3580 draw_deriviatives = (draw_deriviatives + 1) % 3;
3581 redraw();
3582 break;
3583 case focusKey:
3584 focus_on_selection ^= true;
3585 setScale(xmin, xmax, ymin, ymax);
3586 redraw();
3587 break;
caryclarkdac1d172014-06-17 05:15:38 -07003588 case idKey:
3589 draw_id ^= true;
3590 redraw();
3591 break;
3592 case intersectionBackKey:
3593 draw_intersection = (draw_intersection + 3) % 4;
3594 redraw();
3595 break;
3596 case intersectionKey:
3597 draw_intersection = (draw_intersection + 1) % 4;
3598 redraw();
3599 break;
3600 case intersectTKey:
3601 draw_intersectT ^= true;
3602 redraw();
3603 break;
3604 case logCurvesKey:
3605 logCurves(tests[testIndex]);
3606 break;
3607 case logKey:
3608 draw_log ^= true;
3609 redraw();
3610 break;
3611 case logToConsoleKey:
3612 if (draw_log) {
3613 dumpLogToConsole();
3614 }
3615 break;
3616 case markKey:
3617 draw_mark ^= true;
3618 redraw();
3619 break;
3620 case midpointKey:
3621 draw_midpoint ^= true;
3622 redraw();
3623 break;
3624 case opKey:
3625 draw_op = (draw_op + 1) % 3;
3626 redraw();
3627 break;
3628 case opBackKey:
3629 draw_op = (draw_op + 2) % 3;
3630 redraw();
3631 break;
3632 case pathKey:
3633 draw_path = (draw_path + 1) % 4;
3634 redraw();
3635 break;
3636 case pathBackKey:
3637 draw_path = (draw_path + 3) % 4;
3638 redraw();
3639 break;
3640 case ptsKey:
3641 pt_labels = (pt_labels + 1) % 3;
3642 redraw();
3643 break;
3644 case retinaKey:
3645 retina_scale ^= true;
3646 drawTop();
3647 break;
3648 case sequenceKey:
3649 draw_sequence ^= true;
3650 redraw();
3651 break;
3652 case sortKey:
3653 draw_sort = (draw_sort + 1) % 3;
3654 drawTop();
3655 break;
3656 case stepKey:
3657 step_limit++;
3658 if (step_limit > stepMax) {
3659 step_limit = stepMax;
3660 }
3661 redraw();
3662 break;
3663 case stepBackKey:
3664 step_limit--;
3665 if (step_limit < 0) {
3666 step_limit = 0;
3667 }
3668 redraw();
3669 break;
caryclark03b03ca2015-04-23 09:13:37 -07003670 case topKey:
3671 draw_top ^= true;
3672 redraw();
3673 break;
caryclarkdac1d172014-06-17 05:15:38 -07003674 case xyKey:
3675 debug_xy = (debug_xy + 1) % 3;
3676 redraw();
3677 break;
3678 case '-':
3679 focusWasOn = focus_on_selection;
3680 if (focusWasOn) {
3681 focus_on_selection = false;
3682 scale /= 1.2;
3683 } else {
3684 scale /= 2;
3685 calcLeftTop();
3686 }
3687 redraw();
3688 focus_on_selection = focusWasOn;
3689 break;
3690 case '=':
3691 case '+':
3692 focusWasOn = focus_on_selection;
3693 if (focusWasOn) {
3694 focus_on_selection = false;
3695 scale *= 1.2;
3696 } else {
3697 scale *= 2;
3698 calcLeftTop();
3699 }
3700 redraw();
3701 focus_on_selection = focusWasOn;
3702 break;
3703 case '?':
3704 draw_hints ^= true;
3705 if (draw_hints && !draw_legend) {
3706 draw_legend = true;
3707 }
3708 redraw();
3709 break;
3710 case '/':
3711 draw_legend ^= true;
3712 redraw();
3713 break;
3714 }
3715}
3716
3717function doKeyDown(evt) {
3718 var char = evt.keyCode;
3719 var preventDefault = false;
3720 switch (char) {
3721 case 37: // left arrow
3722 if (evt.shiftKey) {
3723 testIndex -= 9;
3724 }
3725 if (--testIndex < 0)
3726 testIndex = tests.length - 1;
3727 drawTop();
3728 preventDefault = true;
3729 break;
3730 case 39: // right arrow
3731 if (evt.shiftKey) {
3732 testIndex += 9;
3733 }
3734 if (++testIndex >= tests.length)
3735 testIndex = 0;
3736 drawTop();
3737 preventDefault = true;
3738 break;
3739 }
3740 if (preventDefault) {
3741 evt.preventDefault();
3742 return false;
3743 }
3744 return true;
3745}
3746
3747(function() {
3748 var hidden = "hidden";
3749
3750 // Standards:
3751 if (hidden in document)
3752 document.addEventListener("visibilitychange", onchange);
3753 else if ((hidden = "mozHidden") in document)
3754 document.addEventListener("mozvisibilitychange", onchange);
3755 else if ((hidden = "webkitHidden") in document)
3756 document.addEventListener("webkitvisibilitychange", onchange);
3757 else if ((hidden = "msHidden") in document)
3758 document.addEventListener("msvisibilitychange", onchange);
3759 // IE 9 and lower:
3760 else if ('onfocusin' in document)
3761 document.onfocusin = document.onfocusout = onchange;
3762 // All others:
3763 else
3764 window.onpageshow = window.onpagehide
3765 = window.onfocus = window.onblur = onchange;
3766
3767 function onchange (evt) {
3768 var v = 'visible', h = 'hidden',
3769 evtMap = {
3770 focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
3771 };
3772
3773 evt = evt || window.event;
3774 if (evt.type in evtMap)
3775 document.body.className = evtMap[evt.type];
3776 else
3777 document.body.className = this[hidden] ? "hidden" : "visible";
3778 }
3779})();
3780
3781function calcXY() {
3782 var e = window.event;
3783 var tgt = e.target || e.srcElement;
3784 var left = tgt.offsetLeft;
3785 var top = tgt.offsetTop;
3786 mouseX = (e.clientX - left) / scale + srcLeft;
3787 mouseY = (e.clientY - top) / scale + srcTop;
3788}
3789
3790function calcLeftTop() {
3791 srcLeft = mouseX - screenWidth / 2 / scale;
3792 srcTop = mouseY - screenHeight / 2 / scale;
3793}
3794
3795var disableClick = false;
3796
3797function handleMouseClick() {
3798 if (disableClick) {
3799 return;
3800 }
3801 if (!curve_t || !ptInTControl()) {
3802 calcXY();
3803 calcLeftTop();
3804 }
3805 redraw();
3806// if (!curve_t || !ptInTControl()) {
3807// mouseX = screenWidth / 2 / scale + srcLeft;
3808// mouseY = screenHeight / 2 / scale + srcTop;
3809// }
3810}
3811
3812function handleMouseOver() {
3813 calcXY();
3814 if (debug_xy != 2) {
3815 return;
3816 }
3817 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
3818 ctx.beginPath();
3819 ctx.rect(300,100,num.length * 6,10);
3820 ctx.fillStyle="white";
3821 ctx.fill();
3822 ctx.font = "normal 10px Arial";
3823 ctx.fillStyle="black";
3824 ctx.textAlign = "left";
3825 ctx.fillText(num, 300, 108);
3826}
3827
3828function start() {
3829 for (var i = 0; i < testDivs.length; ++i) {
3830 tests[i] = null;
3831 }
3832 testIndex = 0;
3833 drawTop();
3834 window.addEventListener('keypress', doKeyPress, true);
3835 window.addEventListener('keydown', doKeyDown, true);
3836 window.onresize = function() {
3837 drawTop();
3838 }
3839 /*
3840 window.onpagehide = function() {
3841 disableClick = true;
3842 }
3843 */
3844 window.onpageshow = function () {
3845 disableClick = false;
3846 }
3847}
3848
3849</script>
3850</head>
3851
3852<body onLoad="start();">
3853<canvas id="canvas" width="750" height="500"
3854 onmousemove="handleMouseOver()"
3855 onclick="handleMouseClick()"
3856 ></canvas >
3857</body>
3858</html>