| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 | var PathProxy = require("../core/PathProxy");var line = require("./line");var cubic = require("./cubic");var quadratic = require("./quadratic");var arc = require("./arc");var _util = require("./util");var normalizeRadian = _util.normalizeRadian;var curve = require("../core/curve");var windingLine = require("./windingLine");var CMD = PathProxy.CMD;var PI2 = Math.PI * 2;var EPSILON = 1e-4;function isAroundEqual(a, b) {  return Math.abs(a - b) < EPSILON;} // 临时数组var roots = [-1, -1, -1];var extrema = [-1, -1];function swapExtrema() {  var tmp = extrema[0];  extrema[0] = extrema[1];  extrema[1] = tmp;}function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {  // Quick reject  if (y > y0 && y > y1 && y > y2 && y > y3 || y < y0 && y < y1 && y < y2 && y < y3) {    return 0;  }  var nRoots = curve.cubicRootAt(y0, y1, y2, y3, y, roots);  if (nRoots === 0) {    return 0;  } else {    var w = 0;    var nExtrema = -1;    var y0_;    var y1_;    for (var i = 0; i < nRoots; i++) {      var t = roots[i]; // Avoid winding error when intersection point is the connect point of two line of polygon      var unit = t === 0 || t === 1 ? 0.5 : 1;      var x_ = curve.cubicAt(x0, x1, x2, x3, t);      if (x_ < x) {        // Quick reject        continue;      }      if (nExtrema < 0) {        nExtrema = curve.cubicExtrema(y0, y1, y2, y3, extrema);        if (extrema[1] < extrema[0] && nExtrema > 1) {          swapExtrema();        }        y0_ = curve.cubicAt(y0, y1, y2, y3, extrema[0]);        if (nExtrema > 1) {          y1_ = curve.cubicAt(y0, y1, y2, y3, extrema[1]);        }      }      if (nExtrema === 2) {        // 分成三段单调函数        if (t < extrema[0]) {          w += y0_ < y0 ? unit : -unit;        } else if (t < extrema[1]) {          w += y1_ < y0_ ? unit : -unit;        } else {          w += y3 < y1_ ? unit : -unit;        }      } else {        // 分成两段单调函数        if (t < extrema[0]) {          w += y0_ < y0 ? unit : -unit;        } else {          w += y3 < y0_ ? unit : -unit;        }      }    }    return w;  }}function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {  // Quick reject  if (y > y0 && y > y1 && y > y2 || y < y0 && y < y1 && y < y2) {    return 0;  }  var nRoots = curve.quadraticRootAt(y0, y1, y2, y, roots);  if (nRoots === 0) {    return 0;  } else {    var t = curve.quadraticExtremum(y0, y1, y2);    if (t >= 0 && t <= 1) {      var w = 0;      var y_ = curve.quadraticAt(y0, y1, y2, t);      for (var i = 0; i < nRoots; i++) {        // Remove one endpoint.        var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1;        var x_ = curve.quadraticAt(x0, x1, x2, roots[i]);        if (x_ < x) {          // Quick reject          continue;        }        if (roots[i] < t) {          w += y_ < y0 ? unit : -unit;        } else {          w += y2 < y_ ? unit : -unit;        }      }      return w;    } else {      // Remove one endpoint.      var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1;      var x_ = curve.quadraticAt(x0, x1, x2, roots[0]);      if (x_ < x) {        // Quick reject        return 0;      }      return y2 < y0 ? unit : -unit;    }  }} // TODO// Arc 旋转function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) {  y -= cy;  if (y > r || y < -r) {    return 0;  }  var tmp = Math.sqrt(r * r - y * y);  roots[0] = -tmp;  roots[1] = tmp;  var diff = Math.abs(startAngle - endAngle);  if (diff < 1e-4) {    return 0;  }  if (diff % PI2 < 1e-4) {    // Is a circle    startAngle = 0;    endAngle = PI2;    var dir = anticlockwise ? 1 : -1;    if (x >= roots[0] + cx && x <= roots[1] + cx) {      return dir;    } else {      return 0;    }  }  if (anticlockwise) {    var tmp = startAngle;    startAngle = normalizeRadian(endAngle);    endAngle = normalizeRadian(tmp);  } else {    startAngle = normalizeRadian(startAngle);    endAngle = normalizeRadian(endAngle);  }  if (startAngle > endAngle) {    endAngle += PI2;  }  var w = 0;  for (var i = 0; i < 2; i++) {    var x_ = roots[i];    if (x_ + cx > x) {      var angle = Math.atan2(y, x_);      var dir = anticlockwise ? 1 : -1;      if (angle < 0) {        angle = PI2 + angle;      }      if (angle >= startAngle && angle <= endAngle || angle + PI2 >= startAngle && angle + PI2 <= endAngle) {        if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {          dir = -dir;        }        w += dir;      }    }  }  return w;}function containPath(data, lineWidth, isStroke, x, y) {  var w = 0;  var xi = 0;  var yi = 0;  var x0 = 0;  var y0 = 0;  for (var i = 0; i < data.length;) {    var cmd = data[i++]; // Begin a new subpath    if (cmd === CMD.M && i > 1) {      // Close previous subpath      if (!isStroke) {        w += windingLine(xi, yi, x0, y0, x, y);      } // 如果被任何一个 subpath 包含      // if (w !== 0) {      //     return true;      // }    }    if (i === 1) {      // 如果第一个命令是 L, C, Q      // 则 previous point 同绘制命令的第一个 point      //      // 第一个命令为 Arc 的情况下会在后面特殊处理      xi = data[i];      yi = data[i + 1];      x0 = xi;      y0 = yi;    }    switch (cmd) {      case CMD.M:        // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点        // 在 closePath 的时候使用        x0 = data[i++];        y0 = data[i++];        xi = x0;        yi = y0;        break;      case CMD.L:        if (isStroke) {          if (line.containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {            return true;          }        } else {          // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN          w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;        }        xi = data[i++];        yi = data[i++];        break;      case CMD.C:        if (isStroke) {          if (cubic.containStroke(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {            return true;          }        } else {          w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0;        }        xi = data[i++];        yi = data[i++];        break;      case CMD.Q:        if (isStroke) {          if (quadratic.containStroke(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {            return true;          }        } else {          w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0;        }        xi = data[i++];        yi = data[i++];        break;      case CMD.A:        // TODO Arc 判断的开销比较大        var cx = data[i++];        var cy = data[i++];        var rx = data[i++];        var ry = data[i++];        var theta = data[i++];        var dTheta = data[i++]; // TODO Arc 旋转        i += 1;        var anticlockwise = 1 - data[i++];        var x1 = Math.cos(theta) * rx + cx;        var y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令        if (i > 1) {          w += windingLine(xi, yi, x1, y1, x, y);        } else {          // 第一个命令起点还未定义          x0 = x1;          y0 = y1;        } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放        var _x = (x - cx) * ry / rx + cx;        if (isStroke) {          if (arc.containStroke(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) {            return true;          }        } else {          w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y);        }        xi = Math.cos(theta + dTheta) * rx + cx;        yi = Math.sin(theta + dTheta) * ry + cy;        break;      case CMD.R:        x0 = xi = data[i++];        y0 = yi = data[i++];        var width = data[i++];        var height = data[i++];        var x1 = x0 + width;        var y1 = y0 + height;        if (isStroke) {          if (line.containStroke(x0, y0, x1, y0, lineWidth, x, y) || line.containStroke(x1, y0, x1, y1, lineWidth, x, y) || line.containStroke(x1, y1, x0, y1, lineWidth, x, y) || line.containStroke(x0, y1, x0, y0, lineWidth, x, y)) {            return true;          }        } else {          // FIXME Clockwise ?          w += windingLine(x1, y0, x1, y1, x, y);          w += windingLine(x0, y1, x0, y0, x, y);        }        break;      case CMD.Z:        if (isStroke) {          if (line.containStroke(xi, yi, x0, y0, lineWidth, x, y)) {            return true;          }        } else {          // Close a subpath          w += windingLine(xi, yi, x0, y0, x, y); // 如果被任何一个 subpath 包含          // FIXME subpaths may overlap          // if (w !== 0) {          //     return true;          // }        }        xi = x0;        yi = y0;        break;    }  }  if (!isStroke && !isAroundEqual(yi, y0)) {    w += windingLine(xi, yi, x0, y0, x, y) || 0;  }  return w !== 0;}function contain(pathData, x, y) {  return containPath(pathData, 0, false, x, y);}function containStroke(pathData, lineWidth, x, y) {  return containPath(pathData, lineWidth, true, x, y);}exports.contain = contain;exports.containStroke = containStroke;
 |