mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Implemented group destination spacing
This commit is contained in:
parent
9cc0058e32
commit
bf88c9b951
@ -71,7 +71,7 @@ const DEMO_UNIT_DATA = {
|
||||
AI: true,
|
||||
name: "KC-135",
|
||||
unitName: "Olympus 1-2",
|
||||
groupName: "Group 1",
|
||||
groupName: "Group 3",
|
||||
alive: true,
|
||||
category: "Aircraft",
|
||||
},
|
||||
@ -114,7 +114,7 @@ const DEMO_UNIT_DATA = {
|
||||
AI: true,
|
||||
name: "2S6 Tunguska",
|
||||
unitName: "Olympus 1-3",
|
||||
groupName: "Group 1",
|
||||
groupName: "Group 4",
|
||||
alive: true,
|
||||
category: "GroundUnit",
|
||||
},
|
||||
|
||||
@ -930,4 +930,16 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
|
||||
.hotgroup-selector>.unit-hotgroup {
|
||||
display: flex;
|
||||
translate: 0% -300%;
|
||||
}
|
||||
|
||||
.ol-destination-preview-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
background-color: var(--secondary-yellow);
|
||||
pointer-events: none;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.ol-destination-preview {
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -9,6 +9,7 @@ import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { Airbase } from "../missionhandler/airbase";
|
||||
import { Unit } from "../units/unit";
|
||||
import { bearing } from "../other/utils";
|
||||
|
||||
// TODO a bit of a hack, this module is provided as pure javascript only
|
||||
require("../../node_modules/leaflet.nauticscale/dist/leaflet.nauticscale.js")
|
||||
@ -24,6 +25,13 @@ var temporaryIcon = new L.Icon({
|
||||
iconAnchor: [26, 26]
|
||||
});
|
||||
|
||||
var destinationPreviewIcon = new L.DivIcon({
|
||||
html: `<div class="ol-destination-preview-icon"></div>`,
|
||||
iconSize: [52, 52],
|
||||
iconAnchor: [26, 26],
|
||||
className: "ol-destination-preview"
|
||||
})
|
||||
|
||||
export class ClickableMiniMap extends MiniMap {
|
||||
constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) {
|
||||
super(layer, options);
|
||||
@ -51,6 +59,10 @@ export class Map extends L.Map {
|
||||
#miniMap: ClickableMiniMap | null = null;
|
||||
#miniMapLayerGroup: L.LayerGroup;
|
||||
#temporaryMarkers: L.Marker[] = [];
|
||||
#destinationPreviewMarkers: L.Marker[] = [];
|
||||
#destinationGroupRotation: number = 0;
|
||||
#computeDestinationRotation: boolean = false;
|
||||
#destinationRotationCenter: L.LatLng | null = null;
|
||||
|
||||
#mapContextMenu: MapContextMenu = new MapContextMenu("map-contextmenu");
|
||||
#unitContextMenu: UnitContextMenu = new UnitContextMenu("unit-contextmenu");
|
||||
@ -67,53 +79,18 @@ export class Map extends L.Map {
|
||||
this.setLayer("ArcGIS Satellite");
|
||||
|
||||
/* Minimap */
|
||||
/* Draw the limits of the maps in the minimap*/
|
||||
var latlngs = [[ // NTTR
|
||||
new L.LatLng(39.7982463, -119.985425),
|
||||
new L.LatLng(34.4037128, -119.7806729),
|
||||
new L.LatLng(34.3483316, -112.4529351),
|
||||
new L.LatLng(39.7372411, -112.1130805),
|
||||
new L.LatLng(39.7982463, -119.985425)
|
||||
],
|
||||
[ // Syria
|
||||
new L.LatLng(37.3630556, 29.2686111),
|
||||
new L.LatLng(31.8472222, 29.8975),
|
||||
new L.LatLng(32.1358333, 42.1502778),
|
||||
new L.LatLng(37.7177778, 42.3716667),
|
||||
new L.LatLng(37.3630556, 29.2686111)
|
||||
],
|
||||
[ // Caucasus
|
||||
new L.LatLng(39.6170191, 27.634935),
|
||||
new L.LatLng(38.8735863, 47.1423108),
|
||||
new L.LatLng(47.3907982, 49.3101946),
|
||||
new L.LatLng(48.3955879, 26.7753625),
|
||||
new L.LatLng(39.6170191, 27.634935)
|
||||
],
|
||||
[ // Persian Gulf
|
||||
new L.LatLng(32.9355285, 46.5623682),
|
||||
new L.LatLng(21.729393, 47.572675),
|
||||
new L.LatLng(21.8501348, 63.9734737),
|
||||
new L.LatLng(33.131584, 64.7313594),
|
||||
new L.LatLng(32.9355285, 46.5623682)
|
||||
],
|
||||
[ // Marianas
|
||||
new L.LatLng(22.09, 135.0572222),
|
||||
new L.LatLng(10.5777778, 135.7477778),
|
||||
new L.LatLng(10.7725, 149.3918333),
|
||||
new L.LatLng(22.5127778, 149.5427778),
|
||||
new L.LatLng(22.09, 135.0572222)
|
||||
]
|
||||
];
|
||||
|
||||
var minimapLayer = new L.TileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { minZoom: 0, maxZoom: 13 });
|
||||
this.#miniMapLayerGroup = new L.LayerGroup([minimapLayer]);
|
||||
var miniMapPolyline = new L.Polyline(latlngs, { color: '#202831' });
|
||||
var miniMapPolyline = new L.Polyline(this.#getMinimapBoundaries(), { color: '#202831' });
|
||||
miniMapPolyline.addTo(this.#miniMapLayerGroup);
|
||||
|
||||
/* Scale */
|
||||
//@ts-ignore TODO more hacking because the module is provided as a pure javascript module only
|
||||
L.control.scalenautic({ position: "topright", maxWidth: 300, nautic: true, metric: true, imperial: false }).addTo(this);
|
||||
|
||||
/* Map source dropdown */
|
||||
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers())
|
||||
|
||||
/* Init the state machine */
|
||||
this.#state = IDLE;
|
||||
|
||||
@ -127,7 +104,10 @@ export class Map extends L.Map {
|
||||
this.on('mousedown', (e: any) => this.#onMouseDown(e));
|
||||
this.on('mouseup', (e: any) => this.#onMouseUp(e));
|
||||
this.on('mousemove', (e: any) => this.#onMouseMove(e));
|
||||
|
||||
this.on('keydown', (e: any) => this.#updateDestinationPreview(e));
|
||||
this.on('keyup', (e: any) => this.#updateDestinationPreview(e));
|
||||
|
||||
/* Event listeners */
|
||||
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||
ev.detail._element.classList.toggle("off");
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.coalition);
|
||||
@ -144,8 +124,7 @@ export class Map extends L.Map {
|
||||
this.#panToUnit(this.#centerUnit);
|
||||
});
|
||||
|
||||
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers())
|
||||
|
||||
/* Pan interval */
|
||||
this.#panInterval = window.setInterval(() => {
|
||||
this.panBy(new L.Point( ((this.#panLeft? -1: 0) + (this.#panRight? 1: 0)) * this.#deafultPanDelta,
|
||||
((this.#panUp? -1: 0) + (this.#panDown? 1: 0)) * this.#deafultPanDelta));
|
||||
@ -205,9 +184,34 @@ export class Map extends L.Map {
|
||||
this.#state = state;
|
||||
if (this.#state === IDLE) {
|
||||
L.DomUtil.removeClass(this.getContainer(), 'crosshair-cursor-enabled');
|
||||
|
||||
/* Remove all the destination preview markers */
|
||||
this.#destinationPreviewMarkers.forEach((marker: L.Marker) => {
|
||||
this.removeLayer(marker);
|
||||
})
|
||||
this.#destinationPreviewMarkers = [];
|
||||
|
||||
this.#destinationGroupRotation = 0;
|
||||
this.#computeDestinationRotation = false;
|
||||
this.#destinationRotationCenter = null;
|
||||
}
|
||||
else if (this.#state === MOVE_UNIT) {
|
||||
L.DomUtil.addClass(this.getContainer(), 'crosshair-cursor-enabled');
|
||||
|
||||
/* Remove all the exising destination preview markers */
|
||||
this.#destinationPreviewMarkers.forEach((marker: L.Marker) => {
|
||||
this.removeLayer(marker);
|
||||
})
|
||||
this.#destinationPreviewMarkers = [];
|
||||
|
||||
if (getUnitsManager().getSelectedUnits({excludeHumans: true}).length < 20) {
|
||||
/* Create the unit destination preview markers */
|
||||
this.#destinationPreviewMarkers = getUnitsManager().getSelectedUnits({excludeHumans: true}).map((unit: Unit) => {
|
||||
var marker = new L.Marker(this.getMouseCoordinates(), {icon: destinationPreviewIcon, interactive: false});
|
||||
marker.addTo(this);
|
||||
return marker;
|
||||
})
|
||||
}
|
||||
}
|
||||
document.dispatchEvent(new CustomEvent("mapStateChanged"));
|
||||
}
|
||||
@ -328,7 +332,6 @@ export class Map extends L.Map {
|
||||
if (this.#miniMap)
|
||||
this.setView(e.latlng);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
getMiniMapLayerGroup() {
|
||||
@ -433,7 +436,7 @@ export class Map extends L.Map {
|
||||
if (!e.originalEvent.ctrlKey) {
|
||||
getUnitsManager().selectedUnitsClearDestinations();
|
||||
}
|
||||
getUnitsManager().selectedUnitsAddDestination(e.latlng)
|
||||
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null? this.#destinationRotationCenter: e.latlng, !e.originalEvent.shiftKey, this.#destinationGroupRotation)
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,14 +451,31 @@ export class Map extends L.Map {
|
||||
|
||||
#onMouseDown(e: any) {
|
||||
this.hideAllContextMenus();
|
||||
|
||||
if (this.#state == MOVE_UNIT && e.originalEvent.button == 2)
|
||||
{
|
||||
this.#computeDestinationRotation = true;
|
||||
this.#destinationRotationCenter = this.getMouseCoordinates();
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseUp(e: any) {
|
||||
if (this.#state == MOVE_UNIT)
|
||||
{
|
||||
this.#computeDestinationRotation = false;
|
||||
this.#destinationRotationCenter = null;
|
||||
this.#destinationGroupRotation = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseMove(e: any) {
|
||||
this.#lastMousePosition.x = e.originalEvent.x;
|
||||
this.#lastMousePosition.y = e.originalEvent.y;
|
||||
|
||||
if (this.#computeDestinationRotation && this.#destinationRotationCenter != null)
|
||||
this.#destinationGroupRotation = -bearing(this.#destinationRotationCenter.lat, this.#destinationRotationCenter.lng, this.getMouseCoordinates().lat, this.getMouseCoordinates().lng);
|
||||
|
||||
this.#updateDestinationPreview(e);
|
||||
}
|
||||
|
||||
#onZoom(e: any) {
|
||||
@ -467,4 +487,51 @@ export class Map extends L.Map {
|
||||
var unitPosition = new L.LatLng(unit.getFlightData().latitude, unit.getFlightData().longitude);
|
||||
this.setView(unitPosition, this.getZoom(), { animate: false });
|
||||
}
|
||||
|
||||
#getMinimapBoundaries() {
|
||||
/* Draw the limits of the maps in the minimap*/
|
||||
return [[ // NTTR
|
||||
new L.LatLng(39.7982463, -119.985425),
|
||||
new L.LatLng(34.4037128, -119.7806729),
|
||||
new L.LatLng(34.3483316, -112.4529351),
|
||||
new L.LatLng(39.7372411, -112.1130805),
|
||||
new L.LatLng(39.7982463, -119.985425)
|
||||
],
|
||||
[ // Syria
|
||||
new L.LatLng(37.3630556, 29.2686111),
|
||||
new L.LatLng(31.8472222, 29.8975),
|
||||
new L.LatLng(32.1358333, 42.1502778),
|
||||
new L.LatLng(37.7177778, 42.3716667),
|
||||
new L.LatLng(37.3630556, 29.2686111)
|
||||
],
|
||||
[ // Caucasus
|
||||
new L.LatLng(39.6170191, 27.634935),
|
||||
new L.LatLng(38.8735863, 47.1423108),
|
||||
new L.LatLng(47.3907982, 49.3101946),
|
||||
new L.LatLng(48.3955879, 26.7753625),
|
||||
new L.LatLng(39.6170191, 27.634935)
|
||||
],
|
||||
[ // Persian Gulf
|
||||
new L.LatLng(32.9355285, 46.5623682),
|
||||
new L.LatLng(21.729393, 47.572675),
|
||||
new L.LatLng(21.8501348, 63.9734737),
|
||||
new L.LatLng(33.131584, 64.7313594),
|
||||
new L.LatLng(32.9355285, 46.5623682)
|
||||
],
|
||||
[ // Marianas
|
||||
new L.LatLng(22.09, 135.0572222),
|
||||
new L.LatLng(10.5777778, 135.7477778),
|
||||
new L.LatLng(10.7725, 149.3918333),
|
||||
new L.LatLng(22.5127778, 149.5427778),
|
||||
new L.LatLng(22.09, 135.0572222)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
#updateDestinationPreview(e: any) {
|
||||
Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null? this.#destinationRotationCenter: this.getMouseCoordinates(), this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
|
||||
if (idx < this.#destinationPreviewMarkers.length)
|
||||
this.#destinationPreviewMarkers[idx].setLatLng(!e.originalEvent.shiftKey? latlng: this.getMouseCoordinates());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,48 +11,6 @@ export function bearing(lat1: number, lon1: number, lat2: number, lon2: number)
|
||||
return brng;
|
||||
}
|
||||
|
||||
|
||||
export function ConvertDDToDMS(D: number, lng: boolean) {
|
||||
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
|
||||
var deg = 0 | (D < 0 ? (D = -D) : D);
|
||||
var min = 0 | (((D += 1e-9) % 1) * 60);
|
||||
var sec = (0 | (((D * 60) % 1) * 6000)) / 100;
|
||||
var dec = Math.round((sec - Math.floor(sec)) * 100);
|
||||
var sec = Math.floor(sec);
|
||||
if (lng)
|
||||
return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
|
||||
else
|
||||
return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
|
||||
}
|
||||
|
||||
|
||||
export function dataPointMap( container:HTMLElement, data:any) {
|
||||
|
||||
Object.keys( data ).forEach( ( key ) => {
|
||||
|
||||
const val = "" + data[ key ]; // Ensure a string
|
||||
|
||||
container.querySelectorAll( `[data-point="${key}"]`).forEach( el => {
|
||||
|
||||
// We could probably have options here
|
||||
if ( el instanceof HTMLInputElement ) {
|
||||
el.value = val;
|
||||
} else if ( el instanceof HTMLElement ) {
|
||||
el.innerText = val;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function deg2rad(deg: number) {
|
||||
var pi = Math.PI;
|
||||
return deg * (pi / 180);
|
||||
}
|
||||
|
||||
|
||||
export function distance(lat1: number, lon1: number, lat2: number, lon2: number) {
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
@ -68,6 +26,42 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
|
||||
return d;
|
||||
}
|
||||
|
||||
export function ConvertDDToDMS(D: number, lng: boolean) {
|
||||
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
|
||||
var deg = 0 | (D < 0 ? (D = -D) : D);
|
||||
var min = 0 | (((D += 1e-9) % 1) * 60);
|
||||
var sec = (0 | (((D * 60) % 1) * 6000)) / 100;
|
||||
var dec = Math.round((sec - Math.floor(sec)) * 100);
|
||||
var sec = Math.floor(sec);
|
||||
if (lng)
|
||||
return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
|
||||
else
|
||||
return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
|
||||
}
|
||||
|
||||
export function dataPointMap( container:HTMLElement, data:any) {
|
||||
Object.keys( data ).forEach( ( key ) => {
|
||||
const val = "" + data[ key ]; // Ensure a string
|
||||
container.querySelectorAll( `[data-point="${key}"]`).forEach( el => {
|
||||
// We could probably have options here
|
||||
if ( el instanceof HTMLInputElement ) {
|
||||
el.value = val;
|
||||
} else if ( el instanceof HTMLElement ) {
|
||||
el.innerText = val;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function deg2rad(deg: number) {
|
||||
var pi = Math.PI;
|
||||
return deg * (pi / 180);
|
||||
}
|
||||
|
||||
export function rad2deg(rad: number) {
|
||||
var pi = Math.PI;
|
||||
return rad / (pi / 180);
|
||||
}
|
||||
|
||||
export function generateUUIDv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
@ -76,33 +70,15 @@ export function generateUUIDv4() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function keyEventWasInInput( event:KeyboardEvent ) {
|
||||
|
||||
const target = event.target;
|
||||
|
||||
return ( target instanceof HTMLElement && ( [ "INPUT", "TEXTAREA" ].includes( target.nodeName ) ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function rad2deg(rad: number) {
|
||||
var pi = Math.PI;
|
||||
return rad / (pi / 180);
|
||||
}
|
||||
|
||||
|
||||
export function reciprocalHeading(heading: number): number {
|
||||
|
||||
if (heading > 180) {
|
||||
return heading - 180;
|
||||
}
|
||||
|
||||
return heading + 180;
|
||||
|
||||
return heading > 180? heading - 180: heading + 180;
|
||||
}
|
||||
|
||||
|
||||
export const zeroAppend = function (num: number, places: number) {
|
||||
var string = String(num);
|
||||
while (string.length < places) {
|
||||
@ -111,7 +87,6 @@ export const zeroAppend = function (num: number, places: number) {
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
export const zeroPad = function (num: number, places: number) {
|
||||
var string = String(num);
|
||||
while (string.length < places) {
|
||||
@ -120,7 +95,6 @@ export const zeroPad = function (num: number, places: number) {
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
export function similarity(s1: string, s2: string) {
|
||||
var longer = s1;
|
||||
var shorter = s2;
|
||||
@ -160,4 +134,24 @@ export function editDistance(s1: string, s2: string) {
|
||||
costs[s2.length] = lastValue;
|
||||
}
|
||||
return costs[s2.length];
|
||||
}
|
||||
|
||||
export function latLngToMercator(lat: number, lng: number): {x: number, y: number} {
|
||||
var rMajor = 6378137; //Equatorial Radius, WGS84
|
||||
var shift = Math.PI * rMajor;
|
||||
var x = lng * shift / 180;
|
||||
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
|
||||
y = y * shift / 180;
|
||||
|
||||
return {x: x, y: y};
|
||||
}
|
||||
|
||||
export function mercatorToLatLng(x: number, y: number) {
|
||||
var rMajor = 6378137; //Equatorial Radius, WGS84
|
||||
var shift = Math.PI * rMajor;
|
||||
var lng = x / shift * 180.0;
|
||||
var lat = y / shift * 180.0;
|
||||
lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
|
||||
|
||||
return { lng: lng, lat: lat };
|
||||
}
|
||||
@ -142,14 +142,11 @@ export class Unit extends Marker {
|
||||
if ((this.getBaseData().alive || !selected) && this.getSelectable() && this.getSelected() != selected) {
|
||||
this.#selected = selected;
|
||||
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-selected");
|
||||
if (selected){
|
||||
if (selected)
|
||||
document.dispatchEvent(new CustomEvent("unitSelection", { detail: this }));
|
||||
this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(true));
|
||||
}
|
||||
else {
|
||||
else
|
||||
document.dispatchEvent(new CustomEvent("unitDeselection", { detail: this }));
|
||||
this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(false));
|
||||
}
|
||||
this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(selected));
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,8 +171,11 @@ export class Unit extends Marker {
|
||||
}
|
||||
|
||||
setHighlighted(highlighted: boolean) {
|
||||
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-highlighted", highlighted);
|
||||
this.#highlighted = highlighted;
|
||||
if (this.#highlighted != highlighted) {
|
||||
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-highlighted", highlighted);
|
||||
this.#highlighted = highlighted;
|
||||
this.getGroupMembers().forEach((unit: Unit) => unit.setHighlighted(highlighted));
|
||||
}
|
||||
}
|
||||
|
||||
getHighlighted() {
|
||||
|
||||
@ -3,7 +3,7 @@ import { getHotgroupPanel, getInfoPopup, getMap, getUnitDataTable } from "..";
|
||||
import { Unit } from "./unit";
|
||||
import { cloneUnit } from "../server/server";
|
||||
import { IDLE, MOVE_UNIT } from "../map/map";
|
||||
import { keyEventWasInInput } from "../other/utils";
|
||||
import { deg2rad, keyEventWasInInput, latLngToMercator, mercatorToLatLng } from "../other/utils";
|
||||
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
@ -171,8 +171,16 @@ export class UnitsManager {
|
||||
};
|
||||
|
||||
/*********************** Actions on selected units ************************/
|
||||
selectedUnitsAddDestination(latlng: L.LatLng) {
|
||||
selectedUnitsAddDestination(latlng: L.LatLng, mantainRelativePosition: boolean, rotation: number) {
|
||||
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
|
||||
|
||||
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative distances */
|
||||
var unitDestinations: {[key: number]: LatLng} = {};
|
||||
if (mantainRelativePosition)
|
||||
unitDestinations = this.selectedUnitsComputeGroupDestination(latlng, rotation);
|
||||
else
|
||||
selectedUnits.forEach((unit: Unit) => {unitDestinations[unit.ID] = latlng});
|
||||
|
||||
for (let idx in selectedUnits) {
|
||||
const unit = selectedUnits[idx];
|
||||
/* If a unit is following another unit, and that unit is also selected, send the command to the followed unit */
|
||||
@ -180,11 +188,14 @@ export class UnitsManager {
|
||||
const leader = this.getUnitByID(unit.getFormationData().leaderID)
|
||||
if (leader && leader.getSelected())
|
||||
leader.addDestination(latlng);
|
||||
else
|
||||
else
|
||||
unit.addDestination(latlng);
|
||||
}
|
||||
else
|
||||
unit.addDestination(latlng);
|
||||
else {
|
||||
if (unit.ID in unitDestinations)
|
||||
unit.addDestination(unitDestinations[unit.ID]);
|
||||
}
|
||||
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " new destination added");
|
||||
}
|
||||
@ -307,7 +318,7 @@ export class UnitsManager {
|
||||
else if (formation === "Front") { offset.x = 100; offset.y = 0; offset.z = 0; }
|
||||
else offset = undefined;
|
||||
}
|
||||
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
|
||||
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
|
||||
var count = 1;
|
||||
var xr = 0; var yr = 1; var zr = -1;
|
||||
var layer = 1;
|
||||
@ -351,6 +362,39 @@ export class UnitsManager {
|
||||
getHotgroupPanel().refreshHotgroups();
|
||||
}
|
||||
|
||||
selectedUnitsComputeGroupDestination(latlng: LatLng, rotation: number)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
|
||||
/* Compute the center of the group */
|
||||
var center = {x: 0, y: 0};
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(unit.getFlightData().latitude, unit.getFlightData().longitude);
|
||||
center.x += mercator.x / selectedUnits.length;
|
||||
center.y += mercator.y / selectedUnits.length;
|
||||
});
|
||||
|
||||
/* Compute the distances from the center of the group */
|
||||
|
||||
var unitDestinations: {[key: number]: LatLng} = {};
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(unit.getFlightData().latitude, unit.getFlightData().longitude);
|
||||
var distancesFromCenter = {dx: mercator.x - center.x, dy: mercator.y - center.y};
|
||||
|
||||
/* Rotate the distance according to the group rotation */
|
||||
var rotatedDistancesFromCenter: {dx: number, dy: number} = {dx: 0, dy: 0};
|
||||
rotatedDistancesFromCenter.dx = distancesFromCenter.dx * Math.cos(deg2rad(rotation)) - distancesFromCenter.dy * Math.sin(deg2rad(rotation));
|
||||
rotatedDistancesFromCenter.dy = distancesFromCenter.dx * Math.sin(deg2rad(rotation)) + distancesFromCenter.dy * Math.cos(deg2rad(rotation));
|
||||
|
||||
/* Compute the final position of the unit */
|
||||
var destMercator = latLngToMercator(latlng.lat, latlng.lng); // Convert destination point to mercator
|
||||
var unitMercator = {x: destMercator.x + rotatedDistancesFromCenter.dx, y: destMercator.y + rotatedDistancesFromCenter.dy}; // Compute final position of this unit in mercator coordinates
|
||||
var unitLatLng = mercatorToLatLng(unitMercator.x, unitMercator.y);
|
||||
unitDestinations[unit.ID] = new LatLng(unitLatLng.lat, unitLatLng.lng);
|
||||
});
|
||||
|
||||
return unitDestinations;
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
copyUnits() {
|
||||
this.#copiedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user