mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: started adding ability to set and draw racetracks
This commit is contained in:
parent
96415fd087
commit
c2ea746d48
@ -51,6 +51,9 @@ namespace DataIndex {
|
||||
shotsScatter,
|
||||
shotsIntensity,
|
||||
health,
|
||||
racetrackLength,
|
||||
racetrackAnchor,
|
||||
racetrackBearing,
|
||||
lastIndex,
|
||||
endOfData = 255
|
||||
};
|
||||
|
||||
@ -109,6 +109,9 @@ public:
|
||||
virtual void setShotsScatter(unsigned char newValue) { updateValue(shotsScatter, newValue, DataIndex::shotsScatter); }
|
||||
virtual void setShotsIntensity(unsigned char newValue) { updateValue(shotsIntensity, newValue, DataIndex::shotsIntensity); }
|
||||
virtual void setHealth(unsigned char newValue) { updateValue(health, newValue, DataIndex::health); }
|
||||
virtual void setRacetrackLength(double newValue) { updateValue(racetrackLength, newValue, DataIndex::racetrackLength); }
|
||||
virtual void setRacetrackAnchor(Coords newValue) { updateValue(racetrackAnchor, newValue, DataIndex::racetrackAnchor); }
|
||||
virtual void setRacetrackBearing(double newValue) { updateValue(racetrackBearing, newValue, DataIndex::racetrackBearing); }
|
||||
|
||||
/********** Getters **********/
|
||||
virtual string getCategory() { return category; };
|
||||
@ -157,6 +160,9 @@ public:
|
||||
virtual unsigned char getShotsScatter() { return shotsScatter; }
|
||||
virtual unsigned char getShotsIntensity() { return shotsIntensity; }
|
||||
virtual unsigned char getHealth() { return health; }
|
||||
virtual double getRacetrackLength() { return racetrackLength; }
|
||||
virtual Coords getRacetrackAnchor() { return racetrackAnchor; }
|
||||
virtual double getRacetrackBearing() { return racetrackBearing; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@ -190,6 +196,9 @@ protected:
|
||||
double desiredAltitude = 1;
|
||||
bool desiredAltitudeType = 0; /* ASL */
|
||||
unsigned int leaderID = NULL;
|
||||
double racetrackLength = NULL;
|
||||
Coords racetrackAnchor = Coords(NULL);
|
||||
double racetrackBearing = NULL;
|
||||
Offset formationOffset = Offset(NULL);
|
||||
unsigned int targetID = NULL;
|
||||
Coords targetPosition = Coords(NULL);
|
||||
|
||||
@ -154,6 +154,11 @@ void AirUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
|
||||
if (state != State::IDLE) {
|
||||
setRacetrackAnchor(Coords(NULL));
|
||||
setRacetrackBearing(NULL);
|
||||
}
|
||||
|
||||
/* State machine */
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
@ -166,23 +171,27 @@ void AirUnit::AIloop()
|
||||
|
||||
if (!getHasTask())
|
||||
{
|
||||
if (racetrackAnchor == Coords(NULL)) setRacetrackAnchor(position);
|
||||
if (racetrackBearing == NULL) setRacetrackBearing(heading);
|
||||
|
||||
std::ostringstream taskSS;
|
||||
if (isActiveTanker) {
|
||||
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
heading << ", length = " << (50000 * 1.852) << " }}";
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength : (50000 * 1.852)) << " }}";
|
||||
}
|
||||
else if (isActiveAWACS) {
|
||||
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}";
|
||||
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength : (desiredSpeed * 30)) << " }}";
|
||||
}
|
||||
else {
|
||||
taskSS << "{ id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
heading << ", length = " << desiredSpeed * 30 << " }";
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength: (desiredSpeed * 30)) << " }";
|
||||
}
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
@ -353,6 +353,16 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unit->setDesiredAltitudeType(to_string(value[L"altitudeType"]));
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude type: " + to_string(value[L"altitudeType"]), true);
|
||||
}
|
||||
}/************************/
|
||||
else if (key.compare("setRacetrackLength") == 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);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("cloneUnits") == 0)
|
||||
|
||||
@ -295,6 +295,9 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
case DataIndex::shotsScatter: appendNumeric(ss, datumIndex, shotsScatter); break;
|
||||
case DataIndex::shotsIntensity: appendNumeric(ss, datumIndex, shotsIntensity); break;
|
||||
case DataIndex::health: appendNumeric(ss, datumIndex, health); break;
|
||||
case DataIndex::racetrackLength: appendNumeric(ss, datumIndex, racetrackLength); break;
|
||||
case DataIndex::racetrackAnchor: appendNumeric(ss, datumIndex, racetrackAnchor); break;
|
||||
case DataIndex::racetrackBearing: appendNumeric(ss, datumIndex, racetrackBearing); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,6 +484,9 @@ export enum DataIndexes {
|
||||
shotsScatter,
|
||||
shotsIntensity,
|
||||
health,
|
||||
racetrackLength,
|
||||
racetrackAnchor,
|
||||
racetrackBearing,
|
||||
endOfData = 255,
|
||||
}
|
||||
|
||||
|
||||
@ -248,6 +248,9 @@ export interface UnitData {
|
||||
shotsScatter: number;
|
||||
shotsIntensity: number;
|
||||
health: number;
|
||||
racetrackLength: number;
|
||||
racetrackAnchor: LatLng;
|
||||
racetrackBearing: number;
|
||||
}
|
||||
|
||||
export interface LoadoutItemBlueprint {
|
||||
|
||||
@ -555,8 +555,8 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
</div>
|
||||
<OlLabelToggle
|
||||
toggled={selectedUnitsData.desiredAltitudeType === undefined ? undefined : selectedUnitsData.desiredAltitudeType === "AGL"}
|
||||
leftLabel={"AGL"}
|
||||
rightLabel={"ASL"}
|
||||
leftLabel={"ASL"}
|
||||
rightLabel={"AGL"}
|
||||
onClick={() => {
|
||||
selectedUnits.forEach((unit) => {
|
||||
unit.setAltitudeType(selectedUnitsData.desiredAltitudeType === "ASL" ? "AGL" : "ASL");
|
||||
@ -617,8 +617,8 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
{!(everyUnitIsGround || everyUnitIsNavy) && (
|
||||
<OlLabelToggle
|
||||
toggled={selectedUnitsData.desiredSpeedType === undefined ? undefined : selectedUnitsData.desiredSpeedType === "GS"}
|
||||
leftLabel={"GS"}
|
||||
rightLabel={"CAS"}
|
||||
leftLabel={"CAS"}
|
||||
rightLabel={"GS"}
|
||||
onClick={() => {
|
||||
selectedUnits.forEach((unit) => {
|
||||
unit.setSpeedType(selectedUnitsData.desiredSpeedType === "CAS" ? "GS" : "CAS");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point, LeafletMouseEvent, DomEvent, DomUtil } from "leaflet";
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point, LeafletMouseEvent, DomEvent, DomUtil, Circle } from "leaflet";
|
||||
import { getApp } from "../olympusapp";
|
||||
import {
|
||||
enumToCoalition,
|
||||
@ -17,6 +17,8 @@ import {
|
||||
zeroAppend,
|
||||
computeBearingRangeString,
|
||||
adjustBrightness,
|
||||
bearingAndDistanceToLatLng,
|
||||
mToNm,
|
||||
} from "../other/utils";
|
||||
import { CustomMarker } from "../map/markers/custommarker";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
@ -145,6 +147,9 @@ export abstract class Unit extends CustomMarker {
|
||||
#shotsScatter: number = 2;
|
||||
#shotsIntensity: number = 2;
|
||||
#health: number = 100;
|
||||
#racetrackLength: number = 0;
|
||||
#racetrackAnchor: LatLng = new LatLng(0, 0);
|
||||
#racetrackBearing: number = 0;
|
||||
|
||||
/* Other members used to draw the unit, mostly ancillary stuff like targets, ranges and so on */
|
||||
#blueprint: UnitBlueprint | null = null;
|
||||
@ -166,6 +171,9 @@ 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[];
|
||||
|
||||
/* Inputs timers */
|
||||
#debounceTimeout: number | null = null;
|
||||
@ -312,6 +320,15 @@ export abstract class Unit extends CustomMarker {
|
||||
getHealth() {
|
||||
return this.#health;
|
||||
}
|
||||
getRaceTrackLength() {
|
||||
return this.#racetrackLength;
|
||||
}
|
||||
getRaceTrackAnchor() {
|
||||
return this.#racetrackAnchor;
|
||||
}
|
||||
getRaceTrackBearing() {
|
||||
return this.#racetrackBearing;
|
||||
}
|
||||
|
||||
static getConstructor(type: string) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
@ -326,7 +343,7 @@ export abstract class Unit extends CustomMarker {
|
||||
this.ID = ID;
|
||||
|
||||
this.#pathPolyline = new Polyline([], {
|
||||
color: colors.GRAY,
|
||||
color: colors.STEEL_BLUE,
|
||||
weight: 3,
|
||||
opacity: 0.5,
|
||||
smoothFactor: 1,
|
||||
@ -588,6 +605,15 @@ export abstract class Unit extends CustomMarker {
|
||||
this.#health = dataExtractor.extractUInt8();
|
||||
updateMarker = true;
|
||||
break;
|
||||
case DataIndexes.racetrackLength:
|
||||
this.#racetrackLength = dataExtractor.extractFloat64();
|
||||
break;
|
||||
case DataIndexes.racetrackAnchor:
|
||||
this.#racetrackAnchor = dataExtractor.extractLatLng();
|
||||
break;
|
||||
case DataIndexes.racetrackBearing:
|
||||
this.#racetrackBearing = dataExtractor.extractFloat64();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,6 +717,9 @@ export abstract class Unit extends CustomMarker {
|
||||
shotsScatter: this.#shotsScatter,
|
||||
shotsIntensity: this.#shotsIntensity,
|
||||
health: this.#health,
|
||||
racetrackLength: this.#racetrackLength,
|
||||
racetrackAnchor: this.#racetrackAnchor,
|
||||
racetrackBearing: this.#racetrackBearing,
|
||||
};
|
||||
}
|
||||
|
||||
@ -719,6 +748,7 @@ export abstract class Unit extends CustomMarker {
|
||||
this.#clearContacts();
|
||||
this.#clearPath();
|
||||
this.#clearTargetPosition();
|
||||
this.#clearRacetrack();
|
||||
}
|
||||
|
||||
/* When the group leader is selected, if grouping is active, all the other group members are also selected */
|
||||
@ -861,6 +891,7 @@ export abstract class Unit extends CustomMarker {
|
||||
/* Leaflet does not like it when you change coordinates when the map is zooming */
|
||||
if (!getApp().getMap().isZooming()) {
|
||||
this.#drawPath();
|
||||
this.#drawRacetrack();
|
||||
this.#drawContacts();
|
||||
this.#drawTarget();
|
||||
}
|
||||
@ -893,7 +924,7 @@ export abstract class Unit extends CustomMarker {
|
||||
el.classList.add("unit");
|
||||
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
|
||||
el.setAttribute("data-coalition", this.#coalition);
|
||||
|
||||
|
||||
var iconOptions = this.getIconOptions();
|
||||
|
||||
/* Generate and append elements depending on active options */
|
||||
@ -1569,12 +1600,14 @@ export abstract class Unit extends CustomMarker {
|
||||
} else if (element.querySelector(".unit-braa")) (<HTMLElement>element.querySelector(".unit-braa")).innerText = ``;
|
||||
|
||||
/* Set operate as */
|
||||
element.querySelector(".unit")?.setAttribute(
|
||||
"data-operate-as",
|
||||
this.getState() === UnitState.MISS_ON_PURPOSE || this.getState() === UnitState.SCENIC_AAA || this.getState() === UnitState.SIMULATE_FIRE_FIGHT
|
||||
? this.#operateAs
|
||||
: "neutral"
|
||||
);
|
||||
element
|
||||
.querySelector(".unit")
|
||||
?.setAttribute(
|
||||
"data-operate-as",
|
||||
this.getState() === UnitState.MISS_ON_PURPOSE || this.getState() === UnitState.SCENIC_AAA || this.getState() === UnitState.SIMULATE_FIRE_FIGHT
|
||||
? this.#operateAs
|
||||
: "neutral"
|
||||
);
|
||||
}
|
||||
|
||||
/* Set vertical offset for altitude stacking */
|
||||
@ -1677,6 +1710,67 @@ export abstract class Unit extends CustomMarker {
|
||||
}
|
||||
}
|
||||
|
||||
#drawRacetrack() {
|
||||
let groundspeed = this.#speed;
|
||||
|
||||
let racetrackLength = this.#racetrackLength;
|
||||
if (racetrackLength === 0) {
|
||||
if (this.getIsActiveTanker())
|
||||
racetrackLength = nmToM(50);
|
||||
else
|
||||
racetrackLength = this.#desiredSpeed * 30;
|
||||
}
|
||||
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);
|
||||
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 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]);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
const arc1Points: LatLng[] = [];
|
||||
const arc2Points: LatLng[] = [];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#clearRacetrack() {
|
||||
this.#racetrackPolylines.forEach((polyline) => getApp().getMap().removeLayer(polyline));
|
||||
this.#racetrackArcs.forEach((arc) => getApp().getMap().removeLayer(arc));
|
||||
}
|
||||
|
||||
#drawContacts() {
|
||||
this.#clearContacts();
|
||||
if (getApp().getMap().getOptions().showUnitContacts) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user