diff --git a/app/components/Map.tsx b/app/components/Map.tsx index a26779c..3c3ce3c 100644 --- a/app/components/Map.tsx +++ b/app/components/Map.tsx @@ -7,10 +7,14 @@ import { LayerGroup, useMap, } from 'react-leaflet'; -import L from 'leaflet'; -// import L, { LatLngExpression } from 'leaflet'; +// import L from 'leaflet'; +import L, { LatLngExpression } from 'leaflet'; import 'leaflet/dist/leaflet.css'; +import { intersect } from '@turf/intersect'; +import { polygon } from '@turf/helpers'; +import { Position } from 'geojson'; + import Antennas from './Antennas'; import SectorLobes from './SectorLobes'; import AntennaInfo from './AntennaInfo'; @@ -22,7 +26,7 @@ import { Device } from '../accessPointTypes'; import { useAppSelector, useAppDispatch, useAppStore } from '../../lib/hooks'; // import { AccessPoint, Antenna } from '../types'; -import { AccessPoint } from '../types'; +import { AccessPoint, SectorlobeData } from '../types'; import { initializeActual } from '../../lib/features/actual/actualSlice'; @@ -37,6 +41,45 @@ import { changeCurrent, } from '../../lib/features/currentAntennas/currentAntennasSlice'; +import { initializeSectorlobes } from '../../lib/features/sectorlobes/sectorlobesSlice'; + +function IntersectionInfo({ + intersections, + setPanToCoords, +}: { + intersections: SectorlobeData[][][]; + setPanToCoords: (coords: L.LatLngExpression) => void; +}) { + return ( +
+ {intersections.map((intersection, index) => { + return ( +
+ {intersection.map((pair: SectorlobeData[], index: number) => { + const lobe1 = pair[0]; + const lobe2 = pair[1]; + return ( +
+

Frequency {lobe1.frequency} intersection between lobes

+

+ {lobe1.id} and {lobe2.id} +

+ +
+ ); + })} +
+ ); + })} +
+ ); +} + function DynamicCircleRadius() { const map = useMap(); @@ -69,8 +112,17 @@ function DynamicCircleRadius() { return null; } +function RecenterMap({ panToCoords }: { panToCoords: LatLngExpression }) { + const map = useMap(); + map.setView(panToCoords, map.getZoom()); + return null; +} + export default function Map() { const [toggleInfo, setToggleInfo] = useState(false); + const [intersections, setIntersections] = useState([]); + const [panToCoords, setPanToCoords] = useState(null); + const [intersectionToggle, setIntersectionToggle] = useState(false); const [currentAntenna, setCurrentAntenna] = useState( null @@ -83,6 +135,9 @@ export default function Map() { const actualData = useAppSelector((state) => state.actual.value); const oldPlaygroundData = useAppSelector((state) => state.playground.old); + const sectorlobesData: SectorlobeData[] = useAppSelector( + (state) => state.sectorlobes.value + ); const antennasData = useAppSelector((state) => state.currentAntennas.value); const dispatch = useAppDispatch(); @@ -128,10 +183,68 @@ export default function Map() { }) ); + const sectorlobeData: SectorlobeData[] = antennasData.map((ap) => { + const center: L.LatLngTuple = [ + parseFloat(ap.lat.trim()), + parseFloat(ap.lon.trim()), + ]; + const heading = ap.azimuth; + const radiusInMeters = 100; + const sectorWidth = 45; + let radius: number = 0; + + if (heading < 45) { + // 0-45 + radius = radiusInMeters; + } else if (heading < 135) { + // 45-135 + radius = radiusInMeters - (radiusInMeters / 100) * 20; + } else if (heading < 225) { + // 135-225 + radius = radiusInMeters; + } else if (heading < 315) { + // 225-315 + radius = radiusInMeters - (radiusInMeters / 100) * 20; + } else if (heading <= 360) { + // 315-360 + radius = radiusInMeters; + } + const numberOfVertices: number = 100; + const earthCircumferenceAtLatitude = + 40008000 * Math.cos((center[0] * Math.PI) / 180); + + const scaleFactor = (radius / earthCircumferenceAtLatitude) * 360; + const sectorVertices: LatLngExpression[] = Array.from( + { length: numberOfVertices + 1 }, + (_, index) => { + const angle: number = + (90 + + heading - + sectorWidth / 2 + + (sectorWidth * index) / numberOfVertices) * + (Math.PI / 180); + + const lat: number = center[0] + scaleFactor * Math.sin(angle); + // const lng: number = center[1] + scaleFactor * Math.cos(angle) * 0.3; + const lng: number = center[1] + scaleFactor * Math.cos(angle); + + return [lat, lng]; + } + ); + sectorVertices.push(center); + return { + id: ap.id, + center, + sectorVertices, + frequency: ap.frequency, + }; + }); + if (!initialized.current) { store.dispatch(initializeActual(antennasData)); store.dispatch(initializePlayground(antennasData)); store.dispatch(initializeCurrent(antennasData)); + store.dispatch(initializeSectorlobes(sectorlobeData)); initialized.current = true; } } @@ -161,41 +274,97 @@ export default function Map() { fetchDataAndSetAntennasData(); }, [store]); - // function getSectorVertices( - // center: [number, number], - // radius: number, - // heading: number, - // sectorWidth: number, - // numberOfVertices: number - // ): LatLngExpression[] { - // const earthCircumferenceAtLatitude = - // 40008000 * Math.cos((center[0] * Math.PI) / 180); - - // const scaleFactor = (radius / earthCircumferenceAtLatitude) * 360; - - // const sectorVertices: LatLngExpression[] = Array.from( - // { length: 2 }, - // (_, index) => { - // const angle: number = - // (90 + - // heading - - // sectorWidth / 2 + - // (sectorWidth * index) / numberOfVertices) * - // (Math.PI / 180); - - // const lat: number = center[0] + scaleFactor * Math.sin(angle); - // // const lng: number = center[1] + scaleFactor * Math.cos(angle) * 0.3; - // const lng: number = center[1] + scaleFactor * Math.cos(angle); - - // return [lat, lng]; - // } - // ); - - // return sectorVertices; - // } + useEffect(() => { + // gather lobes into clusters by frequency + if (sectorlobesData.length > 0) { + const clusters: { [key: string]: SectorlobeData[] } = {}; + const foundIntersections: { [key: string]: SectorlobeData[][] } = {}; + for (const lobe of sectorlobesData) { + const key = lobe.frequency.toString(); + if (!(key in clusters)) { + clusters[key] = []; + } + clusters[key].push(lobe); + } + + // for each cluster, find if any lobes overlap + for (const key in clusters) { + const cluster = clusters[key]; + for (let i = 0; i < cluster.length; i++) { + const lobe1 = cluster[i]; + for (let j = i + 1; j < cluster.length; j++) { + const lobe2 = cluster[j]; + + // Convert the LatLngExpression[] to a Position[] for turf.js + const lobe1Positions: Position[] = lobe1.sectorVertices.map( + (vertex) => { + if (Array.isArray(vertex)) { + return [vertex[1], vertex[0]]; + } else { + return [vertex.lng, vertex.lat]; + } + } + ); + + const lobe2Positions: Position[] = lobe2.sectorVertices.map( + (vertex) => { + if (Array.isArray(vertex)) { + return [vertex[1], vertex[0]]; + } else { + return [vertex.lng, vertex.lat]; + } + } + ); + + const center1: Position = [lobe1.center[1], lobe1.center[0]]; + + const center2: Position = [lobe2.center[1], lobe2.center[0]]; + + lobe1Positions.unshift(center1); + lobe2Positions.unshift(center2); + + const poly1 = polygon([lobe1Positions]); + const poly2 = polygon([lobe2Positions]); + const intersection = intersect({ + type: 'FeatureCollection', + features: [poly1, poly2], + }); + if (intersection) { + if (!(key in foundIntersections)) { + foundIntersections[key] = []; + } + foundIntersections[key].push([lobe1, lobe2]); + } + } + } + } + setIntersections(Object.values(foundIntersections)); + } + }, [sectorlobesData]); return ( <> +
+ {intersections.length > 0 ? ( +

+ Found {intersections.length} intersection + {intersections.length > 1 ? 's' : ''}. +

+ ) : ( +

No intersections found.

+ )} + {intersectionToggle && intersections.length > 0 ? ( + + setPanToCoords(coords) + } + /> + ) : null} + +
{toggleInfo ? ( + {panToCoords ? : null} {/* Call anything you want to add to the map here. */} diff --git a/app/components/SectorLobe.tsx b/app/components/SectorLobe.tsx index 4000b7a..6cbf532 100644 --- a/app/components/SectorLobe.tsx +++ b/app/components/SectorLobe.tsx @@ -9,6 +9,7 @@ import { SectorLobeProps } from '../types'; import { useAppSelector, useAppDispatch } from '../../lib/hooks'; import { updateCurrent } from '@/lib/features/currentAntennas/currentAntennasSlice'; +import { updateSectorlobes } from '@/lib/features/sectorlobes/sectorlobesSlice'; export default function SectorLobe({ key_path, @@ -152,9 +153,18 @@ export default function SectorLobe({ const newAp = { ...currentAp }; newAp.azimuth = tempHeading; newAp.frequency = tempFreq; + + const newSectorLobe = { + id: ap.id, + center: center, + sectorVertices: sectorVertices, + frequency: tempFreq, + }; + setCurrentAp(newAp); if (currentMode === 'playground') { dispatch(updateCurrent(newAp)); + dispatch(updateSectorlobes(newSectorLobe)); } } diff --git a/app/components/SectorLobes.tsx b/app/components/SectorLobes.tsx index da21a6a..b0768fc 100644 --- a/app/components/SectorLobes.tsx +++ b/app/components/SectorLobes.tsx @@ -3,13 +3,12 @@ import 'leaflet/dist/leaflet.css'; import SectorLobe from './SectorLobe'; -// ! Current known issues: +// ! Current known issues/map quirks: // ! 1. The sectorlobes, when tuned to different headings, the look of the width changes. // ! This is because the way shapes are warped due to the projection of the map. // ! 2. The sectorLobes do not represent the actual shape of the sectorLobe. // ! This is because the sectorLobe is not a cone. It is an ellipse. // ! So their needs to be a specific algorithm which will aid in the creation of the sectorLobe based on the model of the antenna. -// ! 3. The sectorlobes do not appear if heading is at 360 degrees import { useAppSelector } from '../../lib/hooks'; diff --git a/app/types.ts b/app/types.ts index 689ad08..80295d7 100644 --- a/app/types.ts +++ b/app/types.ts @@ -1,3 +1,5 @@ +import { LatLngExpression, LatLngTuple } from 'leaflet'; + // Interfaces export type Antenna = { @@ -38,6 +40,13 @@ export interface ReducedPoints { [key: string]: ReducedContent; } +export interface SectorlobeData { + id: string; + center: LatLngTuple; + sectorVertices: LatLngExpression[]; + frequency: number; +} + // Props export interface InfoProps { diff --git a/lib/features/sectorlobes/sectorlobesSlice.ts b/lib/features/sectorlobes/sectorlobesSlice.ts new file mode 100644 index 0000000..b5e1612 --- /dev/null +++ b/lib/features/sectorlobes/sectorlobesSlice.ts @@ -0,0 +1,50 @@ +import { PayloadAction, createSlice } from '@reduxjs/toolkit'; + +import { SectorlobeData } from '../../../app/types'; + +type SectorlobesState = { value: SectorlobeData[] }; + +export const sectorlobesSlice = createSlice({ + name: 'sectorlobes', + initialState: { + value: [], + } satisfies SectorlobesState as SectorlobesState, + reducers: { + initializeSectorlobes: (state, action: PayloadAction) => { + return { ...state, value: action.payload, old: action.payload }; + }, + replaceSectorlobes: (state, action: PayloadAction) => { + return { ...state, value: action.payload }; + }, + addSectorlobes: (state, action: PayloadAction) => { + return { ...state, value: [...state.value, action.payload] }; + }, + removeSectorlobes: (state, action: PayloadAction) => { + return { + ...state, + value: state.value.filter((item) => item.id !== action.payload.id), + }; + }, + updateSectorlobes: (state, action: PayloadAction) => { + const newArray = state.value.map((item) => { + if (item.id === action.payload.id) { + return action.payload; + } + return item; + }); + state = { ...state, value: newArray }; + }, + }, +}); + +export const { + initializeSectorlobes, + replaceSectorlobes, + addSectorlobes, + removeSectorlobes, + updateSectorlobes, +} = sectorlobesSlice.actions; + +export default sectorlobesSlice.reducer; + +// https://redux-toolkit.js.org/usage/usage-with-typescript diff --git a/lib/store.ts b/lib/store.ts index 1410478..af7d34e 100644 --- a/lib/store.ts +++ b/lib/store.ts @@ -2,6 +2,7 @@ import { configureStore } from '@reduxjs/toolkit'; import playgroundReducer from './features/playground/playgroundSlice'; import actualReducer from './features/actual/actualSlice'; import currentAntennasReducer from './features/currentAntennas/currentAntennasSlice'; +import sectorlobesReducer from './features/sectorlobes/sectorlobesSlice'; export const makeStore = () => { return configureStore({ @@ -9,6 +10,7 @@ export const makeStore = () => { playground: playgroundReducer, actual: actualReducer, currentAntennas: currentAntennasReducer, + sectorlobes: sectorlobesReducer, }, }); }; diff --git a/package-lock.json b/package-lock.json index 1b4fc41..8ac827a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@reduxjs/toolkit": "^2.2.1", + "@turf/helpers": "^7.0.0-alpha.114", + "@turf/intersect": "^7.0.0-alpha.114", "cors": "^2.8.5", "cypress": "^13.6.4", "dotenv": "^16.4.2", @@ -3331,6 +3333,43 @@ "node": ">= 10" } }, + "node_modules/@turf/helpers": { + "version": "7.0.0-alpha.114", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.0.0-alpha.114.tgz", + "integrity": "sha512-hqoARkwAaFMK/8wOWDQhmvIxjUL2l9jUhn1GUzW3fsumImPxuHoJZbIZhiHjE7ceQngveCeUCtkiKw89lekN8w==", + "dependencies": { + "deep-equal": "^2.2.3", + "tslib": "^2.6.2" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/intersect": { + "version": "7.0.0-alpha.114", + "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-7.0.0-alpha.114.tgz", + "integrity": "sha512-YQ99CzN4atud30pY9brGxECWibOs9S9v5ztsnKUxDdOlqi2+zgP5LHOrKwrydZrDX6qsi0O6RE+w+0/a/cnX+A==", + "dependencies": { + "@turf/helpers": "^7.0.0-alpha.114+e0bdd0add", + "@turf/meta": "^7.0.0-alpha.114+e0bdd0add", + "polygon-clipping": "^0.15.3", + "tslib": "^2.6.2" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "7.0.0-alpha.114", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.0.0-alpha.114.tgz", + "integrity": "sha512-R/VHKBLqVnPcXaawR7PlXSfgLSPvMUBwe04m2riTPhOrUCrh5/UW3+NTshAg9tjIMk1njsnlpqgUcrG0OYu9OQ==", + "dependencies": { + "@turf/helpers": "^7.0.0-alpha.114+e0bdd0add" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, "node_modules/@types/aria-query": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.3.tgz", @@ -4304,7 +4343,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -4528,7 +4566,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -5714,15 +5751,14 @@ } }, "node_modules/deep-equal": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", - "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", - "dev": true, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dependencies": { "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", @@ -5732,11 +5768,14 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5942,7 +5981,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -6212,7 +6250,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -7215,7 +7252,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, "dependencies": { "is-callable": "^1.1.3" } @@ -7326,7 +7362,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7551,7 +7586,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7601,7 +7635,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -7861,7 +7894,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.2", "hasown": "^2.0.0", @@ -7875,7 +7907,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7891,7 +7922,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -7926,7 +7956,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -7950,7 +7979,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7966,7 +7994,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -8001,7 +8028,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -8129,7 +8155,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8158,7 +8183,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -8187,7 +8211,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -8203,7 +8226,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8212,7 +8234,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -8235,7 +8256,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -8250,7 +8270,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -8265,7 +8284,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, "dependencies": { "which-typed-array": "^1.1.11" }, @@ -8296,7 +8314,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8317,7 +8334,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -8356,8 +8372,7 @@ "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "node_modules/isexe": { "version": "2.0.0", @@ -14685,7 +14700,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -14701,7 +14715,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -14710,7 +14723,6 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -15281,6 +15293,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/polygon-clipping": { + "version": "0.15.7", + "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.7.tgz", + "integrity": "sha512-nhfdr83ECBg6xtqOAJab1tbksbBAOMUltN60bU+llHVOL0e5Onm1WpAXXWXVB39L8AJFssoIhEVuy/S90MmotA==", + "dependencies": { + "robust-predicates": "^3.0.2", + "splaytree": "^3.1.0" + } + }, "node_modules/postcss": { "version": "8.4.32", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", @@ -15830,7 +15851,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -16005,6 +16025,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -16198,7 +16223,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "functions-have-names": "^1.2.3", @@ -16329,6 +16353,11 @@ "source-map": "^0.6.0" } }, + "node_modules/splaytree": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz", + "integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A==" + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -16390,7 +16419,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, "dependencies": { "internal-slot": "^1.0.4" }, @@ -17393,7 +17421,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -17435,7 +17462,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -17450,7 +17476,6 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.4", diff --git a/package.json b/package.json index 0786af7..2521c96 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.2.1", + "@turf/helpers": "^7.0.0-alpha.114", + "@turf/intersect": "^7.0.0-alpha.114", "cors": "^2.8.5", "cypress": "^13.6.4", "dotenv": "^16.4.2",