Spaces:
Runtime error
Runtime error
File size: 6,208 Bytes
2f322ce 8c93eed 7e40962 8c93eed a5e71eb 2f322ce a5e71eb 2f322ce 5e62073 2f322ce a5e71eb 1d6d0dd c2a5a36 2f322ce c2a5a36 1d6d0dd c2a5a36 1d6d0dd c2a5a36 1d6d0dd c2a5a36 1d6d0dd c2a5a36 1d6d0dd c2a5a36 1d6d0dd 5e62073 c2a5a36 1d6d0dd c2a5a36 a5e71eb 5e62073 a5e71eb 5e62073 a5e71eb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import geodesic from 'geographiclib-geodesic';
// Haversine-based geodesic interpolator
function generateGeodesicPoints(lat1, lon1, lat2, lon2, numPoints = 512) {
/**
* Generates a series of points along the geodesic path between two geographic coordinates, using Haversine function.
* @returns {Array} An array of points, each represented as [latitude, longitude].
*/
const toRad = deg => deg * Math.PI / 180;
const toDeg = rad => rad * 180 / Math.PI;
const 蠁1 = toRad(lat1);
const 位1 = toRad(lon1);
const 蠁2 = toRad(lat2);
const 位2 = toRad(lon2);
const 螖 = 2 * Math.asin(
Math.sqrt(
Math.sin((蠁2 - 蠁1) / 2) ** 2 +
Math.cos(蠁1) * Math.cos(蠁2) *
Math.sin((位2 - 位1) / 2) ** 2
)
);
if (螖 === 0) return [[lat1, lon1]];
const sin螖 = Math.sin(螖);
const points = [];
for (let i = 0; i <= numPoints; i++) {
const f = i / numPoints;
const A = Math.sin((1 - f) * 螖) / sin螖;
const B = Math.sin(f * 螖) / sin螖;
const x = A * Math.cos(蠁1) * Math.cos(位1) + B * Math.cos(蠁2) * Math.cos(位2);
const y = A * Math.cos(蠁1) * Math.sin(位1) + B * Math.cos(蠁2) * Math.sin(位2);
const z = A * Math.sin(蠁1) + B * Math.sin(蠁2);
const 蠁i = Math.atan2(z, Math.sqrt(x * x + y * y));
const 位i = Math.atan2(y, x);
points.push([toDeg(蠁i), toDeg(位i)]);
}
return points;
}
function calculatePolygonArea(coords) {
/*** Calculate the geodesic area of a polygon on the WGS84 ellipsoid.
* @param {Array<Array<number>>} coords - Array of [lat, lon] pairs.
* @returns {number} Area in square meters.
*/
// console.log(coords); // Lifesaver
const geod = geodesic.Geodesic.WGS84;
const poly = geod.Polygon(false); // false = polygon, not polyline
for (const [lat, lon] of coords) {
poly.AddPoint(lat, lon);
}
// Closing the polygon is not required as I am already doing it in the frontend.
const result = poly.Compute(); // Returns object (number (of vertices), perimeter, area)
//console.log(result)
return {area: result.area, perimeter: result.perimeter}; // area in square meters, important.
}
function getPolygonCentroid(points) {
// Simple centroid calculation for small polygons
let x = 0, y = 0, n = points.length;
points.forEach(([lat, lon]) => { x += lat; y += lon; });
return [x / n, y / n];
}
function formatArea(area, unit = 'sqm', format = "normal") {
if (typeof area !== 'number' || isNaN(area)) {
console.log('Invalid area input:', area);
return 'Invalid area';
}
let value;
switch (unit) {
case "km2":
value = area / 1e6;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' km虏';
case "ha":
value = area / 1e4;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' ha';
case "sqm":
value = area;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m虏';
case "acres":
value = area / 4046.8564224;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' acres';
case "mi2":
value = area / 2589988.110336;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' mi虏';
case "sqft":
value = area * 10.76391041671;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' ft虏';
default:
value = area;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m虏';
}
}
function formatPerimeter(perimeter, unit = 'sqm', format = "normal") {
if (typeof perimeter !== 'number' || isNaN(perimeter)) {
console.log('Invalid perimeter input:', perimeter);
return 'Invalid perimeter';
}
let value;
switch (unit) {
case "km2":
value = perimeter / 1000;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' km';
case "ha":
value = perimeter / 1000;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' km';
case "m2":
value = perimeter;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m';
case "mi2":
value = perimeter / 1609.344;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' mi';
case "sqft":
value = perimeter * 3.280839895013123; // meters to feet
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' ft';
default:
value = perimeter;
return (format === "scientific" ? value.toExponential(2) : value.toLocaleString(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2 })) + ' m';
}
}
export {generateGeodesicPoints, calculatePolygonArea, getPolygonCentroid, formatArea, formatPerimeter};
// calculatePolygonArea |