mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: completed orbit management
This commit is contained in:
parent
c2ea746d48
commit
79f9905413
@ -18,6 +18,10 @@ public:
|
||||
virtual void changeSpeed(string change) = 0;
|
||||
virtual void changeAltitude(string change) = 0;
|
||||
virtual double getDestinationReachedThreshold() { return AIR_DEST_DIST_THR; }
|
||||
|
||||
virtual void setRacetrackLength(double newValue);
|
||||
virtual void setRacetrackAnchor(Coords newValue);
|
||||
virtual void setRacetrackBearing(double newValue);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
|
||||
@ -154,9 +154,11 @@ void AirUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
|
||||
if (state != State::IDLE) {
|
||||
/* Reset the anchor, but only if the unit is not a tanker or a AWACS */
|
||||
if (state != State::IDLE && !isActiveTanker && !isActiveAWACS) {
|
||||
setRacetrackAnchor(Coords(NULL));
|
||||
setRacetrackBearing(NULL);
|
||||
setRacetrackLength(NULL);
|
||||
}
|
||||
|
||||
/* State machine */
|
||||
@ -387,4 +389,43 @@ void AirUnit::AIloop()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackLength(double newRacetrackLength) {
|
||||
if (racetrackLength != newRacetrackLength) {
|
||||
racetrackLength = newRacetrackLength;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackLength);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackAnchor(Coords newRacetrackAnchor) {
|
||||
if (racetrackAnchor != newRacetrackAnchor) {
|
||||
racetrackAnchor = newRacetrackAnchor;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackBearing(double newRacetrackBearing) {
|
||||
if (racetrackBearing != newRacetrackBearing) {
|
||||
racetrackBearing = newRacetrackBearing;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackBearing);
|
||||
}
|
||||
}
|
||||
@ -354,14 +354,22 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude type: " + to_string(value[L"altitudeType"]), true);
|
||||
}
|
||||
}/************************/
|
||||
else if (key.compare("setRacetrackLength") == 0)
|
||||
else if (key.compare("setRacetrack") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setRacetrackLength(value[L"racetrackLength"].as_double());
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") racetrack length: " + to_string(value[L"racetrackLength"].as_double()), true);
|
||||
unit->setRacetrackLength(value[L"length"].as_double());
|
||||
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
unit->setRacetrackAnchor(location);
|
||||
|
||||
unit->setRacetrackBearing(value[L"bearing"].as_double());
|
||||
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") racetrack length: " + to_string(value[L"length"].as_double()) + " racetrack bearing: " + to_string(value[L"bearing"].as_double()), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
"short_name": "DCS Olympus",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./images/favicons/android-chrome-192x192.png",
|
||||
"src": "images/favicons/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./images/favicons/android-chrome-512x512.png",
|
||||
"src": "images/favicons/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
|
||||
34
frontend/react/src/map/markers/arrowmarker.ts
Normal file
34
frontend/react/src/map/markers/arrowmarker.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { DivIcon, LatLng } from "leaflet";
|
||||
import { CustomMarker } from "../markers/custommarker";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
|
||||
export class ArrowMarker extends CustomMarker {
|
||||
#bearing: number = 0;
|
||||
|
||||
constructor(latlng: LatLng) {
|
||||
super(latlng, { interactive: true, draggable: false });
|
||||
}
|
||||
|
||||
createIcon() {
|
||||
this.setIcon(
|
||||
new DivIcon({
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
className: "leaflet-arrow-marker",
|
||||
})
|
||||
);
|
||||
var div = document.createElement("div");
|
||||
var img = document.createElement("img");
|
||||
img.src = "images/others/arrow.svg";
|
||||
img.onload = () => SVGInjector(img);
|
||||
div.classList.add("ol-arrow-icon");
|
||||
div.append(img);
|
||||
this.getElement()?.appendChild(div);
|
||||
}
|
||||
|
||||
setBearing(bearing: number) {
|
||||
this.#bearing = bearing;
|
||||
let img = this.getElement()?.querySelector("svg");
|
||||
if (img) img.style.transform = `rotate(${bearing}rad)`;
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ export class ExplosionMarker extends CustomMarker {
|
||||
var el = document.createElement("div");
|
||||
el.classList.add("ol-explosion-icon");
|
||||
var img = document.createElement("img");
|
||||
img.src = "./images/markers/explosion.svg";
|
||||
img.src = "images/markers/explosion.svg";
|
||||
img.onload = () => SVGInjector(img);
|
||||
el.appendChild(img);
|
||||
this.getElement()?.appendChild(el);
|
||||
|
||||
@ -28,7 +28,7 @@ export class SmokeMarker extends CustomMarker {
|
||||
el.classList.add("ol-smoke-icon");
|
||||
el.setAttribute("data-color", this.#color);
|
||||
var img = document.createElement("img");
|
||||
img.src = "./images/markers/smoke.svg";
|
||||
img.src = "images/markers/smoke.svg";
|
||||
img.onload = () => SVGInjector(img);
|
||||
el.appendChild(img);
|
||||
this.getElement()?.appendChild(el);
|
||||
|
||||
@ -60,7 +60,7 @@ export class TemporaryUnitMarker extends CustomMarker {
|
||||
var unitIcon = document.createElement("div");
|
||||
unitIcon.classList.add("unit-icon");
|
||||
var img = document.createElement("img");
|
||||
img.src = `./images/units/map/${/*TODO getApp().getMap().getOptions().AWACSMode ? "awacs" :*/ "normal"}/${this.#coalition}/${blueprint.markerFile ?? blueprint.category}.svg`;
|
||||
img.src = `images/units/map/${/*TODO getApp().getMap().getOptions().AWACSMode ? "awacs" :*/ "normal"}/${this.#coalition}/${blueprint.markerFile ?? blueprint.category}.svg`;
|
||||
img.onload = () => SVGInjector(img);
|
||||
unitIcon.appendChild(img);
|
||||
unitIcon.toggleAttribute("data-rotate-to-heading", false);
|
||||
@ -78,7 +78,7 @@ export class TemporaryUnitMarker extends CustomMarker {
|
||||
if (this.#headingHandle) {
|
||||
var handle = document.createElement("div");
|
||||
var handleImg = document.createElement("img");
|
||||
handleImg.src = "/images/others/arrow.svg";
|
||||
handleImg.src = "images/others/arrow.svg";
|
||||
handleImg.onload = () => SVGInjector(handleImg);
|
||||
handle.classList.add("heading-handle");
|
||||
el.append(handle);
|
||||
|
||||
@ -253,4 +253,14 @@ path.leaflet-interactive:focus {
|
||||
|
||||
.pointer-cursor {
|
||||
cursor: url("/images/cursors/pointer.svg") 13 5, auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ol-arrow-icon svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.ol-arrow-icon svg path {
|
||||
fill: #FFFFFFAA;
|
||||
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ export class Airbase extends CustomMarker {
|
||||
el.classList.add("airbase-icon");
|
||||
el.setAttribute("data-object", "airbase");
|
||||
|
||||
this.#img.src = "./images/markers/airbase.svg";
|
||||
this.#img.src = "images/markers/airbase.svg";
|
||||
this.#img.onload = () => SVGInjector(this.#img);
|
||||
el.appendChild(this.#img);
|
||||
this.getElement()?.appendChild(el);
|
||||
|
||||
@ -23,7 +23,7 @@ export class Bullseye extends CustomMarker {
|
||||
el.classList.add("bullseye-icon");
|
||||
el.setAttribute("data-object", "bullseye");
|
||||
var img = document.createElement("img");
|
||||
img.src = "./images/markers/bullseye.svg";
|
||||
img.src = "images/markers/bullseye.svg";
|
||||
img.onload = () => SVGInjector(img);
|
||||
el.appendChild(img);
|
||||
this.getElement()?.appendChild(el);
|
||||
|
||||
@ -488,6 +488,12 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setRacetrack(ID: number, length: number, latlng: LatLng, bearing: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng, bearing: bearing, length: length };
|
||||
var data = { setRacetrack: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAdvancedOptions(
|
||||
ID: number,
|
||||
isActiveTanker: boolean,
|
||||
|
||||
@ -94,7 +94,7 @@ export function LoginModal(props: { open: boolean }) {
|
||||
max-md:border-none
|
||||
`}
|
||||
>
|
||||
<img src="./images/splash/1.jpg" className={`
|
||||
<img src="images/splash/1.jpg" className={`
|
||||
contents-center w-full object-cover opacity-[7%]
|
||||
`}></img>
|
||||
<div
|
||||
@ -154,7 +154,7 @@ export function LoginModal(props: { open: boolean }) {
|
||||
`}
|
||||
>
|
||||
<span className="size-[80px] min-w-14">
|
||||
<img src="./images/olympus-500x500.png" className={`
|
||||
<img src="images/olympus-500x500.png" className={`
|
||||
flex w-full
|
||||
`}></img>
|
||||
</span>
|
||||
@ -360,7 +360,7 @@ export function LoginModal(props: { open: boolean }) {
|
||||
>
|
||||
<Card className="flex">
|
||||
<img
|
||||
src="./images/splash/1.jpg"
|
||||
src="images/splash/1.jpg"
|
||||
className={`
|
||||
h-[40%] max-h-[120px] contents-center w-full rounded-md
|
||||
object-cover
|
||||
@ -385,7 +385,7 @@ export function LoginModal(props: { open: boolean }) {
|
||||
</Card>
|
||||
<Card className="flex">
|
||||
<img
|
||||
src="./images/splash/1.jpg"
|
||||
src="images/splash/1.jpg"
|
||||
className={`
|
||||
h-[40%] max-h-[120px] contents-center w-full rounded-md
|
||||
object-cover
|
||||
|
||||
@ -75,7 +75,7 @@ export function Header() {
|
||||
dark:border-gray-800 dark:bg-olympus-900
|
||||
`}
|
||||
>
|
||||
<img src="./images/icon.png" className={`my-auto h-10 w-10 rounded-md p-0`}></img>
|
||||
<img src="images/icon.png" className={`my-auto h-10 w-10 rounded-md p-0`}></img>
|
||||
{!scrolledLeft && (
|
||||
<FaChevronLeft
|
||||
className={`
|
||||
|
||||
@ -479,12 +479,12 @@ export function UnitSpawnMenu(props: {
|
||||
/>
|
||||
|
||||
<div className={`relative mr-3 h-[60px] w-[60px]`}>
|
||||
<img className="absolute" ref={compassRef} onMouseDown={handleMouseDown} src={"/images/others/arrow_background.png"}></img>
|
||||
<img className="absolute" ref={compassRef} onMouseDown={handleMouseDown} src={"images/others/arrow_background.png"}></img>
|
||||
<img
|
||||
className="absolute left-0"
|
||||
ref={compassRef}
|
||||
onMouseDown={handleMouseDown}
|
||||
src={"/images/others/arrow.png"}
|
||||
src={"images/others/arrow.png"}
|
||||
style={{
|
||||
width: "60px",
|
||||
height: "60px",
|
||||
|
||||
@ -65,7 +65,7 @@ export function ServerOverlay() {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<img src="./images/olympus-500x500.png" className={`
|
||||
<img src="images/olympus-500x500.png" className={`
|
||||
absolute right-4 top-4 ml-auto flex h-24
|
||||
`}></img>
|
||||
</div>
|
||||
|
||||
@ -18,7 +18,6 @@ import {
|
||||
computeBearingRangeString,
|
||||
adjustBrightness,
|
||||
bearingAndDistanceToLatLng,
|
||||
mToNm,
|
||||
} from "../other/utils";
|
||||
import { CustomMarker } from "../map/markers/custommarker";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
@ -67,12 +66,14 @@ import {
|
||||
UnitSelectedEvent,
|
||||
UnitUpdatedEvent,
|
||||
} from "../events";
|
||||
import { CoalitionAreaHandle } from "../map/coalitionarea/coalitionareahandle";
|
||||
import { ArrowMarker } from "../map/markers/arrowmarker";
|
||||
|
||||
const bearingStrings = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west", "north"];
|
||||
|
||||
var pathIcon = new Icon({
|
||||
iconUrl: "./images/markers/marker-icon.png",
|
||||
shadowUrl: "./images/markers/marker-shadow.png",
|
||||
iconUrl: "images/markers/marker-icon.png",
|
||||
shadowUrl: "images/markers/marker-shadow.png",
|
||||
iconAnchor: [13, 41],
|
||||
});
|
||||
|
||||
@ -171,9 +172,11 @@ export abstract class Unit extends CustomMarker {
|
||||
#detectionMethods: number[] = [];
|
||||
#trailPositions: LatLng[] = [];
|
||||
#trailPolylines: Polyline[] = [];
|
||||
#racetrackPolylines: Polyline[] = [new Polyline([]), new Polyline([])];
|
||||
#racetrackArcs: Polyline[] = [new Polyline([]), new Polyline([])];
|
||||
#anchorMarkers: Marker[];
|
||||
#racetrackPolylines: Polyline[] = [];
|
||||
#racetrackArcs: Polyline[] = [];
|
||||
#racetrackAnchorMarkers: CoalitionAreaHandle[] = [new CoalitionAreaHandle(new LatLng(0, 0)), new CoalitionAreaHandle(new LatLng(0, 0))];
|
||||
#racetrackArrow: ArrowMarker = new ArrowMarker(new LatLng(0, 0));
|
||||
#inhibitRacetrackDraw: boolean = false;
|
||||
|
||||
/* Inputs timers */
|
||||
#debounceTimeout: number | null = null;
|
||||
@ -323,7 +326,7 @@ export abstract class Unit extends CustomMarker {
|
||||
getRaceTrackLength() {
|
||||
return this.#racetrackLength;
|
||||
}
|
||||
getRaceTrackAnchor() {
|
||||
getRaceTrackAnchor() {
|
||||
return this.#racetrackAnchor;
|
||||
}
|
||||
getRaceTrackBearing() {
|
||||
@ -343,7 +346,7 @@ export abstract class Unit extends CustomMarker {
|
||||
this.ID = ID;
|
||||
|
||||
this.#pathPolyline = new Polyline([], {
|
||||
color: colors.STEEL_BLUE,
|
||||
color: colors.OLYMPUS_BLUE,
|
||||
weight: 3,
|
||||
opacity: 0.5,
|
||||
smoothFactor: 1,
|
||||
@ -375,6 +378,33 @@ export abstract class Unit extends CustomMarker {
|
||||
bubblingMouseEvents: false,
|
||||
});
|
||||
|
||||
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 }),
|
||||
];
|
||||
|
||||
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 }),
|
||||
];
|
||||
|
||||
this.#racetrackAnchorMarkers[0].on("drag", (e: any) => {
|
||||
this.#inhibitRacetrackDraw = true;
|
||||
this.#drawRacetrack();
|
||||
});
|
||||
|
||||
this.#racetrackAnchorMarkers[1].on("drag", (e: any) => {
|
||||
this.#inhibitRacetrackDraw = true;
|
||||
this.#drawRacetrack();
|
||||
});
|
||||
|
||||
this.#racetrackAnchorMarkers[0].on("dragend", (e: any) => {
|
||||
this.#applyRacetrackEdit();
|
||||
});
|
||||
this.#racetrackAnchorMarkers[1].on("dragend", (e: any) => {
|
||||
this.#applyRacetrackEdit();
|
||||
});
|
||||
|
||||
/* Leaflet events listeners */
|
||||
this.on("mouseup", (e: any) => this.#onMouseUp(e));
|
||||
this.on("mousedown", (e: any) => this.#onMouseDown(e));
|
||||
@ -767,6 +797,8 @@ export abstract class Unit extends CustomMarker {
|
||||
|
||||
/* Trigger events after all (de-)selecting has been done */
|
||||
selected ? UnitSelectedEvent.dispatch(this) : UnitDeselectedEvent.dispatch(this);
|
||||
|
||||
this.#inhibitRacetrackDraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1339,6 +1371,10 @@ export abstract class Unit extends CustomMarker {
|
||||
if (!this.#human) getApp().getServerManager().setShotsIntensity(this.ID, shotsIntensity);
|
||||
}
|
||||
|
||||
setRacetrack(length: number, anchor: LatLng, bearing: number, callback: () => void) {
|
||||
if (!this.#human) getApp().getServerManager().setRacetrack(this.ID, length, anchor, bearing, callback);
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
onAdd(map: Map): this {
|
||||
super.onAdd(map);
|
||||
@ -1687,13 +1723,18 @@ export abstract class Unit extends CustomMarker {
|
||||
for (let WP in this.#activePath) {
|
||||
var destination = this.#activePath[WP];
|
||||
var frozen = this.#pathMarkers[parseInt(WP)].options["freeze"];
|
||||
if (!this.#pathMarkers[parseInt(WP)].options["freeze"]) {
|
||||
if (!frozen) {
|
||||
this.#pathMarkers[parseInt(WP)].setLatLng([destination.lat, destination.lng]);
|
||||
}
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
}
|
||||
|
||||
/* Add racetrack anchor to the path, but only if we are an active tanker or AWACS */
|
||||
if (this.getState() !== UnitState.IDLE && (this.getIsActiveAWACS() || this.getIsActiveTanker()))
|
||||
points.push(this.#racetrackAnchor);
|
||||
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
|
||||
if (points.length == 1) this.#clearPath();
|
||||
} else {
|
||||
this.#clearPath();
|
||||
@ -1712,63 +1753,100 @@ export abstract class Unit extends CustomMarker {
|
||||
|
||||
#drawRacetrack() {
|
||||
let groundspeed = this.#speed;
|
||||
|
||||
|
||||
// Determine racetrack length
|
||||
let racetrackLength = this.#racetrackLength;
|
||||
if (racetrackLength === 0) {
|
||||
if (this.getIsActiveTanker())
|
||||
racetrackLength = nmToM(50);
|
||||
else
|
||||
racetrackLength = this.#desiredSpeed * 30;
|
||||
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));
|
||||
const point1 = this.#racetrackAnchor;
|
||||
const point2 = bearingAndDistanceToLatLng(point1.lat, point1.lng, this.#racetrackBearing, racetrackLength);
|
||||
|
||||
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);
|
||||
|
||||
if (!getApp().getMap().hasLayer(this.#racetrackPolylines[0])) {
|
||||
this.#racetrackPolylines[0] = new Polyline([point1, point2]);
|
||||
this.#racetrackPolylines[0].addTo(getApp().getMap());
|
||||
} else {
|
||||
this.#racetrackPolylines[0].setLatLngs([point1, point2]);
|
||||
}
|
||||
// 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] = new Polyline([point3, point4]);
|
||||
this.#racetrackPolylines[1].addTo(getApp().getMap());
|
||||
} else {
|
||||
this.#racetrackPolylines[1].setLatLngs([point3, point4]);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
if (!getApp().getMap().hasLayer(this.#racetrackArcs[0])) {
|
||||
this.#racetrackArcs[0] = new Polyline(arc1Points);
|
||||
this.#racetrackArcs[0].addTo(getApp().getMap());
|
||||
} else {
|
||||
this.#racetrackArcs[0].setLatLngs(arc1Points);
|
||||
// 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.#racetrackArcs[1])) {
|
||||
this.#racetrackArcs[1] = new Polyline(arc2Points);
|
||||
this.#racetrackArcs[1].addTo(getApp().getMap());
|
||||
} else {
|
||||
this.#racetrackArcs[1].setLatLngs(arc2Points);
|
||||
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() {
|
||||
this.#racetrackPolylines.forEach((polyline) => getApp().getMap().removeLayer(polyline));
|
||||
this.#racetrackArcs.forEach((arc) => getApp().getMap().removeLayer(arc));
|
||||
this.#racetrackAnchorMarkers.forEach((marker) => getApp().getMap().removeLayer(marker));
|
||||
this.#racetrackArrow.removeFrom(getApp().getMap());
|
||||
}
|
||||
|
||||
#applyRacetrackEdit() {
|
||||
const point1 = this.#racetrackAnchorMarkers[0].getLatLng();
|
||||
const point2 = this.#racetrackAnchorMarkers[1].getLatLng();
|
||||
const racetrackLength = point1.distanceTo(point2);
|
||||
const racetrackBearing = deg2rad(bearing(point1.lat, point1.lng, point2.lat, point2.lng, false));
|
||||
this.setRacetrack(racetrackLength, this.#racetrackAnchorMarkers[0].getLatLng(), racetrackBearing, () => {
|
||||
this.#inhibitRacetrackDraw = false;
|
||||
});
|
||||
}
|
||||
|
||||
#drawContacts() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user