1 <!-- bezier clip visualizer --> 2 <html> 3 <head> 4 <div style="height:0"> 5 6 <div id="clip1"> 7 (gdb) p smaller 8 $2 = {{ 9 x = 0.91292418204644155, 10 y = 0.41931201426549197 11 }, { 12 x = 0.70491388044579517, 13 y = 0.64754305977710236 14 }, { 15 x = 0, 16 y = 1 17 }} 18 (gdb) p larger 19 $3 = {{ 20 x = 0.21875, 21 y = 0.765625 22 }, { 23 x = 0.125, 24 y = 0.875 25 }, { 26 x = 0, 27 y = 1 28 }} 29 (gdb) p distance2y 30 $1 = {{ 31 x = 0, 32 y = 0.080355482722450078 33 }, { 34 x = 0.5, 35 y = 0.038383741101172597 36 }, { 37 x = 1, 38 y = 0 39 }} 40 </div> 41 42 <div id="quad21a"> 43 bezier_clip q1=(0,0 1,0 0,2) q2=(0.5,0.25 0.5,0.5 0,1) minT=0 maxT=1 44 </div> 45 <div id="quad21b"> 46 bezier_clip q1=(0.5,0.25 0.5,0.375 0.375,0.5625) q2=(0,0 1,0 0,2) minT=0.3 maxT=0.78125 47 </div> 48 <div id="quad21c"> 49 bezier_clip q1=(0.42,0.18 0.6125,0.46875 0.341796875,1.22070312) q2=(0.5,0.25 0.5,0.375 0.375,0.5625) minT=0 maxT=0.926710098 50 </div> 51 <div id="quad21d"> 52 bezier_clip q1=(0.5,0.25 0.5,0.307919381 0.473162762,0.379257381) q2=(0.42,0.18 0.6125,0.46875 0.341796875,1.22070312) minT=0.187231244 maxT=0.729263299 53 </div> 54 <div id="quad21e"> 55 bezier_clip q1=(0.475846194,0.304363878 0.53317904,0.507883959 0.454423387,0.847492538) q2=(0.5,0.25 0.5,0.307919381 0.473162762,0.379257381) minT=0 maxT=1 56 </div> 57 <div id="quad21f"> 58 bezier_clip q1=(0.493290691,0.311274036 0.486581381,0.343588381 0.473162762,0.379257381) q2=(0.475846194,0.304363878 0.53317904,0.507883959 0.454423387,0.847492538) minT=0.0828748517 maxT=0.150086861 59 </div> 60 61 <div id="quad21g"> 62 (gdb) p smaller 63 $1 = {{ 64 x = 0.48441440743366754, 65 y = 0.33903196011243797 66 }, { 67 x = 0.48750982503868118, 68 y = 0.35346899178071778 69 }, { 70 x = 0.48999046908865357, 71 y = 0.368520797004039 72 }} 73 (gdb) p larger 74 $2 = {{ 75 x = 0.49329069058425024, 76 y = 0.31127403581536672 77 }, { 78 x = 0.48658138116850047, 79 y = 0.34358838107698753 80 }, { 81 x = 0.47316276233700094, 82 y = 0.37925738104648321 83 }} 84 </div> 85 86 <div id="quad36"> 87 (gdb) p fQ 88 $2 = {{ 89 x = 1.8883839294261275, 90 y = 2.1108590606904345 91 }, { 92 x = 1.888463903363252, 93 y = 2.1111576060205435 94 }, { 95 x = 1.8885438199983176, 96 y = 2.1114561800016824 97 }} 98 (gdb) p rh.fQ 99 $3 = {{ 100 x = 1.8883839294260976, 101 y = 2.1108590606903377 102 }, { 103 x = 1.8886366953645748, 104 y = 2.1109850143489544 105 }, { 106 x = 1.8888888888888888, 107 y = 2.1111111111111112 108 }} 109 (gdb) 110 </div> 111 112 <div id="quad37"> 113 {{x = 360.048828125, y = 229.2578125}, {x = 360.048828125, y = 224.4140625}, {x = 362.607421875, y = 221.3671875}} 114 {{x = 362.607421875, y = 221.3671875}, {x = 365.166015625, y = 218.3203125}, {x = 369.228515625, y = 218.3203125}} 115 </div> 116 117 <div id="quad38"> 118 $2 = {{fX = 369.969421, fY = 137.94809}, {fX = 383.982849, fY = 121.260353}, {fX = 406.233154, fY = 121.260353}} 119 $4 = {{fX = 406.232788, fY = 121.260353}, {fX = 409.441956, fY = 121.260353}, {fX = 412.972046, fY = 121.795212}} 120 </div> 121 122 <div id="quad39"> 123 {{x = 406.233154296875, y = 121.26035308837891}, {x = 406.23153587045397, y = 121.26035308837891}, {x = 406.22991748761177, y = 121.26035317666889}}, 124 {{x = 406.23295158013377, y = 121.26035308872596}, {x = 406.2328698329315, y = 121.26035308837889}, {x = 406.2327880859375, y = 121.26035308837891}}, 125 </div> 126 127 </div> 128 129 <script type="text/javascript"> 130 131 var testDivs = [ 132 quad56, 133 quad39, 134 quad38, 135 quad37, 136 quad36, 137 quad21g, 138 quad21a, 139 quad21b, 140 quad21c, 141 quad21d, 142 quad21e, 143 quad21f, 144 clip1, 145 ]; 146 147 var scale, columns, rows, xStart, yStart; 148 149 var ticks = 10; 150 var at_x = 13 + 0.5; 151 var at_y = 13 + 0.5; 152 var init_decimal_places = 1; // make this 3 to show more precision 153 var decimal_places; 154 var tests = []; 155 var testTitles = []; 156 var testIndex = 0; 157 var ctx; 158 var fat1 = true; 159 var fat2 = false; 160 var ctl1 = true; 161 var ctl2 = false; 162 var ctlPts1 = true; 163 var ctlPts2 = false; 164 var minScale = 1; 165 var subscale = 1; 166 167 function parse(test, title) { 168 var curveStrs = test.split("{{"); 169 if (curveStrs.length == 1) 170 curveStrs = test.split("=("); 171 var pattern = /[a-z$=]?-?\d+\.*\d*/g; 172 var curves = []; 173 for (var c in curveStrs) { 174 var curveStr = curveStrs[c]; 175 var points = curveStr.match(pattern); 176 var pts = []; 177 for (var wd in points) { 178 var num = parseFloat(points[wd]); 179 if (isNaN(num)) continue; 180 pts.push(num); 181 } 182 if (pts.length > 0) 183 curves.push(pts); 184 } 185 if (curves.length >= 2) { 186 tests.push(curves); 187 testTitles.push(title); 188 } 189 } 190 191 function init(test) { 192 var canvas = document.getElementById('canvas'); 193 if (!canvas.getContext) return; 194 canvas.width = window.innerWidth - at_x; 195 canvas.height = window.innerHeight - at_y; 196 ctx = canvas.getContext('2d'); 197 var xmin = Infinity; 198 var xmax = -Infinity; 199 var ymin = Infinity; 200 var ymax = -Infinity; 201 for (var curves in test) { 202 var curve = test[curves]; 203 var last = curve.length; 204 for (var idx = 0; idx < last; idx += 2) { 205 xmin = Math.min(xmin, curve[idx]); 206 xmax = Math.max(xmax, curve[idx]); 207 ymin = Math.min(ymin, curve[idx + 1]); 208 ymax = Math.max(ymax, curve[idx + 1]); 209 } 210 } 211 subscale = 1; 212 decimal_places = init_decimal_places; 213 if (xmax != xmin && ymax != ymin) { 214 while ((xmax - xmin) * subscale < 0.1 && (ymax - ymin) * subscale < 0.1) { 215 subscale *= 10; 216 decimal_places += 1; 217 // if (subscale > 100000) { 218 // break; 219 // } 220 } 221 } 222 columns = Math.ceil(xmax * subscale) - Math.floor(xmin * subscale) + 1; 223 rows = Math.ceil(ymax * subscale) - Math.floor(ymin * subscale) + 1; 224 225 xStart = Math.floor(xmin * subscale) / subscale; 226 yStart = Math.floor(ymin * subscale) / subscale; 227 var hscale = ctx.canvas.width / columns / ticks; 228 var vscale = ctx.canvas.height / rows / ticks; 229 minScale = Math.floor(Math.min(hscale, vscale)); 230 scale = minScale * subscale; 231 // while (columns < 1000 && rows < 1000) { 232 // columns *= 2; 233 // rows *= 2; 234 // } 235 } 236 237 function drawPoint(px, py, xoffset, yoffset, unit) { 238 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places); 239 var _px = px * unit + xoffset; 240 var _py = py * unit + yoffset; 241 ctx.beginPath(); 242 ctx.arc(_px, _py, 3, 0, Math.PI*2, true); 243 ctx.closePath(); 244 ctx.fill(); 245 ctx.fillText(label, _px + 5, _py); 246 } 247 248 function draw(test, title, _at_x, _at_y, scale) { 249 ctx.fillStyle = "rgba(0,0,0, 0.1)"; 250 ctx.font = "normal 50px Arial"; 251 ctx.fillText(title, 50, 50); 252 ctx.font = "normal 10px Arial"; 253 254 var unit = scale * ticks; 255 ctx.lineWidth = 1; 256 var i; 257 for (i = 0; i <= rows * ticks; ++i) { 258 ctx.strokeStyle = (i % ticks) != 0 ? "rgb(160,160,160)" : "black"; 259 ctx.beginPath(); 260 ctx.moveTo(_at_x + 0, _at_y + i * minScale); 261 ctx.lineTo(_at_x + unit * columns, _at_y + i * minScale); 262 ctx.stroke(); 263 } 264 for (i = 0; i <= columns * ticks; ++i) { 265 ctx.strokeStyle = (i % ticks) != 0 ? "rgb(160,160,160)" : "black"; 266 ctx.beginPath(); 267 ctx.moveTo(_at_x + i * minScale, _at_y + 0); 268 ctx.lineTo(_at_x + i * minScale, _at_y + unit * rows); 269 ctx.stroke(); 270 } 271 272 var xoffset = xStart * -unit + _at_x; 273 var yoffset = yStart * -unit + _at_y; 274 275 ctx.fillStyle = "rgb(40,80,60)" 276 for (i = 0; i <= columns; i += (1 / ticks)) 277 { 278 num = xStart + i / subscale; 279 ctx.fillText(num.toFixed(decimal_places), xoffset + num * unit - 5, 10); 280 } 281 for (i = 0; i <= rows; i += (1 / ticks)) 282 { 283 num = yStart + i / subscale; 284 ctx.fillText(num.toFixed(decimal_places), 0, yoffset + num * unit + 0); 285 } 286 287 // draw curve 1 and 2 288 var curves, pts; 289 for (curves in test) { 290 var curve = test[curves]; 291 ctx.beginPath(); 292 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 293 switch (curve.length) { 294 case 6: 295 ctx.quadraticCurveTo( 296 xoffset + curve[2] * unit, yoffset + curve[3] * unit, 297 xoffset + curve[4] * unit, yoffset + curve[5] * unit); 298 break; 299 case 8: 300 ctx.bezierCurveTo( 301 xoffset + curve[2] * unit, yoffset + curve[3] * unit, 302 xoffset + curve[4] * unit, yoffset + curve[5] * unit, 303 xoffset + curve[6] * unit, yoffset + curve[7] * unit); 304 break; 305 } 306 if (curves == 2) ctx.strokeStyle = curves ? "red" : "blue"; 307 ctx.stroke(); 308 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 309 ctx.beginPath(); 310 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 311 ctx.lineTo(xoffset + curve[2] * unit, yoffset + curve[3] * unit); 312 ctx.lineTo(xoffset + curve[4] * unit, yoffset + curve[5] * unit); 313 if (curve.length == 8) 314 ctx.lineTo(xoffset + curve[6] * unit, yoffset + curve[7] * unit); 315 ctx.stroke(); 316 } 317 // optionally draw fat lines for curve 318 if (fat1) 319 drawFat(test[0], xoffset, yoffset, unit); 320 if (fat2) 321 drawFat(test[1], xoffset, yoffset, unit); 322 if (ctl1) 323 drawCtl(test[0], xoffset, yoffset, unit); 324 if (ctl2) 325 drawCtl(test[1], xoffset, yoffset, unit); 326 if (ctlPts1) 327 drawCtlPts(test[0], xoffset, yoffset, unit); 328 if (ctlPts2) 329 drawCtlPts(test[1], xoffset, yoffset, unit); 330 } 331 332 function drawCtl(curve, xoffset, yoffset, unit) { 333 var last = curve.length - 2; 334 ctx.strokeStyle = "rgba(0,0,0, 0.5)"; 335 ctx.beginPath(); 336 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 337 ctx.lineTo(xoffset + curve[2] * unit, yoffset + curve[3] * unit); 338 ctx.lineTo(xoffset + curve[4] * unit, yoffset + curve[5] * unit); 339 ctx.stroke(); 340 } 341 342 function drawCtlPts(curve, xoffset, yoffset, unit) { 343 drawPoint(curve[0], curve[1], xoffset, yoffset, unit); 344 drawPoint(curve[2], curve[3], xoffset, yoffset, unit); 345 drawPoint(curve[4], curve[5], xoffset, yoffset, unit); 346 } 347 348 function drawFat(curve, xoffset, yoffset, unit) { 349 var last = curve.length - 2; 350 ctx.strokeStyle = "rgba(0,0,0, 0.5)"; 351 ctx.beginPath(); 352 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 353 ctx.lineTo(xoffset + curve[last] * unit, yoffset + curve[last + 1] * unit); 354 ctx.stroke(); 355 // draw line parallel to end points through control points 356 var dx = curve[last] - curve[0]; 357 var dy = curve[last + 1] - curve[1]; 358 drawParallelLine(curve[2], curve[3], dx, dy, xoffset, yoffset, unit); 359 if (curve.length == 8) 360 drawParallelLine(curve[4], curve[5], dx, dy, xoffset, yoffset, unit); 361 } 362 363 function drawParallelLine(x, y, dx, dy, xoffset, yoffset, unit) { 364 var x1 = x - dx; 365 var y1 = y - dy; 366 var x2 = x + dx; 367 var y2 = y + dy; 368 ctx.beginPath(); 369 ctx.moveTo(xoffset + x1 * unit, yoffset + y1 * unit); 370 ctx.lineTo(xoffset + x2 * unit, yoffset + y2 * unit); 371 ctx.stroke(); 372 } 373 374 function drawTop() { 375 init(tests[testIndex]); 376 redraw(); 377 } 378 379 function redraw() { 380 ctx.beginPath(); 381 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height); 382 ctx.fillStyle="white"; 383 ctx.fill(); 384 draw(tests[testIndex], testTitles[testIndex], at_x, at_y, scale); 385 } 386 387 function doKeyPress(evt) { 388 var char = String.fromCharCode(evt.charCode); 389 switch (char) { 390 case 'c': 391 ctl2 ^= true; 392 if (ctl2 == false) 393 ctl1 ^= true; 394 drawTop(); 395 break; 396 case 'd': 397 ctlPts2 ^= true; 398 if (ctlPts2 == false) 399 ctlPts1 ^= true; 400 drawTop(); 401 break; 402 case 'f': 403 fat2 ^= true; 404 if (fat2 == false) 405 fat1 ^= true; 406 drawTop(); 407 break; 408 case 'N': 409 testIndex += 9; 410 case 'n': 411 if (++testIndex >= tests.length) 412 testIndex = 0; 413 mouseX = Infinity; 414 drawTop(); 415 break; 416 case 'P': 417 testIndex -= 9; 418 case 'p': 419 if (--testIndex < 0) 420 testIndex = tests.length - 1; 421 mouseX = Infinity; 422 drawTop(); 423 break; 424 } 425 } 426 427 function handleMouseClick() { 428 } 429 430 function handleMouseOver() { 431 } 432 433 function start() { 434 for (i = 0; i < testDivs.length; ++i) { 435 var title = testDivs[i].id.toString(); 436 var str = testDivs[i].firstChild.data; 437 parse(str, title); 438 } 439 drawTop(); 440 window.addEventListener('keypress', doKeyPress, true); 441 window.onresize = function() { 442 drawTop(); 443 } 444 } 445 446 </script> 447 </head> 448 449 <body onLoad="start();"> 450 <canvas id="canvas" width="750" height="500" 451 onmousemove="handleMouseOver()" 452 onclick="handleMouseClick()" 453 ></canvas > 454 </body> 455 </html> 456