Draw front lines on the react map.

https://github.com/dcs-liberation/dcs_liberation/issues/2039
This commit is contained in:
Dan Albert 2022-03-02 23:33:15 -08:00
parent 9a2c10a98f
commit b39a44ae37
13 changed files with 116 additions and 0 deletions

View File

@ -0,0 +1,28 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import FrontLine from "./frontline";
import { RootState } from "../app/store";
interface FrontLinesState {
fronts: FrontLine[];
}
const initialState: FrontLinesState = {
fronts: [],
};
export const frontLinesSlice = createSlice({
name: "frontLines",
initialState,
reducers: {
setFrontLines: (state, action: PayloadAction<FrontLine[]>) => {
state.fronts = action.payload;
},
},
});
export const { setFrontLines } = frontLinesSlice.actions;
export const selectFrontLines = (state: RootState) => state.frontLines;
export default frontLinesSlice.reducer;

View File

@ -0,0 +1,7 @@
import { LatLng } from "leaflet";
export interface FrontLine {
extents: LatLng[];
}
export default FrontLine;

View File

@ -2,12 +2,14 @@ import { Action, ThunkAction, configureStore } from "@reduxjs/toolkit";
import controlPointsReducer from "../api/controlPointsSlice";
import flightsReducer from "../api/flightsSlice";
import frontLinesReducer from "../api/frontLinesSlice";
import supplyRoutesReducer from "../api/supplyRoutesSlice";
import tgosReducer from "../api/tgosSlice";
export const store = configureStore({
reducer: {
flights: flightsReducer,
frontLines: frontLinesReducer,
controlPoints: controlPointsReducer,
supplyRoutes: supplyRoutesReducer,
tgos: tgosReducer,

View File

@ -0,0 +1,14 @@
import { FrontLine as FrontLineModel } from "../../api/frontline";
import { Polyline } from "react-leaflet";
interface FrontLineProps {
front: FrontLineModel;
}
function FrontLine(props: FrontLineProps) {
return (
<Polyline positions={props.front.extents} weight={8} color={"#fe7d0a"} />
);
}
export default FrontLine;

View File

@ -0,0 +1 @@
export { default } from "./FrontLine";

View File

@ -0,0 +1,15 @@
import FrontLine from "../frontline";
import { LayerGroup } from "react-leaflet";
import { selectFrontLines } from "../../api/frontLinesSlice";
import { useAppSelector } from "../../app/hooks";
export default function SupplyRoutesLayer() {
const fronts = useAppSelector(selectFrontLines).fronts;
return (
<LayerGroup>
{fronts.map((front, idx) => {
return <FrontLine key={idx} front={front} />;
})}
</LayerGroup>
);
}

View File

@ -0,0 +1 @@
export { default } from "./FrontLinesLayer";

View File

@ -6,6 +6,7 @@ import AirDefenseRangeLayer from "../airdefenserangelayer";
import { BasemapLayer } from "react-esri-leaflet";
import ControlPointsLayer from "../controlpointslayer";
import FlightPlansLayer from "../flightplanslayer";
import FrontLinesLayer from "../frontlineslayer";
import { LatLng } from "leaflet";
import SupplyRoutesLayer from "../supplyrouteslayer";
import { TgoType } from "../../api/tgo";
@ -42,6 +43,9 @@ export default function LiberationMap(props: GameProps) {
<LayersControl.Overlay name="Supply routes" checked>
<SupplyRoutesLayer />
</LayersControl.Overlay>
<LayersControl.Overlay name="Front lines" checked>
<FrontLinesLayer />
</LayersControl.Overlay>
<LayersControl.Overlay name="Enemy SAM threat range" checked>
<AirDefenseRangeLayer blue={false} />
</LayersControl.Overlay>

View File

@ -1,10 +1,12 @@
import { ControlPoint } from "../api/controlpoint";
import { Flight } from "../api/flight";
import FrontLine from "../api/frontline";
import SupplyRoute from "../api/supplyroute";
import Tgo from "../api/tgo";
import backend from "../api/backend";
import { registerFlight } from "../api/flightsSlice";
import { setControlPoints } from "../api/controlPointsSlice";
import { setFrontLines } from "../api/frontLinesSlice";
import { setSupplyRoutes } from "../api/supplyRoutesSlice";
import { setTgos } from "../api/tgosSlice";
import { useAppDispatch } from "../app/hooks";
@ -41,6 +43,14 @@ export const useInitialGameState = () => {
dispatch(setSupplyRoutes(response.data as SupplyRoute[]));
}
});
backend
.get("/front-lines")
.catch((error) => console.log(`Error fetching front-lines: ${error}`))
.then((response) => {
if (response != null) {
dispatch(setFrontLines(response.data as FrontLine[]));
}
});
backend
.get("/flights?with_waypoints=true")
.catch((error) => console.log(`Error fetching flights: ${error}`))

View File

@ -6,6 +6,7 @@ from . import (
debuggeometries,
eventstream,
flights,
frontlines,
mapzones,
navmesh,
supplyroutes,
@ -24,6 +25,7 @@ app.include_router(controlpoints.router)
app.include_router(debuggeometries.router)
app.include_router(eventstream.router)
app.include_router(flights.router)
app.include_router(frontlines.router)
app.include_router(mapzones.router)
app.include_router(navmesh.router)
app.include_router(supplyroutes.router)

View File

@ -0,0 +1 @@
from .routes import router

View File

@ -0,0 +1,9 @@
from __future__ import annotations
from pydantic import BaseModel
from game.server.leaflet import LeafletPoint
class FrontLineJs(BaseModel):
extents: list[LeafletPoint]

View File

@ -0,0 +1,22 @@
from fastapi import APIRouter, Depends
from game import Game
from game.utils import nautical_miles
from .models import FrontLineJs
from ..dependencies import GameContext
router: APIRouter = APIRouter(prefix="/front-lines")
@router.get("/")
def list_front_lines(game: Game = Depends(GameContext.get)) -> list[FrontLineJs]:
front_lines = []
for front_line in game.theater.conflicts():
a = front_line.position.point_from_heading(
front_line.attack_heading.right.degrees, nautical_miles(2).meters
)
b = front_line.position.point_from_heading(
front_line.attack_heading.left.degrees, nautical_miles(2).meters
)
front_lines.append(FrontLineJs(extents=[a.latlng(), b.latlng()]))
return front_lines