1cb93a386Sopenharmony_ci<!DOCTYPE html> 2cb93a386Sopenharmony_ci 3cb93a386Sopenharmony_ci<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 4cb93a386Sopenharmony_ci<head> 5cb93a386Sopenharmony_ci <meta charset="utf-8" /> 6cb93a386Sopenharmony_ci <title></title> 7cb93a386Sopenharmony_ci<div style="height:0"> 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci <div id="cubics"> 10cb93a386Sopenharmony_ci{{{fX=124.70011901855469 fY=9.3718261718750000 } {fX=124.66775026544929 fY=9.3744316215161234 } {fX=124.63530969619751 fY=9.3770743012428284 }{fX=124.60282897949219 fY=9.3797206878662109 } id=10 11cb93a386Sopenharmony_ci{{{fX=124.70011901855469 fY=9.3718004226684570 } {fX=124.66775026544929 fY=9.3744058723095804 } {fX=124.63530969619751 fY=9.3770485520362854 } {fX=124.60282897949219 fY=9.3796949386596680 } id=1 12cb93a386Sopenharmony_ci{{{fX=124.70011901855469 fY=9.3718004226684570 } {fX=124.66786243087600 fY=9.3743968522034287 } {fX=124.63553249625420 fY=9.3770303056986286 } {fX=124.60316467285156 fY=9.3796672821044922 } id=2 13cb93a386Sopenharmony_ci </div> 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci </div> 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci<script type="text/javascript"> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci var testDivs = [ 20cb93a386Sopenharmony_ci cubics, 21cb93a386Sopenharmony_ci ]; 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci var decimal_places = 3; 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci var tests = []; 26cb93a386Sopenharmony_ci var testTitles = []; 27cb93a386Sopenharmony_ci var testIndex = 0; 28cb93a386Sopenharmony_ci var ctx; 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci var subscale = 1; 31cb93a386Sopenharmony_ci var xmin, xmax, ymin, ymax; 32cb93a386Sopenharmony_ci var hscale, vscale; 33cb93a386Sopenharmony_ci var hinitScale, vinitScale; 34cb93a386Sopenharmony_ci var uniformScale = true; 35cb93a386Sopenharmony_ci var mouseX, mouseY; 36cb93a386Sopenharmony_ci var mouseDown = false; 37cb93a386Sopenharmony_ci var srcLeft, srcTop; 38cb93a386Sopenharmony_ci var screenWidth, screenHeight; 39cb93a386Sopenharmony_ci var drawnPts; 40cb93a386Sopenharmony_ci var curveT = 0; 41cb93a386Sopenharmony_ci var curveW = -1; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci var lastX, lastY; 44cb93a386Sopenharmony_ci var activeCurve = []; 45cb93a386Sopenharmony_ci var activePt; 46cb93a386Sopenharmony_ci var ids = []; 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci var focus_on_selection = 0; 49cb93a386Sopenharmony_ci var draw_t = false; 50cb93a386Sopenharmony_ci var draw_w = false; 51cb93a386Sopenharmony_ci var draw_closest_t = false; 52cb93a386Sopenharmony_ci var draw_cubic_red = false; 53cb93a386Sopenharmony_ci var draw_derivative = false; 54cb93a386Sopenharmony_ci var draw_endpoints = 2; 55cb93a386Sopenharmony_ci var draw_id = 0; 56cb93a386Sopenharmony_ci var draw_midpoint = 0; 57cb93a386Sopenharmony_ci var draw_mouse_xy = false; 58cb93a386Sopenharmony_ci var draw_order = false; 59cb93a386Sopenharmony_ci var draw_point_xy = false; 60cb93a386Sopenharmony_ci var draw_ray_intersect = false; 61cb93a386Sopenharmony_ci var draw_quarterpoint = 0; 62cb93a386Sopenharmony_ci var draw_tangents = 1; 63cb93a386Sopenharmony_ci var draw_sortpoint = 0; 64cb93a386Sopenharmony_ci var retina_scale = !!window.devicePixelRatio; 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci function parse(test, title) { 67cb93a386Sopenharmony_ci var curveStrs = test.split("{{"); 68cb93a386Sopenharmony_ci var pattern = /-?\d+\.*\d*e?-?\d*/g; 69cb93a386Sopenharmony_ci var curves = []; 70cb93a386Sopenharmony_ci for (var c in curveStrs) { 71cb93a386Sopenharmony_ci var curveStr = curveStrs[c]; 72cb93a386Sopenharmony_ci var idPart = curveStr.split("id="); 73cb93a386Sopenharmony_ci var id = -1; 74cb93a386Sopenharmony_ci if (idPart.length == 2) { 75cb93a386Sopenharmony_ci id = parseInt(idPart[1]); 76cb93a386Sopenharmony_ci curveStr = idPart[0]; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci var points = curveStr.match(pattern); 79cb93a386Sopenharmony_ci var pts = []; 80cb93a386Sopenharmony_ci for (var wd in points) { 81cb93a386Sopenharmony_ci var num = parseFloat(points[wd]); 82cb93a386Sopenharmony_ci if (isNaN(num)) continue; 83cb93a386Sopenharmony_ci pts.push(num); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci if (pts.length > 2) { 86cb93a386Sopenharmony_ci curves.push(pts); 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci if (id >= 0) { 89cb93a386Sopenharmony_ci ids.push(id); 90cb93a386Sopenharmony_ci ids.push(pts); 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci if (curves.length >= 1) { 94cb93a386Sopenharmony_ci tests.push(curves); 95cb93a386Sopenharmony_ci testTitles.push(title); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci function init(test) { 100cb93a386Sopenharmony_ci var canvas = document.getElementById('canvas'); 101cb93a386Sopenharmony_ci if (!canvas.getContext) return; 102cb93a386Sopenharmony_ci ctx = canvas.getContext('2d'); 103cb93a386Sopenharmony_ci var resScale = retina_scale && window.devicePixelRatio ? window.devicePixelRatio : 1; 104cb93a386Sopenharmony_ci var unscaledWidth = window.innerWidth - 20; 105cb93a386Sopenharmony_ci var unscaledHeight = window.innerHeight - 20; 106cb93a386Sopenharmony_ci screenWidth = unscaledWidth; 107cb93a386Sopenharmony_ci screenHeight = unscaledHeight; 108cb93a386Sopenharmony_ci canvas.width = unscaledWidth * resScale; 109cb93a386Sopenharmony_ci canvas.height = unscaledHeight * resScale; 110cb93a386Sopenharmony_ci canvas.style.width = unscaledWidth + 'px'; 111cb93a386Sopenharmony_ci canvas.style.height = unscaledHeight + 'px'; 112cb93a386Sopenharmony_ci if (resScale != 1) { 113cb93a386Sopenharmony_ci ctx.scale(resScale, resScale); 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci xmin = Infinity; 116cb93a386Sopenharmony_ci xmax = -Infinity; 117cb93a386Sopenharmony_ci ymin = Infinity; 118cb93a386Sopenharmony_ci ymax = -Infinity; 119cb93a386Sopenharmony_ci for (var curves in test) { 120cb93a386Sopenharmony_ci var curve = test[curves]; 121cb93a386Sopenharmony_ci var last = curve.length - (curve.length % 2 == 1 ? 1 : 0); 122cb93a386Sopenharmony_ci for (var idx = 0; idx < last; idx += 2) { 123cb93a386Sopenharmony_ci xmin = Math.min(xmin, curve[idx]); 124cb93a386Sopenharmony_ci xmax = Math.max(xmax, curve[idx]); 125cb93a386Sopenharmony_ci ymin = Math.min(ymin, curve[idx + 1]); 126cb93a386Sopenharmony_ci ymax = Math.max(ymax, curve[idx + 1]); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci xmin -= Math.min(1, Math.max(xmax - xmin, ymax - ymin)); 130cb93a386Sopenharmony_ci var testW = xmax - xmin; 131cb93a386Sopenharmony_ci var testH = ymax - ymin; 132cb93a386Sopenharmony_ci subscale = 1; 133cb93a386Sopenharmony_ci while (testW * subscale < 0.1 && testH * subscale < 0.1) { 134cb93a386Sopenharmony_ci subscale *= 10; 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci while (testW * subscale > 10 && testH * subscale > 10) { 137cb93a386Sopenharmony_ci subscale /= 10; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci setScale(xmin, xmax, ymin, ymax); 140cb93a386Sopenharmony_ci mouseX = (screenWidth / 2) / hscale + srcLeft; 141cb93a386Sopenharmony_ci mouseY = (screenHeight / 2) / vscale + srcTop; 142cb93a386Sopenharmony_ci hinitScale = hscale; 143cb93a386Sopenharmony_ci vinitScale = vscale; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci function setScale(x0, x1, y0, y1) { 147cb93a386Sopenharmony_ci var srcWidth = x1 - x0; 148cb93a386Sopenharmony_ci var srcHeight = y1 - y0; 149cb93a386Sopenharmony_ci var usableWidth = screenWidth; 150cb93a386Sopenharmony_ci var xDigits = Math.ceil(Math.log(Math.abs(xmax)) / Math.log(10)); 151cb93a386Sopenharmony_ci var yDigits = Math.ceil(Math.log(Math.abs(ymax)) / Math.log(10)); 152cb93a386Sopenharmony_ci usableWidth -= (xDigits + yDigits) * 10; 153cb93a386Sopenharmony_ci usableWidth -= decimal_places * 10; 154cb93a386Sopenharmony_ci hscale = usableWidth / srcWidth; 155cb93a386Sopenharmony_ci vscale = screenHeight / srcHeight; 156cb93a386Sopenharmony_ci if (uniformScale) { 157cb93a386Sopenharmony_ci hscale = Math.min(hscale, vscale); 158cb93a386Sopenharmony_ci vscale = hscale; 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci var hinvScale = 1 / hscale; 161cb93a386Sopenharmony_ci var vinvScale = 1 / vscale; 162cb93a386Sopenharmony_ci var sxmin = x0 - hinvScale * 5; 163cb93a386Sopenharmony_ci var symin = y0 - vinvScale * 10; 164cb93a386Sopenharmony_ci var sxmax = x1 + hinvScale * (6 * decimal_places + 10); 165cb93a386Sopenharmony_ci var symax = y1 + vinvScale * 10; 166cb93a386Sopenharmony_ci srcWidth = sxmax - sxmin; 167cb93a386Sopenharmony_ci srcHeight = symax - symin; 168cb93a386Sopenharmony_ci hscale = usableWidth / srcWidth; 169cb93a386Sopenharmony_ci vscale = screenHeight / srcHeight; 170cb93a386Sopenharmony_ci if (uniformScale) { 171cb93a386Sopenharmony_ci hscale = Math.min(hscale, vscale); 172cb93a386Sopenharmony_ci vscale = hscale; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci srcLeft = sxmin; 175cb93a386Sopenharmony_ci srcTop = symin; 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_cifunction dxy_at_t(curve, t) { 179cb93a386Sopenharmony_ci var dxy = {}; 180cb93a386Sopenharmony_ci if (curve.length == 6) { 181cb93a386Sopenharmony_ci var a = t - 1; 182cb93a386Sopenharmony_ci var b = 1 - 2 * t; 183cb93a386Sopenharmony_ci var c = t; 184cb93a386Sopenharmony_ci dxy.x = a * curve[0] + b * curve[2] + c * curve[4]; 185cb93a386Sopenharmony_ci dxy.y = a * curve[1] + b * curve[3] + c * curve[5]; 186cb93a386Sopenharmony_ci } else if (curve.length == 7) { 187cb93a386Sopenharmony_ci var p20x = curve[4] - curve[0]; 188cb93a386Sopenharmony_ci var p20y = curve[5] - curve[1]; 189cb93a386Sopenharmony_ci var p10xw = (curve[2] - curve[0]) * curve[6]; 190cb93a386Sopenharmony_ci var p10yw = (curve[3] - curve[1]) * curve[6]; 191cb93a386Sopenharmony_ci var coeff0x = curve[6] * p20x - p20x; 192cb93a386Sopenharmony_ci var coeff0y = curve[6] * p20y - p20y; 193cb93a386Sopenharmony_ci var coeff1x = p20x - 2 * p10xw; 194cb93a386Sopenharmony_ci var coeff1y = p20y - 2 * p10yw; 195cb93a386Sopenharmony_ci dxy.x = t * (t * coeff0x + coeff1x) + p10xw; 196cb93a386Sopenharmony_ci dxy.y = t * (t * coeff0y + coeff1y) + p10yw; 197cb93a386Sopenharmony_ci } else if (curve.length == 8) { 198cb93a386Sopenharmony_ci var one_t = 1 - t; 199cb93a386Sopenharmony_ci var a = curve[0]; 200cb93a386Sopenharmony_ci var b = curve[2]; 201cb93a386Sopenharmony_ci var c = curve[4]; 202cb93a386Sopenharmony_ci var d = curve[6]; 203cb93a386Sopenharmony_ci dxy.x = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 204cb93a386Sopenharmony_ci a = curve[1]; 205cb93a386Sopenharmony_ci b = curve[3]; 206cb93a386Sopenharmony_ci c = curve[5]; 207cb93a386Sopenharmony_ci d = curve[7]; 208cb93a386Sopenharmony_ci dxy.y = 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t); 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci return dxy; 211cb93a386Sopenharmony_ci} 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci var flt_epsilon = 1.19209290E-07; 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci function approximately_zero(A) { 216cb93a386Sopenharmony_ci return Math.abs(A) < flt_epsilon; 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci function approximately_zero_inverse(A) { 220cb93a386Sopenharmony_ci return Math.abs(A) > (1 / flt_epsilon); 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci function quad_real_roots(A, B, C) { 224cb93a386Sopenharmony_ci var s = []; 225cb93a386Sopenharmony_ci var p = B / (2 * A); 226cb93a386Sopenharmony_ci var q = C / A; 227cb93a386Sopenharmony_ci if (approximately_zero(A) && (approximately_zero_inverse(p) 228cb93a386Sopenharmony_ci || approximately_zero_inverse(q))) { 229cb93a386Sopenharmony_ci if (approximately_zero(B)) { 230cb93a386Sopenharmony_ci if (C == 0) { 231cb93a386Sopenharmony_ci s[0] = 0; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci return s; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci s[0] = -C / B; 236cb93a386Sopenharmony_ci return s; 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci /* normal form: x^2 + px + q = 0 */ 239cb93a386Sopenharmony_ci var p2 = p * p; 240cb93a386Sopenharmony_ci if (!approximately_zero(p2 - q) && p2 < q) { 241cb93a386Sopenharmony_ci return s; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci var sqrt_D = 0; 244cb93a386Sopenharmony_ci if (p2 > q) { 245cb93a386Sopenharmony_ci sqrt_D = Math.sqrt(p2 - q); 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci s[0] = sqrt_D - p; 248cb93a386Sopenharmony_ci var flip = -sqrt_D - p; 249cb93a386Sopenharmony_ci if (!approximately_zero(s[0] - flip)) { 250cb93a386Sopenharmony_ci s[1] = flip; 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci return s; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci function cubic_real_roots(A, B, C, D) { 256cb93a386Sopenharmony_ci if (approximately_zero(A)) { // we're just a quadratic 257cb93a386Sopenharmony_ci return quad_real_roots(B, C, D); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci if (approximately_zero(D)) { // 0 is one root 260cb93a386Sopenharmony_ci var s = quad_real_roots(A, B, C); 261cb93a386Sopenharmony_ci for (var i = 0; i < s.length; ++i) { 262cb93a386Sopenharmony_ci if (approximately_zero(s[i])) { 263cb93a386Sopenharmony_ci return s; 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci s.push(0); 267cb93a386Sopenharmony_ci return s; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci if (approximately_zero(A + B + C + D)) { // 1 is one root 270cb93a386Sopenharmony_ci var s = quad_real_roots(A, A + B, -D); 271cb93a386Sopenharmony_ci for (var i = 0; i < s.length; ++i) { 272cb93a386Sopenharmony_ci if (approximately_zero(s[i] - 1)) { 273cb93a386Sopenharmony_ci return s; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci s.push(1); 277cb93a386Sopenharmony_ci return s; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci var a, b, c; 280cb93a386Sopenharmony_ci var invA = 1 / A; 281cb93a386Sopenharmony_ci a = B * invA; 282cb93a386Sopenharmony_ci b = C * invA; 283cb93a386Sopenharmony_ci c = D * invA; 284cb93a386Sopenharmony_ci var a2 = a * a; 285cb93a386Sopenharmony_ci var Q = (a2 - b * 3) / 9; 286cb93a386Sopenharmony_ci var R = (2 * a2 * a - 9 * a * b + 27 * c) / 54; 287cb93a386Sopenharmony_ci var R2 = R * R; 288cb93a386Sopenharmony_ci var Q3 = Q * Q * Q; 289cb93a386Sopenharmony_ci var R2MinusQ3 = R2 - Q3; 290cb93a386Sopenharmony_ci var adiv3 = a / 3; 291cb93a386Sopenharmony_ci var r; 292cb93a386Sopenharmony_ci var roots = []; 293cb93a386Sopenharmony_ci if (R2MinusQ3 < 0) { // we have 3 real roots 294cb93a386Sopenharmony_ci var theta = Math.acos(R / Math.sqrt(Q3)); 295cb93a386Sopenharmony_ci var neg2RootQ = -2 * Math.sqrt(Q); 296cb93a386Sopenharmony_ci r = neg2RootQ * Math.cos(theta / 3) - adiv3; 297cb93a386Sopenharmony_ci roots.push(r); 298cb93a386Sopenharmony_ci r = neg2RootQ * Math.cos((theta + 2 * Math.PI) / 3) - adiv3; 299cb93a386Sopenharmony_ci if (!approximately_zero(roots[0] - r)) { 300cb93a386Sopenharmony_ci roots.push(r); 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci r = neg2RootQ * Math.cos((theta - 2 * Math.PI) / 3) - adiv3; 303cb93a386Sopenharmony_ci if (!approximately_zero(roots[0] - r) && (roots.length == 1 304cb93a386Sopenharmony_ci || !approximately_zero(roots[1] - r))) { 305cb93a386Sopenharmony_ci roots.push(r); 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci } else { // we have 1 real root 308cb93a386Sopenharmony_ci var sqrtR2MinusQ3 = Math.sqrt(R2MinusQ3); 309cb93a386Sopenharmony_ci var A = Math.abs(R) + sqrtR2MinusQ3; 310cb93a386Sopenharmony_ci A = Math.pow(A, 1/3); 311cb93a386Sopenharmony_ci if (R > 0) { 312cb93a386Sopenharmony_ci A = -A; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci if (A != 0) { 315cb93a386Sopenharmony_ci A += Q / A; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci r = A - adiv3; 318cb93a386Sopenharmony_ci roots.push(r); 319cb93a386Sopenharmony_ci if (approximately_zero(R2 - Q3)) { 320cb93a386Sopenharmony_ci r = -A / 2 - adiv3; 321cb93a386Sopenharmony_ci if (!approximately_zero(roots[0] - r)) { 322cb93a386Sopenharmony_ci roots.push(r); 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci return roots; 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci function approximately_zero_or_more(tValue) { 330cb93a386Sopenharmony_ci return tValue >= -flt_epsilon; 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci function approximately_one_or_less(tValue) { 334cb93a386Sopenharmony_ci return tValue <= 1 + flt_epsilon; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci function approximately_less_than_zero(tValue) { 338cb93a386Sopenharmony_ci return tValue < flt_epsilon; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci function approximately_greater_than_one(tValue) { 342cb93a386Sopenharmony_ci return tValue > 1 - flt_epsilon; 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci function add_valid_ts(s) { 346cb93a386Sopenharmony_ci var t = []; 347cb93a386Sopenharmony_ci nextRoot: 348cb93a386Sopenharmony_ci for (var index = 0; index < s.length; ++index) { 349cb93a386Sopenharmony_ci var tValue = s[index]; 350cb93a386Sopenharmony_ci if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) { 351cb93a386Sopenharmony_ci if (approximately_less_than_zero(tValue)) { 352cb93a386Sopenharmony_ci tValue = 0; 353cb93a386Sopenharmony_ci } else if (approximately_greater_than_one(tValue)) { 354cb93a386Sopenharmony_ci tValue = 1; 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci for (var idx2 = 0; idx2 < t.length; ++idx2) { 357cb93a386Sopenharmony_ci if (approximately_zero(t[idx2] - tValue)) { 358cb93a386Sopenharmony_ci continue nextRoot; 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci } 361cb93a386Sopenharmony_ci t.push(tValue); 362cb93a386Sopenharmony_ci } 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci return t; 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci function quad_roots(A, B, C) { 368cb93a386Sopenharmony_ci var s = quad_real_roots(A, B, C); 369cb93a386Sopenharmony_ci var foundRoots = add_valid_ts(s); 370cb93a386Sopenharmony_ci return foundRoots; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci 373cb93a386Sopenharmony_ci function cubic_roots(A, B, C, D) { 374cb93a386Sopenharmony_ci var s = cubic_real_roots(A, B, C, D); 375cb93a386Sopenharmony_ci var foundRoots = add_valid_ts(s); 376cb93a386Sopenharmony_ci return foundRoots; 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci function ray_curve_intersect(startPt, endPt, curve) { 380cb93a386Sopenharmony_ci var adj = endPt[0] - startPt[0]; 381cb93a386Sopenharmony_ci var opp = endPt[1] - startPt[1]; 382cb93a386Sopenharmony_ci var r = []; 383cb93a386Sopenharmony_ci var len = (curve.length == 7 ? 6 : curve.length) / 2; 384cb93a386Sopenharmony_ci for (var n = 0; n < len; ++n) { 385cb93a386Sopenharmony_ci r[n] = (curve[n * 2 + 1] - startPt[1]) * adj - (curve[n * 2] - startPt[0]) * opp; 386cb93a386Sopenharmony_ci } 387cb93a386Sopenharmony_ci if (curve.length == 6) { 388cb93a386Sopenharmony_ci var A = r[2]; 389cb93a386Sopenharmony_ci var B = r[1]; 390cb93a386Sopenharmony_ci var C = r[0]; 391cb93a386Sopenharmony_ci A += C - 2 * B; // A = a - 2*b + c 392cb93a386Sopenharmony_ci B -= C; // B = -(b - c) 393cb93a386Sopenharmony_ci return quad_roots(A, 2 * B, C); 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci if (curve.length == 7) { 396cb93a386Sopenharmony_ci var A = r[2]; 397cb93a386Sopenharmony_ci var B = r[1] * curve[6]; 398cb93a386Sopenharmony_ci var C = r[0]; 399cb93a386Sopenharmony_ci A += C - 2 * B; // A = a - 2*b + c 400cb93a386Sopenharmony_ci B -= C; // B = -(b - c) 401cb93a386Sopenharmony_ci return quad_roots(A, 2 * B, C); 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci var A = r[3]; // d 404cb93a386Sopenharmony_ci var B = r[2] * 3; // 3*c 405cb93a386Sopenharmony_ci var C = r[1] * 3; // 3*b 406cb93a386Sopenharmony_ci var D = r[0]; // a 407cb93a386Sopenharmony_ci A -= D - C + B; // A = -a + 3*b - 3*c + d 408cb93a386Sopenharmony_ci B += 3 * D - 2 * C; // B = 3*a - 6*b + 3*c 409cb93a386Sopenharmony_ci C -= 3 * D; // C = -3*a + 3*b 410cb93a386Sopenharmony_ci return cubic_roots(A, B, C, D); 411cb93a386Sopenharmony_ci } 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci function x_at_t(curve, t) { 414cb93a386Sopenharmony_ci var one_t = 1 - t; 415cb93a386Sopenharmony_ci if (curve.length == 4) { 416cb93a386Sopenharmony_ci return one_t * curve[0] + t * curve[2]; 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci var one_t2 = one_t * one_t; 419cb93a386Sopenharmony_ci var t2 = t * t; 420cb93a386Sopenharmony_ci if (curve.length == 6) { 421cb93a386Sopenharmony_ci return one_t2 * curve[0] + 2 * one_t * t * curve[2] + t2 * curve[4]; 422cb93a386Sopenharmony_ci } 423cb93a386Sopenharmony_ci if (curve.length == 7) { 424cb93a386Sopenharmony_ci var numer = one_t2 * curve[0] + 2 * one_t * t * curve[2] * curve[6] 425cb93a386Sopenharmony_ci + t2 * curve[4]; 426cb93a386Sopenharmony_ci var denom = one_t2 + 2 * one_t * t * curve[6] 427cb93a386Sopenharmony_ci + t2; 428cb93a386Sopenharmony_ci return numer / denom; 429cb93a386Sopenharmony_ci } 430cb93a386Sopenharmony_ci var a = one_t2 * one_t; 431cb93a386Sopenharmony_ci var b = 3 * one_t2 * t; 432cb93a386Sopenharmony_ci var c = 3 * one_t * t2; 433cb93a386Sopenharmony_ci var d = t2 * t; 434cb93a386Sopenharmony_ci return a * curve[0] + b * curve[2] + c * curve[4] + d * curve[6]; 435cb93a386Sopenharmony_ci } 436cb93a386Sopenharmony_ci 437cb93a386Sopenharmony_ci function y_at_t(curve, t) { 438cb93a386Sopenharmony_ci var one_t = 1 - t; 439cb93a386Sopenharmony_ci if (curve.length == 4) { 440cb93a386Sopenharmony_ci return one_t * curve[1] + t * curve[3]; 441cb93a386Sopenharmony_ci } 442cb93a386Sopenharmony_ci var one_t2 = one_t * one_t; 443cb93a386Sopenharmony_ci var t2 = t * t; 444cb93a386Sopenharmony_ci if (curve.length == 6) { 445cb93a386Sopenharmony_ci return one_t2 * curve[1] + 2 * one_t * t * curve[3] + t2 * curve[5]; 446cb93a386Sopenharmony_ci } 447cb93a386Sopenharmony_ci if (curve.length == 7) { 448cb93a386Sopenharmony_ci var numer = one_t2 * curve[1] + 2 * one_t * t * curve[3] * curve[6] 449cb93a386Sopenharmony_ci + t2 * curve[5]; 450cb93a386Sopenharmony_ci var denom = one_t2 + 2 * one_t * t * curve[6] 451cb93a386Sopenharmony_ci + t2; 452cb93a386Sopenharmony_ci return numer / denom; 453cb93a386Sopenharmony_ci } 454cb93a386Sopenharmony_ci var a = one_t2 * one_t; 455cb93a386Sopenharmony_ci var b = 3 * one_t2 * t; 456cb93a386Sopenharmony_ci var c = 3 * one_t * t2; 457cb93a386Sopenharmony_ci var d = t2 * t; 458cb93a386Sopenharmony_ci return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7]; 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci function drawPointAtT(curve) { 462cb93a386Sopenharmony_ci var x = x_at_t(curve, curveT); 463cb93a386Sopenharmony_ci var y = y_at_t(curve, curveT); 464cb93a386Sopenharmony_ci drawPoint(x, y, false); 465cb93a386Sopenharmony_ci } 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci function drawLine(x1, y1, x2, y2) { 468cb93a386Sopenharmony_ci ctx.beginPath(); 469cb93a386Sopenharmony_ci ctx.moveTo((x1 - srcLeft) * hscale, 470cb93a386Sopenharmony_ci (y1 - srcTop) * vscale); 471cb93a386Sopenharmony_ci ctx.lineTo((x2 - srcLeft) * hscale, 472cb93a386Sopenharmony_ci (y2 - srcTop) * vscale); 473cb93a386Sopenharmony_ci ctx.stroke(); 474cb93a386Sopenharmony_ci } 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ci function drawPoint(px, py, xend) { 477cb93a386Sopenharmony_ci for (var pts = 0; pts < drawnPts.length; pts += 2) { 478cb93a386Sopenharmony_ci var x = drawnPts[pts]; 479cb93a386Sopenharmony_ci var y = drawnPts[pts + 1]; 480cb93a386Sopenharmony_ci if (px == x && py == y) { 481cb93a386Sopenharmony_ci return; 482cb93a386Sopenharmony_ci } 483cb93a386Sopenharmony_ci } 484cb93a386Sopenharmony_ci drawnPts.push(px); 485cb93a386Sopenharmony_ci drawnPts.push(py); 486cb93a386Sopenharmony_ci var _px = (px - srcLeft) * hscale; 487cb93a386Sopenharmony_ci var _py = (py - srcTop) * vscale; 488cb93a386Sopenharmony_ci ctx.beginPath(); 489cb93a386Sopenharmony_ci if (xend) { 490cb93a386Sopenharmony_ci ctx.moveTo(_px - 3, _py - 3); 491cb93a386Sopenharmony_ci ctx.lineTo(_px + 3, _py + 3); 492cb93a386Sopenharmony_ci ctx.moveTo(_px - 3, _py + 3); 493cb93a386Sopenharmony_ci ctx.lineTo(_px + 3, _py - 3); 494cb93a386Sopenharmony_ci } else { 495cb93a386Sopenharmony_ci ctx.arc(_px, _py, 3, 0, Math.PI * 2, true); 496cb93a386Sopenharmony_ci ctx.closePath(); 497cb93a386Sopenharmony_ci } 498cb93a386Sopenharmony_ci ctx.stroke(); 499cb93a386Sopenharmony_ci if (draw_point_xy) { 500cb93a386Sopenharmony_ci var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places); 501cb93a386Sopenharmony_ci ctx.font = "normal 10px Arial"; 502cb93a386Sopenharmony_ci ctx.textAlign = "left"; 503cb93a386Sopenharmony_ci ctx.fillStyle = "black"; 504cb93a386Sopenharmony_ci ctx.fillText(label, _px + 5, _py); 505cb93a386Sopenharmony_ci } 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci function drawPointSolid(px, py) { 509cb93a386Sopenharmony_ci drawPoint(px, py, false); 510cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,0, 0.4)"; 511cb93a386Sopenharmony_ci ctx.fill(); 512cb93a386Sopenharmony_ci } 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci function crossPt(origin, pt1, pt2) { 515cb93a386Sopenharmony_ci return ((pt1[0] - origin[0]) * (pt2[1] - origin[1]) 516cb93a386Sopenharmony_ci - (pt1[1] - origin[1]) * (pt2[0] - origin[0])) > 0 ? 0 : 1; 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci // may not work well for cubics 520cb93a386Sopenharmony_ci function curveClosestT(curve, x, y) { 521cb93a386Sopenharmony_ci var closest = -1; 522cb93a386Sopenharmony_ci var closestDist = Infinity; 523cb93a386Sopenharmony_ci var l = Infinity, t = Infinity, r = -Infinity, b = -Infinity; 524cb93a386Sopenharmony_ci for (var i = 0; i < 16; ++i) { 525cb93a386Sopenharmony_ci var testX = x_at_t(curve, i / 16); 526cb93a386Sopenharmony_ci l = Math.min(testX, l); 527cb93a386Sopenharmony_ci r = Math.max(testX, r); 528cb93a386Sopenharmony_ci var testY = y_at_t(curve, i / 16); 529cb93a386Sopenharmony_ci t = Math.min(testY, t); 530cb93a386Sopenharmony_ci b = Math.max(testY, b); 531cb93a386Sopenharmony_ci var dx = testX - x; 532cb93a386Sopenharmony_ci var dy = testY - y; 533cb93a386Sopenharmony_ci var dist = dx * dx + dy * dy; 534cb93a386Sopenharmony_ci if (closestDist > dist) { 535cb93a386Sopenharmony_ci closestDist = dist; 536cb93a386Sopenharmony_ci closest = i; 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci } 539cb93a386Sopenharmony_ci var boundsX = r - l; 540cb93a386Sopenharmony_ci var boundsY = b - t; 541cb93a386Sopenharmony_ci var boundsDist = boundsX * boundsX + boundsY * boundsY; 542cb93a386Sopenharmony_ci if (closestDist > boundsDist) { 543cb93a386Sopenharmony_ci return -1; 544cb93a386Sopenharmony_ci } 545cb93a386Sopenharmony_ci console.log("closestDist = " + closestDist + " boundsDist = " + boundsDist 546cb93a386Sopenharmony_ci + " t = " + closest / 16); 547cb93a386Sopenharmony_ci return closest / 16; 548cb93a386Sopenharmony_ci } 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_ci var kMaxConicToQuadPOW2 = 5; 551cb93a386Sopenharmony_ci 552cb93a386Sopenharmony_ci function computeQuadPOW2(curve, tol) { 553cb93a386Sopenharmony_ci var a = curve[6] - 1; 554cb93a386Sopenharmony_ci var k = a / (4 * (2 + a)); 555cb93a386Sopenharmony_ci var x = k * (curve[0] - 2 * curve[2] + curve[4]); 556cb93a386Sopenharmony_ci var y = k * (curve[1] - 2 * curve[3] + curve[5]); 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ci var error = Math.sqrt(x * x + y * y); 559cb93a386Sopenharmony_ci var pow2; 560cb93a386Sopenharmony_ci for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) { 561cb93a386Sopenharmony_ci if (error <= tol) { 562cb93a386Sopenharmony_ci break; 563cb93a386Sopenharmony_ci } 564cb93a386Sopenharmony_ci error *= 0.25; 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci return pow2; 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci function subdivide_w_value(w) { 570cb93a386Sopenharmony_ci return Math.sqrt(0.5 + w * 0.5); 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci 573cb93a386Sopenharmony_ci function chop(curve, part1, part2) { 574cb93a386Sopenharmony_ci var w = curve[6]; 575cb93a386Sopenharmony_ci var scale = 1 / (1 + w); 576cb93a386Sopenharmony_ci part1[0] = curve[0]; 577cb93a386Sopenharmony_ci part1[1] = curve[1]; 578cb93a386Sopenharmony_ci part1[2] = (curve[0] + curve[2] * w) * scale; 579cb93a386Sopenharmony_ci part1[3] = (curve[1] + curve[3] * w) * scale; 580cb93a386Sopenharmony_ci part1[4] = part2[0] = (curve[0] + (curve[2] * w) * 2 + curve[4]) * scale * 0.5; 581cb93a386Sopenharmony_ci part1[5] = part2[1] = (curve[1] + (curve[3] * w) * 2 + curve[5]) * scale * 0.5; 582cb93a386Sopenharmony_ci part2[2] = (curve[2] * w + curve[4]) * scale; 583cb93a386Sopenharmony_ci part2[3] = (curve[3] * w + curve[5]) * scale; 584cb93a386Sopenharmony_ci part2[4] = curve[4]; 585cb93a386Sopenharmony_ci part2[5] = curve[5]; 586cb93a386Sopenharmony_ci part1[6] = part2[6] = subdivide_w_value(w); 587cb93a386Sopenharmony_ci } 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci function subdivide(curve, level, pts) { 590cb93a386Sopenharmony_ci if (0 == level) { 591cb93a386Sopenharmony_ci pts.push(curve[2]); 592cb93a386Sopenharmony_ci pts.push(curve[3]); 593cb93a386Sopenharmony_ci pts.push(curve[4]); 594cb93a386Sopenharmony_ci pts.push(curve[5]); 595cb93a386Sopenharmony_ci } else { 596cb93a386Sopenharmony_ci var part1 = [], part2 = []; 597cb93a386Sopenharmony_ci chop(curve, part1, part2); 598cb93a386Sopenharmony_ci --level; 599cb93a386Sopenharmony_ci subdivide(part1, level, pts); 600cb93a386Sopenharmony_ci subdivide(part2, level, pts); 601cb93a386Sopenharmony_ci } 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_ci function chopIntoQuadsPOW2(curve, pow2, pts) { 605cb93a386Sopenharmony_ci subdivide(curve, pow2, pts); 606cb93a386Sopenharmony_ci return 1 << pow2; 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci 609cb93a386Sopenharmony_ci function drawConic(curve, srcLeft, srcTop, hscale, vscale) { 610cb93a386Sopenharmony_ci var tol = 1 / Math.min(hscale, vscale); 611cb93a386Sopenharmony_ci var pow2 = computeQuadPOW2(curve, tol); 612cb93a386Sopenharmony_ci var pts = []; 613cb93a386Sopenharmony_ci chopIntoQuadsPOW2(curve, pow2, pts); 614cb93a386Sopenharmony_ci for (var i = 0; i < pts.length; i += 4) { 615cb93a386Sopenharmony_ci ctx.quadraticCurveTo( 616cb93a386Sopenharmony_ci (pts[i + 0] - srcLeft) * hscale, (pts[i + 1] - srcTop) * vscale, 617cb93a386Sopenharmony_ci (pts[i + 2] - srcLeft) * hscale, (pts[i + 3] - srcTop) * vscale); 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci } 620cb93a386Sopenharmony_ci 621cb93a386Sopenharmony_ci function draw(test, title) { 622cb93a386Sopenharmony_ci ctx.font = "normal 50px Arial"; 623cb93a386Sopenharmony_ci ctx.textAlign = "left"; 624cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,0, 0.1)"; 625cb93a386Sopenharmony_ci ctx.fillText(title, 50, 50); 626cb93a386Sopenharmony_ci ctx.font = "normal 10px Arial"; 627cb93a386Sopenharmony_ci // ctx.lineWidth = "1.001"; "0.999"; 628cb93a386Sopenharmony_ci var hullStarts = []; 629cb93a386Sopenharmony_ci var hullEnds = []; 630cb93a386Sopenharmony_ci var midSpokes = []; 631cb93a386Sopenharmony_ci var midDist = []; 632cb93a386Sopenharmony_ci var origin = []; 633cb93a386Sopenharmony_ci var shortSpokes = []; 634cb93a386Sopenharmony_ci var shortDist = []; 635cb93a386Sopenharmony_ci var sweeps = []; 636cb93a386Sopenharmony_ci drawnPts = []; 637cb93a386Sopenharmony_ci for (var curves in test) { 638cb93a386Sopenharmony_ci var curve = test[curves]; 639cb93a386Sopenharmony_ci origin.push(curve[0]); 640cb93a386Sopenharmony_ci origin.push(curve[1]); 641cb93a386Sopenharmony_ci var startPt = []; 642cb93a386Sopenharmony_ci startPt.push(curve[2]); 643cb93a386Sopenharmony_ci startPt.push(curve[3]); 644cb93a386Sopenharmony_ci hullStarts.push(startPt); 645cb93a386Sopenharmony_ci var endPt = []; 646cb93a386Sopenharmony_ci if (curve.length == 4) { 647cb93a386Sopenharmony_ci endPt.push(curve[2]); 648cb93a386Sopenharmony_ci endPt.push(curve[3]); 649cb93a386Sopenharmony_ci } else if (curve.length == 6 || curve.length == 7) { 650cb93a386Sopenharmony_ci endPt.push(curve[4]); 651cb93a386Sopenharmony_ci endPt.push(curve[5]); 652cb93a386Sopenharmony_ci } else if (curve.length == 8) { 653cb93a386Sopenharmony_ci endPt.push(curve[6]); 654cb93a386Sopenharmony_ci endPt.push(curve[7]); 655cb93a386Sopenharmony_ci } 656cb93a386Sopenharmony_ci hullEnds.push(endPt); 657cb93a386Sopenharmony_ci var sweep = crossPt(origin, startPt, endPt); 658cb93a386Sopenharmony_ci sweeps.push(sweep); 659cb93a386Sopenharmony_ci var midPt = []; 660cb93a386Sopenharmony_ci midPt.push(x_at_t(curve, 0.5)); 661cb93a386Sopenharmony_ci midPt.push(y_at_t(curve, 0.5)); 662cb93a386Sopenharmony_ci midSpokes.push(midPt); 663cb93a386Sopenharmony_ci var shortPt = []; 664cb93a386Sopenharmony_ci shortPt.push(x_at_t(curve, 0.25)); 665cb93a386Sopenharmony_ci shortPt.push(y_at_t(curve, 0.25)); 666cb93a386Sopenharmony_ci shortSpokes.push(shortPt); 667cb93a386Sopenharmony_ci var dx = midPt[0] - origin[0]; 668cb93a386Sopenharmony_ci var dy = midPt[1] - origin[1]; 669cb93a386Sopenharmony_ci var dist = Math.sqrt(dx * dx + dy * dy); 670cb93a386Sopenharmony_ci midDist.push(dist); 671cb93a386Sopenharmony_ci dx = shortPt[0] - origin[0]; 672cb93a386Sopenharmony_ci dy = shortPt[1] - origin[1]; 673cb93a386Sopenharmony_ci dist = Math.sqrt(dx * dx + dy * dy); 674cb93a386Sopenharmony_ci shortDist.push(dist); 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci var intersect = []; 677cb93a386Sopenharmony_ci var useIntersect = false; 678cb93a386Sopenharmony_ci var maxWidth = Math.max(xmax - xmin, ymax - ymin); 679cb93a386Sopenharmony_ci for (var curves in test) { 680cb93a386Sopenharmony_ci var curve = test[curves]; 681cb93a386Sopenharmony_ci if (curve.length >= 6 && curve.length <= 8) { 682cb93a386Sopenharmony_ci var opp = curves == 0 || curves == 1 ? 0 : 1; 683cb93a386Sopenharmony_ci var sects = ray_curve_intersect(origin, hullEnds[opp], curve); 684cb93a386Sopenharmony_ci intersect.push(sects); 685cb93a386Sopenharmony_ci if (sects.length > 1) { 686cb93a386Sopenharmony_ci var intersection = sects[0]; 687cb93a386Sopenharmony_ci if (intersection == 0) { 688cb93a386Sopenharmony_ci intersection = sects[1]; 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci var ix = x_at_t(curve, intersection) - origin[0]; 691cb93a386Sopenharmony_ci var iy = y_at_t(curve, intersection) - origin[1]; 692cb93a386Sopenharmony_ci var ex = hullEnds[opp][0] - origin[0]; 693cb93a386Sopenharmony_ci var ey = hullEnds[opp][1] - origin[1]; 694cb93a386Sopenharmony_ci if (ix * ex >= 0 && iy * ey >= 0) { 695cb93a386Sopenharmony_ci var iDist = Math.sqrt(ix * ix + iy * iy); 696cb93a386Sopenharmony_ci var eDist = Math.sqrt(ex * ex + ey * ey); 697cb93a386Sopenharmony_ci var delta = Math.abs(iDist - eDist) / maxWidth; 698cb93a386Sopenharmony_ci if (delta > (curve.length != 8 ? 1e-5 : 1e-4)) { 699cb93a386Sopenharmony_ci useIntersect ^= true; 700cb93a386Sopenharmony_ci } 701cb93a386Sopenharmony_ci } 702cb93a386Sopenharmony_ci } 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci } 705cb93a386Sopenharmony_ci var midLeft = curves != 0 ? crossPt(origin, midSpokes[0], midSpokes[1]) : 0; 706cb93a386Sopenharmony_ci var firstInside; 707cb93a386Sopenharmony_ci if (useIntersect) { 708cb93a386Sopenharmony_ci var sect1 = intersect[0].length > 1; 709cb93a386Sopenharmony_ci var sIndex = sect1 ? 0 : 1; 710cb93a386Sopenharmony_ci var sects = intersect[sIndex]; 711cb93a386Sopenharmony_ci var intersection = sects[0]; 712cb93a386Sopenharmony_ci if (intersection == 0) { 713cb93a386Sopenharmony_ci intersection = sects[1]; 714cb93a386Sopenharmony_ci } 715cb93a386Sopenharmony_ci var curve = test[sIndex]; 716cb93a386Sopenharmony_ci var ix = x_at_t(curve, intersection) - origin[0]; 717cb93a386Sopenharmony_ci var iy = y_at_t(curve, intersection) - origin[1]; 718cb93a386Sopenharmony_ci var opp = sect1 ? 1 : 0; 719cb93a386Sopenharmony_ci var ex = hullEnds[opp][0] - origin[0]; 720cb93a386Sopenharmony_ci var ey = hullEnds[opp][1] - origin[1]; 721cb93a386Sopenharmony_ci var iDist = ix * ix + iy * iy; 722cb93a386Sopenharmony_ci var eDist = ex * ex + ey * ey; 723cb93a386Sopenharmony_ci firstInside = (iDist > eDist) ^ (sIndex == 0) ^ sweeps[0]; 724cb93a386Sopenharmony_ci// console.log("iDist=" + iDist + " eDist=" + eDist + " sIndex=" + sIndex 725cb93a386Sopenharmony_ci // + " sweeps[0]=" + sweeps[0]); 726cb93a386Sopenharmony_ci } else { 727cb93a386Sopenharmony_ci // console.log("midLeft=" + midLeft); 728cb93a386Sopenharmony_ci firstInside = midLeft != 0; 729cb93a386Sopenharmony_ci } 730cb93a386Sopenharmony_ci var shorter = midDist[1] < midDist[0]; 731cb93a386Sopenharmony_ci var shortLeft = shorter ? crossPt(origin, shortSpokes[0], midSpokes[1]) 732cb93a386Sopenharmony_ci : crossPt(origin, midSpokes[0], shortSpokes[1]); 733cb93a386Sopenharmony_ci var startCross = crossPt(origin, hullStarts[0], hullStarts[1]); 734cb93a386Sopenharmony_ci var disallowShort = midLeft == startCross && midLeft == sweeps[0] 735cb93a386Sopenharmony_ci && midLeft == sweeps[1]; 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci // console.log("midLeft=" + midLeft + " startCross=" + startCross); 738cb93a386Sopenharmony_ci var intersectIndex = 0; 739cb93a386Sopenharmony_ci for (var curves in test) { 740cb93a386Sopenharmony_ci var curve = test[draw_id != 2 ? curves : test.length - curves - 1]; 741cb93a386Sopenharmony_ci if (curve.length != 4 && curve.length != 6 && curve.length != 7 && curve.length != 8) { 742cb93a386Sopenharmony_ci continue; 743cb93a386Sopenharmony_ci } 744cb93a386Sopenharmony_ci ctx.lineWidth = 1; 745cb93a386Sopenharmony_ci if (draw_tangents != 0) { 746cb93a386Sopenharmony_ci if (draw_cubic_red ? curve.length == 8 : firstInside == curves) { 747cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(255,0,0, 0.3)"; 748cb93a386Sopenharmony_ci } else { 749cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,0,255, 0.3)"; 750cb93a386Sopenharmony_ci } 751cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], curve[2], curve[3]); 752cb93a386Sopenharmony_ci if (draw_tangents != 2) { 753cb93a386Sopenharmony_ci if (curve.length > 4) drawLine(curve[2], curve[3], curve[4], curve[5]); 754cb93a386Sopenharmony_ci if (curve.length == 8) drawLine(curve[4], curve[5], curve[6], curve[7]); 755cb93a386Sopenharmony_ci } 756cb93a386Sopenharmony_ci if (draw_tangents != 1) { 757cb93a386Sopenharmony_ci if (curve.length == 6 || curve.length == 7) { 758cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], curve[4], curve[5]); 759cb93a386Sopenharmony_ci } 760cb93a386Sopenharmony_ci if (curve.length == 8) drawLine(curve[0], curve[1], curve[6], curve[7]); 761cb93a386Sopenharmony_ci } 762cb93a386Sopenharmony_ci } 763cb93a386Sopenharmony_ci ctx.beginPath(); 764cb93a386Sopenharmony_ci ctx.moveTo((curve[0] - srcLeft) * hscale, (curve[1] - srcTop) * vscale); 765cb93a386Sopenharmony_ci if (curve.length == 4) { 766cb93a386Sopenharmony_ci ctx.lineTo((curve[2] - srcLeft) * hscale, (curve[3] - srcTop) * vscale); 767cb93a386Sopenharmony_ci } else if (curve.length == 6) { 768cb93a386Sopenharmony_ci ctx.quadraticCurveTo( 769cb93a386Sopenharmony_ci (curve[2] - srcLeft) * hscale, (curve[3] - srcTop) * vscale, 770cb93a386Sopenharmony_ci (curve[4] - srcLeft) * hscale, (curve[5] - srcTop) * vscale); 771cb93a386Sopenharmony_ci } else if (curve.length == 7) { 772cb93a386Sopenharmony_ci drawConic(curve, srcLeft, srcTop, hscale, vscale); 773cb93a386Sopenharmony_ci } else { 774cb93a386Sopenharmony_ci ctx.bezierCurveTo( 775cb93a386Sopenharmony_ci (curve[2] - srcLeft) * hscale, (curve[3] - srcTop) * vscale, 776cb93a386Sopenharmony_ci (curve[4] - srcLeft) * hscale, (curve[5] - srcTop) * vscale, 777cb93a386Sopenharmony_ci (curve[6] - srcLeft) * hscale, (curve[7] - srcTop) * vscale); 778cb93a386Sopenharmony_ci } 779cb93a386Sopenharmony_ci if (draw_cubic_red ? curve.length == 8 : firstInside == curves) { 780cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(255,0,0, 1)"; 781cb93a386Sopenharmony_ci } else { 782cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,0,255, 1)"; 783cb93a386Sopenharmony_ci } 784cb93a386Sopenharmony_ci ctx.stroke(); 785cb93a386Sopenharmony_ci if (draw_endpoints > 0) { 786cb93a386Sopenharmony_ci drawPoint(curve[0], curve[1], false); 787cb93a386Sopenharmony_ci if (draw_endpoints > 1 || curve.length == 4) { 788cb93a386Sopenharmony_ci drawPoint(curve[2], curve[3], curve.length == 4 && draw_endpoints == 3); 789cb93a386Sopenharmony_ci } 790cb93a386Sopenharmony_ci if (curve.length == 6 || curve.length == 7 || 791cb93a386Sopenharmony_ci (draw_endpoints > 1 && curve.length == 8)) { 792cb93a386Sopenharmony_ci drawPoint(curve[4], curve[5], (curve.length == 6 || curve.length == 7) && draw_endpoints == 3); 793cb93a386Sopenharmony_ci } 794cb93a386Sopenharmony_ci if (curve.length == 8) { 795cb93a386Sopenharmony_ci drawPoint(curve[6], curve[7], curve.length == 8 && draw_endpoints == 3); 796cb93a386Sopenharmony_ci } 797cb93a386Sopenharmony_ci } 798cb93a386Sopenharmony_ci if (draw_midpoint != 0) { 799cb93a386Sopenharmony_ci if ((curves == 0) == (midLeft == 0)) { 800cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,180,127, 0.6)"; 801cb93a386Sopenharmony_ci } else { 802cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(127,0,127, 0.6)"; 803cb93a386Sopenharmony_ci } 804cb93a386Sopenharmony_ci var midX = x_at_t(curve, 0.5); 805cb93a386Sopenharmony_ci var midY = y_at_t(curve, 0.5); 806cb93a386Sopenharmony_ci drawPointSolid(midX, midY); 807cb93a386Sopenharmony_ci if (draw_midpoint > 1) { 808cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], midX, midY); 809cb93a386Sopenharmony_ci } 810cb93a386Sopenharmony_ci } 811cb93a386Sopenharmony_ci if (draw_quarterpoint != 0) { 812cb93a386Sopenharmony_ci if ((curves == 0) == (shortLeft == 0)) { 813cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,191,63, 0.6)"; 814cb93a386Sopenharmony_ci } else { 815cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(63,0,191, 0.6)"; 816cb93a386Sopenharmony_ci } 817cb93a386Sopenharmony_ci var midT = (curves == 0) == shorter ? 0.25 : 0.5; 818cb93a386Sopenharmony_ci var midX = x_at_t(curve, midT); 819cb93a386Sopenharmony_ci var midY = y_at_t(curve, midT); 820cb93a386Sopenharmony_ci drawPointSolid(midX, midY); 821cb93a386Sopenharmony_ci if (draw_quarterpoint > 1) { 822cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], midX, midY); 823cb93a386Sopenharmony_ci } 824cb93a386Sopenharmony_ci } 825cb93a386Sopenharmony_ci if (draw_sortpoint != 0) { 826cb93a386Sopenharmony_ci if ((curves == 0) == ((disallowShort == -1 ? midLeft : shortLeft) == 0)) { 827cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,155,37, 0.6)"; 828cb93a386Sopenharmony_ci } else { 829cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(37,0,155, 0.6)"; 830cb93a386Sopenharmony_ci } 831cb93a386Sopenharmony_ci var midT = (curves == 0) == shorter && disallowShort != curves ? 0.25 : 0.5; 832cb93a386Sopenharmony_ci console.log("curves=" + curves + " disallowShort=" + disallowShort 833cb93a386Sopenharmony_ci + " midLeft=" + midLeft + " shortLeft=" + shortLeft 834cb93a386Sopenharmony_ci + " shorter=" + shorter + " midT=" + midT); 835cb93a386Sopenharmony_ci var midX = x_at_t(curve, midT); 836cb93a386Sopenharmony_ci var midY = y_at_t(curve, midT); 837cb93a386Sopenharmony_ci drawPointSolid(midX, midY); 838cb93a386Sopenharmony_ci if (draw_sortpoint > 1) { 839cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], midX, midY); 840cb93a386Sopenharmony_ci } 841cb93a386Sopenharmony_ci } 842cb93a386Sopenharmony_ci if (draw_ray_intersect != 0) { 843cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(75,45,199, 0.6)"; 844cb93a386Sopenharmony_ci if (curve.length >= 6 && curve.length <= 8) { 845cb93a386Sopenharmony_ci var intersections = intersect[intersectIndex]; 846cb93a386Sopenharmony_ci for (var i in intersections) { 847cb93a386Sopenharmony_ci var intersection = intersections[i]; 848cb93a386Sopenharmony_ci var x = x_at_t(curve, intersection); 849cb93a386Sopenharmony_ci var y = y_at_t(curve, intersection); 850cb93a386Sopenharmony_ci drawPointSolid(x, y); 851cb93a386Sopenharmony_ci if (draw_ray_intersect > 1) { 852cb93a386Sopenharmony_ci drawLine(curve[0], curve[1], x, y); 853cb93a386Sopenharmony_ci } 854cb93a386Sopenharmony_ci } 855cb93a386Sopenharmony_ci } 856cb93a386Sopenharmony_ci ++intersectIndex; 857cb93a386Sopenharmony_ci } 858cb93a386Sopenharmony_ci if (draw_order) { 859cb93a386Sopenharmony_ci var px = x_at_t(curve, 0.75); 860cb93a386Sopenharmony_ci var py = y_at_t(curve, 0.75); 861cb93a386Sopenharmony_ci var _px = (px - srcLeft) * hscale; 862cb93a386Sopenharmony_ci var _py = (py - srcTop) * vscale; 863cb93a386Sopenharmony_ci ctx.beginPath(); 864cb93a386Sopenharmony_ci ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 865cb93a386Sopenharmony_ci ctx.closePath(); 866cb93a386Sopenharmony_ci ctx.fillStyle = "white"; 867cb93a386Sopenharmony_ci ctx.fill(); 868cb93a386Sopenharmony_ci if (draw_cubic_red ? curve.length == 8 : firstInside == curves) { 869cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(255,0,0, 1)"; 870cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(255,0,0, 1)"; 871cb93a386Sopenharmony_ci } else { 872cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,0,255, 1)"; 873cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,255, 1)"; 874cb93a386Sopenharmony_ci } 875cb93a386Sopenharmony_ci ctx.stroke(); 876cb93a386Sopenharmony_ci ctx.font = "normal 16px Arial"; 877cb93a386Sopenharmony_ci ctx.textAlign = "center"; 878cb93a386Sopenharmony_ci ctx.fillText(parseInt(curves) + 1, _px, _py + 5); 879cb93a386Sopenharmony_ci } 880cb93a386Sopenharmony_ci if (draw_closest_t) { 881cb93a386Sopenharmony_ci var t = curveClosestT(curve, mouseX, mouseY); 882cb93a386Sopenharmony_ci if (t >= 0) { 883cb93a386Sopenharmony_ci var x = x_at_t(curve, t); 884cb93a386Sopenharmony_ci var y = y_at_t(curve, t); 885cb93a386Sopenharmony_ci drawPointSolid(x, y); 886cb93a386Sopenharmony_ci } 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci if (!approximately_zero(hscale - hinitScale)) { 889cb93a386Sopenharmony_ci ctx.font = "normal 20px Arial"; 890cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,0, 0.3)"; 891cb93a386Sopenharmony_ci ctx.textAlign = "right"; 892cb93a386Sopenharmony_ci var scaleTextOffset = hscale != vscale ? -25 : -5; 893cb93a386Sopenharmony_ci ctx.fillText(hscale.toFixed(decimal_places) + 'x', 894cb93a386Sopenharmony_ci screenWidth - 10, screenHeight - scaleTextOffset); 895cb93a386Sopenharmony_ci if (hscale != vscale) { 896cb93a386Sopenharmony_ci ctx.fillText(vscale.toFixed(decimal_places) + 'y', 897cb93a386Sopenharmony_ci screenWidth - 10, screenHeight - 5); 898cb93a386Sopenharmony_ci } 899cb93a386Sopenharmony_ci } 900cb93a386Sopenharmony_ci if (draw_t) { 901cb93a386Sopenharmony_ci drawPointAtT(curve); 902cb93a386Sopenharmony_ci } 903cb93a386Sopenharmony_ci if (draw_id != 0) { 904cb93a386Sopenharmony_ci var id = -1; 905cb93a386Sopenharmony_ci for (var i = 0; i < ids.length; i += 2) { 906cb93a386Sopenharmony_ci if (ids[i + 1] == curve) { 907cb93a386Sopenharmony_ci id = ids[i]; 908cb93a386Sopenharmony_ci break; 909cb93a386Sopenharmony_ci } 910cb93a386Sopenharmony_ci } 911cb93a386Sopenharmony_ci if (id >= 0) { 912cb93a386Sopenharmony_ci var px = x_at_t(curve, 0.5); 913cb93a386Sopenharmony_ci var py = y_at_t(curve, 0.5); 914cb93a386Sopenharmony_ci var _px = (px - srcLeft) * hscale; 915cb93a386Sopenharmony_ci var _py = (py - srcTop) * vscale; 916cb93a386Sopenharmony_ci ctx.beginPath(); 917cb93a386Sopenharmony_ci ctx.arc(_px, _py, 15, 0, Math.PI * 2, true); 918cb93a386Sopenharmony_ci ctx.closePath(); 919cb93a386Sopenharmony_ci ctx.fillStyle = "white"; 920cb93a386Sopenharmony_ci ctx.fill(); 921cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(255,0,0, 1)"; 922cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(255,0,0, 1)"; 923cb93a386Sopenharmony_ci ctx.stroke(); 924cb93a386Sopenharmony_ci ctx.font = "normal 16px Arial"; 925cb93a386Sopenharmony_ci ctx.textAlign = "center"; 926cb93a386Sopenharmony_ci ctx.fillText(id, _px, _py + 5); 927cb93a386Sopenharmony_ci } 928cb93a386Sopenharmony_ci } 929cb93a386Sopenharmony_ci } 930cb93a386Sopenharmony_ci if (draw_t) { 931cb93a386Sopenharmony_ci drawCurveTControl(); 932cb93a386Sopenharmony_ci } 933cb93a386Sopenharmony_ci if (draw_w) { 934cb93a386Sopenharmony_ci drawCurveWControl(); 935cb93a386Sopenharmony_ci } 936cb93a386Sopenharmony_ci } 937cb93a386Sopenharmony_ci 938cb93a386Sopenharmony_ci function drawCurveTControl() { 939cb93a386Sopenharmony_ci ctx.lineWidth = 2; 940cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 941cb93a386Sopenharmony_ci ctx.beginPath(); 942cb93a386Sopenharmony_ci ctx.rect(screenWidth - 80, 40, 28, screenHeight - 80); 943cb93a386Sopenharmony_ci ctx.stroke(); 944cb93a386Sopenharmony_ci var ty = 40 + curveT * (screenHeight - 80); 945cb93a386Sopenharmony_ci ctx.beginPath(); 946cb93a386Sopenharmony_ci ctx.moveTo(screenWidth - 80, ty); 947cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 85, ty - 5); 948cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 85, ty + 5); 949cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 80, ty); 950cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,0, 0.6)"; 951cb93a386Sopenharmony_ci ctx.fill(); 952cb93a386Sopenharmony_ci var num = curveT.toFixed(decimal_places); 953cb93a386Sopenharmony_ci ctx.font = "normal 10px Arial"; 954cb93a386Sopenharmony_ci ctx.textAlign = "left"; 955cb93a386Sopenharmony_ci ctx.fillText(num, screenWidth - 78, ty); 956cb93a386Sopenharmony_ci } 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ci function drawCurveWControl() { 959cb93a386Sopenharmony_ci var w = -1; 960cb93a386Sopenharmony_ci var choice = 0; 961cb93a386Sopenharmony_ci for (var curves in tests[testIndex]) { 962cb93a386Sopenharmony_ci var curve = tests[testIndex][curves]; 963cb93a386Sopenharmony_ci if (curve.length != 7) { 964cb93a386Sopenharmony_ci continue; 965cb93a386Sopenharmony_ci } 966cb93a386Sopenharmony_ci if (choice == curveW) { 967cb93a386Sopenharmony_ci w = curve[6]; 968cb93a386Sopenharmony_ci break; 969cb93a386Sopenharmony_ci } 970cb93a386Sopenharmony_ci ++choice; 971cb93a386Sopenharmony_ci } 972cb93a386Sopenharmony_ci if (w < 0) { 973cb93a386Sopenharmony_ci return; 974cb93a386Sopenharmony_ci } 975cb93a386Sopenharmony_ci ctx.lineWidth = 2; 976cb93a386Sopenharmony_ci ctx.strokeStyle = "rgba(0,0,0, 0.3)"; 977cb93a386Sopenharmony_ci ctx.beginPath(); 978cb93a386Sopenharmony_ci ctx.rect(screenWidth - 40, 40, 28, screenHeight - 80); 979cb93a386Sopenharmony_ci ctx.stroke(); 980cb93a386Sopenharmony_ci var ty = 40 + w * (screenHeight - 80); 981cb93a386Sopenharmony_ci ctx.beginPath(); 982cb93a386Sopenharmony_ci ctx.moveTo(screenWidth - 40, ty); 983cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 45, ty - 5); 984cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 45, ty + 5); 985cb93a386Sopenharmony_ci ctx.lineTo(screenWidth - 40, ty); 986cb93a386Sopenharmony_ci ctx.fillStyle = "rgba(0,0,0, 0.6)"; 987cb93a386Sopenharmony_ci ctx.fill(); 988cb93a386Sopenharmony_ci var num = w.toFixed(decimal_places); 989cb93a386Sopenharmony_ci ctx.font = "normal 10px Arial"; 990cb93a386Sopenharmony_ci ctx.textAlign = "left"; 991cb93a386Sopenharmony_ci ctx.fillText(num, screenWidth - 38, ty); 992cb93a386Sopenharmony_ci } 993cb93a386Sopenharmony_ci 994cb93a386Sopenharmony_ci function ptInTControl() { 995cb93a386Sopenharmony_ci var e = window.event; 996cb93a386Sopenharmony_ci var tgt = e.target || e.srcElement; 997cb93a386Sopenharmony_ci var left = tgt.offsetLeft; 998cb93a386Sopenharmony_ci var top = tgt.offsetTop; 999cb93a386Sopenharmony_ci var x = (e.clientX - left); 1000cb93a386Sopenharmony_ci var y = (e.clientY - top); 1001cb93a386Sopenharmony_ci if (x < screenWidth - 80 || x > screenWidth - 50) { 1002cb93a386Sopenharmony_ci return false; 1003cb93a386Sopenharmony_ci } 1004cb93a386Sopenharmony_ci if (y < 40 || y > screenHeight - 80) { 1005cb93a386Sopenharmony_ci return false; 1006cb93a386Sopenharmony_ci } 1007cb93a386Sopenharmony_ci curveT = (y - 40) / (screenHeight - 120); 1008cb93a386Sopenharmony_ci if (curveT < 0 || curveT > 1) { 1009cb93a386Sopenharmony_ci throw "stop execution"; 1010cb93a386Sopenharmony_ci } 1011cb93a386Sopenharmony_ci return true; 1012cb93a386Sopenharmony_ci } 1013cb93a386Sopenharmony_ci 1014cb93a386Sopenharmony_ci function ptInWControl() { 1015cb93a386Sopenharmony_ci var e = window.event; 1016cb93a386Sopenharmony_ci var tgt = e.target || e.srcElement; 1017cb93a386Sopenharmony_ci var left = tgt.offsetLeft; 1018cb93a386Sopenharmony_ci var top = tgt.offsetTop; 1019cb93a386Sopenharmony_ci var x = (e.clientX - left); 1020cb93a386Sopenharmony_ci var y = (e.clientY - top); 1021cb93a386Sopenharmony_ci if (x < screenWidth - 40 || x > screenWidth - 10) { 1022cb93a386Sopenharmony_ci return false; 1023cb93a386Sopenharmony_ci } 1024cb93a386Sopenharmony_ci if (y < 40 || y > screenHeight - 80) { 1025cb93a386Sopenharmony_ci return false; 1026cb93a386Sopenharmony_ci } 1027cb93a386Sopenharmony_ci var w = (y - 40) / (screenHeight - 120); 1028cb93a386Sopenharmony_ci if (w < 0 || w > 1) { 1029cb93a386Sopenharmony_ci throw "stop execution"; 1030cb93a386Sopenharmony_ci } 1031cb93a386Sopenharmony_ci var choice = 0; 1032cb93a386Sopenharmony_ci for (var curves in tests[testIndex]) { 1033cb93a386Sopenharmony_ci var curve = tests[testIndex][curves]; 1034cb93a386Sopenharmony_ci if (curve.length != 7) { 1035cb93a386Sopenharmony_ci continue; 1036cb93a386Sopenharmony_ci } 1037cb93a386Sopenharmony_ci if (choice == curveW) { 1038cb93a386Sopenharmony_ci curve[6] = w; 1039cb93a386Sopenharmony_ci break; 1040cb93a386Sopenharmony_ci } 1041cb93a386Sopenharmony_ci ++choice; 1042cb93a386Sopenharmony_ci } 1043cb93a386Sopenharmony_ci return true; 1044cb93a386Sopenharmony_ci } 1045cb93a386Sopenharmony_ci 1046cb93a386Sopenharmony_ci function drawTop() { 1047cb93a386Sopenharmony_ci init(tests[testIndex]); 1048cb93a386Sopenharmony_ci redraw(); 1049cb93a386Sopenharmony_ci } 1050cb93a386Sopenharmony_ci 1051cb93a386Sopenharmony_ci function redraw() { 1052cb93a386Sopenharmony_ci if (focus_on_selection > 0) { 1053cb93a386Sopenharmony_ci var focusXmin = focusYmin = Infinity; 1054cb93a386Sopenharmony_ci var focusXmax = focusYmax = -Infinity; 1055cb93a386Sopenharmony_ci var choice = 0; 1056cb93a386Sopenharmony_ci for (var curves in tests[testIndex]) { 1057cb93a386Sopenharmony_ci if (++choice != focus_on_selection) { 1058cb93a386Sopenharmony_ci continue; 1059cb93a386Sopenharmony_ci } 1060cb93a386Sopenharmony_ci var curve = tests[testIndex][curves]; 1061cb93a386Sopenharmony_ci var last = curve.length - (curve.length % 2 == 1 ? 1 : 0); 1062cb93a386Sopenharmony_ci for (var idx = 0; idx < last; idx += 2) { 1063cb93a386Sopenharmony_ci focusXmin = Math.min(focusXmin, curve[idx]); 1064cb93a386Sopenharmony_ci focusXmax = Math.max(focusXmax, curve[idx]); 1065cb93a386Sopenharmony_ci focusYmin = Math.min(focusYmin, curve[idx + 1]); 1066cb93a386Sopenharmony_ci focusYmax = Math.max(focusYmax, curve[idx + 1]); 1067cb93a386Sopenharmony_ci } 1068cb93a386Sopenharmony_ci } 1069cb93a386Sopenharmony_ci focusXmin -= Math.min(1, Math.max(focusXmax - focusXmin, focusYmax - focusYmin)); 1070cb93a386Sopenharmony_ci if (focusXmin < focusXmax && focusYmin < focusYmax) { 1071cb93a386Sopenharmony_ci setScale(focusXmin, focusXmax, focusYmin, focusYmax); 1072cb93a386Sopenharmony_ci } 1073cb93a386Sopenharmony_ci } 1074cb93a386Sopenharmony_ci ctx.beginPath(); 1075cb93a386Sopenharmony_ci ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height); 1076cb93a386Sopenharmony_ci ctx.fillStyle = "white"; 1077cb93a386Sopenharmony_ci ctx.fill(); 1078cb93a386Sopenharmony_ci draw(tests[testIndex], testTitles[testIndex]); 1079cb93a386Sopenharmony_ci } 1080cb93a386Sopenharmony_ci 1081cb93a386Sopenharmony_ci function doKeyPress(evt) { 1082cb93a386Sopenharmony_ci var char = String.fromCharCode(evt.charCode); 1083cb93a386Sopenharmony_ci var focusWasOn = false; 1084cb93a386Sopenharmony_ci switch (char) { 1085cb93a386Sopenharmony_ci case '0': 1086cb93a386Sopenharmony_ci case '1': 1087cb93a386Sopenharmony_ci case '2': 1088cb93a386Sopenharmony_ci case '3': 1089cb93a386Sopenharmony_ci case '4': 1090cb93a386Sopenharmony_ci case '5': 1091cb93a386Sopenharmony_ci case '6': 1092cb93a386Sopenharmony_ci case '7': 1093cb93a386Sopenharmony_ci case '8': 1094cb93a386Sopenharmony_ci case '9': 1095cb93a386Sopenharmony_ci decimal_places = char - '0'; 1096cb93a386Sopenharmony_ci redraw(); 1097cb93a386Sopenharmony_ci break; 1098cb93a386Sopenharmony_ci case '-': 1099cb93a386Sopenharmony_ci focusWasOn = focus_on_selection; 1100cb93a386Sopenharmony_ci if (focusWasOn) { 1101cb93a386Sopenharmony_ci focus_on_selection = false; 1102cb93a386Sopenharmony_ci hscale /= 1.2; 1103cb93a386Sopenharmony_ci vscale /= 1.2; 1104cb93a386Sopenharmony_ci } else { 1105cb93a386Sopenharmony_ci hscale /= 2; 1106cb93a386Sopenharmony_ci vscale /= 2; 1107cb93a386Sopenharmony_ci } 1108cb93a386Sopenharmony_ci calcLeftTop(); 1109cb93a386Sopenharmony_ci redraw(); 1110cb93a386Sopenharmony_ci focus_on_selection = focusWasOn; 1111cb93a386Sopenharmony_ci break; 1112cb93a386Sopenharmony_ci case '=': 1113cb93a386Sopenharmony_ci case '+': 1114cb93a386Sopenharmony_ci focusWasOn = focus_on_selection; 1115cb93a386Sopenharmony_ci if (focusWasOn) { 1116cb93a386Sopenharmony_ci focus_on_selection = false; 1117cb93a386Sopenharmony_ci hscale *= 1.2; 1118cb93a386Sopenharmony_ci vscale *= 1.2; 1119cb93a386Sopenharmony_ci } else { 1120cb93a386Sopenharmony_ci hscale *= 2; 1121cb93a386Sopenharmony_ci vscale *= 2; 1122cb93a386Sopenharmony_ci } 1123cb93a386Sopenharmony_ci calcLeftTop(); 1124cb93a386Sopenharmony_ci redraw(); 1125cb93a386Sopenharmony_ci focus_on_selection = focusWasOn; 1126cb93a386Sopenharmony_ci break; 1127cb93a386Sopenharmony_ci case 'b': 1128cb93a386Sopenharmony_ci draw_cubic_red ^= true; 1129cb93a386Sopenharmony_ci redraw(); 1130cb93a386Sopenharmony_ci break; 1131cb93a386Sopenharmony_ci case 'c': 1132cb93a386Sopenharmony_ci drawTop(); 1133cb93a386Sopenharmony_ci break; 1134cb93a386Sopenharmony_ci case 'd': 1135cb93a386Sopenharmony_ci var test = tests[testIndex]; 1136cb93a386Sopenharmony_ci var testClone = []; 1137cb93a386Sopenharmony_ci for (var curves in test) { 1138cb93a386Sopenharmony_ci var c = test[curves]; 1139cb93a386Sopenharmony_ci var cClone = []; 1140cb93a386Sopenharmony_ci for (var index = 0; index < c.length; ++index) { 1141cb93a386Sopenharmony_ci cClone.push(c[index]); 1142cb93a386Sopenharmony_ci } 1143cb93a386Sopenharmony_ci testClone.push(cClone); 1144cb93a386Sopenharmony_ci } 1145cb93a386Sopenharmony_ci tests.push(testClone); 1146cb93a386Sopenharmony_ci testTitles.push(testTitles[testIndex] + " copy"); 1147cb93a386Sopenharmony_ci testIndex = tests.length - 1; 1148cb93a386Sopenharmony_ci redraw(); 1149cb93a386Sopenharmony_ci break; 1150cb93a386Sopenharmony_ci case 'e': 1151cb93a386Sopenharmony_ci draw_endpoints = (draw_endpoints + 1) % 4; 1152cb93a386Sopenharmony_ci redraw(); 1153cb93a386Sopenharmony_ci break; 1154cb93a386Sopenharmony_ci case 'f': 1155cb93a386Sopenharmony_ci draw_derivative ^= true; 1156cb93a386Sopenharmony_ci redraw(); 1157cb93a386Sopenharmony_ci break; 1158cb93a386Sopenharmony_ci case 'g': 1159cb93a386Sopenharmony_ci hscale *= 1.2; 1160cb93a386Sopenharmony_ci calcLeftTop(); 1161cb93a386Sopenharmony_ci redraw(); 1162cb93a386Sopenharmony_ci break; 1163cb93a386Sopenharmony_ci case 'G': 1164cb93a386Sopenharmony_ci hscale /= 1.2; 1165cb93a386Sopenharmony_ci calcLeftTop(); 1166cb93a386Sopenharmony_ci redraw(); 1167cb93a386Sopenharmony_ci break; 1168cb93a386Sopenharmony_ci case 'h': 1169cb93a386Sopenharmony_ci vscale *= 1.2; 1170cb93a386Sopenharmony_ci calcLeftTop(); 1171cb93a386Sopenharmony_ci redraw(); 1172cb93a386Sopenharmony_ci break; 1173cb93a386Sopenharmony_ci case 'H': 1174cb93a386Sopenharmony_ci vscale /= 1.2; 1175cb93a386Sopenharmony_ci calcLeftTop(); 1176cb93a386Sopenharmony_ci redraw(); 1177cb93a386Sopenharmony_ci break; 1178cb93a386Sopenharmony_ci case 'i': 1179cb93a386Sopenharmony_ci draw_ray_intersect = (draw_ray_intersect + 1) % 3; 1180cb93a386Sopenharmony_ci redraw(); 1181cb93a386Sopenharmony_ci break; 1182cb93a386Sopenharmony_ci case 'l': 1183cb93a386Sopenharmony_ci var test = tests[testIndex]; 1184cb93a386Sopenharmony_ci console.log("<div id=\"" + testTitles[testIndex] + "\" >"); 1185cb93a386Sopenharmony_ci for (var curves in test) { 1186cb93a386Sopenharmony_ci var c = test[curves]; 1187cb93a386Sopenharmony_ci var s = "{{"; 1188cb93a386Sopenharmony_ci for (var i = 0; i < c.length; i += 2) { 1189cb93a386Sopenharmony_ci s += "{"; 1190cb93a386Sopenharmony_ci s += c[i] + "," + c[i + 1]; 1191cb93a386Sopenharmony_ci s += "}"; 1192cb93a386Sopenharmony_ci if (i + 2 < c.length) { 1193cb93a386Sopenharmony_ci s += ", "; 1194cb93a386Sopenharmony_ci } 1195cb93a386Sopenharmony_ci } 1196cb93a386Sopenharmony_ci console.log(s + "}},"); 1197cb93a386Sopenharmony_ci } 1198cb93a386Sopenharmony_ci console.log("</div>"); 1199cb93a386Sopenharmony_ci break; 1200cb93a386Sopenharmony_ci case 'm': 1201cb93a386Sopenharmony_ci draw_midpoint = (draw_midpoint + 1) % 3; 1202cb93a386Sopenharmony_ci redraw(); 1203cb93a386Sopenharmony_ci break; 1204cb93a386Sopenharmony_ci case 'N': 1205cb93a386Sopenharmony_ci testIndex += 9; 1206cb93a386Sopenharmony_ci case 'n': 1207cb93a386Sopenharmony_ci testIndex = (testIndex + 1) % tests.length; 1208cb93a386Sopenharmony_ci drawTop(); 1209cb93a386Sopenharmony_ci break; 1210cb93a386Sopenharmony_ci case 'o': 1211cb93a386Sopenharmony_ci draw_order ^= true; 1212cb93a386Sopenharmony_ci redraw(); 1213cb93a386Sopenharmony_ci break; 1214cb93a386Sopenharmony_ci case 'P': 1215cb93a386Sopenharmony_ci testIndex -= 9; 1216cb93a386Sopenharmony_ci case 'p': 1217cb93a386Sopenharmony_ci if (--testIndex < 0) 1218cb93a386Sopenharmony_ci testIndex = tests.length - 1; 1219cb93a386Sopenharmony_ci drawTop(); 1220cb93a386Sopenharmony_ci break; 1221cb93a386Sopenharmony_ci case 'q': 1222cb93a386Sopenharmony_ci draw_quarterpoint = (draw_quarterpoint + 1) % 3; 1223cb93a386Sopenharmony_ci redraw(); 1224cb93a386Sopenharmony_ci break; 1225cb93a386Sopenharmony_ci case 'r': 1226cb93a386Sopenharmony_ci for (var i = 0; i < testDivs.length; ++i) { 1227cb93a386Sopenharmony_ci var title = testDivs[i].id.toString(); 1228cb93a386Sopenharmony_ci if (title == testTitles[testIndex]) { 1229cb93a386Sopenharmony_ci var str = testDivs[i].firstChild.data; 1230cb93a386Sopenharmony_ci parse(str, title); 1231cb93a386Sopenharmony_ci var original = tests.pop(); 1232cb93a386Sopenharmony_ci testTitles.pop(); 1233cb93a386Sopenharmony_ci tests[testIndex] = original; 1234cb93a386Sopenharmony_ci break; 1235cb93a386Sopenharmony_ci } 1236cb93a386Sopenharmony_ci } 1237cb93a386Sopenharmony_ci redraw(); 1238cb93a386Sopenharmony_ci break; 1239cb93a386Sopenharmony_ci case 's': 1240cb93a386Sopenharmony_ci draw_sortpoint = (draw_sortpoint + 1) % 3; 1241cb93a386Sopenharmony_ci redraw(); 1242cb93a386Sopenharmony_ci break; 1243cb93a386Sopenharmony_ci case 't': 1244cb93a386Sopenharmony_ci draw_t ^= true; 1245cb93a386Sopenharmony_ci redraw(); 1246cb93a386Sopenharmony_ci break; 1247cb93a386Sopenharmony_ci case 'u': 1248cb93a386Sopenharmony_ci draw_closest_t ^= true; 1249cb93a386Sopenharmony_ci redraw(); 1250cb93a386Sopenharmony_ci break; 1251cb93a386Sopenharmony_ci case 'v': 1252cb93a386Sopenharmony_ci draw_tangents = (draw_tangents + 1) % 4; 1253cb93a386Sopenharmony_ci redraw(); 1254cb93a386Sopenharmony_ci break; 1255cb93a386Sopenharmony_ci case 'w': 1256cb93a386Sopenharmony_ci ++curveW; 1257cb93a386Sopenharmony_ci var choice = 0; 1258cb93a386Sopenharmony_ci draw_w = false; 1259cb93a386Sopenharmony_ci for (var curves in tests[testIndex]) { 1260cb93a386Sopenharmony_ci var curve = tests[testIndex][curves]; 1261cb93a386Sopenharmony_ci if (curve.length != 7) { 1262cb93a386Sopenharmony_ci continue; 1263cb93a386Sopenharmony_ci } 1264cb93a386Sopenharmony_ci if (choice == curveW) { 1265cb93a386Sopenharmony_ci draw_w = true; 1266cb93a386Sopenharmony_ci break; 1267cb93a386Sopenharmony_ci } 1268cb93a386Sopenharmony_ci ++choice; 1269cb93a386Sopenharmony_ci } 1270cb93a386Sopenharmony_ci if (!draw_w) { 1271cb93a386Sopenharmony_ci curveW = -1; 1272cb93a386Sopenharmony_ci } 1273cb93a386Sopenharmony_ci redraw(); 1274cb93a386Sopenharmony_ci break; 1275cb93a386Sopenharmony_ci case 'x': 1276cb93a386Sopenharmony_ci draw_point_xy ^= true; 1277cb93a386Sopenharmony_ci redraw(); 1278cb93a386Sopenharmony_ci break; 1279cb93a386Sopenharmony_ci case 'y': 1280cb93a386Sopenharmony_ci draw_mouse_xy ^= true; 1281cb93a386Sopenharmony_ci redraw(); 1282cb93a386Sopenharmony_ci break; 1283cb93a386Sopenharmony_ci case '\\': 1284cb93a386Sopenharmony_ci retina_scale ^= true; 1285cb93a386Sopenharmony_ci drawTop(); 1286cb93a386Sopenharmony_ci break; 1287cb93a386Sopenharmony_ci case '`': 1288cb93a386Sopenharmony_ci ++focus_on_selection; 1289cb93a386Sopenharmony_ci if (focus_on_selection >= tests[testIndex].length) { 1290cb93a386Sopenharmony_ci focus_on_selection = 0; 1291cb93a386Sopenharmony_ci } 1292cb93a386Sopenharmony_ci setScale(xmin, xmax, ymin, ymax); 1293cb93a386Sopenharmony_ci redraw(); 1294cb93a386Sopenharmony_ci break; 1295cb93a386Sopenharmony_ci case '.': 1296cb93a386Sopenharmony_ci draw_id = (draw_id + 1) % 3; 1297cb93a386Sopenharmony_ci redraw(); 1298cb93a386Sopenharmony_ci break; 1299cb93a386Sopenharmony_ci } 1300cb93a386Sopenharmony_ci } 1301cb93a386Sopenharmony_ci 1302cb93a386Sopenharmony_ci function doKeyDown(evt) { 1303cb93a386Sopenharmony_ci var char = evt.keyCode; 1304cb93a386Sopenharmony_ci var preventDefault = false; 1305cb93a386Sopenharmony_ci switch (char) { 1306cb93a386Sopenharmony_ci case 37: // left arrow 1307cb93a386Sopenharmony_ci if (evt.shiftKey) { 1308cb93a386Sopenharmony_ci testIndex -= 9; 1309cb93a386Sopenharmony_ci } 1310cb93a386Sopenharmony_ci if (--testIndex < 0) 1311cb93a386Sopenharmony_ci testIndex = tests.length - 1; 1312cb93a386Sopenharmony_ci if (evt.ctrlKey) { 1313cb93a386Sopenharmony_ci redraw(); 1314cb93a386Sopenharmony_ci } else { 1315cb93a386Sopenharmony_ci drawTop(); 1316cb93a386Sopenharmony_ci } 1317cb93a386Sopenharmony_ci preventDefault = true; 1318cb93a386Sopenharmony_ci break; 1319cb93a386Sopenharmony_ci case 39: // right arrow 1320cb93a386Sopenharmony_ci if (evt.shiftKey) { 1321cb93a386Sopenharmony_ci testIndex += 9; 1322cb93a386Sopenharmony_ci } 1323cb93a386Sopenharmony_ci if (++testIndex >= tests.length) 1324cb93a386Sopenharmony_ci testIndex = 0; 1325cb93a386Sopenharmony_ci if (evt.ctrlKey) { 1326cb93a386Sopenharmony_ci redraw(); 1327cb93a386Sopenharmony_ci } else { 1328cb93a386Sopenharmony_ci drawTop(); 1329cb93a386Sopenharmony_ci } 1330cb93a386Sopenharmony_ci preventDefault = true; 1331cb93a386Sopenharmony_ci break; 1332cb93a386Sopenharmony_ci } 1333cb93a386Sopenharmony_ci if (preventDefault) { 1334cb93a386Sopenharmony_ci evt.preventDefault(); 1335cb93a386Sopenharmony_ci return false; 1336cb93a386Sopenharmony_ci } 1337cb93a386Sopenharmony_ci return true; 1338cb93a386Sopenharmony_ci } 1339cb93a386Sopenharmony_ci 1340cb93a386Sopenharmony_ci function calcXY() { 1341cb93a386Sopenharmony_ci var e = window.event; 1342cb93a386Sopenharmony_ci var tgt = e.target || e.srcElement; 1343cb93a386Sopenharmony_ci var left = tgt.offsetLeft; 1344cb93a386Sopenharmony_ci var top = tgt.offsetTop; 1345cb93a386Sopenharmony_ci mouseX = (e.clientX - left) / hscale + srcLeft; 1346cb93a386Sopenharmony_ci mouseY = (e.clientY - top) / vscale + srcTop; 1347cb93a386Sopenharmony_ci } 1348cb93a386Sopenharmony_ci 1349cb93a386Sopenharmony_ci function calcLeftTop() { 1350cb93a386Sopenharmony_ci srcLeft = mouseX - screenWidth / 2 / hscale; 1351cb93a386Sopenharmony_ci srcTop = mouseY - screenHeight / 2 / vscale; 1352cb93a386Sopenharmony_ci } 1353cb93a386Sopenharmony_ci 1354cb93a386Sopenharmony_ci function handleMouseClick() { 1355cb93a386Sopenharmony_ci if ((!draw_t || !ptInTControl()) && (!draw_w || !ptInWControl())) { 1356cb93a386Sopenharmony_ci calcXY(); 1357cb93a386Sopenharmony_ci } else { 1358cb93a386Sopenharmony_ci redraw(); 1359cb93a386Sopenharmony_ci } 1360cb93a386Sopenharmony_ci } 1361cb93a386Sopenharmony_ci 1362cb93a386Sopenharmony_ci function initDown() { 1363cb93a386Sopenharmony_ci var test = tests[testIndex]; 1364cb93a386Sopenharmony_ci var bestDistance = 1000000; 1365cb93a386Sopenharmony_ci activePt = -1; 1366cb93a386Sopenharmony_ci for (var curves in test) { 1367cb93a386Sopenharmony_ci var testCurve = test[curves]; 1368cb93a386Sopenharmony_ci if (testCurve.length != 4 && (testCurve.length < 6 || testCurve.length > 8)) { 1369cb93a386Sopenharmony_ci continue; 1370cb93a386Sopenharmony_ci } 1371cb93a386Sopenharmony_ci var testMax = testCurve.length == 7 ? 6 : testCurve.length; 1372cb93a386Sopenharmony_ci for (var i = 0; i < testMax; i += 2) { 1373cb93a386Sopenharmony_ci var testX = testCurve[i]; 1374cb93a386Sopenharmony_ci var testY = testCurve[i + 1]; 1375cb93a386Sopenharmony_ci var dx = testX - mouseX; 1376cb93a386Sopenharmony_ci var dy = testY - mouseY; 1377cb93a386Sopenharmony_ci var dist = dx * dx + dy * dy; 1378cb93a386Sopenharmony_ci if (dist > bestDistance) { 1379cb93a386Sopenharmony_ci continue; 1380cb93a386Sopenharmony_ci } 1381cb93a386Sopenharmony_ci activeCurve = testCurve; 1382cb93a386Sopenharmony_ci activePt = i; 1383cb93a386Sopenharmony_ci bestDistance = dist; 1384cb93a386Sopenharmony_ci } 1385cb93a386Sopenharmony_ci } 1386cb93a386Sopenharmony_ci if (activePt >= 0) { 1387cb93a386Sopenharmony_ci lastX = mouseX; 1388cb93a386Sopenharmony_ci lastY = mouseY; 1389cb93a386Sopenharmony_ci } 1390cb93a386Sopenharmony_ci } 1391cb93a386Sopenharmony_ci 1392cb93a386Sopenharmony_ci function handleMouseOver() { 1393cb93a386Sopenharmony_ci calcXY(); 1394cb93a386Sopenharmony_ci if (draw_mouse_xy) { 1395cb93a386Sopenharmony_ci var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places); 1396cb93a386Sopenharmony_ci ctx.beginPath(); 1397cb93a386Sopenharmony_ci ctx.rect(300, 100, num.length * 6, 10); 1398cb93a386Sopenharmony_ci ctx.fillStyle = "white"; 1399cb93a386Sopenharmony_ci ctx.fill(); 1400cb93a386Sopenharmony_ci ctx.font = "normal 10px Arial"; 1401cb93a386Sopenharmony_ci ctx.fillStyle = "black"; 1402cb93a386Sopenharmony_ci ctx.textAlign = "left"; 1403cb93a386Sopenharmony_ci ctx.fillText(num, 300, 108); 1404cb93a386Sopenharmony_ci } 1405cb93a386Sopenharmony_ci if (!mouseDown) { 1406cb93a386Sopenharmony_ci activePt = -1; 1407cb93a386Sopenharmony_ci return; 1408cb93a386Sopenharmony_ci } 1409cb93a386Sopenharmony_ci if (activePt < 0) { 1410cb93a386Sopenharmony_ci initDown(); 1411cb93a386Sopenharmony_ci return; 1412cb93a386Sopenharmony_ci } 1413cb93a386Sopenharmony_ci var deltaX = mouseX - lastX; 1414cb93a386Sopenharmony_ci var deltaY = mouseY - lastY; 1415cb93a386Sopenharmony_ci lastX = mouseX; 1416cb93a386Sopenharmony_ci lastY = mouseY; 1417cb93a386Sopenharmony_ci if (activePt == 0) { 1418cb93a386Sopenharmony_ci var test = tests[testIndex]; 1419cb93a386Sopenharmony_ci for (var curves in test) { 1420cb93a386Sopenharmony_ci var testCurve = test[curves]; 1421cb93a386Sopenharmony_ci testCurve[0] += deltaX; 1422cb93a386Sopenharmony_ci testCurve[1] += deltaY; 1423cb93a386Sopenharmony_ci } 1424cb93a386Sopenharmony_ci } else { 1425cb93a386Sopenharmony_ci activeCurve[activePt] += deltaX; 1426cb93a386Sopenharmony_ci activeCurve[activePt + 1] += deltaY; 1427cb93a386Sopenharmony_ci } 1428cb93a386Sopenharmony_ci redraw(); 1429cb93a386Sopenharmony_ci } 1430cb93a386Sopenharmony_ci 1431cb93a386Sopenharmony_ci function start() { 1432cb93a386Sopenharmony_ci for (var i = 0; i < testDivs.length; ++i) { 1433cb93a386Sopenharmony_ci var title = testDivs[i].id.toString(); 1434cb93a386Sopenharmony_ci var str = testDivs[i].firstChild.data; 1435cb93a386Sopenharmony_ci parse(str, title); 1436cb93a386Sopenharmony_ci } 1437cb93a386Sopenharmony_ci drawTop(); 1438cb93a386Sopenharmony_ci window.addEventListener('keypress', doKeyPress, true); 1439cb93a386Sopenharmony_ci window.addEventListener('keydown', doKeyDown, true); 1440cb93a386Sopenharmony_ci window.onresize = function () { 1441cb93a386Sopenharmony_ci drawTop(); 1442cb93a386Sopenharmony_ci } 1443cb93a386Sopenharmony_ci } 1444cb93a386Sopenharmony_ci 1445cb93a386Sopenharmony_ci</script> 1446cb93a386Sopenharmony_ci</head> 1447cb93a386Sopenharmony_ci 1448cb93a386Sopenharmony_ci<body onLoad="start();"> 1449cb93a386Sopenharmony_ci 1450cb93a386Sopenharmony_ci<canvas id="canvas" width="750" height="500" 1451cb93a386Sopenharmony_ci onmousedown="mouseDown = true" 1452cb93a386Sopenharmony_ci onmouseup="mouseDown = false" 1453cb93a386Sopenharmony_ci onmousemove="handleMouseOver()" 1454cb93a386Sopenharmony_ci onclick="handleMouseClick()" 1455cb93a386Sopenharmony_ci ></canvas > 1456cb93a386Sopenharmony_ci</body> 1457cb93a386Sopenharmony_ci</html>