StorymapperArrow/BasicShapes.js
2025-05-28 17:45:01 +02:00

152 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as turf from "@turf/turf";
import { toMercator, toWgs84 } from '@turf/projection';
//CIRCLE
const distancePerDegreeLongitude = 111.320; // 2π×6378.1km/360
const distancePerDegreeLatitude = 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) {
const points = [];
const coords = {
latitude: center[1], // Latitude
longitude: center[0] // Longitude
};
const distanceX = radius / (distancePerDegreeLongitude * Math.cos(coords.latitude * Math.PI / 180));
const distanceY = radius / distancePerDegreeLatitude;
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) {
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) {
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) {
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