add: function(p,x,y){ var v = vec.make(x,y) if( p.length ){ // an edge is a vector between the last and // the current vertex var l = p.vertices[p.length-1]; p.edges.push(vec.sub(v,l)); } p.vertices.push(v); p.length++; return p; },
translate: function(p,x,y,o){ if( o && (o.length !== p.length) ){ // TODO this will not make a functional `o` (should use poly.add()/poly.close()) throw new Error('translate to unequal polys are not supported') return; } var t = vec.make(x,y) o = o || p; for(var j=0; j < p.length; j++){ vec.add(p.vertices[j],t,o.vertices[j]); } vec.free(t) return o; },
project: function(p,axis,i){ i = i || vec.make(); i[0] = Infinity; i[1] = -Infinity; for(var j=0; j < p.length; j++){ var dot = vec.dot(axis,p.vertices[j]) if( dot < i[0] ){ i[0] = dot; } if( dot > i[1] ){ i[1] = dot; } } return i; }
centroid: function(p){ var a = poly.area(p) // TODO maybe accept area as an argument (in case it's cached?) , n = p.length , P = p.vertices , c = vec.make(); for(var i=0, j=n-1; i < n; j=i, i++){ var v = P[i] , q = P[j] , x = vec.cross(v,q); c[0] += (v[0] + q[0]) * x c[1] += (v[1] + q[1]) * x } var b = 1 / (6 * a); vec.smul(c,b,c) if( c[0] < 0 ){ vec.neg(c,c) } return c; },
collides: function(a,b,v,o){ var res = o || {}; res.intersect = true; res.willIntersect = true; res.minTranslationVector = null; res.nearestEdge = null; v = v || vec.make() var minIntervalDistance = Infinity; var translationAxis = vec.make(); var nearestEdge = vec.make(); var axis = vec.make() var iA = vec.make(); var iB = vec.make(); var cA, cB, cD; // loop through all edges of both polygons for(var i=0; i < (a.length+b.length); i++){ var e = i < a.length ? i : i-a.length var edge = i < a.length ? a.edges[e] : b.edges[e] vec.perp(edge,axis) vec.norm(axis,axis) poly.project(a,axis,iA) poly.project(b,axis,iB) // are they currently intersecting? var iD = intervalDistance(iA,iB); if( iD >= 0 ){ res.intersect = false; } // will they intersect? var vProj = vec.dot(axis,v); if( vProj < 0 ){ iA[0] += vProj; } else { iA[1] += vProj; } iD = intervalDistance(iA,iB); if( iD >= 0 ){ res.willIntersect = false; } // find out if it's the closest one iD = Math.abs(iD); if( iD < minIntervalDistance ){ minIntervalDistance = iD; vec.copy(edge, nearestEdge); vec.copy(axis, translationAxis); cA = cA || poly.centroid(a) cB = cB || poly.centroid(b) cD = vec.sub(cA, cB, cD); if( vec.dot(cD, translationAxis) < 0 ){ vec.neg(translationAxis,translationAxis) } } // no intersection is and won't happen if( !res.intersect && !res.willIntersect ){ break; } } // the minimum translation vector can // be used to push the polygons apart if( res.willIntersect ){ translationAxis[0] *= minIntervalDistance; translationAxis[1] *= minIntervalDistance; res.minTranslationVector = translationAxis; res.nearestEdge = nearestEdge; } else { vec.free(translationAxis) vec.free(nearestEdge) } vec.free(iA) vec.free(iB) vec.free(cA) vec.free(cB) vec.free(cD) vec.free(axis) // free `v` if it wasn't passed in as // an argument if( !arguments[2] ){ vec.free(v); } return res; },