Exemple #1
0
    Polygon(raw).each(function(p, c, n, i) {

      var isect = segseg(c, c.point, n, n.point);

      if (isect && isect !== true) {
        // This means that the offset is self-intersecting
        // find where and use that as the current vec instead

        var isect2 = segseg(
          p,
          c,
          n,
          this.point(i+2)
        );

        if (isect2 && isect2 !== false) {
          isect = isect2;
        }

        this.remove(c);
        c.set(isect[0], isect[1]);

      }

      ret.push(c)
    });
Exemple #2
0
  orig.each(function(prev, current, next, idx) {
    var normal = Vec2(delta, 0);
    var pdiff = current.subtract(prev, true);
    var ndiff = next.subtract(current, true);
    var pnormal = normal.clone().rotate(normal.angleTo(pdiff)).skew();
    var nnormal = normal.clone().rotate(normal.angleTo(ndiff)).skew();

    if (delta < 0) {
      pnormal.negate();
      nnormal.negate();
    }

    var a = pnormal.add(prev, true)
    var b = pnormal.add(current, true);
    var c = nnormal.add(current, true);
    var d = nnormal.add(next, true);

    var cornerAngle = toTAU(current.subtract(prev, true).angleTo(next.subtract(current, true)));

    if ((delta < 0 && cornerAngle - TAU/2 < 0) ||
        (delta > 0 && cornerAngle - TAU/2 > 0))
    {
      !skip && ret.push(b);
      ret = ret.concat(cornerFn.call(orig, current, b, c, delta, cornerAngle) || []);
      skip = false;
    } else {
      var i = segseg(a, b, c, d);
      if (i && i!==true) {
        console.log(i);
        ret.push(Vec2.fromArray(i));
        skip = true;
      }
    }
  });
Exemple #3
0
  containsPolygon : function(subject) {
    if (isArray(subject)) {
      subject = new Polygon(subject);
    }

    for (var i=0; i<subject.points.length; i++) {
      if (!this.containsPoint(subject.points[i])) {
        return false;
      }
    }

    for (var i=0; i<this.points.length; i++) {
      var outer = this.line(i);
      for (var j=0; j<subject.points.length; j++) {
        var inner = subject.line(j);

        var isect = segseg(outer[0], outer[1], inner[0], inner[1]);
        if (isect && isect !== true) {
          return false;
        }
      }
    }

    return true;
  },
Exemple #4
0
      this.lines(function(s2, e2, i2) {

        if (!s2.equal(e) && !s2.equal(s) && !e2.equal(s) && !e2.equal(e) && i+1 < i2) {
          var isect = segseg(s, e, s2, e2);
          // self-intersection
          if (isect && isect !== true) {
            var vec = Vec2.fromArray(isect);
            // TODO: wow, this is inneficient but is crucial for creating the
            //       tree later on.
            vec.s = i + (s.subtract(vec, true).length() / s.subtract(e, true).length())
            vec.b = i2 + (s2.subtract(vec, true).length() / s2.subtract(e2, true).length())

            ret.push(vec);
          }
        }
      });
Exemple #5
0
  O.each(function(p, c, n, i) {
    var n2 = (i<O.length-2) ? O.point(i+2) : O.point((i+2) % O.length);

    var i2 = segseg(p, c, n, n2);
    if (i2 && i2 !== true) {
      var i2v = v.fromArray(i2);
      i++;

      var c1 = closest(p.point, c.point, i2v, i2v);
      var d1 = i2v.distance(c1[0]);
      ctx.strokeStyle = '#fff';
      ctx.beginPath();
      ctx.moveTo(i2v.x, i2v.y);
      ctx.lineTo(c1[0].x, c1[0].y);
      ctx.closePath();
      ctx.stroke();

      var c2 = closest(n.point, n2.point, i2v, i2v);
      var d2 = i2v.distance(c2[0]);
      ctx.strokeStyle = '#fff';
      ctx.beginPath();
      ctx.moveTo(i2v.x, i2v.y);
      ctx.lineTo(c2[0].x, c2[0].y);
      ctx.closePath();
      ctx.stroke();

      var c3 = closest(c.point, n.point, i2v, i2v);
      var d3 = i2v.distance(c3[0]);
      ctx.strokeStyle = '#fff';
      ctx.beginPath();
      ctx.moveTo(i2v.x, i2v.y);
      ctx.lineTo(c3[0].x, c3[0].y);
      ctx.closePath();
      ctx.stroke();

      var skipIsect = 0;

      if (skipIsect < 2) {
        out.push(i2v);
        circle(i2v, r, '#333');
      }
      circle(v(i2[0], i2[1]), r, '#333');
    } else if (!i2 && polygon.closestPointTo(c).distance(c) >= (r - .0001)) {
      out.push(c);
    }
  });
