summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/experimental/Intersection/hg.htm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/experimental/Intersection/hg.htm')
-rw-r--r--chromium/third_party/skia/experimental/Intersection/hg.htm649
1 files changed, 649 insertions, 0 deletions
diff --git a/chromium/third_party/skia/experimental/Intersection/hg.htm b/chromium/third_party/skia/experimental/Intersection/hg.htm
new file mode 100644
index 00000000000..32f49a74469
--- /dev/null
+++ b/chromium/third_party/skia/experimental/Intersection/hg.htm
@@ -0,0 +1,649 @@
+<html>
+<head>
+<div style="height:0">
+
+<div id="cubic1">
+{{3.13,2.74}, {1.08,4.62}, {3.71,0.94}, {2.01,3.81}}
+{{6.71,3.14}, {7.99,2.75}, {8.27,1.96}, {6.35,3.57}}
+{{9.45,10.67}, {10.05,5.78}, {13.95,7.46}, {14.72,5.29}}
+{{3.34,8.98}, {1.95,10.27}, {3.76,7.65}, {4.96,10.64}}
+</div>
+
+</div>
+
+<script type="text/javascript">
+
+var testDivs = [
+ cubic1,
+];
+
+var scale, columns, rows, xStart, yStart;
+
+var ticks = 10;
+var at_x = 13 + 0.5;
+var at_y = 23 + 0.5;
+var decimal_places = 3;
+var tests = [];
+var testTitles = [];
+var testIndex = 0;
+var ctx;
+var minScale = 1;
+var subscale = 1;
+var curveT = -1;
+var xmin, xmax, ymin, ymax;
+
+var mouseX, mouseY;
+var mouseDown = false;
+
+var draw_deriviatives = false;
+var draw_endpoints = true;
+var draw_hodo = false;
+var draw_hodo2 = false;
+var draw_hodo_origin = true;
+var draw_midpoint = false;
+var draw_tangents = true;
+var draw_sequence = true;
+
+function parse(test, title) {
+ var curveStrs = test.split("{{");
+ if (curveStrs.length == 1)
+ curveStrs = test.split("=(");
+ var pattern = /[a-z$=]?-?\d+\.*\d*e?-?\d*/g;
+ var curves = [];
+ for (var c in curveStrs) {
+ var curveStr = curveStrs[c];
+ var points = curveStr.match(pattern);
+ var pts = [];
+ for (var wd in points) {
+ var num = parseFloat(points[wd]);
+ if (isNaN(num)) continue;
+ pts.push(num);
+ }
+ if (pts.length > 2)
+ curves.push(pts);
+ }
+ if (curves.length >= 1) {
+ tests.push(curves);
+ testTitles.push(title);
+ }
+}
+
+function init(test) {
+ var canvas = document.getElementById('canvas');
+ if (!canvas.getContext) return;
+ canvas.width = window.innerWidth - 20;
+ canvas.height = window.innerHeight - 20;
+ ctx = canvas.getContext('2d');
+ xmin = Infinity;
+ xmax = -Infinity;
+ ymin = Infinity;
+ ymax = -Infinity;
+ for (var curves in test) {
+ var curve = test[curves];
+ var last = curve.length;
+ for (var idx = 0; idx < last; idx += 2) {
+ xmin = Math.min(xmin, curve[idx]);
+ xmax = Math.max(xmax, curve[idx]);
+ ymin = Math.min(ymin, curve[idx + 1]);
+ ymax = Math.max(ymax, curve[idx + 1]);
+ }
+ }
+ xmin -= 1;
+ var testW = xmax - xmin;
+ var testH = ymax - ymin;
+ subscale = 1;
+ while (testW * subscale < 0.1 && testH * subscale < 0.1) {
+ subscale *= 10;
+ }
+ while (testW * subscale > 10 && testH * subscale > 10) {
+ subscale /= 10;
+ }
+ calcFromScale();
+}
+
+function hodograph(cubic) {
+ var hodo = [];
+ hodo[0] = 3 * (cubic[2] - cubic[0]);
+ hodo[1] = 3 * (cubic[3] - cubic[1]);
+ hodo[2] = 3 * (cubic[4] - cubic[2]);
+ hodo[3] = 3 * (cubic[5] - cubic[3]);
+ hodo[4] = 3 * (cubic[6] - cubic[4]);
+ hodo[5] = 3 * (cubic[7] - cubic[5]);
+ return hodo;
+}
+
+function hodograph2(cubic) {
+ var quad = hodograph(cubic);
+ var hodo = [];
+ hodo[0] = 2 * (quad[2] - quad[0]);
+ hodo[1] = 2 * (quad[3] - quad[1]);
+ hodo[2] = 2 * (quad[4] - quad[2]);
+ hodo[3] = 2 * (quad[5] - quad[3]);
+ return hodo;
+}
+
+function quadraticRootsReal(A, B, C, s) {
+ if (A == 0) {
+ if (B == 0) {
+ s[0] = 0;
+ return C == 0;
+ }
+ s[0] = -C / B;
+ return 1;
+ }
+ /* normal form: x^2 + px + q = 0 */
+ var p = B / (2 * A);
+ var q = C / A;
+ var p2 = p * p;
+ if (p2 < q) {
+ return 0;
+ }
+ var sqrt_D = 0;
+ if (p2 > q) {
+ sqrt_D = sqrt(p2 - q);
+ }
+ s[0] = sqrt_D - p;
+ s[1] = -sqrt_D - p;
+ return 1 + s[0] != s[1];
+}
+
+function add_valid_ts(s, realRoots, t) {
+ var foundRoots = 0;
+ for (var index = 0; index < realRoots; ++index) {
+ var tValue = s[index];
+ if (tValue >= 0 && tValue <= 1) {
+ for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
+ if (t[idx2] != tValue) {
+ t[foundRoots++] = tValue;
+ }
+ }
+ }
+ }
+ return foundRoots;
+}
+
+function quadraticRootsValidT(a, b, c, t) {
+ var s = [];
+ var realRoots = quadraticRootsReal(A, B, C, s);
+ var foundRoots = add_valid_ts(s, realRoots, t);
+ return foundRoots != 0;
+}
+
+function find_cubic_inflections(cubic, tValues)
+{
+ var Ax = src[2] - src[0];
+ var Ay = src[3] - src[1];
+ var Bx = src[4] - 2 * src[2] + src[0];
+ var By = src[5] - 2 * src[3] + src[1];
+ var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
+ var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
+ return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
+ Ax * By - Ay * Bx, tValues);
+}
+
+function dx_at_t(cubic, t) {
+ var one_t = 1 - t;
+ var a = cubic[0];
+ var b = cubic[2];
+ var c = cubic[4];
+ var d = cubic[6];
+ return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
+}
+
+function dy_at_t(cubic, t) {
+ var one_t = 1 - t;
+ var a = cubic[1];
+ var b = cubic[3];
+ var c = cubic[5];
+ var d = cubic[7];
+ return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
+}
+
+function x_at_t(cubic, t) {
+ var one_t = 1 - t;
+ var one_t2 = one_t * one_t;
+ var a = one_t2 * one_t;
+ var b = 3 * one_t2 * t;
+ var t2 = t * t;
+ var c = 3 * one_t * t2;
+ var d = t2 * t;
+ return a * cubic[0] + b * cubic[2] + c * cubic[4] + d * cubic[6];
+}
+
+function y_at_t(cubic, t) {
+ var one_t = 1 - t;
+ var one_t2 = one_t * one_t;
+ var a = one_t2 * one_t;
+ var b = 3 * one_t2 * t;
+ var t2 = t * t;
+ var c = 3 * one_t * t2;
+ var d = t2 * t;
+ return a * cubic[1] + b * cubic[3] + c * cubic[5] + d * cubic[7];
+}
+
+function calcFromScale() {
+ xStart = Math.floor(xmin * subscale) / subscale;
+ yStart = Math.floor(ymin * subscale) / subscale;
+ var xEnd = Math.ceil(xmin * subscale) / subscale;
+ var yEnd = Math.ceil(ymin * subscale) / subscale;
+ var cCelsW = Math.floor(ctx.canvas.width / 10);
+ var cCelsH = Math.floor(ctx.canvas.height / 10);
+ var testW = xEnd - xStart;
+ var testH = yEnd - yStart;
+ var scaleWH = 1;
+ while (cCelsW > testW * scaleWH * 10 && cCelsH > testH * scaleWH * 10) {
+ scaleWH *= 10;
+ }
+ while (cCelsW * 10 < testW * scaleWH && cCelsH * 10 < testH * scaleWH) {
+ scaleWH /= 10;
+ }
+
+ columns = Math.ceil(xmax * subscale) - Math.floor(xmin * subscale) + 1;
+ rows = Math.ceil(ymax * subscale) - Math.floor(ymin * subscale) + 1;
+
+ var hscale = ctx.canvas.width / columns / ticks;
+ var vscale = ctx.canvas.height / rows / ticks;
+ minScale = Math.floor(Math.min(hscale, vscale));
+ scale = minScale * subscale;
+}
+
+function drawLine(x1, y1, x2, y2) {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ ctx.beginPath();
+ ctx.moveTo(xoffset + x1 * unit, yoffset + y1 * unit);
+ ctx.lineTo(xoffset + x2 * unit, yoffset + y2 * unit);
+ ctx.stroke();
+}
+
+function drawPoint(px, py) {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ var _px = px * unit + xoffset;
+ var _py = py * unit + yoffset;
+ ctx.beginPath();
+ ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
+ ctx.closePath();
+ ctx.stroke();
+}
+
+function drawPointSolid(px, py) {
+ drawPoint(px, py);
+ ctx.fillStyle = "rgba(0,0,0, 0.4)";
+ ctx.fill();
+}
+
+function drawLabel(num, px, py) {
+ ctx.beginPath();
+ ctx.arc(px, py, 8, 0, Math.PI*2, true);
+ ctx.closePath();
+ ctx.strokeStyle = "rgba(0,0,0, 0.4)";
+ ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
+ ctx.stroke();
+ ctx.fillStyle = "black";
+ ctx.font = "normal 10px Arial";
+ // ctx.rotate(0.001);
+ ctx.fillText(num, px - 2, py + 3);
+ // ctx.rotate(-0.001);
+}
+
+function drawLabelX(ymin, num, loc) {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ var px = loc * unit + xoffset;
+ var py = ymin * unit + yoffset - 20;
+ drawLabel(num, px, py);
+}
+
+function drawLabelY(xmin, num, loc) {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ var px = xmin * unit + xoffset - 20;
+ var py = loc * unit + yoffset;
+ drawLabel(num, px, py);
+}
+
+function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
+ ctx.beginPath();
+ ctx.moveTo(hx, hy - 100);
+ ctx.lineTo(hx, hy);
+ ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(hx, hy);
+ ctx.lineTo(hx, hy + 100);
+ ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(hx - 100, hy);
+ ctx.lineTo(hx, hy);
+ ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(hx, hy);
+ ctx.lineTo(hx + 100, hy);
+ ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
+ ctx.stroke();
+}
+
+function logCurves(test) {
+ for (curves in test) {
+ var curve = test[curves];
+ if (curve.length != 8) {
+ continue;
+ }
+ var str = "{{";
+ for (i = 0; i < 8; i += 2) {
+ str += curve[i].toFixed(2) + "," + curve[i + 1].toFixed(2);
+ if (i < 6) {
+ str += "}, {";
+ }
+ }
+ str += "}}";
+ console.log(str);
+ }
+}
+
+function scalexy(x, y, mag) {
+ var length = Math.sqrt(x * x + y * y);
+ return mag / length;
+}
+
+function drawArrow(x, y, dx, dy) {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ var dscale = scalexy(dx, dy, 1);
+ dx *= dscale;
+ dy *= dscale;
+ ctx.beginPath();
+ ctx.moveTo(xoffset + x * unit, yoffset + y * unit);
+ x += dx;
+ y += dy;
+ ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
+ dx /= 10;
+ dy /= 10;
+ ctx.lineTo(xoffset + (x - dy) * unit, yoffset + (y + dx) * unit);
+ ctx.lineTo(xoffset + (x + dx * 2) * unit, yoffset + (y + dy * 2) * unit);
+ ctx.lineTo(xoffset + (x + dy) * unit, yoffset + (y - dx) * unit);
+ ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
+ ctx.strokeStyle = "rgba(0,75,0, 0.4)";
+ ctx.stroke();
+}
+
+function draw(test, title) {
+ ctx.fillStyle = "rgba(0,0,0, 0.1)";
+ ctx.font = "normal 50px Arial";
+ ctx.fillText(title, 50, 50);
+ ctx.font = "normal 10px Arial";
+ var unit = scale * ticks;
+ // ctx.lineWidth = "1.001"; "0.999";
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+
+ for (curves in test) {
+ var curve = test[curves];
+ if (curve.length != 8) {
+ continue;
+ }
+ ctx.lineWidth = 1;
+ if (draw_tangents) {
+ ctx.strokeStyle = "rgba(0,0,255, 0.3)";
+ drawLine(curve[0], curve[1], curve[2], curve[3]);
+ drawLine(curve[2], curve[3], curve[4], curve[5]);
+ drawLine(curve[4], curve[5], curve[6], curve[7]);
+ }
+ if (draw_deriviatives) {
+ var dx = dx_at_t(curve, 0);
+ var dy = dy_at_t(curve, 0);
+ drawArrow(curve[0], curve[1], dx, dy);
+ dx = dx_at_t(curve, 1);
+ dy = dy_at_t(curve, 1);
+ drawArrow(curve[6], curve[7], dx, dy);
+ if (draw_midpoint) {
+ var midX = x_at_t(curve, 0.5);
+ var midY = y_at_t(curve, 0.5);
+ dx = dx_at_t(curve, 0.5);
+ dy = dy_at_t(curve, 0.5);
+ drawArrow(midX, midY, dx, dy);
+ }
+ }
+ ctx.beginPath();
+ ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit);
+ ctx.bezierCurveTo(
+ xoffset + curve[2] * unit, yoffset + curve[3] * unit,
+ xoffset + curve[4] * unit, yoffset + curve[5] * unit,
+ xoffset + curve[6] * unit, yoffset + curve[7] * unit);
+ ctx.strokeStyle = "black";
+ ctx.stroke();
+ if (draw_endpoints) {
+ drawPoint(curve[0], curve[1]);
+ drawPoint(curve[2], curve[3]);
+ drawPoint(curve[4], curve[5]);
+ drawPoint(curve[6], curve[7]);
+ }
+ if (draw_midpoint) {
+ var midX = x_at_t(curve, 0.5);
+ var midY = y_at_t(curve, 0.5);
+ drawPointSolid(midX, midY);
+ }
+ if (draw_hodo) {
+ var hodo = hodograph(curve);
+ var hMinX = Math.min(0, hodo[0], hodo[2], hodo[4]);
+ var hMinY = Math.min(0, hodo[1], hodo[3], hodo[5]);
+ var hMaxX = Math.max(0, hodo[0], hodo[2], hodo[4]);
+ var hMaxY = Math.max(0, hodo[1], hodo[3], hodo[5]);
+ var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
+ var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
+ var hUnit = Math.min(hScaleX, hScaleY);
+ hUnit /= 2;
+ var hx = xoffset - hMinX * hUnit;
+ var hy = yoffset - hMinY * hUnit;
+ ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
+ ctx.quadraticCurveTo(
+ hx + hodo[2] * hUnit, hy + hodo[3] * hUnit,
+ hx + hodo[4] * hUnit, hy + hodo[5] * hUnit);
+ ctx.strokeStyle = "red";
+ ctx.stroke();
+ if (draw_hodo_origin) {
+ drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
+ }
+ }
+ if (draw_hodo2) {
+ var hodo = hodograph2(curve);
+ var hMinX = Math.min(0, hodo[0], hodo[2]);
+ var hMinY = Math.min(0, hodo[1], hodo[3]);
+ var hMaxX = Math.max(0, hodo[0], hodo[2]);
+ var hMaxY = Math.max(0, hodo[1], hodo[3]);
+ var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
+ var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
+ var hUnit = Math.min(hScaleX, hScaleY);
+ hUnit /= 2;
+ var hx = xoffset - hMinX * hUnit;
+ var hy = yoffset - hMinY * hUnit;
+ ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
+ ctx.lineTo(hx + hodo[2] * hUnit, hy + hodo[3] * hUnit);
+ ctx.strokeStyle = "red";
+ ctx.stroke();
+ drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
+ }
+ if (draw_sequence) {
+ var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
+ for (var i = 0; i < 8; i+= 2) {
+ drawLabelX(ymin, i >> 1, curve[i]);
+ }
+ var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
+ for (var i = 1; i < 8; i+= 2) {
+ drawLabelY(xmin, i >> 1, curve[i]);
+ }
+ }
+ }
+}
+
+function drawTop() {
+ init(tests[testIndex]);
+ redraw();
+}
+
+function redraw() {
+ ctx.beginPath();
+ ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.fillStyle="white";
+ ctx.fill();
+ draw(tests[testIndex], testTitles[testIndex]);
+}
+
+function doKeyPress(evt) {
+ var char = String.fromCharCode(evt.charCode);
+ switch (char) {
+ case '2':
+ draw_hodo2 ^= true;
+ redraw();
+ break;
+ case 'd':
+ draw_deriviatives ^= true;
+ redraw();
+ break;
+ case 'e':
+ draw_endpoints ^= true;
+ redraw();
+ break;
+ case 'h':
+ draw_hodo ^= true;
+ redraw();
+ break;
+ case 'N':
+ testIndex += 9;
+ case 'n':
+ if (++testIndex >= tests.length)
+ testIndex = 0;
+ drawTop();
+ break;
+ case 'l':
+ logCurves(tests[testIndex]);
+ break;
+ case 'm':
+ draw_midpoint ^= true;
+ redraw();
+ break;
+ case 'o':
+ draw_hodo_origin ^= true;
+ redraw();
+ break;
+ case 'P':
+ testIndex -= 9;
+ case 'p':
+ if (--testIndex < 0)
+ testIndex = tests.length - 1;
+ drawTop();
+ break;
+ case 's':
+ draw_sequence ^= true;
+ redraw();
+ break;
+ case 't':
+ draw_tangents ^= true;
+ redraw();
+ break;
+ }
+}
+
+function calcXY() {
+ var e = window.event;
+ var tgt = e.target || e.srcElement;
+ var left = tgt.offsetLeft;
+ var top = tgt.offsetTop;
+ var unit = scale * ticks;
+ mouseX = (e.clientX - left - Math.ceil(at_x) + 1) / unit + xStart;
+ mouseY = (e.clientY - top - Math.ceil(at_y)) / unit + yStart;
+}
+
+var lastX, lastY;
+var activeCurve = [];
+var activePt;
+
+function handleMouseClick() {
+ calcXY();
+}
+
+function initDown() {
+ var unit = scale * ticks;
+ var xoffset = xStart * -unit + at_x;
+ var yoffset = yStart * -unit + at_y;
+ var test = tests[testIndex];
+ var bestDistance = 1000000;
+ activePt = -1;
+ for (curves in test) {
+ var testCurve = test[curves];
+ if (testCurve.length != 8) {
+ continue;
+ }
+ for (var i = 0; i < 8; i += 2) {
+ var testX = testCurve[i];
+ var testY = testCurve[i + 1];
+ var dx = testX - mouseX;
+ var dy = testY - mouseY;
+ var dist = dx * dx + dy * dy;
+ if (dist > bestDistance) {
+ continue;
+ }
+ activeCurve = testCurve;
+ activePt = i;
+ bestDistance = dist;
+ }
+ }
+ if (activePt >= 0) {
+ lastX = mouseX;
+ lastY = mouseY;
+ }
+}
+
+function handleMouseOver() {
+ if (!mouseDown) {
+ activePt = -1;
+ return;
+ }
+ calcXY();
+ if (activePt < 0) {
+ initDown();
+ return;
+ }
+ var unit = scale * ticks;
+ var deltaX = (mouseX - lastX) /* / unit */;
+ var deltaY = (mouseY - lastY) /*/ unit */;
+ lastX = mouseX;
+ lastY = mouseY;
+ activeCurve[activePt] += deltaX;
+ activeCurve[activePt + 1] += deltaY;
+ redraw();
+}
+
+function start() {
+ for (i = 0; i < testDivs.length; ++i) {
+ var title = testDivs[i].id.toString();
+ var str = testDivs[i].firstChild.data;
+ parse(str, title);
+ }
+ drawTop();
+ window.addEventListener('keypress', doKeyPress, true);
+ window.onresize = function() {
+ drawTop();
+ }
+}
+
+</script>
+</head>
+
+<body onLoad="start();">
+<canvas id="canvas" width="750" height="500"
+ onmousedown="mouseDown = true"
+ onmouseup="mouseDown = false"
+ onmousemove="handleMouseOver()"
+ onclick="handleMouseClick()"
+ ></canvas >
+</body>
+</html>