LCOV - code coverage report
 Current view: top level - maps/random/rmgen - math.js (source / functions) Hit Total Coverage Test: lcov.info Lines: 13 59 22.0 % Date: 2023-04-02 12:52:40 Functions: 2 10 20.0 %
 ` Line data Source code` ``` 1 6 : const g_TileVertices = deepfreeze([ 2 : new Vector2D(0, 0), 3 : new Vector2D(0, 1), 4 : new Vector2D(1, 0), 5 : new Vector2D(1, 1) 6 : ]); 7 : 8 6 : const g_AdjacentCoordinates = deepfreeze([ 9 : new Vector2D(1, 0), 10 : new Vector2D(1, 1), 11 : new Vector2D(0, 1), 12 : new Vector2D(-1, 1), 13 : new Vector2D(-1, 0), 14 : new Vector2D(-1, -1), 15 : new Vector2D(0, -1), 16 : new Vector2D(1, -1) 17 : ]); 18 : 19 : function diskArea(radius) 20 : { 21 0 : return Math.PI * Math.square(radius); 22 : } 23 : 24 : /** 25 : * Returns the angle of the vector between point 1 and point 2. 26 : * The angle is counterclockwise from the positive x axis. 27 : */ 28 : function getAngle(x1, z1, x2, z2) 29 : { 30 0 : return Math.atan2(z2 - z1, x2 - x1); 31 : } 32 : 33 : /** 34 : * Get pointCount points equidistantly located on a circle. 35 : * @param {Vector2D} center 36 : */ 37 : function distributePointsOnCircle(pointCount, startAngle, radius, center) 38 : { 39 0 : return distributePointsOnCircularSegment(pointCount, 2 * Math.PI * (pointCount - 1) / pointCount, startAngle, radius, center); 40 : } 41 : 42 : /** 43 : * Get pointCount points equidistantly located on a circular segment, including both endpoints. 44 : */ 45 : function distributePointsOnCircularSegment(pointCount, maxAngle, startAngle, radius, center) 46 : { 47 0 : let points = []; 48 0 : let angle = []; 49 0 : pointCount = Math.round(pointCount); 50 : 51 0 : for (let i = 0; i < pointCount; ++i) 52 : { 53 0 : angle[i] = startAngle + maxAngle * i / Math.max(1, pointCount - 1); 54 0 : points[i] = Vector2D.add(center, new Vector2D(radius, 0).rotate(-angle[i])); 55 : } 56 : 57 0 : return [points, angle]; 58 : } 59 : 60 : /** 61 : * Returns the shortest distance from a point to a line. 62 : * The sign of the return value determines the direction! 63 : * 64 : * @param {Vector2D} - lineStart, lineEnd, point 65 : */ 66 : function distanceOfPointFromLine(lineStart, lineEnd, point) 67 : { 68 : // Since the cross product is the area of the parallelogram with the vectors for sides and 69 : // one of the two vectors having length one, that area equals the distance between the points. 70 0 : return Vector2D.sub(lineStart, lineEnd).normalize().cross(Vector2D.sub(point, lineEnd)); 71 : } 72 : 73 : /** 74 : * Returns whether the two lines of the given width going through the given Vector2D intersect. 75 : */ 76 : function testLineIntersection(start1, end1, start2, end2, width) 77 : { 78 0 : let start1end1 = Vector2D.sub(start1, end1); 79 0 : let start2end2 = Vector2D.sub(start2, end2); 80 0 : let start1start2 = Vector2D.sub(start1, start2); 81 : 82 0 : return ( 83 : Math.abs(distanceOfPointFromLine(start1, end1, start2)) < width || 84 : Math.abs(distanceOfPointFromLine(start1, end1, end2)) < width || 85 : Math.abs(distanceOfPointFromLine(start2, end2, start1)) < width || 86 : Math.abs(distanceOfPointFromLine(start2, end2, end1)) < width || 87 : start1end1.cross(start1start2) * start1end1.cross(Vector2D.sub(start1, end2)) <= 0 && 88 : start2end2.cross(start1start2) * start2end2.cross(Vector2D.sub(start2, end1)) >= 0); 89 : } 90 : 91 : /** 92 : * Returns the topleft and bottomright coordinate of the given two points. 93 : */ 94 : function getBoundingBox(points) 95 : { 96 4 : let min = points[0].clone(); 97 4 : let max = points[0].clone(); 98 : 99 4 : for (let point of points) 100 : { 101 8 : min.set(Math.min(min.x, point.x), Math.min(min.y, point.y)); 102 8 : max.set(Math.max(max.x, point.x), Math.max(max.y, point.y)); 103 : } 104 : 105 4 : return { 106 : "min": min, 107 : "max": max 108 : }; 109 : } 110 : 111 : function getPointsInBoundingBox(boundingBox) 112 : { 113 4 : let points = []; 114 4 : for (let x = boundingBox.min.x; x <= boundingBox.max.x; ++x) 115 18 : for (let y = boundingBox.min.y; y <= boundingBox.max.y; ++y) 116 92 : points.push(new Vector2D(x, y)); 117 4 : return points; 118 : } 119 : 120 : /** 121 : * Get the order of the given points to get the shortest closed path (similar to the traveling salesman problem). 122 : * @param {Vectro2D[]} points - Points the path should go through 123 : * @returns {number[]} Ordered indices, same length as points 124 : */ 125 : function sortPointsShortestCycle(points) 126 : { 127 0 : let order = []; 128 0 : let distances = []; 129 0 : if (points.length <= 3) 130 : { 131 0 : for (let i = 0; i < points.length; ++i) 132 0 : order.push(i); 133 : 134 0 : return order; 135 : } 136 : 137 : // Just add the first 3 points 138 0 : let pointsToAdd = points.map(p => p.clone()); 139 0 : for (let i = 0; i < 3; ++i) 140 : { 141 0 : order.push(i); 142 0 : pointsToAdd.shift(); 143 0 : if (i) 144 0 : distances.push(points[order[i]].distanceTo(points[order[i - 1]])); 145 : } 146 : 147 0 : distances.push(points[order[0]].distanceTo(points[order[order.length - 1]])); 148 : 149 : // Add remaining points so the path lengthens the least 150 0 : let numPointsToAdd = pointsToAdd.length; 151 0 : for (let i = 0; i < numPointsToAdd; ++i) 152 : { 153 : let indexToAddTo; 154 0 : let minEnlengthen = Infinity; 155 0 : let minDist1 = 0; 156 0 : let minDist2 = 0; 157 0 : for (let k = 0; k < order.length; ++k) 158 : { 159 0 : let dist1 = pointsToAdd[0].distanceTo(points[order[k]]); 160 0 : let dist2 = pointsToAdd[0].distanceTo(points[order[(k + 1) % order.length]]); 161 : 162 0 : let enlengthen = dist1 + dist2 - distances[k]; 163 0 : if (enlengthen < minEnlengthen) 164 : { 165 0 : indexToAddTo = k; 166 0 : minEnlengthen = enlengthen; 167 0 : minDist1 = dist1; 168 0 : minDist2 = dist2; 169 : } 170 : } 171 0 : order.splice(indexToAddTo + 1, 0, i + 3); 172 0 : distances.splice(indexToAddTo, 1, minDist1, minDist2); 173 0 : pointsToAdd.shift(); 174 : } 175 : 176 0 : return order; 177 : } ```

 Generated by: LCOV version 1.14