Unify Caledonian Meadows and Wild Lake player location duplication from rP19704 ...
[0ad.git] / binaries / data / mods / public / maps / random / rmgen / math.js
blobb7ce22b8fdd01c4f6fd33e3e54554c00bdadc9f7
1 function diskArea(radius)
3         return Math.PI * Math.square(radius);
6 /**
7  * Returns the angle of the vector between point 1 and point 2.
8  * The angle is counterclockwise from the positive x axis.
9  */
10 function getAngle(x1, z1, x2, z2)
12         return Math.atan2(z2 - z1, x2 - x1);
15 /**
16  * Revolve the given point around the given rotation center.
17  */
18 function rotateCoordinates(x, z, angle, centerX = 0.5, centerZ = 0.5)
20         let sin = Math.sin(angle);
21         let cos = Math.cos(angle);
23         return [
24                 cos * (x - centerX) - sin * (z - centerZ) + centerX,
25                 sin * (x - centerX) + cos * (z - centerZ) + centerZ
26         ];
29 /**
30  * Get pointCount points equidistantly located on a circle.
31  */
32 function distributePointsOnCircle(pointCount, startAngle, radius, centerX, centerZ)
34         let x = [];
35         let z = [];
36         let angle = [];
38         for (let i = 0; i < pointCount; ++i)
39         {
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]);
43         }
45         return [x, z, angle];
48 /**
49  * Returns the distance of a point from a line.
50  */
51 function distanceOfPointFromLine(line_x1, line_y1, line_x2, line_y2, point_x, point_y)
53         let width_x = line_x1 - line_x2;
54         if (!width_x)
55                 return Math.abs(point_x - line_x1);
57         let width_y = line_y1 - line_y2;
58         if (!width_y)
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)));
67 /**
68  * Determines whether two lines with the given width intersect.
69  */
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)
73         {
74                 if (line2_x1 - line1_x1 < width || line2_x2 - line1_x2 < width)
75                         return true;
76         }
77         else
78         {
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)
84                         return true;
86                 if (line2_x1 == line2_x2)
87                 {
88                         if (line1_x1 - line2_x1 < width || line1_x2 - line2_x2 < width)
89                                 return true;
90                 }
91                 else
92                 {
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)
97                                 return true;
98                 }
99         }
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);
104         if (s * p <= 0)
105         {
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);
109                 if (s * p <= 0)
110                         return true;
111         }
113         return false;
117  * Sorts the given (x, y) points so that the distance between neighboring points becomes minimal (similar to the traveling salesman problem).
118  */
119 function sortPointsShortestCycle(points)
121         let order = [];
122         let distances = [];
123         if (points.length <= 3)
124         {
125                 for (let i = 0; i < points.length; ++i)
126                         order.push(i);
128                 return order;
129         }
131         // Just add the first 3 points
132         let pointsToAdd = clone(points);
133         for (let i = 0; i < 3; ++i)
134         {
135                 order.push(i);
136                 pointsToAdd.shift(i);
137                 if (i)
138                         distances.push(Math.euclidDistance2D(points[order[i]].x, points[order[i]].y, points[order[i - 1]].x, points[order[i - 1]].y));
139         }
141         distances.push(Math.euclidDistance2D(
142                 points[order[0]].x,
143                 points[order[0]].y,
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)
150         {
151                 let indexToAddTo;
152                 let minEnlengthen = Infinity;
153                 let minDist1 = 0;
154                 let minDist2 = 0;
155                 for (let k = 0; k < order.length; ++k)
156                 {
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)
161                         {
162                                 indexToAddTo = k;
163                                 minEnlengthen = enlengthen;
164                                 minDist1 = dist1;
165                                 minDist2 = dist2;
166                         }
167                 }
168                 order.splice(indexToAddTo + 1, 0, i + 3);
169                 distances.splice(indexToAddTo, 1, minDist1, minDist2);
170                 pointsToAdd.shift();
171         }
173         return order;