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 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 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