function skip_points(points, angle_threshold = 3) { //var timenow = performance.now(); var ret = []; var last = {x:points[points.length-2], y:points[points.length-1]}; var first = {x:points[0],y:points[1]}; for (var i = 0; i < points.length; i +=2) { var a = last; var b = {x:points[i+0],y:points[i+1]}; var c = points[i+3]?{x:points[i+2],y:points[i+3]}:first; if(dist(b,c) > 0.0001) { var angle = point_angle(a,b,c); if(angle == 0 || angle > angle_threshold) { ret.push(points[i+0]); ret.push(points[i+1]); } } last = b; } //console.log("Runtime: skip_points => "+(performance.now()-timenow)+" ms"); return ret; } function offset_points(points, offset) { //straight point offeset for snapping //var timenow = performance.now(); var new_points = []; points = sort_polygon(points) points = convert_xy(points); for (var j = 0; j < points.length; j++) { var i = (j - 1); if (i < 0) i += points.length; var k = (j + 1) % points.length; var v1 = [points[j].x - points[i].x, points[j].y - points[i].y]; var mag1 = Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]); v1 = [v1[0] / mag1, v1[1] / mag1]; v1 = [v1[0] * offset, v1[1] * offset]; var n1 = [-v1[1], v1[0]]; var x1 = points[i].x + n1[0]; var y1 = points[i].y + n1[1]; var x2 = points[j].x + n1[0]; var y2 = points[j].y + n1[1]; var v2 = [points[k].x - points[j].x, points[k].y - points[j].y]; var mag2 = Math.sqrt(v2[0] * v2[0] + v2[1] * v2[1]); v2 = [v2[0] / mag2, v2[1] / mag2]; v2 = [v2[0] * offset, v2[1] * offset]; var n2 = [-v2[1], v2[0]]; var x3 = points[j].x + n2[0]; var y3 = points[j].y + n2[1]; var x4 = points[k].x + n2[0]; var y4 = points[k].y + n2[1]; var den = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)); var ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / den; var x = x1 + ua * (x2 - x1); var y = y1 + ua * (y2 - y1); if( isNaN(x) || isNaN(y) ) continue; new_points.push(x); new_points.push(y); } //console.log("Runtime "+(performance.now()-timenow)+" ms"); return new_points; } function remove_duplicates(points, precision = 100000000000) { //var timenow = performance.now(); var ret = []; var last = {x:null, y:null}; var first = {x:Math.round(points[0]*precision)/precision,y:Math.round(points[1]*precision)/precision}; for (var i = 0; i < points.length; i +=2) { var current = {x:Math.round(points[i+0]*precision)/precision,y:Math.round(points[i+1]*precision)/precision}; if(last.x != current.x || last.y != current.y) { // check if last point != first point if(i == 0 || current.x != first.x || current.y != first.y) { ret.push(points[i+0]); ret.push(points[i+1]); } last = {x:current.x, y:current.y}; } } //console.log("Runtime: remove_duplicates => "+(performance.now()-timenow)+" ms"); return ret; } function convert_xy(points) { //var timenow = performance.now(); var xy = []; //var last = {x:null, y:null}; for (var i = 0; i < points.length; i +=2) { //var rpx = Math.round(points[i+0]*100000000000)/100000000000; //var rpy = Math.round(points[i+1]*100000000000)/100000000000; //if(last.x != rpx || last.y != rpy) //{ // check if last point != first point if(i == 0 || points[i] != points[0] || points[i+1] != points[1]) { xy.push({x:points[i], y:points[i+1]}); } //last.x = rpx; //last.y = rpy; //} } //console.log("Runtime "+(performance.now()-timenow)+" ms"); return xy; } function inwardEdgeNormal(edge) { // Assuming that polygon vertices are in clockwise order var dx = edge.vertex2.x - edge.vertex1.x; var dy = edge.vertex2.y - edge.vertex1.y; var edgeLength = Math.sqrt(dx*dx + dy*dy); return {x: -dy/edgeLength, y: dx/edgeLength}; } function outwardEdgeNormal(edge) { var n = inwardEdgeNormal(edge); return {x: -n.x, y: -n.y}; } function leftSide(vertex1, vertex2, p) { // If the slope of line vertex1,vertex2 greater than the slope of vertex1,p then p is on the left side of vertex1,vertex2 and the return value is > 0. // If p is colinear with vertex1,vertex2 then return 0, otherwise return a value < 0. return ((p.x - vertex1.x) * (vertex2.y - vertex1.y)) - ((vertex2.x - vertex1.x) * (p.y - vertex1.y)); } function isReflexVertex(polygon, vertexIndex) { // Assuming that polygon vertices are in clockwise order var thisVertex = polygon.vertices[vertexIndex]; var nextVertex = polygon.vertices[(vertexIndex + 1) % polygon.vertices.length]; var prevVertex = polygon.vertices[(vertexIndex + polygon.vertices.length - 1) % polygon.vertices.length]; if (leftSide(prevVertex, nextVertex, thisVertex) < 0) return true; // TBD: return true if thisVertex is inside polygon when thisVertex isn't included return false; } function createPolygon(vertices) { var polygon = {vertices: vertices}; var edges = []; var minX = (vertices.length > 0) ? vertices[0].x : undefined; var minY = (vertices.length > 0) ? vertices[0].y : undefined; var maxX = minX; var maxY = minY; for (var i = 0; i < polygon.vertices.length; i++) { vertices[i].label = String(i); vertices[i].isReflex = isReflexVertex(polygon, i); var edge = { vertex1: vertices[i], vertex2: vertices[(i + 1) % vertices.length], polygon: polygon, index: i }; edge.outwardNormal = outwardEdgeNormal(edge); edge.inwardNormal = inwardEdgeNormal(edge); edges.push(edge); var x = vertices[i].x; var y = vertices[i].y; minX = Math.min(x, minX); minY = Math.min(y, minY); maxX = Math.max(x, maxX); maxY = Math.max(y, maxY); } polygon.edges = edges; polygon.minX = minX; polygon.minY = minY; polygon.maxX = maxX; polygon.maxY = maxY; polygon.closed = true; return polygon; } function edgesIntersection(edgeA, edgeB) { var den = (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) - (edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y); if (den == 0) return null; // lines are parallel or conincident var ua = ((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) - (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) / den; var ub = ((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) - (edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) / den; if (ua < 0 || ub < 0 || ua > 1 || ub > 1) return null; return {x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x), y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y)}; } function appendArc(vertices, center, radius, startVertex, endVertex, isPaddingBoundary) { const twoPI = Math.PI * 2; var startAngle = Math.atan2(startVertex.y - center.y, startVertex.x - center.x); var endAngle = Math.atan2(endVertex.y - center.y, endVertex.x - center.x); if (startAngle < 0) startAngle += twoPI; if (endAngle < 0) endAngle += twoPI; var arcSegmentCount = 3; // An odd number so that one arc vertex will be eactly arcRadius from center. var angle = ((startAngle > endAngle) ? (startAngle - endAngle) : (startAngle + twoPI - endAngle)); var angle5 = ((isPaddingBoundary) ? -angle : twoPI - angle) / arcSegmentCount; vertices.push(startVertex); for (var i = 1; i < arcSegmentCount; ++i) { var angle = startAngle + angle5 * i; var vertex = { x: center.x + Math.cos(angle) * radius, y: center.y + Math.sin(angle) * radius, }; vertices.push(vertex); } vertices.push(endVertex); } function createOffsetEdge(edge, dx, dy) { return { vertex1: {x: edge.vertex1.x + dx, y: edge.vertex1.y + dy}, vertex2: {x: edge.vertex2.x + dx, y: edge.vertex2.y + dy} }; } function offset_points_rounded(pts, offset) { var kpcw = sort_polygon(pts); var paddingPolygon = createPaddingPolygon(createPolygon(convert_xy(kpcw)), offset); return convert_kp(paddingPolygon.vertices); } function createMarginPolygon(polygon, shapeMargin) { var offsetEdges = []; for (var i = 0; i < polygon.edges.length; i++) { var edge = polygon.edges[i]; var dx = edge.outwardNormal.x * shapeMargin; var dy = edge.outwardNormal.y * shapeMargin; offsetEdges.push(createOffsetEdge(edge, dx, dy)); } var vertices = []; for (var i = 0; i < offsetEdges.length; i++) { var thisEdge = offsetEdges[i]; var prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length]; var vertex = edgesIntersection(prevEdge, thisEdge); if (vertex) vertices.push(vertex); else { var arcCenter = polygon.edges[i].vertex1; appendArc(vertices, arcCenter, shapeMargin, prevEdge.vertex2, thisEdge.vertex1, false); } } var marginPolygon = createPolygon(vertices); marginPolygon.offsetEdges = offsetEdges; return marginPolygon; } function createPaddingPolygon(polygon, shapePadding) { var offsetEdges = []; for (var i = 0; i < polygon.edges.length; i++) { var edge = polygon.edges[i]; var dx = edge.inwardNormal.x * shapePadding; var dy = edge.inwardNormal.y * shapePadding; offsetEdges.push(createOffsetEdge(edge, dx, dy)); } var vertices = []; for (var i = 0; i < offsetEdges.length; i++) { var thisEdge = offsetEdges[i]; var prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length]; var vertex = edgesIntersection(prevEdge, thisEdge); if (vertex) { if(!isNaN(vertex.x) && !isNaN(vertex.y)) vertices.push(vertex); } else { var arcCenter = polygon.edges[i].vertex1; appendArc(vertices, arcCenter, shapePadding, prevEdge.vertex2, thisEdge.vertex1, true); } } var paddingPolygon = createPolygon(vertices); paddingPolygon.offsetEdges = offsetEdges; return paddingPolygon; } function move_points(points, offset) { var ret = []; for (var i = 0; i < points.length; i+=2){ ret.push(points[i+0] + offset.x); ret.push(points[i+1] + offset.y); } return ret; } function sort_polygon(points) { points = close_polygon(points); var edgesum = 0; for (var i = 0; i < points.length-2; i+=2) { edgesum += (points[i+2]-points[i])*(points[i+3]+points[i+1]); } if(edgesum > 0) { return points; } else { var points_reverse = []; for (var i = points.length-1; i >= 0; i-=2) { points_reverse.push(points[i-1]); points_reverse.push(points[i]); } return points_reverse; } } function convert_kp(xy)//new { var points = []; for (var i = 0; i < xy.length; i++) { points.push(xy[i].x); points.push(xy[i].y); } return points; } /*function offset_points(pts, offset) { //straight point offeset for snapping var newPoints = []; pts = convert_xy(pts); for (var j = 0; j < pts.length; j++) { var i = (j - 1); if (i < 0) i += pts.length; var k = (j + 1) % pts.length; var v1 = [pts[j].x - pts[i].x, pts[j].y - pts[i].y]; var mag1 = Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]); v1 = [v1[0] / mag1, v1[1] / mag1]; v1 = [v1[0] * offset, v1[1] * offset]; var n1 = [-v1[1], v1[0]]; var x1 = pts[i].x + n1[0]; var y1 = pts[i].y + n1[1]; var x2 = pts[j].x + n1[0]; var y2 = pts[j].y + n1[1]; var v2 = [pts[k].x - pts[j].x, pts[k].y - pts[j].y]; var mag2 = Math.sqrt(v2[0] * v2[0] + v2[1] * v2[1]); v2 = [v2[0] / mag2, v2[1] / mag2]; v2 = [v2[0] * offset, v2[1] * offset]; var n2 = [-v2[1], v2[0]]; var x3 = pts[j].x + n2[0]; var y3 = pts[j].y + n2[1]; var x4 = pts[k].x + n2[0]; var y4 = pts[k].y + n2[1]; var den = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)); var ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / den; var x = x1 + ua * (x2 - x1); var y = y1 + ua * (y2 - y1); newPoints.push(x); newPoints.push(y); } return newPoints; }*/ function extend_line(a,b,length) { var lenAB = Math.sqrt(Math.pow(a.x - b.x, 2.0) + Math.pow(a.y - b.y, 2.0)); return [ b.x + (b.x - a.x) / length * lenAB, b.y + (b.y - a.y) / length * lenAB, a.x - (b.x - a.x) / length * lenAB, a.y - (b.y - a.y) / length * lenAB ]; } function line_intersect(line1, line2) { var ua, ub, denom = (line2[3] - line2[1])*(line1[2] - line1[0]) - (line2[2] - line2[0])*(line1[3] - line1[1]); if (denom == 0) { return null; } ua = ((line2[2] - line2[0])*(line1[1] - line2[1]) - (line2[3] - line2[1])*(line1[0] - line2[0]))/denom; ub = ((line1[2] - line1[0])*(line1[1] - line2[1]) - (line1[3] - line1[1])*(line1[0] - line2[0]))/denom; var x = line1[0] + ua * (line1[2] - line1[0]); var y = line1[1] + ua * (line1[3] - line1[1]); if(x < -1000000 || x > 1000000 || y < -1000000 || y > 1000000){ return null } return { x: x, y: y, //seg1: ua >= 0 && ua <= 1, //seg2: ub >= 0 && ub <= 1 }; } function line_angle(line1, line2) { //find vector components var dAx = line1[2] - line1[0]; var dAy = line1[3] - line1[1]; var dBx = line2[2] - line2[0]; var dBy = line2[3] - line2[1]; var angle = Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy); if(angle < 0) {angle = angle * -1;} return angle * (180 / Math.PI); } function point_angle(a,b,c) { //find vector components var dAx = b.x - a.x; var dAy = b.y - a.y; var dBx = c.x - b.x; var dBy = c.y - b.y; var angle = Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy); if(angle < 0) {angle = angle * -1;} return angle * (180 / Math.PI); } function project( p, line)//a, b ) { // calculates projection from p to line a b // project({"x":px, "y":py}, {"x":ax,"y":ay}, {"x":bx, "y":by}) var atob = { x: line[2] - line[0], y: line[3] - line[1] }; var atop = { x: p.x - line[0], y: p.y - line[1] }; var len = atob.x * atob.x + atob.y * atob.y; var dot = atop.x * atob.x + atop.y * atob.y; var t = Math.min( 1, Math.max( 0, dot / len ) ); //dot = ( b.x - a.x ) * ( p.y - a.y ) - ( b.y - a.y ) * ( p.x - a.x ); return { point: { x: line[0] + atob.x * t, y: line[1] + atob.y * t }, //distance: Math.abs(dot), dist: Math.hypot((line[0] + atob.x * t) - p.x, (line[1] + atob.y * t) - p.y) //dot: dot, //t: t }; } function get_box(p) { var box_x = []; var box_y = []; for (var i = 0; i < p.length; i+=2) { box_x.push(p[i]); box_y.push(-p[i+1]); } return {"x":Math.min.apply(Math,box_x), "y":Math.min.apply(Math,box_y), "w":Math.max.apply(Math,box_x), "h":Math.max.apply(Math,box_y)}; } function point_in_polygon(x, y, poly) { var inside = false; var n = poly.length; var j = n - 2; for (var i = 0; i < n; i += 2) { var xi = poly[i]; var yi = poly[i + 1]; var xj = poly[j]; var yj = poly[j + 1]; var intersect = ((yi > y) !== (yj > y)) && (x < ((xj - xi) * (y - yi)) / (yj - yi) + xi); if (intersect) { inside = !inside; } j = i; } if (inside) return "inside"; else return "outside"; } /*function point_in_polygon(px, py, polygon) { //polygon.push(polygon[0]); // repeat first x //polygon.push(polygon[1]); // repeat first y polygon = close_polygon(polygon); var intersections = 0; for(i = 2; i < polygon.length; i+=2) { if( (px == polygon[i-2] && py == polygon[i-1]) || (px == polygon[i] && py == polygon[i+1]) ) return "vertex"; if (polygon[i-1] != polygon[i+1] && py <= Math.max(polygon[i-1], polygon[i+1]) && px <= Math.max(polygon[i-2], polygon[i]) && py > Math.min(polygon[i-1], polygon[i+1])) { var xinters = (py - polygon[i-1]) * (polygon[i] - polygon[i-2]) / (polygon[i+1] - polygon[i-1]) + polygon[i-2]; if (xinters == px) // Check if point is on the polygon boundary (other than horizontal) return "boundary"; if (polygon[i-2] == polygon[i] || px <= xinters) { intersections++; } } else if(polygon[i-1] == polygon[i+1] && polygon[i-1] == py && px > Math.min(polygon[i-2], polygon[i]) && px < Math.max(polygon[i-2], polygon[i])) return "boundary";// Check if point is on an horizontal polygon boundary } // If the number of edges we passed through is odd, then it's in the polygon. if (intersections % 2 != 0) return "inside"; else return "outside"; }*/ function rotate_point({ x, y }, rad) { const rcos = Math.cos(rad); const rsin = Math.sin(rad); return { x: x * rcos - y * rsin, y: y * rcos + x * rsin }; } function rotate_points(points, rotation, position = {x:0, y:0}) { // rotate points var prp = []; for (var i = 0; i < points.length; i += 2) { var x = points[i]; var y = points[i+1]; var r = -rotation * (Math.PI / 180); var xr = x*Math.cos(r) - y*Math.sin(r); var yr = x*Math.sin(r) + y*Math.cos(r); // store rotated points prp.push(xr+position.x); prp.push(yr+position.y); } return prp; } function line_midpoint(x1, y1, x2, y2) { return {"x":(x1 + x2) / 2, "y":(y1 + y2) / 2}; } function rotate_around_point(shape, angleDegrees, point) { /* Rotate a shape around any point. shape is a Konva shape angleDegrees is the angle to rotate by, in degrees point is an object {x: posX, y: posY} */ // sin + cos require radians let angleRadians = angleDegrees * Math.PI / 180; const x = point.x + (shape.x() - point.x) * Math.cos(angleRadians) - (shape.y() - point.y) * Math.sin(angleRadians); const y = point.y + (shape.x() - point.x) * Math.sin(angleRadians) + (shape.y() - point.y) * Math.cos(angleRadians); // move the rotated shape in relation to the rotation point. shape.position({x: x, y: y}); // rotate the shape in place around its natural rotation point shape.rotation(shape.rotation() + angleDegrees); } function offset_polylines(p, dist) { var polygon = createPolygon(convert_xy(sort_polygon(p))); var offsetEdges = []; for (var i = 0; i < polygon.edges.length; i++) { var edge = polygon.edges[i]; var dx = edge.inwardNormal.x * dist; var dy = edge.inwardNormal.y * dist; offsetEdges.push(createOffsetEdge(edge, dx, dy)); } var points = []; for(var xx in offsetEdges) { points.push(offsetEdges[xx].vertex1.x); points.push(offsetEdges[xx].vertex1.y); points.push(offsetEdges[xx].vertex2.x); points.push(offsetEdges[xx].vertex2.y); } return points; } function angle(x1, y1, x2, y2) { var dy = y2 - y1; var dx = x2 - x1; var theta = Math.atan2(dy, dx); // range (-PI, PI] theta *= 180 / Math.PI; // rads to degs, range (-180, 180] return theta; } function simple_p(kp, tol = 0.5) { var out = []; var lx = 0; var ly = 0; for (var i = 0; i < kp.length; i +=2) { if( distance(lx, ly, kp[i], kp[i+1]) > tol ) { lx = kp[i]; ly = kp[i+1]; out.push(Math.round(kp[i]*1000)/1000); out.push(Math.round(kp[i+1]*1000)/1000); } } return out; } function distance(x1, y1, x2, y2) { return Math.hypot(x2 - x1, y2 - y1); } function dist(p1, p2) { return Math.hypot(p2.x - p1.x, p2.y - p1.y); } function bulgetopoints(bp) { var points = []; for(i = 0; i < bp.length; i+=2) { if(bp[i+2] == "circle") { //points = []; center_x = bp[i+0]; center_y = bp[i+1]; radius = bp[i+3]; theta = 0; while (theta <= 360) { // Calculate the new x,y coordinates. points.push(center_x + radius * Math.cos(theta/ 180 * Math.PI)); points.push(center_y + radius * Math.sin(theta/ 180 * Math.PI)); theta += 1; } //break; i+=2; } else if( !isNaN(bp[i]) ) { points.push(bp[i]); points.push(bp[i+1]); } else if(bp[i] == "bulge") { b = {}; b["bulge"] = bp[i+1]; if(b["bulge"] < 0) // if bulge is negative revert start end end point { b["theta"] = Math.atan(-b["bulge"]) * 4; // get start point b["ax"] = bp[i-2]; b["ay"] = bp[i-1]; // get end point b["bx"] = bp[i+2]; b["by"] = bp[i+3]; if(i == bp.length -2) { b["bx"] = bp[0]; b["by"] = bp[1]; } } else { b["theta"] = Math.atan(b["bulge"]) * 4; // get start point reversed b["bx"] = bp[i-2]; b["by"] = bp[i-1]; // get end point reversed b["ax"] = bp[i+2]; b["ay"] = bp[i+3]; if(i == bp.length -2) { b["ax"] = bp[0]; b["ay"] = bp[1]; } } if(b["ax"] == null || b["bx"] == null) continue; // distance ab b["distance"] = Math.sqrt(Math.pow(b["bx"]-b["ax"], 2) + Math.pow(b["by"]-b["ay"], 2)); if(b["bulge"] < 0) { d = (b["distance"]/2) * (1-Math.pow(b["bulge"], 2)) / (2*b["bulge"]); } else { d = (b["distance"]/2) * (1-Math.pow(b["bulge"], 2)) / (2*-b["bulge"]); } u = (b["bx"]-b["ax"])/ b["distance"]; v = (b["by"]-b["ay"])/ b["distance"]; b["center_x"] = -v*d + (b["ax"]+b["bx"])/2; b["center_y"] = u*d + (b["ay"]+b["by"])/2; // radius b["radius"] = Math.sqrt(Math.pow(b["center_x"]-b["ax"], 2) + Math.pow(b["center_y"]-b["ay"], 2)); // get satrt and end angle b["startAngle"] = Math.atan2(b["by"]-b["center_y"], b["bx"]-b["center_x"]) / Math.PI * 180; b["endAngle"] = Math.atan2(b["ay"]-b["center_y"], b["ax"]-b["center_x"]) / Math.PI * 180; // normalize angle if (b["endAngle"] < b["startAngle"]) { b["endAngle"] += 360; } // get start and end interator b["startInter"] = b["startAngle"]; b["endInter"] = b["endAngle"]; // Maintain the right ordering to join the from and to points if(b["bulge"] < 0) { for (k=b["endInter"]; k >= b["startInter"]; k -= 1) //steps { points.push(b["center_x"] + (Math.cos(k / 180 * Math.PI) * b["radius"])); points.push(b["center_y"] + (Math.sin(k / 180 * Math.PI) * b["radius"])); } } else { for (k=b["startInter"]; k <= b["endInter"]; k += 1) //steps { points.push(b["center_x"] + (Math.cos(k / 180 * Math.PI) * b["radius"])); points.push(b["center_y"] + (Math.sin(k / 180 * Math.PI) * b["radius"])); } } // counter clockwise b["endAngle"] = rad2deg(Math.atan2(b["ax"]-b["cx"], b["ay"]-b["cy"]))+90; // start at 0 and go clockwise b["startAngle"] = rad2deg(Math.atan2(b["bx"]-b["cx"], b["by"]-b["cy"]))+90; // to 125.31 deg } else if(bp[i] == "arc") { points = []; center_x = bp[0]; center_y = bp[1]; radius = bp[3]; start = bp[4]; end = bp[5]; if(start > end) { start = bp[4]-360; end = bp[5]; } for (k=start; k <= end; k += 1) { points.push(center_x + radius * Math.cos(k/ 180 * Math.PI)); points.push(center_y + radius * Math.sin(k/ 180 * Math.PI)); } // end point points.push(center_x + radius * Math.cos(end/ 180 * Math.PI)); points.push(center_y + radius * Math.sin(end/ 180 * Math.PI)); break; } } //return simple_p(points); return points; } function rad2deg(radians) { return radians * (180/Math.PI); } function invertp(p) { var out = []; for (var i = 0; i < p.length; i+=2) { out.push(p[i]); out.push(-p[i+1]); } return out; } function polygon_centroid(pts_array) { var pts = []; for (var i = 0; i < pts_array.length; i +=2) { pts.push({x:pts_array[i], y:pts_array[i+1]}); } var first = pts[0]; var last = pts[pts.length-1]; if (first.x != last.x || first.y != last.y) { pts.push(first); } var twicearea=0; var x=0; var y=0; var nPts = pts.length; var p1; var p2; var f; for ( var i=0, j=nPts-1; i> 2] |= a.charCodeAt(d) << 8 * d--; for (i = a = 0; i < r; i += 16) { for (d = t; 64 > a; d = [ n = d[3], o + ((n = d[0] + [ o & e | ~o & n, n & o | ~n & e, o ^ e ^ n, e ^ (o | ~n) ][d = a >> 4] + f[a] + ~~c[i | 15 & [ a, 5 * a + 1, 3 * a + 5, 7 * a ][d]]) << (d = [ 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21 ][4 * d + a++ % 4]) | n >>> -d), o, e ]) o = 0 | d[1], e = d[2]; for (a = 4; a; ) t[--a] += d[a]; } for (r = ""; 32 > a; ) r += (t[a >> 3] >> 4 * (1 ^ a++) & 15).toString(16); return r; }