Home | History | Annotate | Download | only in Intersection
      1 <html>
      2 <head>
      3 <div style="height:0">
      4 
      5 <div id="test1">
      6 computeDelta c1=(0,1 1,6 1,0 2,0) t1=0.0166500365 scale1=1 c2=(0,1 0,2 1,0 6,1) t2=0.126935168 scale2=1
      7 cubicTangent t=0.0166500365 tangent=(-2.85263545,-12.6745554 2.95089079,15.1559166) pt=(0.0491276698 1.24068063) dxy=(2.90176312 13.915236)
      8 cubicTangent t=0.126935168 tangent=(-0.852150487,0.242871519 0.961097194,2.2532568) pt=(0.0544733534 1.24806416) dxy=(0.90662384 1.00519264)
      9 cubicDelta tangent=(-0.00039510851,-0.00189471984 0.0495227783,1.24257535) intersectLen=0.00193547772 tangentLen=14.2145708 scale=0.00390625 result=0.00404241153
     10 cubicDelta tangent=(0.00495057512,0.00548880522 0.0495227783,1.24257535) intersectLen=0.00739156118 tangentLen=1.35365395 scale=0.00390625 result=0.00936670107
     11 </div>
     12 
     13 <div id="test2">
     14 computeDelta c1=(0,1 0,2 1,0 6,1) t1=0.121215914 scale1=0.0187334021 c2=(0,1 1,6 1,0 2,0) t2=0.0167515231 scale2=0.00808482306
     15 cubicTangent t=0.121215914 tangent=(-0.810112087,0.159501524 0.908958243,2.32468734) pt=(0.0494230781 1.24209443) dxy=(0.859535165 1.08259291)
     16 cubicTangent t=0.0167515231 tangent=(-2.85175241,-12.6666182 2.95059667,15.1508033) pt=(0.0494221303 1.24209251) dxy=(2.90117454 13.9087108)
     17 cubicDelta tangent=(7.4284882e-07,9.35625319e-07 0.0494223352,1.2420935) intersectLen=1.19466276e-06 tangentLen=1.38231983 scale=7.31773521e-05 result=7.40415969e-05
     18 cubicDelta tangent=(-2.04951629e-07,-9.82572016e-07 0.0494223352,1.2420935) intersectLen=1.00371955e-06 tangentLen=14.2080628 scale=3.15813401e-05 result=3.16519844e-05
     19 </div>
     20 
     21 <div id="test3">
     22 computeDelta c1=(0,1 1,6 1,0 2,0) t1=0.0167458976 scale1=6.33039689e-05 c2=(0,1 0,2 1,0 6,1) t2=0.121141872 scale2=0.000148083194
     23 cubicTangent t=0.0167458976 tangent=(-2.85180136,-12.6670582 2.95061297,15.1510867) pt=(0.0494058095 1.24201427) dxy=(2.90120716 13.9090724)
     24 cubicTangent t=0.121141872 tangent=(-0.809569955,0.158411583 0.908288874,2.32561689) pt=(0.0493594591 1.24201424) dxy=(0.858929414 1.08360265)
     25 cubicDelta tangent=(-1.65436799e-05,-7.93143093e-05 0.0494223532,1.24209358) intersectLen=8.1021312e-05 tangentLen=14.2084235 scale=2.47281129e-07 result=5.94962466e-06
     26 cubicDelta tangent=(-6.28940702e-05,-7.93454971e-05 0.0494223532,1.24209358) intersectLen=0.000101249059 tangentLen=1.38273441 scale=5.78449976e-07 result=7.38022436e-05
     27 </div>
     28 
     29 </div>
     30 
     31 <script type="text/javascript">
     32 
     33 var testDivs = [
     34     test3,
     35     test2,
     36     test1,
     37 ];
     38 
     39 var scale, columns, rows, xStart, yStart;
     40 
     41 var ticks = 10;
     42 var at_x = 13 + 0.5;
     43 var at_y = 23 + 0.5;
     44 var decimal_places = 3;
     45 var tests = [];
     46 var testTitles = [];
     47 var testIndex = 0;
     48 var ctx;
     49 var minScale = 1;
     50 var subscale = 1;
     51 var curveT = -1;
     52 var drawCubics = true;
     53 var drawQuads = true;
     54 var drawControlLines = true;
     55 var drawT = true;
     56 
     57 var xmin, xmax, ymin, ymax;
     58 
     59 function strs_to_nums(strs) {
     60     var result = [];
     61     for (var idx in strs) {
     62         var str = strs[idx];
     63         var num = parseFloat(str);
     64         if (isNaN(num)) {
     65             result.push(str);
     66         } else {
     67             result.push(num);
     68         }
     69     }
     70     return result;
     71 }
     72 
     73 function construct_regexp(pattern) {
     74     var escape = pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
     75     escape = escape.replace(/PT_VAL/g, "(-?\\d+\\.?\\d*e?-?\\d*),(-?\\d+\\.?\\d*e?-?\\d*)");
     76     escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*e?-?\\d*)");
     77     escape = escape.replace(/IDX/g, "(\\d+)");
     78     escape = escape.replace(/OPT/g, "(\\?|-?\\d+)");
     79     return new RegExp(escape, 'i');
     80 }
     81 
     82 var COMPUTE_DELTA = 1;
     83 var CUBIC_TANGENT = 2;
     84 var CUBIC_DATA = 3;
     85 
     86 var DELTA_C1_X1 = 1;
     87 var DELTA_C1_Y1 = 2;
     88 var DELTA_C1_X2 = 3;
     89 var DELTA_C1_Y2 = 4;
     90 var DELTA_C1_X3 = 5;
     91 var DELTA_C1_Y3 = 6;
     92 var DELTA_C1_X4 = 7;
     93 var DELTA_C1_Y4 = 8;
     94 var DELTA_T1 = 9;
     95 var DELTA_SCALE1 = 10;
     96 var DELTA_C2_X1 = 11;
     97 var DELTA_C2_Y1 = 12;
     98 var DELTA_C2_X2 = 13;
     99 var DELTA_C2_Y2 = 14;
    100 var DELTA_C2_X3 = 15;
    101 var DELTA_C2_Y3 = 16;
    102 var DELTA_C2_X4 = 17;
    103 var DELTA_C2_Y4 = 18;
    104 var DELTA_T2 = 19;
    105 var DELTA_SCALE2 = 20;
    106 
    107 var TANGENT_T = 1;
    108 var TANGENT_TANGENT_X1 = 2;
    109 var TANGENT_TANGENT_Y1 = 3;
    110 var TANGENT_TANGENT_X2 = 4;
    111 var TANGENT_TANGENT_Y2 = 5;
    112 var TANGENT_PT_X = 6;
    113 var TANGENT_PT_Y = 7;
    114 var TANGENT_DXY_X = 8;
    115 var TANGENT_DXY_Y = 9;
    116 
    117 var CUBIC_TANGENT_X1 = 1;
    118 var CUBIC_TANGENT_Y1 = 2;
    119 var CUBIC_TANGENT_X2 = 3;
    120 var CUBIC_TANGENT_Y2 = 4;
    121 var CUBIC_INTERSECTION_LEN = 5;
    122 var CUBIC_TANGENT_LEN = 6;
    123 var CUBIC_SCALE = 7;
    124 var CUBIC_RESULT = 8;
    125 
    126 function parse(test, title) {
    127     var compute_delta = construct_regexp(" c1=(PT_VAL PT_VAL PT_VAL PT_VAL)"
    128         + " t1=T_VAL scale1=T_VAL c2=(PT_VAL PT_VAL PT_VAL PT_VAL) t2=T_VAL scale2=T_VAL");
    129     var cubic_tangent = construct_regexp(" t=T_VAL tangent=(PT_VAL PT_VAL)"
    130         + " pt=(T_VAL T_VAL) dxy=(T_VAL T_VAL)");
    131     var cubic_data = construct_regexp(" tangent=(PT_VAL PT_VAL)"
    132         + " intersectLen=T_VAL tangentLen=T_VAL scale=T_VAL result=T_VAL");
    133 
    134     var cStrs = test.split("computeDelta");
    135     var data = [];
    136     for (var cs in cStrs) {
    137         var str = cStrs[cs];
    138         if (str == "\n") {
    139             continue;
    140         }
    141         var tStrs = str.split("cubicTangent");
    142         for (var ts in tStrs) {
    143             str = tStrs[ts];
    144             if (str == "\n") {
    145                 continue;
    146             }
    147             var dStrs = str.split("cubicDelta");
    148             var dataStrs;
    149             for (var ds in dStrs) {
    150                 str = dStrs[ds];
    151                 if (str == "\n") {
    152                     continue;
    153                 }
    154                 var lineMatch, lineStrs;
    155                 if (compute_delta.test(str)) {
    156                     lineMatch = COMPUTE_DELTA;
    157                     lineStrs = compute_delta.exec(str);
    158                 } else if (cubic_tangent.test(str)) {
    159                     lineMatch = CUBIC_TANGENT;
    160                     lineStrs = cubic_tangent.exec(str);
    161                 } else if (cubic_data.test(str)) {
    162                     lineMatch = CUBIC_DATA;
    163                     lineStrs = cubic_data.exec(str);
    164                 } else {
    165                     continue;
    166                 }
    167                 var line = strs_to_nums(lineStrs);
    168                 data.push(lineMatch);
    169                 data.push(line);
    170             }
    171         }
    172     }
    173     if (data.length >= 1) {
    174         tests.push(data);
    175         testTitles.push(title);
    176     }
    177 }
    178 
    179 function init(test) {
    180     var canvas = document.getElementById('canvas');
    181     if (!canvas.getContext) return;
    182     canvas.width = window.innerWidth - at_x;
    183     canvas.height = window.innerHeight - at_y;
    184     ctx = canvas.getContext('2d');
    185     xmin = Infinity;
    186     xmax = -Infinity;
    187     ymin = Infinity;
    188     ymax = -Infinity;
    189     var scanType = -1;
    190     for (var scansStr in test) {
    191         var scans = parseInt(scansStr);
    192         var scan = test[scans];
    193         if (scanType == -1) {
    194             scanType = scan;
    195             continue;
    196         }
    197         if (scanType == CUBIC_TANGENT) {
    198             for (var idx = TANGENT_TANGENT_X1; idx < TANGENT_PT_X; idx += 2) {
    199                 xmin = Math.min(xmin, scan[idx]);
    200                 xmax = Math.max(xmax, scan[idx]);
    201                 ymin = Math.min(ymin, scan[idx + 1]);
    202                 ymax = Math.max(ymax, scan[idx + 1]);
    203             }
    204         }
    205         scanType = -1;
    206     }
    207     var testW = xmax - xmin;
    208     var testH = ymax - ymin;
    209     subscale = 1;
    210     if (testW > 1e10 || testH > 1e10) {
    211         return;
    212     }
    213     while (testW * subscale < 0.1 && testH * subscale < 0.1) {
    214         subscale *= 10;
    215     }
    216     while (testW * subscale > 10 && testH * subscale > 10) {
    217         subscale /= 10;
    218     }
    219     calcFromScale();
    220 }
    221 
    222 function calcFromScale() {
    223     xStart = Math.floor(xmin * subscale) / subscale;
    224     yStart = Math.floor(ymin * subscale) / subscale;
    225     var xEnd = Math.ceil(xmin * subscale) / subscale;
    226     var yEnd = Math.ceil(ymin * subscale) / subscale;
    227     var cCelsW = Math.floor(ctx.canvas.width / 10);
    228     var cCelsH = Math.floor(ctx.canvas.height / 10);
    229     var testW = xEnd - xStart;
    230     var testH = yEnd - yStart; 
    231     var scaleWH = 1;
    232     while (cCelsW > testW * scaleWH * 10 && cCelsH > testH * scaleWH * 10) {
    233         scaleWH *= 10;
    234     }
    235     while (cCelsW * 10 < testW * scaleWH && cCelsH * 10 < testH * scaleWH) {
    236         scaleWH /= 10;
    237     }
    238     
    239     columns = Math.ceil(xmax * subscale) - Math.floor(xmin * subscale) + 1;
    240     rows = Math.ceil(ymax * subscale) - Math.floor(ymin * subscale) + 1;
    241     
    242     var hscale = ctx.canvas.width / columns / ticks;
    243     var vscale = ctx.canvas.height / rows / ticks;
    244     minScale = Math.floor(Math.min(hscale, vscale));
    245     scale = minScale * subscale;
    246 }
    247 
    248 function drawPoint(px, py, xoffset, yoffset, unit) {
    249     var label = px.toFixed(decimal_places) + ", " + py.toFixed(decimal_places);
    250     var _px = px * unit + xoffset;
    251     var _py = py * unit + yoffset;
    252     ctx.beginPath();
    253     ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
    254     ctx.closePath();
    255     ctx.fill();
    256     ctx.fillText(label, _px + 5, _py);
    257 }
    258 
    259 function drawTPt(scan, cIdx, tIdx, xoffset, yoffset, unit) {
    260     var t = scan[tIdx];
    261     var one_t = 1 - t;
    262     var one_t2 = one_t * one_t;
    263     var a = one_t2 * one_t;
    264     var b = 3 * one_t2 * t;
    265     var t2 = t * t;
    266     var c = 3 * one_t * t2;
    267     var d = t2 * t;
    268     var x = a * scan[cIdx + 0] + b * scan[cIdx + 2] + c * scan[cIdx + 4] + d * scan[cIdx + 6];
    269     var y = a * scan[cIdx + 1] + b * scan[cIdx + 3] + c * scan[cIdx + 5] + d * scan[cIdx + 7];
    270     drawPoint(x, y, xoffset, yoffset, unit);
    271 }
    272 
    273 function draw(test, title, scale) {
    274     ctx.fillStyle = "rgba(0,0,0, 0.1)";
    275     ctx.font = "normal 50px Arial";
    276     ctx.fillText(title, 50, 50);
    277     ctx.font = "normal 10px Arial";
    278 
    279     var unit = scale * ticks;
    280     ctx.lineWidth = 1;
    281     var i;
    282     for (i = 0; i <= rows * ticks; ++i) {
    283         ctx.strokeStyle = (i % ticks) != 0 ? "rgb(200,200,200)" : "black";
    284         ctx.beginPath();
    285         ctx.moveTo(at_x + 0, at_y + i * minScale);
    286         ctx.lineTo(at_x + ticks * columns * minScale, at_y + i * minScale);
    287         ctx.stroke();
    288     }
    289     for (i = 0; i <= columns * ticks; ++i) {
    290         ctx.strokeStyle = (i % ticks) != 0 ? "rgb(200,200,200)" : "black";
    291         ctx.beginPath();
    292         ctx.moveTo(at_x + i * minScale, at_y + 0);
    293         ctx.lineTo(at_x + i * minScale, at_y + ticks * rows * minScale);
    294         ctx.stroke();
    295     }
    296  
    297     var xoffset = xStart * -unit + at_x;
    298     var yoffset = yStart * -unit + at_y;
    299 
    300     ctx.fillStyle = "rgb(40,80,60)"
    301     for (i = 0; i <= columns; i += 1)
    302     {
    303         num = xStart + i / subscale; 
    304         ctx.fillText(num.toFixed(decimal_places), xoffset + num * unit - 5, 10);
    305     }
    306     for (i = 0; i <= rows; i += 1)
    307     {
    308         num = yStart + i / subscale; 
    309         ctx.fillText(num.toFixed(decimal_places), 0, yoffset + num * unit + 0);
    310     }
    311     var scanType = -1;
    312     var partIndex = 0;
    313     for (var scans in test) {
    314         var scan = test[scans];
    315         if (scanType == -1) {
    316             scanType = scan;
    317             continue;
    318         }
    319         partIndex++;
    320         if (scanType == COMPUTE_DELTA) {
    321             ctx.beginPath();
    322             ctx.moveTo(xoffset + scan[DELTA_C1_X1] * unit, yoffset + scan[DELTA_C1_Y1] * unit);
    323             ctx.bezierCurveTo(
    324                 xoffset + scan[DELTA_C1_X2] * unit, yoffset + scan[DELTA_C1_Y2] * unit,
    325                 xoffset + scan[DELTA_C1_X3] * unit, yoffset + scan[DELTA_C1_Y3] * unit,
    326                 xoffset + scan[DELTA_C1_X4] * unit, yoffset + scan[DELTA_C1_Y4] * unit);
    327             ctx.strokeStyle = "red"; // "rgba(0,0,0, 1.0)";
    328             ctx.stroke();
    329             ctx.beginPath();
    330             ctx.moveTo(xoffset + scan[DELTA_C2_X1] * unit, yoffset + scan[DELTA_C2_Y1] * unit);
    331             ctx.bezierCurveTo(
    332                 xoffset + scan[DELTA_C2_X2] * unit, yoffset + scan[DELTA_C2_Y2] * unit,
    333                 xoffset + scan[DELTA_C2_X3] * unit, yoffset + scan[DELTA_C2_Y3] * unit,
    334                 xoffset + scan[DELTA_C2_X4] * unit, yoffset + scan[DELTA_C2_Y4] * unit);
    335             ctx.strokeStyle = "blue"; // "rgba(0,0,0, 1.0)";
    336             ctx.stroke();
    337         }
    338         if (scanType == COMPUTE_DELTA && drawControlLines) {
    339             ctx.beginPath();
    340             ctx.moveTo(xoffset + scan[DELTA_C1_X1] * unit, yoffset + scan[DELTA_C1_Y1] * unit);
    341             ctx.lineTo(xoffset + scan[DELTA_C1_X2] * unit, yoffset + scan[DELTA_C1_Y2] * unit);
    342             ctx.lineTo(xoffset + scan[DELTA_C1_X3] * unit, yoffset + scan[DELTA_C1_Y3] * unit);
    343             ctx.lineTo(xoffset + scan[DELTA_C1_X4] * unit, yoffset + scan[DELTA_C1_Y4] * unit);
    344             ctx.strokeStyle = "rgba(0,0,0, 0.3)";
    345             ctx.stroke();
    346             ctx.beginPath();
    347             ctx.moveTo(xoffset + scan[DELTA_C2_X1] * unit, yoffset + scan[DELTA_C2_Y1] * unit);
    348             ctx.lineTo(xoffset + scan[DELTA_C2_X2] * unit, yoffset + scan[DELTA_C2_Y2] * unit);
    349             ctx.lineTo(xoffset + scan[DELTA_C2_X3] * unit, yoffset + scan[DELTA_C2_Y3] * unit);
    350             ctx.lineTo(xoffset + scan[DELTA_C2_X4] * unit, yoffset + scan[DELTA_C2_Y4] * unit);
    351             ctx.strokeStyle = "rgba(0,0,0, 0.3)";
    352             ctx.stroke();
    353         }
    354         if (scanType == COMPUTE_DELTA && drawT) {
    355             drawTPt(scan, DELTA_C1_X1, DELTA_T1, xoffset, yoffset, unit);
    356             drawTPt(scan, DELTA_C2_X1, DELTA_T2, xoffset, yoffset, unit);
    357             var num = "c1=" + scan[DELTA_T1].toFixed(decimal_places)
    358                     + " c2=" + scan[DELTA_T2].toFixed(decimal_places);
    359             ctx.beginPath();
    360             ctx.rect(200,10,200,10);
    361             ctx.fillStyle="white";
    362             ctx.fill();
    363             ctx.fillStyle="black";
    364             ctx.fillText(num, 230, 18);
    365         }
    366         if (scanType == CUBIC_TANGENT) {
    367             ctx.beginPath();
    368             ctx.moveTo(xoffset + scan[TANGENT_TANGENT_X1] * unit, yoffset + scan[TANGENT_TANGENT_Y1] * unit);
    369             ctx.lineTo(xoffset + scan[TANGENT_TANGENT_X2] * unit, yoffset + scan[TANGENT_TANGENT_Y2] * unit);
    370             ctx.strokeStyle = partIndex > 2 ? "rgba(0,0,255, 0.7)" : "rgba(255,0,0, 0.7)";
    371             ctx.stroke();
    372         }
    373         scanType = -1;
    374     }
    375 }
    376 
    377 function drawTop() {
    378     init(tests[testIndex]);
    379     redraw();
    380 }
    381 
    382 function redraw() {
    383     ctx.beginPath();
    384     ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
    385     ctx.fillStyle="white";
    386     ctx.fill();
    387     draw(tests[testIndex], testTitles[testIndex], scale);
    388 }
    389 
    390 function doKeyPress(evt) {
    391     var char = String.fromCharCode(evt.charCode);
    392     switch (char) {
    393     case 'c':
    394         drawCubics ^= true;
    395         redraw();
    396         break;
    397     case 'd':
    398         decimal_places++;
    399         redraw();
    400         break;
    401     case 'D':
    402         decimal_places--;
    403         if (decimal_places < 1) {
    404             decimal_places = 1;
    405         }
    406         redraw();
    407         break;
    408     case 'l':
    409         drawControlLines ^= true;
    410         redraw();
    411         break;
    412     case 'N':
    413         testIndex += 9;
    414     case 'n':
    415         if (++testIndex >= tests.length)
    416             testIndex = 0;
    417         mouseX = Infinity;
    418         drawTop();
    419         break;
    420     case 'P':
    421         testIndex -= 9;
    422     case 'p':
    423         if (--testIndex < 0)
    424             testIndex = tests.length - 1;
    425         mouseX = Infinity;
    426         drawTop();
    427         break;
    428     case 'q':
    429         drawQuads ^= true;
    430         redraw();
    431         break;
    432     case 't':
    433         drawT ^= true;
    434         redraw();
    435         break;
    436     case 'x':
    437         drawCubics ^= true;
    438         drawQuads ^= true;
    439         redraw();
    440         break;
    441     case '-':
    442     case '_':
    443         subscale /= 2;
    444         calcFromScale();
    445         redraw();
    446         break;
    447     case '+':
    448     case '=':
    449         subscale *= 2;
    450         calcFromScale();
    451         redraw();
    452         break;
    453     }
    454 }
    455 
    456 /*
    457     var e = window.event;
    458 	var tgt = e.target || e.srcElement;
    459     var min = tgt.offsetTop + Math.ceil(at_y);
    460     var max = min + ticks * rows * minScale;
    461     curveT = (e.clientY - min) / (max - min);
    462     redraw();
    463 }
    464 */
    465 
    466 function calcXY() {
    467     var e = window.event;
    468 	var tgt = e.target || e.srcElement;
    469     var left = tgt.offsetLeft;
    470     var top = tgt.offsetTop;
    471     var unit = scale * ticks;
    472     mouseX = (e.clientX - left - Math.ceil(at_x) + 1) / unit + xStart;
    473     mouseY = (e.clientY - top - Math.ceil(at_y)) / unit + yStart;
    474 }
    475 
    476 function handleMouseOver() {
    477  /*   calcXY();
    478     var num = mouseX.toFixed(decimal_places) + ", " + mouseY.toFixed(decimal_places);
    479     ctx.beginPath();
    480     ctx.rect(30,10,200,10);
    481     ctx.fillStyle="white";
    482     ctx.fill();
    483     ctx.fillStyle="black";
    484     ctx.fillText(num, 30, 18);
    485 */
    486 }
    487 
    488 function start() {
    489     for (i = 0; i < testDivs.length; ++i) {
    490         var title = testDivs[i].id.toString();
    491         var str = testDivs[i].firstChild.data;
    492         parse(str, title);
    493     }
    494     drawTop();
    495     window.addEventListener('keypress', doKeyPress, true);
    496     window.onresize = function() {
    497         drawTop();
    498     }
    499 }
    500 
    501 function handleMouseClick() {
    502     start();
    503 }
    504 
    505 function startx() {
    506 }
    507 
    508 </script>
    509 </head>
    510 
    511 <body onLoad="startx();">
    512 <canvas id="canvas" width="750" height="500"
    513     onmousemove="handleMouseOver()"
    514     onclick="handleMouseClick()"
    515     ></canvas >
    516 </body>
    517 </html>
    518