blob: b5487668b65db415cb54af60c81892ba8c4f0a2a [file] [log] [blame]
caryclark@google.comf839c032012-10-26 21:03:50 +00001<html>
2<head>
3<div style="height:0">
4
caryclark@google.comc83c70e2013-02-22 21:50:07 +00005<div id="cubicOp25i">
6debugShowActiveSpans id=1 (0,1 2,4 5,0 3,2) t=0.466666667 (2.84355545,1.9478519) tEnd=0.605057566 other=2 otherT=0.0521481481 otherIndex=1 windSum=-1 windValue=1 oppValue=0
7debugShowActiveSpans id=2 (3,2 0,1) t=0.0521481481 (2.84355545,1.9478519) tEnd=0.377811276 other=1 otherT=0.466666667 otherIndex=2 windSum=1 windValue=1 oppValue=0
8</div>
9
caryclark@google.com47d73da2013-02-17 01:41:25 +000010<div id="cubicOp19i">
11debugShowActiveSpans 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
12debugShowActiveSpans 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
13debugShowActiveSpans 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
14debugShowActiveSpans id=4 (1,0 1,2) t=0 (1,0) tEnd=0.637627564 other=3 otherT=1 otherIndex=4 windSum=? windValue=1 oppValue=0
15debugShowActiveSpans 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
16debugShowActiveSpans 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
17debugShowActiveSpans 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
18debugShowActiveSpans 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
19debugShowActiveSpans id=2 (6,2 0,2) t=0 (6,2) tEnd=0.711411698 other=1 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
20debugShowActiveSpans 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
21debugShowActiveSpans 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 +000022</div>
23
caryclark@google.comc83c70e2013-02-22 21:50:07 +000024<div id="cubicOp28u">
25debugShowActiveSpans id=3 (0,6 2,3 1,0 4,1) t=0 (0,6) tEnd=0.473902244 other=4 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
26debugShowActiveSpans id=3 (0,6 2,3 1,0 4,1) t=0.473902244 (1.5671773,2.16060209) tEnd=0.57224743 other=1 otherT=0.287206281 otherIndex=1 windSum=? windValue=1 oppValue=0
27debugShowActiveSpans id=3 (0,6 2,3 1,0 4,1) t=0.57224743 (1.79802597,1.59934199) tEnd=1 other=2 otherT=0.400657994 otherIndex=2 windSum=? windValue=1 oppValue=0
28debugShowActiveSpans id=4 (4,1 0,6) t=0 (4,1) tEnd=0.13678207 other=3 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
29debugShowActiveSpans id=4 (4,1 0,6) t=0.13678207 (3.4528718,1.68391037) tEnd=0.145041093 other=1 otherT=0.583645693 otherIndex=3 windSum=? windValue=1 oppValue=0
30debugShowActiveSpans id=4 (4,1 0,6) t=0.145041093 (3.41983557,1.72520542) tEnd=1 other=1 otherT=0.945703361 otherIndex=6 windSum=? windValue=1 oppValue=0
31debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0 (0,1) tEnd=0.287206281 other=2 otherT=1 otherIndex=3 windSum=? windValue=1 oppValue=0
32debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.287206281 (1.5671773,2.16060209) tEnd=0.470588235 other=3 otherT=0.473902244 otherIndex=1 windSum=? windValue=1 oppValue=0
33debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.470588235 (2.81864452,1.93954813) tEnd=0.583645693 other=2 otherT=0.0604518624 otherIndex=1 windSum=? windValue=1 oppValue=0
34debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.583645693 (3.4528718,1.68391037) tEnd=0.614942976 other=4 otherT=0.13678207 otherIndex=1 windSum=? windValue=1 oppValue=0
35debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.614942976 (3.59216309,1.61630249) tEnd=0.916307024 other=1 otherT=0.916307024 otherIndex=5 windSum=? windValue=1 oppValue=0
36debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.916307024 (3.59216309,1.61630249) tEnd=0.945703361 other=1 otherT=0.614942976 otherIndex=4 windSum=? windValue=1 oppValue=0
37debugShowActiveSpans id=1 (0,1 1,4 6,0 3,2) t=0.945703361 (3.41983557,1.72520542) tEnd=1 other=4 otherT=0.145041093 otherIndex=2 windSum=? windValue=1 oppValue=0
38debugShowActiveSpans id=2 (3,2 0,1) t=0 (3,2) tEnd=0.0604518624 other=1 otherT=1 otherIndex=7 windSum=? windValue=1 oppValue=0
39debugShowActiveSpans id=2 (3,2 0,1) t=0.0604518624 (2.81864452,1.93954813) tEnd=0.400657994 other=1 otherT=0.470588235 otherIndex=2 windSum=? windValue=1 oppValue=0
40debugShowActiveSpans id=2 (3,2 0,1) t=0.400657994 (1.79802597,1.59934199) tEnd=1 other=3 otherT=0.57224743 otherIndex=2 windSum=? windValue=1 oppValue=0
41</div>
42
caryclark@google.comf839c032012-10-26 21:03:50 +000043</div>
44
45<script type="text/javascript">
46
47var testDivs = [
caryclark@google.comc83c70e2013-02-22 21:50:07 +000048 cubicOp28u,
49 cubicOp25i,
caryclark@google.com47d73da2013-02-17 01:41:25 +000050 cubicOp19i,
caryclark@google.comf839c032012-10-26 21:03:50 +000051];
52
53var decimal_places = 3; // make this 3 to show more precision
54
55var tests = [];
56var testTitles = [];
57var testIndex = 0;
58var ctx;
59
60var xmin;
61var ymin;
62var scale;
63var mouseX, mouseY;
64var srcLeft, srcTop;
65var srcWidth, srcHeight;
66var screenWidth, screenHeight;
caryclark@google.com47d73da2013-02-17 01:41:25 +000067var drawnPts, drawnLines, drawnQuads, drawnCubics, deferredLines, deferredQuads, deferredCubics;
caryclark@google.comf839c032012-10-26 21:03:50 +000068
69var ptLabels = true;
70var digit_mode = false;
71var index_mode = true;
72var index_bits = -1;
73var debug_xy = false;
74var info_mode = false;
75var intersect_mode = false;
76var sequence = -1;
77
78var SPAN_ID = 1;
79var SPAN_X1 = 2;
80var SPAN_Y1 = 3;
81var SPAN_X2 = 4;
82var SPAN_Y2 = 5;
83var SPAN_L_T = 6;
84var SPAN_L_TX = 7;
85var SPAN_L_TY = 8;
caryclark@google.com47d73da2013-02-17 01:41:25 +000086var SPAN_L_TEND = 9;
87var SPAN_L_OTHER = 10;
88var SPAN_L_OTHERT = 11;
89var SPAN_L_OTHERI = 12;
90var SPAN_L_SUM = 13;
91var SPAN_L_VAL = 14;
92var SPAN_L_OPP = 15;
caryclark@google.comf839c032012-10-26 21:03:50 +000093
94var SPAN_X3 = 6;
95var SPAN_Y3 = 7;
96var SPAN_Q_T = 8;
97var SPAN_Q_TX = 9;
98var SPAN_Q_TY = 10;
caryclark@google.com47d73da2013-02-17 01:41:25 +000099var SPAN_Q_TEND = 11;
100var SPAN_Q_OTHER = 12;
101var SPAN_Q_OTHERT = 13;
102var SPAN_Q_OTHERI = 14;
103var SPAN_Q_SUM = 15;
104var SPAN_Q_VAL = 16;
105var SPAN_Q_OPP = 17;
106
107var SPAN_X4 = 8;
108var SPAN_Y4 = 9;
109var SPAN_C_T = 10;
110var SPAN_C_TX = 11;
111var SPAN_C_TY = 12;
112var SPAN_C_TEND = 13;
113var SPAN_C_OTHER = 14;
114var SPAN_C_OTHERT = 15;
115var SPAN_C_OTHERI = 16;
116var SPAN_C_SUM = 17;
117var SPAN_C_VAL = 18;
118var SPAN_C_OPP = 19;
caryclark@google.comf839c032012-10-26 21:03:50 +0000119
caryclark@google.com0b7da432012-10-31 19:00:20 +0000120var ACTIVE_LINE_SPAN = 1;
121var ACTIVE_QUAD_SPAN = 2;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000122var ACTIVE_CUBIC_SPAN = 3;
123var INTERSECT_QUAD_LINE = 4;
124var INTERSECT_QUAD_LINE_2 = 5;
125var INTERSECT_QUAD_LINE_NO = 6;
126var INTERSECT_QUAD = 7;
127var INTERSECT_QUAD_2 = 8;
128var INTERSECT_QUAD_NO = 9;
caryclark@google.comf839c032012-10-26 21:03:50 +0000129
130function strs_to_nums(strs) {
131 var result = [];
132 for (var idx in strs) {
133 var str = strs[idx];
134 var num = parseFloat(str);
135 if (isNaN(num)) {
136 result.push(str);
137 } else {
138 result.push(num);
139 }
140 }
141 return result;
142}
143
caryclark@google.com0b7da432012-10-31 19:00:20 +0000144function construct_regexp(pattern) {
145 var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
146 escape = escape.replace(/PT_VAL/g, "(\\d+\\.?\\d*),(\\d+\\.?\\d*)");
147 escape = escape.replace(/T_VAL/g, "(\\d+\\.?\\d*e?-?\\d*)");
148 escape = escape.replace(/IDX/g, "(\\d+)");
149 escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
150 return new RegExp(escape, 'i');
151}
152
caryclark@google.comf839c032012-10-26 21:03:50 +0000153function parse_debugShowActiveSpans(test, title) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000154 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");
155 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");
156 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 +0000157
158 var strs = test.split("debugShowActiveSpans");
159 if (strs.length == 1)
160 return;
161 var spans = [];
162 for (var s in strs) {
163 var str = strs[s];
164 if (str == "\n") {
165 continue;
166 }
167 if (re_line.test(str)) {
168 var lineStrs = re_line.exec(str);
169 var line = strs_to_nums(lineStrs);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000170 spans.push(ACTIVE_LINE_SPAN);
caryclark@google.comf839c032012-10-26 21:03:50 +0000171 spans.push(line);
172 } else if (re_quad.test(str)) {
173 var quadStrs = re_quad.exec(str);
174 var quad = strs_to_nums(quadStrs);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000175 spans.push(ACTIVE_QUAD_SPAN);
caryclark@google.comf839c032012-10-26 21:03:50 +0000176 spans.push(quad);
caryclark@google.com47d73da2013-02-17 01:41:25 +0000177 } else if (re_cubic.test(str)) {
178 var cubicStrs = re_cubic.exec(str);
179 var cubic = strs_to_nums(cubicStrs);
180 spans.push(ACTIVE_CUBIC_SPAN);
181 spans.push(cubic);
caryclark@google.comf839c032012-10-26 21:03:50 +0000182 }
183 }
184 if (spans.length >= 1) {
185 tests.push(spans);
186 testTitles.push(title);
187 }
188}
189
caryclark@google.com0b7da432012-10-31 19:00:20 +0000190function filter_str_by(id, str, regex, array) {
191 if (regex.test(str)) {
192 var strs = regex.exec(str);
193 var result = strs_to_nums(strs);
194 array.push(id);
195 array.push(result);
196 }
197}
198
caryclark@google.com47d73da2013-02-17 01:41:25 +0000199// FIXME: add cubic support
caryclark@google.com0b7da432012-10-31 19:00:20 +0000200function parse_intersections(test, title) {
201 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)");
202 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)");
203 var re_quad_line_no_intersect = construct_regexp(" no intersect (PT_VAL PT_VAL PT_VAL) (PT_VAL PT_VAL)");
204 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)");
205 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");
206 var re_quad_no_intersect = construct_regexp(" no intersect (PT_VAL PT_VAL PT_VAL) (PT_VAL PT_VAL PT_VAL)");
207
208 var strs = test.split(/debugShow[A-Za-z]+Intersection/);
209 if (strs.length == 1)
210 return;
211 var spans = [];
212 for (var s in strs) {
213 var str = strs[s];
214 if (str == "\n") {
215 continue;
216 }
217 filter_str_by(INTERSECT_QUAD_LINE, str, re_quad_line, spans);
218 filter_str_by(INTERSECT_QUAD_LINE_2, str, re_quad_line_2, spans);
219 filter_str_by(INTERSECT_QUAD_LINE_NO, str, re_quad_line_no_intersect, spans);
220 filter_str_by(INTERSECT_QUAD, str, re_quad, spans);
221 filter_str_by(INTERSECT_QUAD_2, str, re_quad_2, spans);
222 filter_str_by(INTERSECT_QUAD_NO, str, re_quad_no_intersect, spans);
223 }
224 if (spans.length >= 1) {
225 tests.push(spans);
226 testTitles.push(title);
227 }
228}
229
caryclark@google.comf839c032012-10-26 21:03:50 +0000230function init(test) {
231 var canvas = document.getElementById('canvas');
232 if (!canvas.getContext) return;
233 screenWidth = canvas.width = window.innerWidth - 20;
234 screenHeight = canvas.height = window.innerHeight - 20;
235 ctx = canvas.getContext('2d');
236 xmin = Infinity;
237 var xmax = -Infinity;
238 ymin = Infinity;
239 var ymax = -Infinity;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000240 var scanType = -1;
241 for (var scansStr in test) {
242 var scans = parseInt(scansStr);
caryclark@google.comf839c032012-10-26 21:03:50 +0000243 var scan = test[scans];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000244 if (scanType == -1) {
245 scanType = scan;
246 continue;
caryclark@google.comf839c032012-10-26 21:03:50 +0000247 }
caryclark@google.com47d73da2013-02-17 01:41:25 +0000248 if (scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
249 || scanType == ACTIVE_CUBIC_SPAN) {
250 var last = scanType == ACTIVE_CUBIC_SPAN ? SPAN_X4
251 : scanType == ACTIVE_QUAD_SPAN ? SPAN_X3 : SPAN_X2;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000252 for (var idx = SPAN_X1; idx <= last; idx += 2) {
253 xmin = Math.min(xmin, scan[idx]);
254 xmax = Math.max(xmax, scan[idx]);
255 ymin = Math.min(ymin, scan[idx + 1]);
256 ymax = Math.max(ymax, scan[idx + 1]);
257 }
258 } else {
259 var start = 1;
260 if (scanType != INTERSECT_QUAD_LINE_NO && scanType != INTERSECT_QUAD_NO) {
261 start = 2;
262 }
263 for (var idx = start; idx < start + 6; idx += 2) {
264 xmin = Math.min(xmin, scan[idx]);
265 xmax = Math.max(xmax, scan[idx]);
266 ymin = Math.min(ymin, scan[idx + 1]);
267 ymax = Math.max(ymax, scan[idx + 1]);
268 }
269 start = start + 6;
270 if (scanType == INTERSECT_QUAD_LINE || scanType == INTERSECT_QUAD) {
271 start += 3;
272 }
273 if (scanType == INTERSECT_QUAD_LINE_2) {
274 start += 6;
275 }
276 if (scanType == INTERSECT_QUAD_2) {
277 start += 4;
278 }
279 var end = start + 4;
280 if (scanType == INTERSECT_QUAD || scanType == INTERSECT_QUAD_2 || scanType == INTERSECT_QUAD_NO) {
281 end += 2;
282 }
283 for (var idx = start; idx < end; idx += 2) {
284 xmin = Math.min(xmin, scan[idx]);
285 xmax = Math.max(xmax, scan[idx]);
286 ymin = Math.min(ymin, scan[idx + 1]);
287 ymax = Math.max(ymax, scan[idx + 1]);
288 }
289 }
290 scanType = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000291 }
292 srcWidth = xmax - xmin;
293 srcHeight = ymax - ymin;
294 var hscale = ctx.canvas.width / srcWidth;
295 var vscale = ctx.canvas.height / srcHeight;
296 var minScale = Math.min(hscale, vscale);
297 scale = minScale;
298 srcLeft = xmin;
299 srcTop = ymin;
300}
301
302function drawPoint(px, py) {
303 for (var pts = 0; pts < drawnPts.length; pts += 2) {
304 var x = drawnPts[pts];
305 var y = drawnPts[pts + 1];
306 if (px == x && py == y) {
307 return;
308 }
309 }
310 drawnPts.push(px);
311 drawnPts.push(py);
312 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
313 var _px = (px - srcLeft)* scale;
314 var _py = (py - srcTop) * scale;
315 ctx.beginPath();
316 ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
317 ctx.closePath();
318 ctx.fill();
319 ctx.fillText(label, _px + 5, _py);
320}
321
caryclark@google.com0b7da432012-10-31 19:00:20 +0000322function drawLine(x1, y1, x2, y2, selected) {
323 for (var pts = 0; pts < drawnLines.length; pts += 4) {
324 if (x1 == drawnLines[pts] && y1 == drawnLines[pts + 1]) {
325 return;
326 }
327 if (x2 == drawnLines[pts + 2] && x2 == drawnLines[pts + 3]) {
328 return;
329 }
330 }
331 if (selected) {
332 drawnLines.push(x1);
333 drawnLines.push(y1);
334 drawnLines.push(x2);
335 drawnLines.push(y2);
336 ctx.beginPath();
337 ctx.moveTo((x1 - srcLeft) * scale,
338 (y1 - srcTop) * scale);
339 ctx.lineTo((x2 - srcLeft) * scale,
340 (y2 - srcTop) * scale);
341 ctx.stroke();
342 return;
343 }
344 deferredLines.push(x1);
345 deferredLines.push(y1);
346 deferredLines.push(x2);
347 deferredLines.push(y2);
348}
349
caryclark@google.com47d73da2013-02-17 01:41:25 +0000350function drawLinePartial(x1, y1, x2, y2, t1, t2) {
351 var dx = x1 - x2;
352 var dy = y1 - y2;
353 var ax = x1 - t1 * dx;
354 var ay = y1 - t1 * dy;
355 var bx = x1 - t2 * dx;
356 var by = y1 - t2 * dy;
357 ctx.beginPath();
358 ctx.moveTo((ax - srcLeft) * scale,
359 (ay - srcTop) * scale);
360 ctx.lineTo((bx - srcLeft) * scale,
361 (by - srcTop) * scale);
362 ctx.stroke();
363}
364
caryclark@google.com0b7da432012-10-31 19:00:20 +0000365function drawQuad(x1, y1, x2, y2, x3, y3, selected) {
366 for (var pts = 0; pts < drawnQuads.length; pts += 6) {
367 if (x1 == drawnQuads[pts] && y1 == drawnQuads[pts + 1]) {
368 return;
369 }
370 if (x2 == drawnQuads[pts + 2] && x2 == drawnQuads[pts + 3]) {
371 return;
372 }
373 if (x2 == drawnQuads[pts + 4] && x2 == drawnQuads[pts + 5]) {
374 return;
375 }
376 }
377 if (selected) {
378 drawnQuads.push(x1);
379 drawnQuads.push(y1);
380 drawnQuads.push(x2);
381 drawnQuads.push(y2);
382 drawnQuads.push(x3);
383 drawnQuads.push(y3);
384 ctx.beginPath();
385 ctx.moveTo((x1 - srcLeft) * scale,
386 (y1 - srcTop) * scale);
387 ctx.quadraticCurveTo((x2 - srcLeft) * scale,
388 (y2 - srcTop) * scale,
389 (x3 - srcLeft) * scale,
390 (y3 - srcTop) * scale);
391 ctx.stroke();
392 return;
393 }
394 deferredQuads.push(x1);
395 deferredQuads.push(y1);
396 deferredQuads.push(x2);
397 deferredQuads.push(y2);
398 deferredQuads.push(x3);
399 deferredQuads.push(y3);
400}
401
caryclark@google.com47d73da2013-02-17 01:41:25 +0000402function interp(A, B, t) {
403 return A + (B - A) * t;
404}
405
406function interp_quad_coords(x1, x2, x3, t)
407{
408 var ab = interp(x1, x2, t);
409 var bc = interp(x2, x3, t);
410 var abc = interp(ab, bc, t);
411 return abc;
412}
413
414function drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2) {
415 var ax = interp_quad_coords(x1, x2, x3, t1);
416 var ay = interp_quad_coords(y1, y2, y3, t1);
417 var dx = interp_quad_coords(x1, x2, x3, (t1 + t2) / 2);
418 var dy = interp_quad_coords(y1, y2, y3, (t1 + t2) / 2);
419 var cx = interp_quad_coords(x1, x2, x3, t2);
420 var cy = interp_quad_coords(y1, y2, y3, t2);
421 var bx = 2*dx - (ax + cx)/2;
422 var by = 2*dy - (ay + cy)/2;
423 ctx.beginPath();
424 ctx.moveTo((ax - srcLeft) * scale,
425 (ay - srcTop) * scale);
426 ctx.quadraticCurveTo((bx - srcLeft) * scale,
427 (by - srcTop) * scale,
428 (cx - srcLeft) * scale,
429 (cy - srcTop) * scale);
430 ctx.stroke();
431}
432
433function drawCubic(x1, y1, x2, y2, x3, y3, x4, y4, selected) {
434 for (var pts = 0; pts < drawnCubics.length; pts += 8) {
435 if (x1 == drawnCubics[pts] && y1 == drawnCubics[pts + 1]) {
436 return;
437 }
438 if (x2 == drawnCubics[pts + 2] && x2 == drawnCubics[pts + 3]) {
439 return;
440 }
441 if (x2 == drawnCubics[pts + 4] && x2 == drawnCubics[pts + 5]) {
442 return;
443 }
444 if (x2 == drawnCubics[pts + 6] && x2 == drawnCubics[pts + 7]) {
445 return;
446 }
447 }
448 if (selected) {
449 drawnCubics.push(x1);
450 drawnCubics.push(y1);
451 drawnCubics.push(x2);
452 drawnCubics.push(y2);
453 drawnCubics.push(x3);
454 drawnCubics.push(y3);
455 drawnCubics.push(x4);
456 drawnCubics.push(y4);
457 ctx.beginPath();
458 ctx.moveTo((x1 - srcLeft) * scale,
459 (y1 - srcTop) * scale);
460 ctx.bezierCurveTo((x2 - srcLeft) * scale,
461 (y2 - srcTop) * scale,
462 (x3 - srcLeft) * scale,
463 (y3 - srcTop) * scale,
464 (x4 - srcLeft) * scale,
465 (y4 - srcTop) * scale);
466 ctx.stroke();
467 return;
468 }
469 deferredCubics.push(x1);
470 deferredCubics.push(y1);
471 deferredCubics.push(x2);
472 deferredCubics.push(y2);
473 deferredCubics.push(x3);
474 deferredCubics.push(y3);
475 deferredCubics.push(x4);
476 deferredCubics.push(y4);
477}
478
479function interp_cubic_coords(x1, x2, x3, x4, t)
480{
481 var ab = interp(x1, x2, t);
482 var bc = interp(x2, x3, t);
483 var cd = interp(x3, x4, t);
484 var abc = interp(ab, bc, t);
485 var bcd = interp(bc, cd, t);
486 var abcd = interp(abc, bcd, t);
487 return abcd;
488}
489
490function drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2) {
491 var ax = interp_cubic_coords(x1, x2, x3, x4, t1);
492 var ay = interp_cubic_coords(y1, y2, y3, y4, t1);
493 var ex = interp_cubic_coords(x1, x2, x3, x4, (t1*2+t2)/3);
494 var ey = interp_cubic_coords(y1, y2, y3, y4, (t1*2+t2)/3);
495 var fx = interp_cubic_coords(x1, x2, x3, x4, (t1+t2*2)/3);
496 var fy = interp_cubic_coords(y1, y2, y3, y4, (t1+t2*2)/3);
497 var dx = interp_cubic_coords(x1, x2, x3, x4, t2);
498 var dy = interp_cubic_coords(y1, y2, y3, y4, t2);
499 var mx = ex * 27 - ax * 8 - dx;
500 var my = ey * 27 - ay * 8 - dy;
501 var nx = fx * 27 - ax - dx * 8;
502 var ny = fy * 27 - ay - dy * 8;
503 var bx = (mx * 2 - nx) / 18;
504 var by = (my * 2 - ny) / 18;
505 var cx = (nx * 2 - mx) / 18;
506 var cy = (ny * 2 - my) / 18;
507 ctx.beginPath();
508 ctx.moveTo((ax - srcLeft) * scale,
509 (ay - srcTop) * scale);
510 ctx.bezierCurveTo((bx - srcLeft) * scale,
511 (by - srcTop) * scale,
512 (cx - srcLeft) * scale,
513 (cy - srcTop) * scale,
514 (dx - srcLeft) * scale,
515 (dy - srcTop) * scale,
516 (ex - srcLeft) * scale,
517 (ey - srcTop) * scale);
518 ctx.stroke();
519}
520
521function drawPartial(test) {
522 ctx.lineWidth = 3;
523 ctx.strokeStyle = "rgba(0,0,255, 0.3)";
524 var scanType = -1;
525 var partIndex = 0;
526 for (var scansStr in test) {
527 var scans = parseInt(scansStr);
528 var scan = test[scans];
529 if (scanType == -1) {
530 scanType = scan;
531 continue;
532 }
533 partIndex++;
534 var hasId = scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
535 || scanType == ACTIVE_CUBIC_SPAN ? SPAN_ID : -1;
536 if (hasId < 0) {
537 continue;
538 }
539 var types = [scanType == ACTIVE_LINE_SPAN ? 0 : scanType == ACTIVE_QUAD_SPAN ? 1 : 2];
540 var x1 = scan[SPAN_X1];
541 var y1 = scan[SPAN_Y1];
542 var x2 = scan[SPAN_X2];
543 var y2 = scan[SPAN_Y2];
544 var x3, y3, x3, y4, t1, t2;
545 switch(scanType) {
546 case ACTIVE_LINE_SPAN:
547 t1 = scan[SPAN_L_T];
548 t2 = scan[SPAN_L_TEND];
549 drawLinePartial(x1, y1, x2, y2, t1, t2);
550 break;
551 case ACTIVE_QUAD_SPAN:
552 x3 = scan[SPAN_X3];
553 y3 = scan[SPAN_Y3];
554 t1 = scan[SPAN_Q_T];
555 t2 = scan[SPAN_Q_TEND];
556 drawQuadPartial(x1, y1, x2, y2, x3, y3, t1, t2);
557 break;
558 case ACTIVE_CUBIC_SPAN:
559 x3 = scan[SPAN_X3];
560 y3 = scan[SPAN_Y3];
561 x4 = scan[SPAN_X4];
562 y4 = scan[SPAN_Y4];
563 t1 = scan[SPAN_C_T];
564 t2 = scan[SPAN_C_TEND];
565 drawCubicPartial(x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
566 break;
567 }
568 scanType = -1;
569 }
570}
571
caryclark@google.com0b7da432012-10-31 19:00:20 +0000572function drawDeferred() {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000573 for (var pts = 0; pts < deferredCubics.length; pts += 8) {
574 drawCubic(deferredCubics[pts], deferredCubics[pts + 1],
575 deferredCubics[pts + 2], deferredCubics[pts + 3],
576 deferredCubics[pts + 4], deferredCubics[pts + 5],
577 deferredCubics[pts + 6], deferredCubics[pts + 7], true);
578 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000579 for (var pts = 0; pts < deferredQuads.length; pts += 6) {
580 drawQuad(deferredQuads[pts], deferredQuads[pts + 1],
581 deferredQuads[pts + 2], deferredQuads[pts + 3],
582 deferredQuads[pts + 4], deferredQuads[pts + 5], true);
583 }
584 for (var pts = 0; pts < deferredLines.length; pts += 4) {
585 drawLine(deferredLines[pts], deferredLines[pts + 1],
586 deferredLines[pts + 2], deferredLines[pts + 3], true);
587 }
588}
589
caryclark@google.comf839c032012-10-26 21:03:50 +0000590function draw(test, title) {
591 ctx.fillStyle = "rgba(0,0,0, 0.1)";
592 ctx.font = "normal 50px Arial";
593 ctx.fillText(title, 50, 50);
594 ctx.font = "normal 10px Arial";
595 ctx.lineWidth = "1.001"; "0.999";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000596 var curId = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000597 var firstIdx;
598 var lastIdx;
599 var index_tst = -1;
600 drawnPts = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000601 drawnLines = [];
602 drawnQuads = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000603 drawnCubics = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000604 deferredLines = [];
605 deferredQuads = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000606 deferredCubics = [];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000607 var scanType = -1;
608 var partIndex = 0;
caryclark@google.comf839c032012-10-26 21:03:50 +0000609 for (var scansStr in test) {
610 var scans = parseInt(scansStr);
611 var scan = test[scans];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000612 if (scanType == -1) {
613 scanType = scan;
caryclark@google.comf839c032012-10-26 21:03:50 +0000614 continue;
615 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000616 partIndex++;
caryclark@google.com47d73da2013-02-17 01:41:25 +0000617 var hasId = scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN
618 || scanType == ACTIVE_CUBIC_SPAN ? SPAN_ID : -1;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000619 if (hasId >= 0 && curId != scan[hasId]) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000620 curId = scan[hasId];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000621 firstIdx = lastIdx = partIndex;
622 index_tst++;
623 var nextIdx = lastIdx + 1;
624 while (nextIdx * 2 < test.length && test[nextIdx * 2][hasId] == curId) {
625 lastIdx = nextIdx++;
626 }
627 } else if (hasId < 0) {
628 firstIdx = lastIdx = partIndex;
629 index_tst++;
caryclark@google.comf839c032012-10-26 21:03:50 +0000630 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000631 var seq = sequence % (test.length / 2);
632 var selected = sequence >= 0 ? seq == partIndex
633 : (index_bits & (1 << index_tst)) != 0 && partIndex == firstIdx;
634 var skippable = (sequence >= 0 && seq >= firstIdx && seq <= lastIdx)
635 || partIndex != firstIdx;
636 if (skippable && !selected) {
637 scanType = -1;
638 continue;
639 }
caryclark@google.com47d73da2013-02-17 01:41:25 +0000640 var types = [scanType == ACTIVE_LINE_SPAN ? 0 : scanType == ACTIVE_QUAD_SPAN ? 1 : 2];
caryclark@google.com0b7da432012-10-31 19:00:20 +0000641 var pts = [];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000642 if (scanType == ACTIVE_LINE_SPAN || scanType == ACTIVE_QUAD_SPAN || scanType == ACTIVE_CUBIC_SPAN) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000643 pts.push(SPAN_X1);
644 } else {
645 pts.push(scanType != INTERSECT_QUAD_NO && scanType != INTERSECT_QUAD_LINE_NO ? 2 : 1);
646 types.push(scanType == INTERSECT_QUAD_NO || scanType == INTERSECT_QUAD || scanType == INTERSECT_QUAD_2 ? 1 : 0);
647 pts.push(scanType == INTERSECT_QUAD_LINE || scanType == INTERSECT_QUAD ? 11
648 : scanType == INTERSECT_QUAD_LINE_2 ? 14 : scanType == INTERSECT_QUAD_2 ? 12 : 7);
649 }
650 ctx.strokeStyle = "red";
651 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
652 var type = types[typeIndex];
653 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000654 if (type == 2) {
655 drawCubic(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
656 scan[index + 4], scan[index + 5], scan[index + 6], scan[index + 7],
657 selected);
658 } else if (type == 1) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000659 drawQuad(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
660 scan[index + 4], scan[index + 5], selected);
661 } else {
662 drawLine(scan[index + 0], scan[index + 1], scan[index + 2], scan[index + 3],
663 selected);
664 }
665 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000666 if (debug_xy && selected) {
667 var debugText = "";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000668 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
669 var type = types[typeIndex];
670 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000671 for (var idx = pts[typeIndex]; idx < pts[typeIndex] + (type + 1) * 2; idx += 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000672 var screenX = (scan[idx] - srcLeft) * scale;
673 var screenY = (scan[idx + 1] - srcTop) * scale;
674 debugText += screenX.toFixed(decimal_places) + ", ";
675 debugText += screenY.toFixed(decimal_places) + " ";
676 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000677 }
678 ctx.fillStyle="blue";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000679 ctx.fillText(debugText, 50, partIndex * 50 + 100);
caryclark@google.comf839c032012-10-26 21:03:50 +0000680 }
681 if (ptLabels && selected) {
682 ctx.fillStyle="blue";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000683 for (var typeIndex = 0; typeIndex < types.length; ++typeIndex) {
684 var type = types[typeIndex];
685 var index = pts[typeIndex];
caryclark@google.com47d73da2013-02-17 01:41:25 +0000686 for (var idx = pts[typeIndex]; idx < pts[typeIndex] + (type + 1) * 2; idx += 2) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000687 drawPoint(scan[idx], scan[idx + 1]);
688 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000689 }
690 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000691 var infoText = "";
caryclark@google.comf839c032012-10-26 21:03:50 +0000692 if (info_mode && selected) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000693 infoText += hasId >= 0 ? "id=" + scan[hasId] : partIndex;
694 }
695 if (intersect_mode && selected) {
caryclark@google.com47d73da2013-02-17 01:41:25 +0000696 if (scanType == ACTIVE_CUBIC_SPAN) {
697 infoText += " t=" + scan[SPAN_C_T];
698 } else if (scanType == ACTIVE_QUAD_SPAN) {
caryclark@google.com0b7da432012-10-31 19:00:20 +0000699 infoText += " t=" + scan[SPAN_Q_T];
700 } else if (scanType == ACTIVE_LINE_SPAN) {
701 infoText += " t=" + scan[SPAN_L_T];
702 } else if (scanType == INTERSECT_QUAD_LINE ||scanType == INTERSECT_QUAD) {
703 infoText += " t0[0]=" + scan[1] + " t1[0]=" + scan[10];
704 } else if (scanType == INTERSECT_QUAD_LINE_2 || scanType == INTERSECT_QUAD_2) {
705 infoText += " t0[0]=" + scan[1] + " t0[1]=" + scan[10] + " t1[0]=" + scan[13];
706 if (scanType == INTERSECT_QUAD_LINE_2) {
707 infoText += " t1[1]=" + scan[18];
708 } else {
709 infoText += " t0[1]=" + scan[20];
710 }
711 }
712 }
713 if (infoText.length > 0) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000714 ctx.fillStyle="green";
caryclark@google.com0b7da432012-10-31 19:00:20 +0000715 ctx.fillText(infoText, 10, (hasId >= 0 && sequence >= 0
716 ? hasId : partIndex) * 30 + 50);
caryclark@google.comf839c032012-10-26 21:03:50 +0000717 }
718 if (intersect_mode && selected) {
719 ctx.fillStyle="rgba(50,100,200, 1.0)";
caryclark@google.com47d73da2013-02-17 01:41:25 +0000720 if (scanType == ACTIVE_CUBIC_SPAN) {
721 drawPoint(scan[SPAN_C_TX], scan[SPAN_C_TY]);
722 } else if (scanType == ACTIVE_QUAD_SPAN) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000723 drawPoint(scan[SPAN_Q_TX], scan[SPAN_Q_TY]);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000724 } else if (scanType == ACTIVE_LINE_SPAN) {
caryclark@google.comf839c032012-10-26 21:03:50 +0000725 drawPoint(scan[SPAN_L_TX], scan[SPAN_L_TY]);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000726 } else if (scanType != INTERSECT_QUAD_NO && scanType != INTERSECT_QUAD_LINE_NO) {
727 drawPoint(scan[8], scan[9]);
728 if (scanType == INTERSECT_QUAD_LINE_2 || scanType == INTERSECT_QUAD_2) {
729 drawPoint(scan[11], scan[12]);
730 }
caryclark@google.comf839c032012-10-26 21:03:50 +0000731 }
732 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000733 ctx.strokeStyle = "rgba(0,0,0, 0.2)";
734 scanType = -1;
caryclark@google.comf839c032012-10-26 21:03:50 +0000735 }
caryclark@google.com0b7da432012-10-31 19:00:20 +0000736 drawDeferred();
caryclark@google.com47d73da2013-02-17 01:41:25 +0000737 drawPartial(test);
caryclark@google.comf839c032012-10-26 21:03:50 +0000738}
739
740function drawTop() {
741 init(tests[testIndex]);
742 redraw();
743}
744
745function redraw() {
746 ctx.beginPath();
747 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
748 ctx.fillStyle="white";
749 ctx.fill();
750 draw(tests[testIndex], testTitles[testIndex]);
751}
752
753function doKeyPress(evt) {
754 var char = String.fromCharCode(evt.charCode);
755 switch (char) {
756 case '0':
757 case '1':
758 case '2':
759 case '3':
760 case '4':
761 case '5':
762 case '6':
763 case '7':
764 case '8':
765 case '9':
766 if (digit_mode) {
767 decimal_places = char - '0';
768 } else if (index_mode) {
769 index_bits ^= 1 << (char - '0');
770 }
771 redraw();
772 break;
773 case 'd':
774 digit_mode = true;
775 index_mode = false;
776 break;
777 case 'f':
778 info_mode ^= true;
779 redraw();
780 break;
781 case 'i':
782 digit_mode = false;
783 if (sequence >= 0) {
784 sequence = -1;
785 index_mode = false;
786 } else {
787 index_mode ^= true;
788 }
789 if (index_mode) {
790 index_bits = 0;
791 } else {
792 index_bits = -1;
793 }
794 redraw();
795 break;
796 case 'N':
797 testIndex += 9;
798 case 'n':
799 if (++testIndex >= tests.length)
800 testIndex = 0;
801 drawTop();
802 break;
803 case 'P':
804 testIndex -= 9;
805 case 'p':
806 if (--testIndex < 0)
807 testIndex = tests.length - 1;
808 drawTop();
809 break;
810 case 's':
811 sequence++;
caryclark@google.com0b7da432012-10-31 19:00:20 +0000812 redraw();
813 break;
814 case 'S':
815 sequence--;
816 if (sequence < 0) {
817 sequence = 0;
818 }
819 redraw();
caryclark@google.comf839c032012-10-26 21:03:50 +0000820 break;
821 case 't':
822 intersect_mode ^= true;
823 redraw();
824 break;
825 case 'x':
826 ptLabels ^= true;
827 redraw();
828 break;
829 case 'y':
830 debug_xy ^= true;
831 redraw();
832 break;
833 case '-':
834 scale /= 2;
835 calcLeftTop();
836 redraw();
837 break;
838 case '=':
839 case '+':
840 scale *= 2;
841 calcLeftTop();
842 redraw();
843 break;
844 }
845}
846
847function calcXY() {
848 var e = window.event;
849 var tgt = e.target || e.srcElement;
850 var left = tgt.offsetLeft;
851 var top = tgt.offsetTop;
852 var unit = scale;
853 mouseX = (e.clientX - left) / scale + srcLeft;
854 mouseY = (e.clientY - top) / scale + srcTop;
855}
856
857function calcLeftTop() {
858 srcLeft = mouseX - screenWidth / 2 / scale;
859 srcTop = mouseY - screenHeight / 2 / scale;
860}
861
862function handleMouseClick() {
863 calcXY();
864 calcLeftTop();
865 redraw();
866}
867
868function handleMouseOver() {
869 calcXY();
870 var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
871 ctx.beginPath();
872 ctx.rect(300,100,200,10);
873 ctx.fillStyle="white";
874 ctx.fill();
875 ctx.fillStyle="black";
876 ctx.fillText(num, 300, 108);
877}
878
879function start() {
880 for (i = 0; i < testDivs.length; ++i) {
881 var title = testDivs[i].id.toString();
882 var str = testDivs[i].firstChild.data;
883 parse_debugShowActiveSpans(str, title);
caryclark@google.com0b7da432012-10-31 19:00:20 +0000884 parse_intersections(str, title);
caryclark@google.comf839c032012-10-26 21:03:50 +0000885 }
886 drawTop();
887 window.addEventListener('keypress', doKeyPress, true);
888 window.onresize = function() {
889 drawTop();
890 }
891}
892
893</script>
894</head>
895
896<body onLoad="start();">
897<canvas id="canvas" width="750" height="500"
898 onmousemove="handleMouseOver()"
899 onclick="handleMouseClick()"
900 ></canvas >
901</body>
902</html>