1 function diskArea(radius)
3 return Math.PI * Math.square(radius);
7 * Returns the angle of the vector between point 1 and point 2.
8 * The angle is counterclockwise from the positive x axis.
10 function getAngle(x1, z1, x2, z2)
12 return Math.atan2(z2 - z1, x2 - x1);
16 * Revolve the given point around the given rotation center.
18 function rotateCoordinates(x, z, angle, centerX = 0.5, centerZ = 0.5)
20 let sin = Math.sin(angle);
21 let cos = Math.cos(angle);
24 cos * (x - centerX) - sin * (z - centerZ) + centerX,
25 sin * (x - centerX) + cos * (z - centerZ) + centerZ
30 * Get pointCount points equidistantly located on a circle.
32 function distributePointsOnCircle(pointCount, startAngle, radius, centerX, centerZ)
38 for (let i = 0; i < pointCount; ++i)
40 angle[i] = startAngle + 2 * Math.PI * i / pointCount;
41 x[i] = centerX + radius * Math.cos(angle[i]);
42 z[i] = centerZ + radius * Math.sin(angle[i]);
49 * Returns the distance of a point from a line.
51 function distanceOfPointFromLine(line_x1, line_y1, line_x2, line_y2, point_x, point_y)
53 let width_x = line_x1 - line_x2;
55 return Math.abs(point_x - line_x1);
57 let width_y = line_y1 - line_y2;
59 return Math.abs(point_y - line_y1);
61 let inclination = width_y / width_x;
62 let intercept = line_y1 - inclination * line_x1;
64 return Math.abs((point_y - point_x * inclination - intercept) / Math.sqrt(1 + Math.square(inclination)));
68 * Determines whether two lines with the given width intersect.
70 function checkIfIntersect(line1_x1, line1_y1, line1_x2, line1_y2, line2_x1, line2_y1, line2_x2, line2_y2, width)
72 if (line1_x1 == line1_x2)
74 if (line2_x1 - line1_x1 < width || line2_x2 - line1_x2 < width)
79 let m = (line1_y1 - line1_y2) / (line1_x1 - line1_x2);
80 let b = line1_y1 - m * line1_x1;
81 let m2 = Math.sqrt(1 + Math.square(m));
83 if (Math.abs((line2_y1 - line2_x1 * m - b) / m2) < width || Math.abs((line2_y2 - line2_x2 * m - b) / m2) < width)
86 if (line2_x1 == line2_x2)
88 if (line1_x1 - line2_x1 < width || line1_x2 - line2_x2 < width)
93 let m = (line2_y1 - line2_y2) / (line2_x1 - line2_x2);
94 let b = line2_y1 - m * line2_x1;
95 let m2 = Math.sqrt(1 + Math.square(m));
96 if (Math.abs((line1_y1 - line1_x1 * m - b) / m2) < width || Math.abs((line1_y2 - line1_x2 * m - b) / m2) < width)
101 let s = (line1_x1 - line1_x2) * (line2_y1 - line1_y1) - (line1_y1 - line1_y2) * (line2_x1 - line1_x1);
102 let p = (line1_x1 - line1_x2) * (line2_y2 - line1_y1) - (line1_y1 - line1_y2) * (line2_x2 - line1_x1);
106 s = (line2_x1 - line2_x2) * (line1_y1 - line2_y1) - (line2_y1 - line2_y2) * (line1_x1 - line2_x1);
107 p = (line2_x1 - line2_x2) * (line1_y2 - line2_y1) - (line2_y1 - line2_y2) * (line1_x2 - line2_x1);
117 * Sorts the given (x, y) points so that the distance between neighboring points becomes minimal (similar to the traveling salesman problem).
119 function sortPointsShortestCycle(points)
123 if (points.length <= 3)
125 for (let i = 0; i < points.length; ++i)
131 // Just add the first 3 points
132 let pointsToAdd = clone(points);
133 for (let i = 0; i < 3; ++i)
136 pointsToAdd.shift(i);
138 distances.push(Math.euclidDistance2D(points[order[i]].x, points[order[i]].y, points[order[i - 1]].x, points[order[i - 1]].y));
141 distances.push(Math.euclidDistance2D(
144 points[order[order.length - 1]].x,
145 points[order[order.length - 1]].y));
147 // Add remaining points so the path lengthens the least
148 let numPointsToAdd = pointsToAdd.length;
149 for (let i = 0; i < numPointsToAdd; ++i)
152 let minEnlengthen = Infinity;
155 for (let k = 0; k < order.length; ++k)
157 let dist1 = Math.euclidDistance2D(pointsToAdd[0].x, pointsToAdd[0].y, points[order[k]].x, points[order[k]].y);
158 let dist2 = Math.euclidDistance2D(pointsToAdd[0].x, pointsToAdd[0].y, points[order[(k + 1) % order.length]].x, points[order[(k + 1) % order.length]].y);
159 let enlengthen = dist1 + dist2 - distances[k];
160 if (enlengthen < minEnlengthen)
163 minEnlengthen = enlengthen;
168 order.splice(indexToAddTo + 1, 0, i + 3);
169 distances.splice(indexToAddTo, 1, minDist1, minDist2);