blob: 2ed8015be7f5ae3b0f545059871ac529b3e91b91 [file] [log] [blame]
caryclark@google.comf839c032012-10-26 21:03:50 +00001<html>
2<head>
3<div style="height:0">
4
caryclark@google.com47d73da2013-02-17 01:41:25 +00005<div id="cubicOp19i">
6debugShowActiveSpans id=3 (1,2 2,6 2,0 1,0) t=0 (1,2) tEnd=0.578464835 other=4 otherT=1 otherIndex=2 windSum=? windValue=1 oppValue=0
7debugShowActiveSpans id=3 (1,2 2,6 2,0 1,0) t=0.578464835 (1.73152983,2) tEnd=0.692069746 other=2 otherT=0.711411698 otherIndex=1 windSum=? windValue=1 oppValue=0
8debugShowActiveSpans id=3 (1,2 2,6 2,0 1,0) t=0.692069746 (1.63932765,1.25154662) tEnd=1 other=1 otherT=0.522705723 otherIndex=2 windSum=? windValue=1 oppValue=0
9debugShowActiveSpans id=4 (1,0 1,2) t=0 (1,0) tEnd=0.637627564 other=3 otherT=1 otherIndex=4 windSum=? windValue=1 oppValue=0
10debugShowActiveSpans id=4 (1,0 1,2) t=0.637627564 (1,1.27525508) tEnd=1 other=1 otherT=0.40824829 otherIndex=1 windSum=? windValue=1 oppValue=0
11debugShowActiveSpans id=1 (0,2 0,0.5 6,2) t=0 (0,2) tEnd=0.40824829 other=2 otherT=1 otherIndex=4 windSum=? windValue=1 oppValue=0
12debugShowActiveSpans id=1 (0,2 0,0.5 6,2) t=0.40824829 (1,1.27525508) tEnd=0.522705723 other=4 otherT=0.637627564 otherIndex=1 windSum=? windValue=1 oppValue=0
13debugShowActiveSpans id=1 (0,2 0,0.5 6,2) t=0.522705723 (1.63932765,1.25154662) tEnd=1 other=3 otherT=0.692069746 otherIndex=3 windSum=? windValue=1 oppValue=0
14debugShowActiveSpans id=2 (6,2 0,2) t=0 (6,2) tEnd=0.711411698 other=1 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
15debugShowActiveSpans id=2 (6,2 0,2) t=0.711411698 (1.73152983,2) tEnd=0.833333333 other=3 otherT=0.578464835 otherIndex=2 windSum=? windValue=1 oppValue=0
16debugShowActiveSpans id=2 (6,2 0,2) t=0.833333333 (1,2) tEnd=1 other=3 otherT=0 otherIndex=1 windSum=? windValue=1 oppValue=0
caryclark@google.com0b7da432012-10-31 19:00:20 +000017</div>
18
caryclark@google.comf839c032012-10-26 21:03:50 +000019</div>
20
21<script type="text/javascript">
22
23var testDivs = [
caryclark@google.com47d73da2013-02-17 01:41:25 +000024 cubicOp19i,
caryclark@google.comf839c032012-10-26 21:03:50 +000025];
26
27var decimal_places = 3; // make this 3 to show more precision
28
29var tests = [];
30var testTitles = [];
31var testIndex = 0;
32var ctx;
33
34var xmin;
35var ymin;
36var scale;
37var mouseX, mouseY;
38var srcLeft, srcTop;
39var srcWidth, srcHeight;
40var screenWidth, screenHeight;
caryclark@google.com47d73da2013-02-17 01:41:25 +000041var drawnPts, drawnLines, drawnQuads, drawnCubics, deferredLines, deferredQuads, deferredCubics;
caryclark@google.comf839c032012-10-26 21:03:50 +000042
43var ptLabels = true;
44var digit_mode = false;
45var index_mode = true;
46var index_bits = -1;
47var debug_xy = false;
48var info_mode = false;
49var intersect_mode = false;
50var sequence = -1;
51
52var SPAN_ID = 1;
53var SPAN_X1 = 2;
54var SPAN_Y1 = 3;
55var SPAN_X2 = 4;
56var SPAN_Y2 = 5;
57var SPAN_L_T = 6;
58var SPAN_L_TX = 7;
59var SPAN_L_TY = 8;
caryclark@google.com47d73da2013-02-17 01:41:25 +000060var SPAN_L_TEND = 9;
61var SPAN_L_OTHER = 10;
62var SPAN_L_OTHERT = 11;
63var SPAN_L_OTHERI = 12;
64var SPAN_L_SUM = 13;
65var SPAN_L_VAL = 14;
66var SPAN_L_OPP = 15;
caryclark@google.comf839c032012-10-26 21:03:50 +000067
68var SPAN_X3 = 6;
69var SPAN_Y3 = 7;
70var SPAN_Q_T = 8;
71var SPAN_Q_TX = 9;
72var SPAN_Q_TY = 10;
caryclark@google.com47d73da2013-02-17 01:41:25 +000073var SPAN_Q_TEND = 11;
74var SPAN_Q_OTHER = 12;
75var SPAN_Q_OTHERT = 13;
76var SPAN_Q_OTHERI = 14;
77var SPAN_Q_SUM = 15;
78var SPAN_Q_VAL = 16;
79var SPAN_Q_OPP = 17;
80
81var SPAN_X4 = 8;
82var SPAN_Y4 = 9;
83var SPAN_C_T = 10;
84var SPAN_C_TX = 11;
85var SPAN_C_TY = 12;
86var SPAN_C_TEND = 13;
87var SPAN_C_OTHER = 14;
88var SPAN_C_OTHERT = 15;
89var SPAN_C_OTHERI = 16;
90var SPAN_C_SUM = 17;
91var SPAN_C_VAL = 18;
92var SPAN_C_OPP = 19;
caryclark@google.comf839c032012-10-26 21:03:50 +000093
caryclark@google.com0b7da432012-10-31 19:00:20 +000094var ACTIVE_LINE_SPAN = 1;
95var ACTIVE_QUAD_SPAN = 2;
caryclark@google.com47d73da2013-02-17 01:41:25 +000096var ACTIVE_CUBIC_SPAN = 3;
97var INTERSECT_QUAD_LINE = 4;
98var INTERSECT_QUAD_LINE_2 = 5;
99var INTERSECT_QUAD_LINE_NO = 6;
100var INTERSECT_QUAD = 7;
101var INTERSECT_QUAD_2 = 8;
102var INTERSECT_QUAD_NO = 9;
caryclark@google.comf839c032012-10-26 21:03:50 +0000103
104function strs_to_nums(strs) {
105 var result = [];
106 for (var idx in strs) {
107 var str = strs[idx];
108 var num = parseFloat(str);
109 if (isNaN(num)) {
110 result.push(str);
111 } else {
112 result.push(num);
113 }
114 }
115 return result;
116}
117
caryclark@google.com0b7da432012-10-31 19:00:20 +0000118function construct_regexp(pattern) {
119 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
120 escape = escape.replace(/PT_VAL/g, "(\\d+\\.?\\d*),(\\d+\\.?\\d*)");
121 escape = escape.replace(/T_VAL/g, "(\\d+\\.?\\d*e?-?\\d*)");
122 escape = escape.replace(/IDX/g, "(\\d+)");
123 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
124 return new RegExp(escape, 'i');
125}
126
caryclark@google.comf839c032012-10-26 21:03:50 +0000127function parse_debugShowActiveSpans(test, title) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000128 var re_cubic = construct_regexp(" id=IDX (PT_VAL PT_VAL PT_VAL PT_VAL) t=T_VAL (PT_VAL) tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=IDX");
129 var re_quad = construct_regexp(" id=IDX (PT_VAL PT_VAL PT_VAL) t=T_VAL (PT_VAL) tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=IDX");
130 var re_line = construct_regexp(" id=IDX (PT_VAL PT_VAL) t=T_VAL (PT_VAL) tEnd=T_VAL other=IDX otherT=T_VAL otherIndex=IDX windSum=OPT windValue=IDX oppValue=IDX");
caryclark@google.comf839c032012-10-26 21:03:50 +0000131
132 var strs = test.split("debugShowActiveSpans");
133 if (strs.length == 1)
134 return;
135 var spans = [];
136 for (var s in strs) {
137 var str = strs[s];
138 if (str == "\n") {
139 continue;
140 }
141 if (re_line.test(str)) {
142 var lineStrs = re_line.exec(str);
143 var line = strs_to_nums(lineStrs);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000144 spans.push(ACTIVE_LINE_SPAN);
caryclark@google.comf839c032012-10-26 21:03:50 +0000145 spans.push(line);
146 } else if (re_quad.test(str)) {
147 var quadStrs = re_quad.exec(str);
148 var quad = strs_to_nums(quadStrs);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000149 spans.push(ACTIVE_QUAD_SPAN);
caryclark@google.comf839c032012-10-26 21:03:50 +0000150 spans.push(quad);
caryclark@google.com47d73da2013-02-17 01:41:25 +0000151 } else if (re_cubic.test(str)) {
152 var cubicStrs = re_cubic.exec(str);
153 var cubic = strs_to_nums(cubicStrs);
154 spans.push(ACTIVE_CUBIC_SPAN);
155 spans.push(cubic);
caryclark@google.comf839c032012-10-26 21:03:50 +0000156 }
157 }
158 if (spans.length >= 1) {
159 tests.push(spans);
160 testTitles.push(title);
161 }
162}
163
caryclark@google.com0b7da432012-10-31 19:00:20 +0000164function filter_str_by(id, str, regex, array) {
165 if (regex.test(str)) {
166 var strs = regex.exec(str);
167 var result = strs_to_nums(strs);
168 array.push(id);
169 array.push(result);
170 }
171}
172
caryclark@google.com47d73da2013-02-17 01:41:25 +0000173// FIXME: add cubic support
caryclark@google.com0b7da432012-10-31 19:00:20 +0000174function parse_intersections(test, title) {
175 var re_quad_line = construct_regexp(" wtTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL) wnTs[0]=T_VAL (PT_VAL PT_VAL) (PT_VAL)");
176 var re_quad_line_2 = construct_regexp(" wtTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL) wtTs[1]=T_VAL (PT_VAL) wnTs[0]=T_VAL (PT_VAL PT_VAL) (PT_VAL) wnTs[1]=T_VAL (PT_VAL)");
177 var re_quad_line_no_intersect = construct_regexp(" no intersect (PT_VAL PT_VAL PT_VAL) (PT_VAL PT_VAL)");
178 var re_quad = construct_regexp(" wtTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL) wnTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL)");
179 var re_quad_2 = construct_regexp(" wtTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL) wtTs[1]=T_VAL wnTs[0]=T_VAL (PT_VAL PT_VAL PT_VAL) (PT_VAL) wnTs[1]=T_VAL");
180 var re_quad_no_intersect = construct_regexp(" no intersect (PT_VAL PT_VAL PT_VAL) (PT_VAL PT_VAL PT_VAL)");
181
182 var strs = test.split(/debugShow[A-Za-z]+Intersection/);
183 if (strs.length == 1)
184 return;
185 var spans = [];
186 for (var s in strs) {
187 var str = strs[s];
188 if (str == "\n") {
189 continue;
190 }
191 filter_str_by(INTERSECT_QUAD_LINE, str, re_quad_line, spans);
192 filter_str_by(INTERSECT_QUAD_LINE_2, str, re_quad_line_2, spans);
193 filter_str_by(INTERSECT_QUAD_LINE_NO, str, re_quad_line_no_intersect, spans);
194 filter_str_by(INTERSECT_QUAD, str, re_quad, spans);
195 filter_str_by(INTERSECT_QUAD_2, str, re_quad_2, spans);
196 filter_str_by(INTERSECT_QUAD_NO, str, re_quad_no_intersect, spans);
197 }
198 if (spans.length >= 1) {
199 tests.push(spans);
200 testTitles.push(title);
201 }
202}
203
caryclark@google.comf839c032012-10-26 21:03:50 +0000204function init(test) {
205 var canvas = document.getElementById('canvas');
206 if (!canvas.getContext) return;
207 screenWidth = canvas.width = window.innerWidth - 20;
208 screenHeight = canvas.height = window.innerHeight - 20;
209 ctx = canvas.getContext('2d');
210 xmin = Infinity;
211 var xmax = -Infinity;
212 ymin = Infinity;
213 var ymax = -Infinity;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000214 var scanType = -1;
215 for (var scansStr in test) {
216 var scans = parseInt(scansStr);
caryclark@google.comf839c032012-10-26 21:03:50 +0000217 var scan = test[scans];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000218 if (scanType == -1) {
219 scanType = scan;
220 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000221 }
caryclark@google.com47d73da2013-02-17 01:41:25 +0000222 if (scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
223 || scanType == ACTIVE_CUBIC_SPAN) {
224 var last = scanType == ACTIVE_CUBIC_SPAN ? SPAN_X4
225 : scanType == ACTIVE_QUAD_SPAN ? SPAN_X3 : SPAN_X2;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000226 for (var idx = SPAN_X1; idx <= last; idx += 2) {
227 xmin = Math.min(xmin, scan[idx]);
228 xmax = Math.max(xmax, scan[idx]);
229 ymin = Math.min(ymin, scan[idx + 1]);
230 ymax = Math.max(ymax, scan[idx + 1]);
231 }
232 } else {
233 var start = 1;
234 if (scanType != INTERSECT_QUAD_LINE_NO && scanType != INTERSECT_QUAD_NO) {
235 start = 2;
236 }
237 for (var idx = start; idx < start + 6; idx += 2) {
238 xmin = Math.min(xmin, scan[idx]);
239 xmax = Math.max(xmax, scan[idx]);
240 ymin = Math.min(ymin, scan[idx + 1]);
241 ymax = Math.max(ymax, scan[idx + 1]);
242 }
243 start = start + 6;
244 if (scanType == INTERSECT_QUAD_LINE || scanType == INTERSECT_QUAD) {
245 start += 3;
246 }
247 if (scanType == INTERSECT_QUAD_LINE_2) {
248 start += 6;
249 }
250 if (scanType == INTERSECT_QUAD_2) {
251 start += 4;
252 }
253 var end = start + 4;
254 if (scanType == INTERSECT_QUAD || scanType == INTERSECT_QUAD_2 || scanType == INTERSECT_QUAD_NO) {
255 end += 2;
256 }
257 for (var idx = start; idx < end; idx += 2) {
258 xmin = Math.min(xmin, scan[idx]);
259 xmax = Math.max(xmax, scan[idx]);
260 ymin = Math.min(ymin, scan[idx + 1]);
261 ymax = Math.max(ymax, scan[idx + 1]);
262 }
263 }
264 scanType = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000265 }
266 srcWidth = xmax - xmin;
267 srcHeight = ymax - ymin;
268 var hscale = ctx.canvas.width / srcWidth;
269 var vscale = ctx.canvas.height / srcHeight;
270 var minScale = Math.min(hscale, vscale);
271 scale = minScale;
272 srcLeft = xmin;
273 srcTop = ymin;
274}
275
276function drawPoint(px, py) {
277 for (var pts = 0; pts < drawnPts.length; pts += 2) {
278 var x = drawnPts[pts];
279 var y = drawnPts[pts + 1];
280 if (px == x && py == y) {
281 return;
282 }
283 }
284 drawnPts.push(px);
285 drawnPts.push(py);
286 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
287 var _px = (px - srcLeft)* scale;
288 var _py = (py - srcTop) * scale;
289 ctx.beginPath();
290 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
291 ctx.closePath();
292 ctx.fill();
293 ctx.fillText(label, _px + 5, _py);
294}
295
caryclark@google.com0b7da432012-10-31 19:00:20 +0000296function drawLine(x1, y1, x2, y2, selected) {
297 for (var pts = 0; pts < drawnLines.length; pts += 4) {
298 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]) {
299 return;
300 }
301 if (x2 == drawnLines[pts + 2] && x2 == drawnLines[pts + 3]) {
302 return;
303 }
304 }
305 if (selected) {
306 drawnLines.push(x1);
307 drawnLines.push(y1);
308 drawnLines.push(x2);
309 drawnLines.push(y2);
310 ctx.beginPath();
311 ctx.moveTo((x1 - srcLeft) * scale,
312 (y1 - srcTop) * scale);
313 ctx.lineTo((x2 - srcLeft) * scale,
314 (y2 - srcTop) * scale);
315 ctx.stroke();
316 return;
317 }
318 deferredLines.push(x1);
319 deferredLines.push(y1);
320 deferredLines.push(x2);
321 deferredLines.push(y2);
322}
323
caryclark@google.com47d73da2013-02-17 01:41:25 +0000324function drawLinePartial(x1, y1, x2, y2, t1, t2) {
325 var dx = x1 - x2;
326 var dy = y1 - y2;
327 var ax = x1 - t1 * dx;
328 var ay = y1 - t1 * dy;
329 var bx = x1 - t2 * dx;
330 var by = y1 - t2 * dy;
331 ctx.beginPath();
332 ctx.moveTo((ax - srcLeft) * scale,
333 (ay - srcTop) * scale);
334 ctx.lineTo((bx - srcLeft) * scale,
335 (by - srcTop) * scale);
336 ctx.stroke();
337}
338
caryclark@google.com0b7da432012-10-31 19:00:20 +0000339function drawQuad(x1, y1, x2, y2, x3, y3, selected) {
340 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
341 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]) {
342 return;
343 }
344 if (x2 == drawnQuads[pts + 2] && x2 == drawnQuads[pts + 3]) {
345 return;
346 }
347 if (x2 == drawnQuads[pts + 4] && x2 == drawnQuads[pts + 5]) {
348 return;
349 }
350 }
351 if (selected) {
352 drawnQuads.push(x1);
353 drawnQuads.push(y1);
354 drawnQuads.push(x2);
355 drawnQuads.push(y2);
356 drawnQuads.push(x3);
357 drawnQuads.push(y3);
358 ctx.beginPath();
359 ctx.moveTo((x1 - srcLeft) * scale,
360 (y1 - srcTop) * scale);
361 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
362 (y2 - srcTop) * scale,
363 (x3 - srcLeft) * scale,
364 (y3 - srcTop) * scale);
365 ctx.stroke();
366 return;
367 }
368 deferredQuads.push(x1);
369 deferredQuads.push(y1);
370 deferredQuads.push(x2);
371 deferredQuads.push(y2);
372 deferredQuads.push(x3);
373 deferredQuads.push(y3);
374}
375
caryclark@google.com47d73da2013-02-17 01:41:25 +0000376function interp(A, B, t) {
377 return A + (B - A) * t;
378}
379
380function interp_quad_coords(x1, x2, x3, t)
381{
382 var ab = interp(x1, x2, t);
383 var bc = interp(x2, x3, t);
384 var abc = interp(ab, bc, t);
385 return abc;
386}
387
388function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
389 var ax = interp_quad_coords(x1, x2, x3, t1);
390 var ay = interp_quad_coords(y1, y2, y3, t1);
391 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
392 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
393 var cx = interp_quad_coords(x1, x2, x3, t2);
394 var cy = interp_quad_coords(y1, y2, y3, t2);
395 var bx = 2*dx - (ax + cx)/2;
396 var by = 2*dy - (ay + cy)/2;
397 ctx.beginPath();
398 ctx.moveTo((ax - srcLeft) * scale,
399 (ay - srcTop) * scale);
400 ctx.quadraticCurveTo((bx - srcLeft) * scale,
401 (by - srcTop) * scale,
402 (cx - srcLeft) * scale,
403 (cy - srcTop) * scale);
404 ctx.stroke();
405}
406
407function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4, selected) {
408 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
409 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]) {
410 return;
411 }
412 if (x2 == drawnCubics[pts + 2] && x2 == drawnCubics[pts + 3]) {
413 return;
414 }
415 if (x2 == drawnCubics[pts + 4] && x2 == drawnCubics[pts + 5]) {
416 return;
417 }
418 if (x2 == drawnCubics[pts + 6] && x2 == drawnCubics[pts + 7]) {
419 return;
420 }
421 }
422 if (selected) {
423 drawnCubics.push(x1);
424 drawnCubics.push(y1);
425 drawnCubics.push(x2);
426 drawnCubics.push(y2);
427 drawnCubics.push(x3);
428 drawnCubics.push(y3);
429 drawnCubics.push(x4);
430 drawnCubics.push(y4);
431 ctx.beginPath();
432 ctx.moveTo((x1 - srcLeft) * scale,
433 (y1 - srcTop) * scale);
434 ctx.bezierCurveTo((x2 - srcLeft) * scale,
435 (y2 - srcTop) * scale,
436 (x3 - srcLeft) * scale,
437 (y3 - srcTop) * scale,
438 (x4 - srcLeft) * scale,
439 (y4 - srcTop) * scale);
440 ctx.stroke();
441 return;
442 }
443 deferredCubics.push(x1);
444 deferredCubics.push(y1);
445 deferredCubics.push(x2);
446 deferredCubics.push(y2);
447 deferredCubics.push(x3);
448 deferredCubics.push(y3);
449 deferredCubics.push(x4);
450 deferredCubics.push(y4);
451}
452
453function interp_cubic_coords(x1, x2, x3, x4, t)
454{
455 var ab = interp(x1, x2, t);
456 var bc = interp(x2, x3, t);
457 var cd = interp(x3, x4, t);
458 var abc = interp(ab, bc, t);
459 var bcd = interp(bc, cd, t);
460 var abcd = interp(abc, bcd, t);
461 return abcd;
462}
463
464function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
465 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
466 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
467 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
468 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
469 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
470 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
471 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
472 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
473 var mx = ex * 27 - ax * 8 - dx;
474 var my = ey * 27 - ay * 8 - dy;
475 var nx = fx * 27 - ax - dx * 8;
476 var ny = fy * 27 - ay - dy * 8;
477 var bx = (mx * 2 - nx) / 18;
478 var by = (my * 2 - ny) / 18;
479 var cx = (nx * 2 - mx) / 18;
480 var cy = (ny * 2 - my) / 18;
481 ctx.beginPath();
482 ctx.moveTo((ax - srcLeft) * scale,
483 (ay - srcTop) * scale);
484 ctx.bezierCurveTo((bx - srcLeft) * scale,
485 (by - srcTop) * scale,
486 (cx - srcLeft) * scale,
487 (cy - srcTop) * scale,
488 (dx - srcLeft) * scale,
489 (dy - srcTop) * scale,
490 (ex - srcLeft) * scale,
491 (ey - srcTop) * scale);
492 ctx.stroke();
493}
494
495function drawPartial(test) {
496 ctx.lineWidth = 3;
497 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
498 var scanType = -1;
499 var partIndex = 0;
500 for (var scansStr in test) {
501 var scans = parseInt(scansStr);
502 var scan = test[scans];
503 if (scanType == -1) {
504 scanType = scan;
505 continue;
506 }
507 partIndex++;
508 var hasId = scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
509 || scanType == ACTIVE_CUBIC_SPAN ? SPAN_ID : -1;
510 if (hasId < 0) {
511 continue;
512 }
513 var types = [scanType == ACTIVE_LINE_SPAN ? 0 : scanType == ACTIVE_QUAD_SPAN ? 1 : 2];
514 var x1 = scan[SPAN_X1];
515 var y1 = scan[SPAN_Y1];
516 var x2 = scan[SPAN_X2];
517 var y2 = scan[SPAN_Y2];
518 var x3, y3, x3, y4, t1, t2;
519 switch(scanType) {
520 case ACTIVE_LINE_SPAN:
521 t1 = scan[SPAN_L_T];
522 t2 = scan[SPAN_L_TEND];
523 drawLinePartial(x1, y1, x2, y2, t1, t2);
524 break;
525 case ACTIVE_QUAD_SPAN:
526 x3 = scan[SPAN_X3];
527 y3 = scan[SPAN_Y3];
528 t1 = scan[SPAN_Q_T];
529 t2 = scan[SPAN_Q_TEND];
530 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
531 break;
532 case ACTIVE_CUBIC_SPAN:
533 x3 = scan[SPAN_X3];
534 y3 = scan[SPAN_Y3];
535 x4 = scan[SPAN_X4];
536 y4 = scan[SPAN_Y4];
537 t1 = scan[SPAN_C_T];
538 t2 = scan[SPAN_C_TEND];
539 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
540 break;
541 }
542 scanType = -1;
543 }
544}
545
caryclark@google.com0b7da432012-10-31 19:00:20 +0000546function drawDeferred() {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000547 for (var pts = 0; pts < deferredCubics.length; pts += 8) {
548 drawCubic(deferredCubics[pts], deferredCubics[pts + 1],
549 deferredCubics[pts + 2], deferredCubics[pts + 3],
550 deferredCubics[pts + 4], deferredCubics[pts + 5],
551 deferredCubics[pts + 6], deferredCubics[pts + 7], true);
552 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000553 for (var pts = 0; pts < deferredQuads.length; pts += 6) {
554 drawQuad(deferredQuads[pts], deferredQuads[pts + 1],
555 deferredQuads[pts + 2], deferredQuads[pts + 3],
556 deferredQuads[pts + 4], deferredQuads[pts + 5], true);
557 }
558 for (var pts = 0; pts < deferredLines.length; pts += 4) {
559 drawLine(deferredLines[pts], deferredLines[pts + 1],
560 deferredLines[pts + 2], deferredLines[pts + 3], true);
561 }
562}
563
caryclark@google.comf839c032012-10-26 21:03:50 +0000564function draw(test, title) {
565 ctx.fillStyle = "rgba(0,0,0, 0.1)";
566 ctx.font = "normal 50px Arial";
567 ctx.fillText(title, 50, 50);
568 ctx.font = "normal 10px Arial";
569 ctx.lineWidth = "1.001"; "0.999";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000570 var curId = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000571 var firstIdx;
572 var lastIdx;
573 var index_tst = -1;
574 drawnPts = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000575 drawnLines = [];
576 drawnQuads = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000577 drawnCubics = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000578 deferredLines = [];
579 deferredQuads = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000580 deferredCubics = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000581 var scanType = -1;
582 var partIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000583 for (var scansStr in test) {
584 var scans = parseInt(scansStr);
585 var scan = test[scans];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000586 if (scanType == -1) {
587 scanType = scan;
caryclark@google.comf839c032012-10-26 21:03:50 +0000588 continue;
589 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000590 partIndex++;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000591 var hasId = scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
592 || scanType == ACTIVE_CUBIC_SPAN ? SPAN_ID : -1;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000593 if (hasId >= 0 && curId != scan[hasId]) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000594 curId = scan[hasId];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000595 firstIdx = lastIdx = partIndex;
596 index_tst++;
597 var nextIdx = lastIdx + 1;
598 while (nextIdx * 2 < test.length && test[nextIdx * 2][hasId] == curId) {
599 lastIdx = nextIdx++;
600 }
601 } else if (hasId < 0) {
602 firstIdx = lastIdx = partIndex;
603 index_tst++;
caryclark@google.comf839c032012-10-26 21:03:50 +0000604 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000605 var seq = sequence % (test.length / 2);
606 var selected = sequence >= 0 ? seq == partIndex
607 : (index_bits & (1 << index_tst)) != 0 && partIndex == firstIdx;
608 var skippable = (sequence >= 0 && seq >= firstIdx && seq <= lastIdx)
609 || partIndex != firstIdx;
610 if (skippable && !selected) {
611 scanType = -1;
612 continue;
613 }
caryclark@google.com47d73da2013-02-17 01:41:25 +0000614 var types = [scanType == ACTIVE_LINE_SPAN ? 0 : scanType == ACTIVE_QUAD_SPAN ? 1 : 2];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000615 var pts = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000616 if (scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN || scanType == ACTIVE_CUBIC_SPAN) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000617 pts.push(SPAN_X1);
618 } else {
619 pts.push(scanType != INTERSECT_QUAD_NO && scanType != INTERSECT_QUAD_LINE_NO ? 2 : 1);
620 types.push(scanType == INTERSECT_QUAD_NO || scanType == INTERSECT_QUAD || scanType == INTERSECT_QUAD_2 ? 1 : 0);
621 pts.push(scanType == INTERSECT_QUAD_LINE || scanType == INTERSECT_QUAD ? 11
622 : scanType == INTERSECT_QUAD_LINE_2 ? 14 : scanType == INTERSECT_QUAD_2 ? 12 : 7);
623 }
624 ctx.strokeStyle = "red";
625 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
626 var type = types[typeIndex];
627 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000628 if (type == 2) {
629 drawCubic(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
630 scan[index + 4], scan[index + 5], scan[index + 6], scan[index + 7],
631 selected);
632 } else if (type == 1) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000633 drawQuad(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
634 scan[index + 4], scan[index + 5], selected);
635 } else {
636 drawLine(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
637 selected);
638 }
639 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000640 if (debug_xy && selected) {
641 var debugText = "";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000642 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
643 var type = types[typeIndex];
644 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000645 for (var idx = pts[typeIndex]; idx < pts[typeIndex] + (type + 1) * 2; idx += 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000646 var screenX = (scan[idx] - srcLeft) * scale;
647 var screenY = (scan[idx + 1] - srcTop) * scale;
648 debugText += screenX.toFixed(decimal_places) + ", ";
649 debugText += screenY.toFixed(decimal_places) + " ";
650 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000651 }
652 ctx.fillStyle="blue";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000653 ctx.fillText(debugText, 50, partIndex * 50 + 100);
caryclark@google.comf839c032012-10-26 21:03:50 +0000654 }
655 if (ptLabels && selected) {
656 ctx.fillStyle="blue";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000657 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
658 var type = types[typeIndex];
659 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000660 for (var idx = pts[typeIndex]; idx < pts[typeIndex] + (type + 1) * 2; idx += 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000661 drawPoint(scan[idx], scan[idx + 1]);
662 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000663 }
664 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000665 var infoText = "";
caryclark@google.comf839c032012-10-26 21:03:50 +0000666 if (info_mode && selected) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000667 infoText += hasId >= 0 ? "id=" + scan[hasId] : partIndex;
668 }
669 if (intersect_mode && selected) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000670 if (scanType == ACTIVE_CUBIC_SPAN) {
671 infoText += " t=" + scan[SPAN_C_T];
672 } else if (scanType == ACTIVE_QUAD_SPAN) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000673 infoText += " t=" + scan[SPAN_Q_T];
674 } else if (scanType == ACTIVE_LINE_SPAN) {
675 infoText += " t=" + scan[SPAN_L_T];
676 } else if (scanType == INTERSECT_QUAD_LINE ||scanType == INTERSECT_QUAD) {
677 infoText += " t0[0]=" + scan[1] + " t1[0]=" + scan[10];
678 } else if (scanType == INTERSECT_QUAD_LINE_2 || scanType == INTERSECT_QUAD_2) {
679 infoText += " t0[0]=" + scan[1] + " t0[1]=" + scan[10] + " t1[0]=" + scan[13];
680 if (scanType == INTERSECT_QUAD_LINE_2) {
681 infoText += " t1[1]=" + scan[18];
682 } else {
683 infoText += " t0[1]=" + scan[20];
684 }
685 }
686 }
687 if (infoText.length > 0) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000688 ctx.fillStyle="green";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000689 ctx.fillText(infoText, 10, (hasId >= 0 && sequence >= 0
690 ? hasId : partIndex) * 30 + 50);
caryclark@google.comf839c032012-10-26 21:03:50 +0000691 }
692 if (intersect_mode && selected) {
693 ctx.fillStyle="rgba(50,100,200, 1.0)";
caryclark@google.com47d73da2013-02-17 01:41:25 +0000694 if (scanType == ACTIVE_CUBIC_SPAN) {
695 drawPoint(scan[SPAN_C_TX], scan[SPAN_C_TY]);
696 } else if (scanType == ACTIVE_QUAD_SPAN) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000697 drawPoint(scan[SPAN_Q_TX], scan[SPAN_Q_TY]);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000698 } else if (scanType == ACTIVE_LINE_SPAN) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000699 drawPoint(scan[SPAN_L_TX], scan[SPAN_L_TY]);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000700 } else if (scanType != INTERSECT_QUAD_NO && scanType != INTERSECT_QUAD_LINE_NO) {
701 drawPoint(scan[8], scan[9]);
702 if (scanType == INTERSECT_QUAD_LINE_2 || scanType == INTERSECT_QUAD_2) {
703 drawPoint(scan[11], scan[12]);
704 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000705 }
706 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000707 ctx.strokeStyle = "rgba(0,0,0, 0.2)";
708 scanType = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000709 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000710 drawDeferred();
caryclark@google.com47d73da2013-02-17 01:41:25 +0000711 drawPartial(test);
caryclark@google.comf839c032012-10-26 21:03:50 +0000712}
713
714function drawTop() {
715 init(tests[testIndex]);
716 redraw();
717}
718
719function redraw() {
720 ctx.beginPath();
721 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
722 ctx.fillStyle="white";
723 ctx.fill();
724 draw(tests[testIndex], testTitles[testIndex]);
725}
726
727function doKeyPress(evt) {
728 var char = String.fromCharCode(evt.charCode);
729 switch (char) {
730 case '0':
731 case '1':
732 case '2':
733 case '3':
734 case '4':
735 case '5':
736 case '6':
737 case '7':
738 case '8':
739 case '9':
740 if (digit_mode) {
741 decimal_places = char - '0';
742 } else if (index_mode) {
743 index_bits ^= 1 << (char - '0');
744 }
745 redraw();
746 break;
747 case 'd':
748 digit_mode = true;
749 index_mode = false;
750 break;
751 case 'f':
752 info_mode ^= true;
753 redraw();
754 break;
755 case 'i':
756 digit_mode = false;
757 if (sequence >= 0) {
758 sequence = -1;
759 index_mode = false;
760 } else {
761 index_mode ^= true;
762 }
763 if (index_mode) {
764 index_bits = 0;
765 } else {
766 index_bits = -1;
767 }
768 redraw();
769 break;
770 case 'N':
771 testIndex += 9;
772 case 'n':
773 if (++testIndex >= tests.length)
774 testIndex = 0;
775 drawTop();
776 break;
777 case 'P':
778 testIndex -= 9;
779 case 'p':
780 if (--testIndex < 0)
781 testIndex = tests.length - 1;
782 drawTop();
783 break;
784 case 's':
785 sequence++;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000786 redraw();
787 break;
788 case 'S':
789 sequence--;
790 if (sequence < 0) {
791 sequence = 0;
792 }
793 redraw();
caryclark@google.comf839c032012-10-26 21:03:50 +0000794 break;
795 case 't':
796 intersect_mode ^= true;
797 redraw();
798 break;
799 case 'x':
800 ptLabels ^= true;
801 redraw();
802 break;
803 case 'y':
804 debug_xy ^= true;
805 redraw();
806 break;
807 case '-':
808 scale /= 2;
809 calcLeftTop();
810 redraw();
811 break;
812 case '=':
813 case '+':
814 scale *= 2;
815 calcLeftTop();
816 redraw();
817 break;
818 }
819}
820
821function calcXY() {
822 var e = window.event;
823 var tgt = e.target || e.srcElement;
824 var left = tgt.offsetLeft;
825 var top = tgt.offsetTop;
826 var unit = scale;
827 mouseX = (e.clientX - left) / scale + srcLeft;
828 mouseY = (e.clientY - top) / scale + srcTop;
829}
830
831function calcLeftTop() {
832 srcLeft = mouseX - screenWidth / 2 / scale;
833 srcTop = mouseY - screenHeight / 2 / scale;
834}
835
836function handleMouseClick() {
837 calcXY();
838 calcLeftTop();
839 redraw();
840}
841
842function handleMouseOver() {
843 calcXY();
844 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
845 ctx.beginPath();
846 ctx.rect(300,100,200,10);
847 ctx.fillStyle="white";
848 ctx.fill();
849 ctx.fillStyle="black";
850 ctx.fillText(num, 300, 108);
851}
852
853function start() {
854 for (i = 0; i < testDivs.length; ++i) {
855 var title = testDivs[i].id.toString();
856 var str = testDivs[i].firstChild.data;
857 parse_debugShowActiveSpans(str, title);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000858 parse_intersections(str, title);
caryclark@google.comf839c032012-10-26 21:03:50 +0000859 }
860 drawTop();
861 window.addEventListener('keypress', doKeyPress, true);
862 window.onresize = function() {
863 drawTop();
864 }
865}
866
867</script>
868</head>
869
870<body onLoad="start();">
871<canvas id="canvas" width="750" height="500"
872 onmousemove="handleMouseOver()"
873 onclick="handleMouseClick()"
874 ></canvas >
875</body>
876</html>