From 8aac6b7d7e0099222442ebbb901f6eed16a79d9f Mon Sep 17 00:00:00 2001 From: Davide Passoni Date: Wed, 26 Feb 2025 12:05:59 +0100 Subject: [PATCH] feat: Aligned orbits representation, added visibility option --- frontend/react/public/images/others/arrow.svg | 11 +- frontend/react/src/constants/constants.ts | 1 + .../map/coalitionarea/coalitionareahandle.ts | 6 +- .../src/map/coalitionarea/coalitioncircle.ts | 6 +- .../src/map/coalitionarea/coalitionpolygon.ts | 10 +- frontend/react/src/map/stylesheets/map.css | 52 ++++-- frontend/react/src/types/types.ts | 1 + frontend/react/src/ui/panels/header.tsx | 29 ++- frontend/react/src/ui/panels/optionsmenu.tsx | 36 +++- frontend/react/src/unit/unit.ts | 172 +++++++++--------- 10 files changed, 193 insertions(+), 131 deletions(-) diff --git a/frontend/react/public/images/others/arrow.svg b/frontend/react/public/images/others/arrow.svg index 8ecc05ae..38ef0bce 100644 --- a/frontend/react/public/images/others/arrow.svg +++ b/frontend/react/public/images/others/arrow.svg @@ -22,9 +22,9 @@ inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" - inkscape:zoom="8.9824657" - inkscape:cx="20.985329" - inkscape:cy="21.430641" + inkscape:zoom="12.703125" + inkscape:cx="27.316114" + inkscape:cy="18.145142" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="1912" @@ -33,7 +33,8 @@ inkscape:current-layer="svg1" /> + style="stroke:none;stroke-width:2.30583;stroke-dasharray:none;stroke-opacity:1" + sodipodi:nodetypes="csccsscc" /> diff --git a/frontend/react/src/constants/constants.ts b/frontend/react/src/constants/constants.ts index b9e89445..7fc93bab 100644 --- a/frontend/react/src/constants/constants.ts +++ b/frontend/react/src/constants/constants.ts @@ -403,6 +403,7 @@ export const MAP_OPTIONS_DEFAULTS: MapOptions = { showUnitLabels: true, showUnitsEngagementRings: true, showUnitsAcquisitionRings: true, + showRacetracks: true, fillSelectedRing: false, showMinimap: false, protectDCSUnits: true, diff --git a/frontend/react/src/map/coalitionarea/coalitionareahandle.ts b/frontend/react/src/map/coalitionarea/coalitionareahandle.ts index 9e72f100..3bc95b63 100644 --- a/frontend/react/src/map/coalitionarea/coalitionareahandle.ts +++ b/frontend/react/src/map/coalitionarea/coalitionareahandle.ts @@ -1,7 +1,7 @@ import { DivIcon, LatLng } from "leaflet"; import { CustomMarker } from "../markers/custommarker"; -export class CoalitionAreaHandle extends CustomMarker { +export class DraggableHandle extends CustomMarker { constructor(latlng: LatLng) { super(latlng, { interactive: true, draggable: true }); @@ -15,11 +15,11 @@ export class CoalitionAreaHandle extends CustomMarker { new DivIcon({ iconSize: [24, 24], iconAnchor: [12, 12], - className: "leaflet-coalitionarea-handle-marker", + className: "leaflet-draggable-handle-marker", }) ); var el = document.createElement("div"); - el.classList.add("ol-coalitionarea-handle-icon"); + el.classList.add("ol-draggable-handle-icon"); this.getElement()?.appendChild(el); } } diff --git a/frontend/react/src/map/coalitionarea/coalitioncircle.ts b/frontend/react/src/map/coalitionarea/coalitioncircle.ts index 3c8b1f73..1a6f7f9e 100644 --- a/frontend/react/src/map/coalitionarea/coalitioncircle.ts +++ b/frontend/react/src/map/coalitionarea/coalitioncircle.ts @@ -1,6 +1,6 @@ import { LatLngExpression, Map, Circle, DivIcon, Marker, CircleOptions, LatLng } from "leaflet"; import { getApp } from "../../olympusapp"; -import { CoalitionAreaHandle } from "./coalitionareahandle"; +import { DraggableHandle } from "./coalitionareahandle"; import { BLUE_COMMANDER, colors, RED_COMMANDER } from "../../constants/constants"; import { Coalition } from "../../types/types"; import * as turf from "@turf/turf"; @@ -12,7 +12,7 @@ export class CoalitionCircle extends Circle { #coalition: Coalition = "blue"; #selected: boolean = true; #creating: boolean = false; - #radiusHandle: CoalitionAreaHandle; + #radiusHandle: DraggableHandle; #labelText: string; #label: Marker; #updateTimeout: number | null = null; @@ -140,7 +140,7 @@ export class CoalitionCircle extends Circle { if (this.#selected) { const dest = turf.destination(turf.point([this.getLatLng().lng, this.getLatLng().lat]), this.getRadius() / 1000, 0); - this.#radiusHandle = new CoalitionAreaHandle(new LatLng(dest.geometry.coordinates[1], dest.geometry.coordinates[0])); + this.#radiusHandle = new DraggableHandle(new LatLng(dest.geometry.coordinates[1], dest.geometry.coordinates[0])); this.#radiusHandle.addTo(getApp().getMap()); this.#radiusHandle.on("drag", (e: any) => { this.setRadius(this.getLatLng().distanceTo(e.latlng)); diff --git a/frontend/react/src/map/coalitionarea/coalitionpolygon.ts b/frontend/react/src/map/coalitionarea/coalitionpolygon.ts index a0408358..1a2ead5f 100644 --- a/frontend/react/src/map/coalitionarea/coalitionpolygon.ts +++ b/frontend/react/src/map/coalitionarea/coalitionpolygon.ts @@ -1,6 +1,6 @@ import { LatLng, LatLngExpression, Map, Point, Polygon, PolylineOptions, DivIcon, Marker } from "leaflet"; import { getApp } from "../../olympusapp"; -import { CoalitionAreaHandle } from "./coalitionareahandle"; +import { DraggableHandle } from "./coalitionareahandle"; import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle"; import { BLUE_COMMANDER, colors, RED_COMMANDER } from "../../constants/constants"; import { Coalition } from "../../types/types"; @@ -13,7 +13,7 @@ export class CoalitionPolygon extends Polygon { #coalition: Coalition = "blue"; #selected: boolean = true; #creating: boolean = false; - #handles: CoalitionAreaHandle[] = []; + #handles: DraggableHandle[] = []; #middleHandles: CoalitionAreaMiddleHandle[] = []; #activeIndex: number = 0; #labelText: string; @@ -132,7 +132,7 @@ export class CoalitionPolygon extends Polygon { onRemove(map: Map): this { super.onRemove(map); this.#label?.removeFrom(map); - this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(map)); + this.#handles.concat(this.#middleHandles).forEach((handle: DraggableHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(map)); return this; } @@ -161,13 +161,13 @@ export class CoalitionPolygon extends Polygon { } #setHandles() { - this.#handles.forEach((handle: CoalitionAreaHandle) => handle.removeFrom(getApp().getMap())); + this.#handles.forEach((handle: DraggableHandle) => handle.removeFrom(getApp().getMap())); this.#handles = []; if (this.getSelected()) { var latlngs = this.getLatLngs()[0] as LatLng[]; latlngs.forEach((latlng: LatLng, idx: number) => { /* Add the polygon vertex handle (for moving the vertex) */ - const handle = new CoalitionAreaHandle(latlng); + const handle = new DraggableHandle(latlng); handle.addTo(getApp().getMap()); handle.on("drag", (e: any) => { var latlngs = this.getLatLngs()[0] as LatLng[]; diff --git a/frontend/react/src/map/stylesheets/map.css b/frontend/react/src/map/stylesheets/map.css index 6834f088..155208cd 100644 --- a/frontend/react/src/map/stylesheets/map.css +++ b/frontend/react/src/map/stylesheets/map.css @@ -100,20 +100,26 @@ font-weight: 600; } -.ol-coalitionarea-handle-icon { - cursor: url("/images/cursors/pointer.svg") 13 5, auto; - background-color: #FFFFFFAA; +.ol-draggable-handle-icon { + cursor: + url("/images/cursors/pointer.svg") 13 5, + auto; + background-color: #ffffff; width: 100%; height: 100%; border-radius: 999px; + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } .ol-coalitionarea-middle-handle-icon { - cursor: url("/images/cursors/pointer.svg") 13 5, auto; - background-color: #FFFFFFAA; + cursor: + url("/images/cursors/pointer.svg") 13 5, + auto; + background-color: #ffffff; width: 100%; height: 100%; border-radius: 999px; + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } .ol-coalitionarea-label { @@ -124,7 +130,11 @@ .ol-coalitionarea-label.selected { color: white; /* 1 pixel black shadow to left, top, right and bottom */ - text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + text-shadow: + -1px 0 black, + 0 1px black, + 1px 0 black, + 0 -1px black; } .ol-coalitionarea-label.blue { @@ -139,15 +149,15 @@ background-image: url("/images/markers/target.svg"); height: 100%; width: 100%; - - filter: drop-shadow( 3px 3px 3px rgba(0, 0, 0, .2)); + + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } .ol-spot-icon { background-image: url("/images/markers/target.svg"); height: 100%; width: 100%; - filter: drop-shadow( 3px 3px 3px rgba(0, 0, 0, .2)); + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } .ol-text-icon { @@ -162,10 +172,10 @@ .ol-smoke-icon { opacity: 75%; - filter: drop-shadow( 3px 3px 3px rgba(0, 0, 0, .2)); + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } -.ol-explosion-icon * { +.ol-explosion-icon * { opacity: 75%; } @@ -185,7 +195,9 @@ path.leaflet-interactive:focus { cursor: url("/images/cursors/follow.svg"), auto !important; } -.fire-at-area-cursor, .bomb-cursor, .carpet-bomb-cursor { +.fire-at-area-cursor, +.bomb-cursor, +.carpet-bomb-cursor { cursor: url("/images/cursors/fire-at-area.svg"), auto !important; } @@ -213,9 +225,10 @@ path.leaflet-interactive:focus { cursor: url("/images/cursors/measure.svg"), auto !important; } - #map-container.leaflet-grab { - cursor: url("/images/cursors/grab.svg") 16 16, auto; + cursor: + url("/images/cursors/grab.svg") 16 16, + auto; } .explosion-cursor { @@ -247,7 +260,13 @@ path.leaflet-interactive:focus { } .pointer-cursor { - cursor: url("/images/cursors/pointer.svg") 13 5, auto !important; + cursor: + url("/images/cursors/pointer.svg") 13 5, + auto !important; +} + +.ol-arrow-icon { + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.2)); } .ol-arrow-icon svg { @@ -256,6 +275,5 @@ path.leaflet-interactive:focus { } .ol-arrow-icon svg path { - fill: #FFFFFFAA; - + fill: #ffffff; } diff --git a/frontend/react/src/types/types.ts b/frontend/react/src/types/types.ts index 7dc22e28..f3114a56 100644 --- a/frontend/react/src/types/types.ts +++ b/frontend/react/src/types/types.ts @@ -18,6 +18,7 @@ export type MapOptions = { showUnitLabels: boolean; showUnitsEngagementRings: boolean; showUnitsAcquisitionRings: boolean; + showRacetracks: boolean; fillSelectedRing: boolean; showMinimap: boolean; protectDCSUnits: boolean; diff --git a/frontend/react/src/ui/panels/header.tsx b/frontend/react/src/ui/panels/header.tsx index d7e2b58a..99fb6a36 100644 --- a/frontend/react/src/ui/panels/header.tsx +++ b/frontend/react/src/ui/panels/header.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useRef, useState } from "react"; import { OlRoundStateButton, OlStateButton, OlLockStateButton } from "../components/olstatebutton"; -import { faSkull, faCamera, faFlag, faVolumeHigh, faDownload, faUpload, faDrawPolygon } from "@fortawesome/free-solid-svg-icons"; +import { faSkull, faCamera, faFlag, faVolumeHigh, faDownload, faUpload, faDrawPolygon, faCircle, faTriangleExclamation, faWifi, faHourglass, faInfo } from "@fortawesome/free-solid-svg-icons"; import { OlDropdownItem, OlDropdown } from "../components/oldropdown"; import { OlLabelToggle } from "../components/ollabeltoggle"; import { getApp, IP } from "../../olympusapp"; @@ -146,17 +146,13 @@ export function Header() { }} checked={false} /> - {savingSessionData ? ( + {savingSessionData ? (
- +
) : (
- + +
+
+ getApp().getMap().setOption("showUnitsEngagementRings", !mapOptions.showUnitsEngagementRings)} + checked={mapOptions.showUnitsEngagementRings} + icon={faTriangleExclamation} + className={""} + tooltip={"Hide/show units engagement rings"} + /> + getApp().getMap().setOption("showUnitsAcquisitionRings", !mapOptions.showUnitsAcquisitionRings)} + checked={mapOptions.showUnitsAcquisitionRings} + icon={faWifi} + className={""} + tooltip={"Hide/show units acquisition rings"} + /> +
void; childre onClick={() => getApp().getMap().setOption("showUnitLabels", !mapOptions.showUnitLabels)} > {}}> - Show Unit Labels + Show unit labels
void; childre onClick={() => getApp().getMap().setOption("showUnitsEngagementRings", !mapOptions.showUnitsEngagementRings)} > {}}> - Show Threat Rings + Show threat rings
void; childre onClick={() => getApp().getMap().setOption("showUnitsAcquisitionRings", !mapOptions.showUnitsAcquisitionRings)} > {}}> - Show Detection rings + Show detection rings
void; childre onClick={() => getApp().getMap().setOption("showUnitTargets", !mapOptions.showUnitTargets)} > {}}> - Show Detection lines + Show detection lines
void; childre onClick={() => getApp().getMap().setOption("hideUnitsShortRangeRings", !mapOptions.hideUnitsShortRangeRings)} > {}}> - Hide Short range Rings + Hide short range rings
void; childre onClick={() => getApp().getMap().setOption("hideGroupMembers", !mapOptions.hideGroupMembers)} > {}}> - Hide Group members + Hide group members
void; childre {}}> Show minimap
+
getApp().getMap().setOption("showRacetracks", !mapOptions.showRacetracks)} + > + {}}> + Show racetracks +
void; childre mapOptions.AWACSCoalition === "red" && getApp().getMap().setOption("AWACSCoalition", "blue"); }} > +
+
{}} coalition={mapOptions.AWACSCoalition} /> Coalition of unit bullseye info +
+
+ {" "} +
+ Change the coalition of the bullseye to use to provide bullseye information in the unit tooltip. +
+
+
diff --git a/frontend/react/src/unit/unit.ts b/frontend/react/src/unit/unit.ts index 92db8a1e..6c8c7e2b 100644 --- a/frontend/react/src/unit/unit.ts +++ b/frontend/react/src/unit/unit.ts @@ -67,7 +67,7 @@ import { UnitSelectedEvent, UnitUpdatedEvent, } from "../events"; -import { CoalitionAreaHandle } from "../map/coalitionarea/coalitionareahandle"; +import { DraggableHandle } from "../map/coalitionarea/coalitionareahandle"; import { ArrowMarker } from "../map/markers/arrowmarker"; import { Spot } from "../mission/spot"; import { SpotEditMarker } from "../map/markers/spoteditmarker"; @@ -171,7 +171,7 @@ export abstract class Unit extends CustomMarker { #trailPolylines: Polyline[] = []; #racetrackPolylines: Polyline[] = []; #racetrackArcs: Polyline[] = []; - #racetrackAnchorMarkers: CoalitionAreaHandle[] = [new CoalitionAreaHandle(new LatLng(0, 0)), new CoalitionAreaHandle(new LatLng(0, 0))]; + #racetrackAnchorMarkers: DraggableHandle[] = [new DraggableHandle(new LatLng(0, 0)), new DraggableHandle(new LatLng(0, 0))]; #racetrackArrow: ArrowMarker = new ArrowMarker(new LatLng(0, 0)); #inhibitRacetrackDraw: boolean = false; #spotLines: { [key: number]: Polyline } = {}; @@ -379,13 +379,13 @@ export abstract class Unit extends CustomMarker { }); this.#racetrackPolylines = [ - new Polyline([], { color: colors.OLYMPUS_BLUE, weight: 3, opacity: 0.5, smoothFactor: 1 }), - new Polyline([], { color: colors.OLYMPUS_BLUE, weight: 3, opacity: 0.5, smoothFactor: 1 }), + new Polyline([], { color: colors.WHITE, weight: 3, smoothFactor: 1, dashArray: "5, 5" }), + new Polyline([], { color: colors.WHITE, weight: 3, smoothFactor: 1, dashArray: "5, 5" }), ]; this.#racetrackArcs = [ - new Polyline([], { color: colors.OLYMPUS_BLUE, weight: 3, opacity: 0.5, smoothFactor: 1 }), - new Polyline([], { color: colors.OLYMPUS_BLUE, weight: 3, opacity: 0.5, smoothFactor: 1 }), + new Polyline([], { color: colors.WHITE, weight: 3, smoothFactor: 1, dashArray: "5, 5" }), + new Polyline([], { color: colors.WHITE, weight: 3, smoothFactor: 1, dashArray: "5, 5" }), ]; this.#racetrackAnchorMarkers[0].on("drag", (e: any) => { @@ -1724,84 +1724,88 @@ export abstract class Unit extends CustomMarker { } #drawRacetrack() { - let groundspeed = this.#speed; + this.#clearRacetrack(); - // Determine racetrack length - let racetrackLength = this.#racetrackLength; - if (racetrackLength === 0) { - if (this.getIsActiveTanker()) - racetrackLength = nmToM(50); // Default length for active tanker - else racetrackLength = this.#desiredSpeed * 30; // Default length based on desired speed + if (getApp().getMap().getOptions().showRacetracks) { + let groundspeed = this.#speed; + + // Determine racetrack length + let racetrackLength = this.#racetrackLength; + if (racetrackLength === 0) { + if (this.getIsActiveTanker()) + racetrackLength = nmToM(50); // Default length for active tanker + else racetrackLength = this.#desiredSpeed * 30; // Default length based on desired speed + } + + // Calculate the radius of the racetrack turns + const radius = Math.pow(groundspeed, 2) / 9.81 / Math.tan(deg2rad(22.5)); + + let point1; + let point2; + + // Determine the anchor points of the racetrack + if (!this.#inhibitRacetrackDraw) { + point1 = this.#racetrackAnchor; + point2 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing, racetrackLength); + } else { + point1 = this.#racetrackAnchorMarkers[0].getLatLng(); + point2 = this.#racetrackAnchorMarkers[1].getLatLng(); + this.#racetrackBearing = deg2rad(bearing(point1.lat, point1.lng, point2.lat, point2.lng, false)); + this.#racetrackLength = point1.distanceTo(point2); + } + + // Calculate the other points of the racetrack + const point3 = bearingAndDistanceToLatLng(point2.lat, point2.lng, this.#racetrackBearing - deg2rad(90), radius * 2); + const point4 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing - deg2rad(90), radius * 2); + const pointArrow = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing, racetrackLength / 2); + + // Calculate the centers of the racetrack turns + const center1 = bearingAndDistanceToLatLng(point2.lat, point2.lng, this.#racetrackBearing - deg2rad(90), radius); + const center2 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing - deg2rad(90), radius); + + // Draw or update the straight segments of the racetrack + if (!getApp().getMap().hasLayer(this.#racetrackPolylines[0])) this.#racetrackPolylines[0].addTo(getApp().getMap()); + this.#racetrackPolylines[0].setLatLngs([point1, point2]); + + if (!getApp().getMap().hasLayer(this.#racetrackPolylines[1])) this.#racetrackPolylines[1].addTo(getApp().getMap()); + this.#racetrackPolylines[1].setLatLngs([point3, point4]); + + const arc1Points: LatLng[] = []; + const arc2Points: LatLng[] = []; + + // Calculate the points for the racetrack arcs + for (let theta = 0; theta <= 180; theta += 5) { + arc1Points.push(bearingAndDistanceToLatLng(center1.lat, center1.lng, this.#racetrackBearing + deg2rad(theta - 90), radius)); + arc2Points.push(bearingAndDistanceToLatLng(center2.lat, center2.lng, this.#racetrackBearing + deg2rad(theta + 90), radius)); + } + + // Draw or update the racetrack arcs + if (!getApp().getMap().hasLayer(this.#racetrackArcs[0])) this.#racetrackArcs[0].addTo(getApp().getMap()); + this.#racetrackArcs[0].setLatLngs(arc1Points); + + if (!getApp().getMap().hasLayer(this.#racetrackArcs[1])) this.#racetrackArcs[1].addTo(getApp().getMap()); + + this.#racetrackArcs[1].setLatLngs(arc2Points); + + // Update the positions of the racetrack anchor markers + this.#racetrackAnchorMarkers[0].setLatLng(point1); + this.#racetrackAnchorMarkers[1].setLatLng(point2); + + // Add the racetrack anchor markers to the map if they are not already present + if (!getApp().getMap().hasLayer(this.#racetrackAnchorMarkers[0])) { + this.#racetrackAnchorMarkers[0].addTo(getApp().getMap()); + } + + if (!getApp().getMap().hasLayer(this.#racetrackAnchorMarkers[1])) { + this.#racetrackAnchorMarkers[1].addTo(getApp().getMap()); + } + + if (!getApp().getMap().hasLayer(this.#racetrackArrow)) { + this.#racetrackArrow.addTo(getApp().getMap()); + } + this.#racetrackArrow.setLatLng(pointArrow); + this.#racetrackArrow.setBearing(this.#racetrackBearing); } - - // Calculate the radius of the racetrack turns - const radius = Math.pow(groundspeed, 2) / 9.81 / Math.tan(deg2rad(22.5)); - - let point1; - let point2; - - // Determine the anchor points of the racetrack - if (!this.#inhibitRacetrackDraw) { - point1 = this.#racetrackAnchor; - point2 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing, racetrackLength); - } else { - point1 = this.#racetrackAnchorMarkers[0].getLatLng(); - point2 = this.#racetrackAnchorMarkers[1].getLatLng(); - this.#racetrackBearing = deg2rad(bearing(point1.lat, point1.lng, point2.lat, point2.lng, false)); - this.#racetrackLength = point1.distanceTo(point2); - } - - // Calculate the other points of the racetrack - const point3 = bearingAndDistanceToLatLng(point2.lat, point2.lng, this.#racetrackBearing - deg2rad(90), radius * 2); - const point4 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing - deg2rad(90), radius * 2); - const pointArrow = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing, racetrackLength / 2); - - // Calculate the centers of the racetrack turns - const center1 = bearingAndDistanceToLatLng(point2.lat, point2.lng, this.#racetrackBearing - deg2rad(90), radius); - const center2 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing - deg2rad(90), radius); - - // Draw or update the straight segments of the racetrack - if (!getApp().getMap().hasLayer(this.#racetrackPolylines[0])) this.#racetrackPolylines[0].addTo(getApp().getMap()); - this.#racetrackPolylines[0].setLatLngs([point1, point2]); - - if (!getApp().getMap().hasLayer(this.#racetrackPolylines[1])) this.#racetrackPolylines[1].addTo(getApp().getMap()); - this.#racetrackPolylines[1].setLatLngs([point3, point4]); - - const arc1Points: LatLng[] = []; - const arc2Points: LatLng[] = []; - - // Calculate the points for the racetrack arcs - for (let theta = 0; theta <= 180; theta += 5) { - arc1Points.push(bearingAndDistanceToLatLng(center1.lat, center1.lng, this.#racetrackBearing + deg2rad(theta - 90), radius)); - arc2Points.push(bearingAndDistanceToLatLng(center2.lat, center2.lng, this.#racetrackBearing + deg2rad(theta + 90), radius)); - } - - // Draw or update the racetrack arcs - if (!getApp().getMap().hasLayer(this.#racetrackArcs[0])) this.#racetrackArcs[0].addTo(getApp().getMap()); - this.#racetrackArcs[0].setLatLngs(arc1Points); - - if (!getApp().getMap().hasLayer(this.#racetrackArcs[1])) this.#racetrackArcs[1].addTo(getApp().getMap()); - - this.#racetrackArcs[1].setLatLngs(arc2Points); - - // Update the positions of the racetrack anchor markers - this.#racetrackAnchorMarkers[0].setLatLng(point1); - this.#racetrackAnchorMarkers[1].setLatLng(point2); - - // Add the racetrack anchor markers to the map if they are not already present - if (!getApp().getMap().hasLayer(this.#racetrackAnchorMarkers[0])) { - this.#racetrackAnchorMarkers[0].addTo(getApp().getMap()); - } - - if (!getApp().getMap().hasLayer(this.#racetrackAnchorMarkers[1])) { - this.#racetrackAnchorMarkers[1].addTo(getApp().getMap()); - } - - if (!getApp().getMap().hasLayer(this.#racetrackArrow)) { - this.#racetrackArrow.addTo(getApp().getMap()); - } - this.#racetrackArrow.setLatLng(pointArrow); - this.#racetrackArrow.setBearing(this.#racetrackBearing); } #clearRacetrack() { @@ -1993,8 +1997,8 @@ export abstract class Unit extends CustomMarker { var color; if (contactData.detectionMethod === VISUAL || contactData.detectionMethod === OPTIC) color = colors.MAGENTA; else if (contactData.detectionMethod === RADAR || contactData.detectionMethod === IRST) color = colors.YELLOW; - else if (contactData.detectionMethod === RWR) color = colors.GREEN; - else color = colors.WHITE; + else if (contactData.detectionMethod === RWR) color = colors.GREEN_YELLOW; + else color = colors.LIGHT_GREY; var contactPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3,