bc.htm revision 235f56a92f6eb6accbb243e11b3c45e3798f38f2
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"> 43bezier_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"> 46bezier_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"> 49bezier_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"> 52bezier_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"> 55bezier_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"> 58bezier_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> 87 88<script type="text/javascript"> 89 90var testDivs = [ 91 quad21g, 92 quad21a, 93 quad21b, 94 quad21c, 95 quad21d, 96 quad21e, 97 quad21f, 98 clip1, 99]; 100 101var scale, columns, rows, xStart, yStart; 102 103var ticks = 0.1; 104var at_x = 13 + 0.5; 105var at_y = 13 + 0.5; 106var decimal_places = 0; // make this 3 to show more precision 107 108var tests = []; 109var testTitles = []; 110var testIndex = 0; 111var ctx; 112var fat1 = true; 113var fat2 = false; 114 115function parse(test, title) { 116 var curveStrs = test.split("{{"); 117 if (curveStrs.length == 1) 118 curveStrs = test.split("=("); 119 var pattern = /[a-z$=]?-?\d+\.*\d*/g; 120 var curves = []; 121 for (var c in curveStrs) { 122 var curveStr = curveStrs[c]; 123 var points = curveStr.match(pattern); 124 var pts = []; 125 for (var wd in points) { 126 var num = parseFloat(points[wd]); 127 if (isNaN(num)) continue; 128 pts.push(num); 129 } 130 if (pts.length > 0) 131 curves.push(pts); 132 } 133 if (curves.length >= 2) { 134 tests.push(curves); 135 testTitles.push(title); 136 } 137} 138 139function init(test) { 140 var canvas = document.getElementById('canvas'); 141 if (!canvas.getContext) return; 142 canvas.width = window.innerWidth - at_x; 143 canvas.height = window.innerHeight - at_y; 144 ctx = canvas.getContext('2d'); 145 var xmin = Infinity; 146 var xmax = -Infinity; 147 var ymin = Infinity; 148 var ymax = -Infinity; 149 for (var curves in test) { 150 var curve = test[curves]; 151 var last = curve.length; 152 for (var idx = 0; idx < last; idx += 2) { 153 xmin = Math.min(xmin, curve[idx]); 154 xmax = Math.max(xmax, curve[idx]); 155 ymin = Math.min(ymin, curve[idx + 1]); 156 ymax = Math.max(ymax, curve[idx + 1]); 157 } 158 } 159 var subscale = 1; 160 if (xmax != xmin && ymax != ymin) { 161 while ((xmax - xmin) * subscale < 0.1 && (ymax - ymin) * subscale < 0.1) { 162 subscale *= 10; 163 if (subscale > 100000) { 164 break; 165 } 166 } 167 } 168 columns = Math.ceil(xmax) - Math.floor(xmin) + 1; 169 rows = Math.ceil(ymax) - Math.floor(ymin) + 1; 170 xStart = Math.floor(xmin); 171 yStart = Math.floor(ymin); 172 var hscale = ctx.canvas.width / columns / ticks; 173 var vscale = ctx.canvas.height / rows / ticks; 174 scale = Math.floor(Math.min(hscale, vscale)) * subscale; 175} 176 177function drawPoint(px, py, xoffset, yoffset, unit) { 178 var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places); 179 var _px = px * unit + xoffset; 180 var _py = py * unit + yoffset; 181 ctx.beginPath(); 182 ctx.arc(_px, _py, 3, 0, Math.PI*2, true); 183 ctx.closePath(); 184 ctx.fill(); 185 ctx.fillText(label, _px + 5, _py); 186} 187 188function draw(test, title, _at_x, _at_y, scale) { 189 ctx.fillStyle = "rgba(0,0,0, 0.1)"; 190 ctx.font = "normal 50px Arial"; 191 ctx.fillText(title, 50, 50); 192 ctx.font = "normal 10px Arial"; 193 194 var unit = scale * ticks; 195 ctx.lineWidth = 1; 196 var i; 197 for (i = 0; i <= rows * ticks; ++i) { 198 ctx.strokeStyle = (i % ticks) != 0 ? "rgb(160,160,160)" : "black"; 199 ctx.beginPath(); 200 ctx.moveTo(_at_x + 0, _at_y + i * scale); 201 ctx.lineTo(_at_x + unit * columns, _at_y + i * scale); 202 ctx.stroke(); 203 } 204 for (i = 0; i <= columns * ticks; ++i) { 205 ctx.strokeStyle = (i % ticks) != 0 ? "rgb(160,160,160)" : "black"; 206 ctx.beginPath(); 207 ctx.moveTo(_at_x + i * scale, _at_y + 0); 208 ctx.lineTo(_at_x + i * scale, _at_y + unit * rows); 209 ctx.stroke(); 210 } 211 212 var xoffset = xStart * -unit + _at_x; 213 var yoffset = yStart * -unit + _at_y; 214 215 ctx.fillStyle = "rgb(40,80,60)" 216 for (i = 0; i <= columns; i += (1 / ticks)) 217 { 218 num = (xoffset - _at_x) / -unit + i; 219 ctx.fillText(num.toFixed(0), i * unit + _at_y - 5, 10); 220 } 221 for (i = 0; i <= rows; i += (1 / ticks)) 222 { 223 num = (yoffset - _at_x) / -unit + i; 224 ctx.fillText(num.toFixed(0), 0, i * unit + _at_y + 0); 225 } 226 227 // draw curve 1 and 2 228 var curves, pts; 229 for (curves in test) { 230 var curve = test[curves]; 231 ctx.beginPath(); 232 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 233 switch (curve.length) { 234 case 6: 235 ctx.quadraticCurveTo( 236 xoffset + curve[2] * unit, yoffset + curve[3] * unit, 237 xoffset + curve[4] * unit, yoffset + curve[5] * unit); 238 break; 239 case 8: 240 ctx.bezierCurveTo( 241 xoffset + curve[2] * unit, yoffset + curve[3] * unit, 242 xoffset + curve[4] * unit, yoffset + curve[5] * unit, 243 xoffset + curve[6] * unit, yoffset + curve[7] * unit); 244 break; 245 } 246 if (curves == 2) ctx.strokeStyle = curves ? "red" : "blue"; 247 ctx.stroke(); 248 ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 249 ctx.beginPath(); 250 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 251 ctx.lineTo(xoffset + curve[2] * unit, yoffset + curve[3] * unit); 252 ctx.lineTo(xoffset + curve[4] * unit, yoffset + curve[5] * unit); 253 if (curve.length == 8) 254 ctx.lineTo(xoffset + curve[6] * unit, yoffset + curve[7] * unit); 255 ctx.stroke(); 256 } 257 // optionally draw fat lines for curve 258 if (fat1) 259 drawFat(test[0], xoffset, yoffset, unit); 260 if (fat2) 261 drawFat(test[1], xoffset, yoffset, unit); 262} 263 264function drawFat(curve, xoffset, yoffset, unit) { 265 var last = curve.length - 2; 266 ctx.strokeStyle = "rgba(0,0,0, 0.5)"; 267 ctx.beginPath(); 268 ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit); 269 ctx.lineTo(xoffset + curve[last] * unit, yoffset + curve[last + 1] * unit); 270 ctx.stroke(); 271 // draw line parallel to end points through control points 272 var dx = curve[last] - curve[0]; 273 var dy = curve[last + 1] - curve[1]; 274 drawParallelLine(curve[2], curve[3], dx, dy, xoffset, yoffset, unit); 275 if (curve.length == 8) 276 drawParallelLine(curve[4], curve[5], dx, dy, xoffset, yoffset, unit); 277} 278 279function drawParallelLine(x, y, dx, dy, xoffset, yoffset, unit) { 280 var x1 = x - dx; 281 var y1 = y - dy; 282 var x2 = x + dx; 283 var y2 = y + dy; 284 ctx.beginPath(); 285 ctx.moveTo(xoffset + x1 * unit, yoffset + y1 * unit); 286 ctx.lineTo(xoffset + x2 * unit, yoffset + y2 * unit); 287 ctx.stroke(); 288} 289 290function drawTop() { 291 init(tests[testIndex]); 292 redraw(); 293} 294 295function redraw() { 296 ctx.beginPath(); 297 ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height); 298 ctx.fillStyle="white"; 299 ctx.fill(); 300 draw(tests[testIndex], testTitles[testIndex], at_x, at_y, scale); 301} 302 303function doKeyPress(evt) { 304 var char = String.fromCharCode(evt.charCode); 305 switch (char) { 306 case 'f': 307 fat2 ^= true; 308 if (fat2 == false) 309 fat1 ^= true; 310 drawTop(); 311 break; 312 case 'N': 313 testIndex += 9; 314 case 'n': 315 if (++testIndex >= tests.length) 316 testIndex = 0; 317 mouseX = Infinity; 318 drawTop(); 319 break; 320 case 'P': 321 testIndex -= 9; 322 case 'p': 323 if (--testIndex < 0) 324 testIndex = tests.length - 1; 325 mouseX = Infinity; 326 drawTop(); 327 break; 328 } 329} 330 331function handleMouseClick() { 332} 333 334function handleMouseOver() { 335} 336 337function start() { 338 for (i = 0; i < testDivs.length; ++i) { 339 var title = testDivs[i].id.toString(); 340 var str = testDivs[i].firstChild.data; 341 parse(str, title); 342 } 343 drawTop(); 344 window.addEventListener('keypress', doKeyPress, true); 345 window.onresize = function() { 346 drawTop(); 347 } 348} 349 350</script> 351</head> 352 353<body onLoad="start();"> 354<canvas id="canvas" width="750" height="500" 355 onmousemove="handleMouseOver()" 356 onclick="handleMouseClick()" 357 ></canvas > 358</body> 359</html> 360