173 lines
5.5 KiB
JavaScript
173 lines
5.5 KiB
JavaScript
import * as turf from "@turf/turf";
|
||
import { toMercator, toWgs84 } from '@turf/projection';
|
||
|
||
//CIRCLE
|
||
const DISTANCE_PER_DEGREE_LONGITUDE = 111.320; // 2π×6378.1km/360
|
||
const DISTANCE_PER_DEGREE_LATITUDE = 110.574; // 2π×6356.75km/360
|
||
|
||
//GEOJSON
|
||
/**
|
||
* @param {Object} center - The center point of the circle.
|
||
* @param {number} center.x
|
||
* @param {number} center.y
|
||
* @param {number} radius - The radius of the circle.
|
||
* @param {number} density - The number of points used to approximate the circle.
|
||
*
|
||
* @returns {GeoJSON.Feature<GeoJSON.Polygon>} GeoJSON Feature representing the circle polygon.
|
||
*/
|
||
export function getCirclePolygon(center, radius, density = 64) {
|
||
if (!center || !radius ) {
|
||
console.warn("getCirclePolygon: Invalid center, radius.");
|
||
return [];
|
||
}
|
||
|
||
const points = [];
|
||
|
||
const coords = {
|
||
latitude: center[1],
|
||
longitude: center[0]
|
||
};
|
||
|
||
const distanceX = radius / (DISTANCE_PER_DEGREE_LONGITUDE * Math.cos(coords.latitude * Math.PI / 180));
|
||
const distanceY = radius / DISTANCE_PER_DEGREE_LATITUDE;
|
||
|
||
for (let i = 0; i < density; i++) {
|
||
const angle = (i / density) * Math.PI * 2;
|
||
const x = distanceX * Math.cos(angle);
|
||
const y = distanceY * Math.sin(angle);
|
||
points.push([coords.longitude + x, coords.latitude + y]);
|
||
}
|
||
|
||
// Close the circle by adding the first point again
|
||
points.push(points[0]);
|
||
|
||
return turf.polygon([[...points]]);
|
||
/*
|
||
return {
|
||
"type": "Feature",
|
||
"geometry": {
|
||
"type": "Polygon",
|
||
"coordinates": [points]
|
||
},
|
||
"properties": {}
|
||
};*/
|
||
}
|
||
//GEOJSON
|
||
//CANVAS
|
||
/**
|
||
* @param {Object} center - The center point of the circle.
|
||
* @param {number} center.x
|
||
* @param {number} center.y
|
||
* @param {number} radius - The radius of the circle.
|
||
* @param {number} density - The number of points used to approximate the circle.
|
||
*
|
||
* @returns {{x: number, y: number}[]} An array of points representing the vertices of the circle polygon.
|
||
*/
|
||
export function getCirclePolygonEuclidean(center, radius, density) {
|
||
if (!center || !radius || !density) {
|
||
console.warn("getCirclePolygonEuclidean: Invalid center, radius or density.");
|
||
return [];
|
||
}
|
||
|
||
const points = [];
|
||
for (let i = 0; i < density; i++) {
|
||
const angle = (i / density) * Math.PI * 2;
|
||
const x = center.x + radius * Math.cos(angle);
|
||
const y = center.y + radius * Math.sin(angle);
|
||
points.push({ x, y });
|
||
}
|
||
return points;
|
||
}
|
||
//CANVAS
|
||
//CIRCLE
|
||
|
||
//RECTANGLE
|
||
//GEOJSON
|
||
/**
|
||
* @param {Object} center - The center point of the rectangle.
|
||
* @param {number} center.x
|
||
* @param {number} center.y
|
||
* @param {number} width - The length of the first side of the rectangle.
|
||
* @param {number} height - The length of the second side of the rectangle.
|
||
* @param {number} rotation - The angle (in radians) by which to rotate the rectangle.
|
||
*
|
||
* @returns {GeoJSON.Feature<GeoJSON.Polygon>} GeoJSON Feature representing the rectangle polygon.
|
||
*/
|
||
export function getRectanglePolygon(center, width, height, rotation = 0) {
|
||
if (!center || !width || !height) {
|
||
console.warn("getRectanglePolygon: Invalid center, width or height.");
|
||
return [];
|
||
}
|
||
|
||
const widthMeters = width * 1000 ;
|
||
const heightMeters = height * 1000;
|
||
|
||
const centerMerc = toMercator(turf.point(center)).geometry.coordinates;
|
||
|
||
const halfWidth = widthMeters / 2;
|
||
const halfHeight = heightMeters / 2;
|
||
|
||
let corners = [
|
||
[centerMerc[0] - halfWidth, centerMerc[1] + halfHeight], // topLeft
|
||
[centerMerc[0] + halfWidth, centerMerc[1] + halfHeight], // topRight
|
||
[centerMerc[0] + halfWidth, centerMerc[1] - halfHeight], // bottomRight
|
||
[centerMerc[0] - halfWidth, centerMerc[1] - halfHeight], // bottomLeft
|
||
];
|
||
|
||
if (rotation !== 0) {
|
||
const rad = (rotation * Math.PI) / 180;
|
||
corners = corners.map(([x, y]) => rotateXY(x, y, centerMerc[0], centerMerc[1], rad));
|
||
}
|
||
|
||
corners.push(corners[0]);
|
||
const wgsCoords = corners.map(([x, y]) => toWgs84([x, y]));
|
||
|
||
return turf.polygon([wgsCoords]);
|
||
}
|
||
|
||
function rotateXY(x, y, cx, cy, angleRad) {
|
||
const dx = x - cx;
|
||
const dy = y - cy;
|
||
const cos = Math.cos(angleRad);
|
||
const sin = Math.sin(angleRad);
|
||
const rx = cx + dx * cos - dy * sin;
|
||
const ry = cy + dx * sin + dy * cos;
|
||
return [rx, ry];
|
||
}
|
||
//GEOJSON
|
||
//CANVAS
|
||
/**
|
||
* @param {Object} center - The center point of the rectangle.
|
||
* @param {number} center.x
|
||
* @param {number} center.y
|
||
* @param {number} sideA - The length of the first side of the rectangle.
|
||
* @param {number} sideB - The length of the second side of the rectangle.
|
||
* @param {number} rotation - The angle (in radians) by which to rotate the rectangle.
|
||
*
|
||
* @returns {{x: number, y: number}[]} An array of points representing the vertices of the rectangle polygon.
|
||
*/
|
||
export function getRectanglePolygonEuclidean(center, sideA, sideB, rotation = 0) {
|
||
if (!center || !sideA || !sideB) {
|
||
console.warn("getRectanglePolygonEuclidean: Invalid center, sideA or sideB.");
|
||
return [];
|
||
}
|
||
|
||
const halfA = sideA / 2;
|
||
const halfB = sideB / 2;
|
||
|
||
const corners = [
|
||
{ x: -halfA, y: -halfB },
|
||
{ x: halfA, y: -halfB },
|
||
{ x: halfA, y: halfB },
|
||
{ x: -halfA, y: halfB }
|
||
];
|
||
|
||
return corners.map(point => {
|
||
return {
|
||
x: center.x + point.x * Math.cos(rotation) - point.y * Math.sin(rotation),
|
||
y: center.y + point.x * Math.sin(rotation) + point.y * Math.cos(rotation)
|
||
};
|
||
});
|
||
}
|
||
//CAVNAS
|
||
//RECTANGLE
|