Exemple #6
0
    poly.each(function(ip, ic) {
      var i = segseg(prev, current, ip, ic);

      if (i && i!==true) {
        i = Vec2.fromArray(i);
        if (ip.equal(i) || ic.equal(i)) {
          return;
        }

        var key = i.x + ':'+ i.y;
        if (!seen[key]) {
          f.push(i);
          seen[key] = true;

          // Exit early when we've found a new intersection
          return false;
        }
      }
    });
Exemple #7
0
  lines.forEach(function(line, idx) {
    var prev = (idx === 0) ? lines[lines.length-1] : lines[idx-1];

    var i = segseg(line[0], line[1], prev[0], prev[1]);
    i && i!==true && ret.push(Vec2.fromArray(i));
  });
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){if(typeof require!=="undefined"){var Vec2=require("vec2");var segseg=require("segseg")}var isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"};var defined=function(a){return typeof a!=="undefined"};var definedOr=function(a,defaultValue){return defined(a)?a:defaultValue};var finite=function(a){return a!==Infinity&&a!==-Infinity};var det=function(x1,y1,x2,y2){return x1*y2-y1*x2};function Line2(slope,yintercept,x2,y2){this._listeners=[];if(!(this instanceof Line2)){return new Line2(slope,yintercept,x2,y2)}if(defined(x2)&&defined(y2)){return Line2.fromPoints(slope,yintercept,x2,y2)}else{if(defined(slope)){this.slope(slope)}if(defined(yintercept)){this.yintercept(yintercept)}}}Line2.prototype._yintercept=null;Line2.prototype._xintercept=null;Line2.prototype._slope=null;Line2.prototype.change=function(fn){if(typeof fn==="function"){this._listeners.push(fn);return fn}};Line2.prototype.ignore=function(fn){if(!fn){this._listeners=[]}else{this._listeners=this._listeners.filter(function(a){return a!==fn})}};Line2.prototype.notify=function(fn){var fns=this._listeners,l=fns.length;for(var i=0;i<l;i++){fns[i](this)}};Line2.prototype.yintercept=function(val){if(defined(val)){if(finite(val)){val=Vec2.clean(val)}if(this._yintercept!==val){this._yintercept=val;if(!this.isHorizontal()){this._xintercept=this.solveForX(0)}this.notify()}}return definedOr(this._yintercept,null)};Line2.prototype.xintercept=function(val){if(defined(val)){if(finite(val)){val=Vec2.clean(val)}if(this._xintercept!==val){if(!this.isVertical()){var diff=this._xintercept-val;this._yintercept-=diff*-this._slope}this._xintercept=val;this.notify()}}return definedOr(this._xintercept,null)};Line2.prototype.slope=function(val){if(defined(val)){if(finite(val)){val=Vec2.clean(val)}if(this._slope!==val){var old=this._slope;this._slope=val;if(old!==null){var x=this.solveForX(0);if(!finite(x)){x=null}this._xintercept=x}this.notify()}}return definedOr(this._slope,null)};Line2.prototype.intersectSegment=function(x1,y1,x2,y2){var dx=x2-x1;var dy=y2-y1;var lx1,ly1,lx2,ly2;var horizontal=this.isHorizontal();var vertical=this.isVertical();if(dx===0){if(vertical){return x1===this.xintercept()}}else if(dy===0){if(horizontal){return y1===this.yintercept()}}else{if(dy/dx===this.slope()){return y1===this.solveForY(x1)}}if(x1>x2){lx1=x2-10;lx2=x1+10}else{lx1=x1-10;lx2=x2+10}var isect;if(this.isHorizontal()){y=this.yintercept();isect=segseg(lx1,y,lx2,y,x1,y1,x2,y2)}else if(this.isVertical()){if(y1>y2){ly1=y2-10;ly2=y1+10}else{ly1=y1-10;ly2=y2+10}var x=this.xintercept();isect=segseg(x,ly1,x,ly2,x1,y1,x2,y2)}else{ly1=this.solveForY(lx1);ly2=this.solveForY(lx2);isect=segseg(lx1,ly1,lx2,ly2,x1,y1,x2,y2)}if(isect&&isect!==true){return Vec2.fromArray(isect)}return isect};Line2.prototype.createPerpendicular=function(vec){if(this.isVertical()){return new Line2(0,vec.y)}else if(this.isHorizontal()){var l=new Line2;l.xintercept(vec.x);l.slope(Infinity);return l}else{var perpSlope=-1/this.slope();return new Line2(perpSlope,vec.y-perpSlope*vec.x)}};Line2.prototype.intersectCircle=function(vec,radius){var r2=radius*radius,slope=this.slope(),yintercept=this.yintercept(),f,g,v1,v2;if(this.isHorizontal()){f=1;g=0}else if(this.isVertical()){slope=radius;yintercept=r2;f=0;g=slope}else{f=1/slope;g=1}var x0=this.isVertical()?this.xintercept():1;var y0=yintercept+slope;var f2=f*f;var g2=g*g;var tmp=f*(vec.y-y0)-g*(vec.x-x0);tmp*=tmp;var den=f2+g2;var discriminant=Math.sqrt(r2*(f2+g2)-tmp);if(isNaN(discriminant)){return[]}discriminant/=den;var num=f*(vec.x-x0)+g*(vec.y-y0);var t1=num/den+discriminant;var t2=num/den-discriminant;v1=new Vec2(x0+t1*f,y0+t1*g);v2=new Vec2(x0+t2*f,y0+t2*g);var ret=[v1];if(!v1.equal(v2)){ret.push(v2)}return ret};Line2.prototype.solveForX=function(y){if(this.isVertical()){return this.xintercept()}else{return(y-this.yintercept())/this.slope()}};Line2.prototype.solveForY=function(x){if(this.isHorizontal()){return this.yintercept()}else{return this.slope()*x+this.yintercept()}};Line2.prototype.intersect=function(line,y1,x2,y2){if(defined(y1)&&defined(y2)||defined(line.end)){return this.intersectSegment(line,y1,x2,y2)}var s1=this.slope();var s2=line.slope();if(s1===s2){return this.yintercept()===line.yintercept()&&this.xintercept()===line.xintercept()}if(finite(s1)&&finite(s2)){if(this.isHorizontal()){return new Vec2(line.solveForX(this.yintercept()),this.yintercept())}if(line.isHorizontal()){return new Vec2(this.solveForX(line.yintercept()),line.yintercept())}var x1=line.solveForX(-1);y1=line.solveForY(x1);x2=line.solveForX(1);y2=line.solveForY(x2);var x3=this.solveForX(-1);var y3=this.solveForY(x3);var x4=this.solveForX(1);var y4=this.solveForY(x4);var a=det(x1,y1,x2,y2);var b=det(x3,y3,x4,y4);var xnum=det(a,x1-x2,b,x3-x4);var ynum=det(a,y1-y2,b,y3-y4);var den=det(x1-x2,y1-y2,x3-x4,y3-y4);return Vec2(xnum/den,ynum/den)}else{var slope,yi,x=this.xintercept()||line.xintercept();if(!finite(s1)){slope=s2;yi=line.yintercept()}else{slope=s1;yi=this.yintercept()}if(slope!==0){return Vec2(x,x*slope+yi)}else{return Vec2(x,yi)}}};Line2.fromPoints=function(x1,y1,x2,y2){if(isArray(y1)){y2=y1[1];x2=y1[0]}else if(defined(y1)&&defined(y1.x)&&defined(y1.y)){y2=y1.y;x2=y1.x}if(isArray(x1)){y1=x1[1];x1=x1[0]}else if(defined(x1)&&defined(x1.x)&&defined(x1.y)){y1=x1.y;x1=x1.x}var line=new Line2;var slope=(y2-y1)/(x2-x1);line.slope(slope);if(line.isHorizontal()){line.yintercept(y1)}else if(line.isVertical()){line.xintercept(x2)}else{line.yintercept(y1-slope*x1)}return line};Line2.prototype.isHorizontal=function(){return!this.slope()};Line2.prototype.isVertical=function(){return!finite(this.slope())};Line2.prototype.closestPointTo=function(vec){var yi=this.yintercept();var xi=this.xintercept();var s=this.slope();if(this.isHorizontal()){return Vec2(vec.x,yi)}else if(this.isVertical()){return Vec2(xi,vec.y)}else{return this.intersect(this.createPerpendicular(vec))}};Line2.prototype.containsPoint=function(vec,y){var x=vec;if(!defined(y)){y=vec.y;x=vec.x}if(this.isHorizontal()){return y===this.yintercept()}else if(this.isVertical()){return x===this.xintercept()}else{return y===this.solveForY(x)}};if(typeof module!=="undefined"&&typeof module.exports=="object"){module.exports=Line2}if(typeof window!=="undefined"){window.Line2=window.Line2||Line2}},{segseg:2,vec2:3}],2:[function(require,module,exports){function segseg(x1,y1,x2,y2,x3,y3,x4,y4){if(arguments.length===4){var p1=x1;var p2=y1;var p3=x2;var p4=y2;if(p1.length&&p1.length===2){x1=p1[0];y1=p1[1];x2=p2[0];y2=p2[1];x3=p3[0];y3=p3[1];x4=p4[0];y4=p4[1]}else{x1=p1.x;y1=p1.y;x2=p2.x;y2=p2.y;x3=p3.x;y3=p3.y;x4=p4.x;y4=p4.y}}var a1,a2,b1,b2,c1,c2;var r1,r2,r3,r4;var denom,offset;var x,y;a1=y2-y1;b1=x1-x2;c1=x2*y1-x1*y2;r3=a1*x3+b1*y3+c1;r4=a1*x4+b1*y4+c1;if(r3!==0&&r4!==0&&(r3>=0&&r4>=0||r3<0&&r4<0)){return}a2=y4-y3;b2=x3-x4;c2=x4*y3-x3*y4;r1=a2*x1+b2*y1+c2;r2=a2*x2+b2*y2+c2;if(r1!==0&&r2!==0&&(r1>=0&&r2>=0||r1<0&&r2<0)){return}denom=a1*b2-a2*b1;if(denom===0){return true}offset=denom<0?-denom/2:denom/2;x=b1*c2-b2*c1;y=a2*c1-a1*c2;return[(x<0?x:x)/denom,(y<0?y:y)/denom]}if(typeof module!=="undefined"&&module.exports){module.exports=segseg}if(typeof window!=="undefined"){window.segseg=window.segseg||segseg}},{}],3:[function(require,module,exports){(function inject(clean,precision,undef){function Vec2(x,y){if(!(this instanceof Vec2)){return new Vec2(x,y)}if("object"===typeof x&&x){this.y=x.y||0;this.x=x.x||0;return}this.x=Vec2.clean(x||0);this.y=Vec2.clean(y||0)}Vec2.prototype={change:function(fn){if(fn){if(this.observers){this.observers.push(fn)}else{this.observers=[fn]}}else if(this.observers){for(var i=this.observers.length-1;i>=0;i--){this.observers[i](this)}}return this},ignore:function(fn){if(this.observers){var o=this.observers,l=o.length;while(l--){o[l]===fn&&o.splice(l,1)}}return this},set:function(x,y,silent){if("number"!=typeof x){silent=y;y=x.y;x=x.x}if(this.x===x&&this.y===y)return this;this.x=Vec2.clean(x);this.y=Vec2.clean(y);if(silent!==false)return this.change()},zero:function(){return this.set(0,0)},clone:function(){return new Vec2(this.x,this.y)},negate:function(returnNew){if(returnNew){return new Vec2(-this.x,-this.y)}else{return this.set(-this.x,-this.y)}},add:function(vec2,returnNew){if(!returnNew){this.x+=vec2.x;this.y+=vec2.y;return this.change()}else{return new Vec2(this.x+vec2.x,this.y+vec2.y)}},subtract:function(vec2,returnNew){if(!returnNew){this.x-=vec2.x;this.y-=vec2.y;return this.change()}else{return new Vec2(this.x-vec2.x,this.y-vec2.y)}},multiply:function(vec2,returnNew){var x,y;if("number"!==typeof vec2){x=vec2.x;y=vec2.y}else{x=y=vec2}if(!returnNew){return this.set(this.x*x,this.y*y)}else{return new Vec2(this.x*x,this.y*y)}},rotate:function(r,inverse,returnNew){var x=this.x,y=this.y,cos=Math.cos(r),sin=Math.sin(r),rx,ry;inverse=inverse?-1:1;rx=cos*x-inverse*sin*y;ry=inverse*sin*x+cos*y;if(returnNew){return new Vec2(rx,ry)}else{return this.set(rx,ry)}},length:function(){var x=this.x,y=this.y;return Math.sqrt(x*x+y*y)},lengthSquared:function(){var x=this.x,y=this.y;return x*x+y*y},distance:function(vec2){var x=this.x-vec2.x;var y=this.y-vec2.y;return Math.sqrt(x*x+y*y)},normalize:function(returnNew){var length=this.length();var invertedLength=length<Number.MIN_VALUE?0:1/length;if(!returnNew){return this.set(this.x*invertedLength,this.y*invertedLength)}else{return new Vec2(this.x*invertedLength,this.y*invertedLength)}},equal:function(v,w){if(w===undef){w=v.y;v=v.x}return Vec2.clean(v)===this.x&&Vec2.clean(w)===this.y},abs:function(returnNew){var x=Math.abs(this.x),y=Math.abs(this.y);if(returnNew){return new Vec2(x,y)}else{return this.set(x,y)}},min:function(v,returnNew){var tx=this.x,ty=this.y,vx=v.x,vy=v.y,x=tx<vx?tx:vx,y=ty<vy?ty:vy;if(returnNew){return new Vec2(x,y)}else{return this.set(x,y)}},max:function(v,returnNew){var tx=this.x,ty=this.y,vx=v.x,vy=v.y,x=tx>vx?tx:vx,y=ty>vy?ty:vy;if(returnNew){return new Vec2(x,y)}else{return this.set(x,y)}},clamp:function(low,high,returnNew){var ret=this.min(high,true).max(low);if(returnNew){return ret}else{return this.set(ret.x,ret.y)}},lerp:function(vec,amount){return this.add(vec.subtract(this,true).multiply(amount),true)},skew:function(){return new Vec2(-this.y,this.x)},dot:function(b){return Vec2.clean(this.x*b.x+b.y*this.y)},perpDot:function(b){return Vec2.clean(this.x*b.y-this.y*b.x)},angleTo:function(vec){return Math.atan2(this.perpDot(vec),this.dot(vec))},divide:function(vec2,returnNew){var x,y;if("number"!==typeof vec2){x=vec2.x;y=vec2.y}else{x=y=vec2}if(x===0||y===0){throw new Error("division by zero")}if(isNaN(x)||isNaN(y)){throw new Error("NaN detected")}if(returnNew){return new Vec2(this.x/x,this.y/y)}return this.set(this.x/x,this.y/y)},isPointOnLine:function(start,end){return(start.y-this.y)*(start.x-end.x)===(start.y-end.y)*(start.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(array){return this.set(array[0],array[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"}};Vec2.fromArray=function(array){return new Vec2(array[0],array[1])};Vec2.precision=precision||8;var p=Math.pow(10,Vec2.precision);Vec2.clean=clean||function(val){if(isNaN(val)){throw new Error("NaN detected")}if(!isFinite(val)){throw new Error("Infinity detected")}if(Math.round(val)===val){return val}return Math.round(val*p)/p};Vec2.inject=inject;if(!clean){Vec2.fast=inject(function(k){return k});if(typeof module!=="undefined"&&typeof module.exports=="object"){module.exports=Vec2}else{window.Vec2=window.Vec2||Vec2}}return Vec2})()},{}]},{},[1]);
Exemple #9
0
Line2.prototype.intersectSegment = function(x1, y1, x2, y2) {

  var dx = x2 - x1;
  var dy = y2 - y1;
  var lx1, ly1, lx2, ly2;
  var horizontal = this.isHorizontal();
  var vertical = this.isVertical();

  // vertical
  if (dx === 0) {
    if (vertical) {
      return x1 === this.xintercept();
    }

  // horizontal
  } else if (dy === 0) {
    // parallel
    if (horizontal) {
      return y1 === this.yintercept();
    }

  // diagonal
  } else {
    if (dy/dx === this.slope()) {
      return y1 === this.solveForY(x1);
    }
  }

  if (x1 > x2) {
    lx1 = x2-10;
    lx2 = x1+10;
  } else {
    lx1 = x1-10;
    lx2 = x2+10;
  }

  var isect;
  if (this.isHorizontal()) {
    y = this.yintercept();
    isect = segseg(lx1, y, lx2, y, x1, y1, x2, y2);
  } else if (this.isVertical()) {
    if (y1 > y2) {
      ly1 = y2-10;
      ly2 = y1+10;
    } else {
      ly1 = y1-10;
      ly2 = y2+10;
    }
    var x = this.xintercept();

    isect = segseg(x, ly1, x, ly2, x1, y1, x2, y2);
  } else {
    ly1 = this.solveForY(lx1);
    ly2 = this.solveForY(lx2);
    isect = segseg(lx1, ly1, lx2, ly2, x1, y1, x2, y2);
  }

  if (isect && isect !== true) {
    return Vec2.fromArray(isect);
  }

  return isect;
};