Skip to content

Commit

Permalink
Allow plotting height plot
Browse files Browse the repository at this point in the history
  • Loading branch information
Hoff97 committed Oct 7, 2024
1 parent 4d6fd03 commit 58230df
Show file tree
Hide file tree
Showing 11 changed files with 688 additions and 8 deletions.
407 changes: 407 additions & 0 deletions frontend/package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"react-dom": "^18.2.0",
"react-leaflet": "^4.2.1",
"react-scripts": "5.0.1",
"react-vis": "^1.12.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
Expand Down Expand Up @@ -45,5 +46,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react-vis": "^1.11.15"
}
}
}
2 changes: 2 additions & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>

<link rel="stylesheet" href="https://unpkg.com/react-vis/dist/style.css">

<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,25 @@ img.gridImage {

div.restrictedSlider > .bp5-slider-track > .bp5-slider-progress:first-child {
background-color: #888;
}

.heightPlotButton {
position: absolute;
bottom: 10px;
z-index: 5000;
left: calc(50% - 75px);
width: 150px;
}

.heightPlotDrawer {
z-index: 5001;
}

.heightPlotDrawerBody {
display: flex;
justify-content: center;
}

.invisibleCrosshair > .rv-crosshair__line {
stroke-width: 0;
}
8 changes: 6 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import {
import { LatLng } from "leaflet";
import { Spinner, Intent, OverlaysProvider } from "@blueprintjs/core";
import { InfoPanel } from "./components/InfoPanel";
import { GridState, GridTile, ImageState, Settings } from "./utils/types";
import { GridState, GridTile, HeightPoint, ImageState, Settings } from "./utils/types";
import { SettingsCard } from "./components/SettingsCard";
import { ImageOverlays } from "./components/ImageOverlay";
import { SearchComponent } from "./components/SearchComponent";
import { CurrenLocationPane } from "./components/CurrentLocation";
import { HeightPlotCard } from "./components/HeightPlotCard";



Expand Down Expand Up @@ -43,8 +44,10 @@ function App() {
const [path, setPath] = useState<LatLng[] | undefined>();
const [fixed, setFixed] = useState<boolean>(false);
const [node, setNode] = useState<GridTile | undefined>();
const [heightPoints, setHeightPoints] = useState<HeightPoint[] | undefined>();
const [cursorNode, setCursorNode] = useState<HeightPoint | undefined>();
const pathAndNode = {
path, setPath, node, setNode, fixed, setFixed
path, setPath, node, setNode, fixed, setFixed, heightPoints, setHeightPoints, cursorNode, setCursorNode
};
const [isInfoOpen, setIsisInfoOpen] = useState<boolean>(false);

Expand All @@ -71,6 +74,7 @@ function App() {
setImageState={setImageState}
pathAndNode={pathAndNode}
setIsInfoOpen={setIsisInfoOpen}></SettingsCard>
<HeightPlotCard pathAndNode={pathAndNode} />
<MapContainer center={[lastLocationLat, lastLocationLon]} zoom={13} scrollWheelZoom={true}>
<LayersControl position="bottomright">
<LayersControl.BaseLayer checked name="OpenTopoMap">
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/components/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Polyline, useMapEvents } from "react-leaflet";
import { Polyline, useMapEvents, CircleMarker, useMap } from "react-leaflet";
import { CurrentNode } from "./CurrentNode";
import { PathOptions } from "leaflet";
import { nodeInGrid, setPath } from "../utils/utils";
Expand All @@ -10,6 +10,8 @@ interface GridProps {
}

export function Grid({ grid, pathAndNode }: GridProps) {
const map = useMap();

useMapEvents({
mousemove(ev) {
if (grid.response === undefined || grid.grid === undefined || pathAndNode.fixed) {
Expand All @@ -34,6 +36,14 @@ export function Grid({ grid, pathAndNode }: GridProps) {
lineJoin: "round",
};

const blackOptions = {
color: "black",
weight: 1.0,
opacity: 1.0,
fillColor: "black",
fillOpacity: 1.0,
};

return (
<>
{pathAndNode.path !== undefined ? (
Expand All @@ -46,6 +56,13 @@ export function Grid({ grid, pathAndNode }: GridProps) {
) : (
<></>
)}
{pathAndNode.cursorNode !== undefined ? (<>
<CircleMarker
center={pathAndNode.cursorNode.location}
radius={(map.getZoom() / 20) * 10}
pathOptions={blackOptions}
></CircleMarker>
</>) : <></>}
</>
);
}
117 changes: 117 additions & 0 deletions frontend/src/components/HeightPlotCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { Button, Drawer } from "@blueprintjs/core";
import { PathAndNode } from "../utils/types";
import { useState } from "react";

import { Crosshair, HorizontalGridLines, LineSeries, LineSeriesPoint, MarkSeries, VerticalGridLines, XAxis, XYPlot, YAxis } from "react-vis";

interface HeightPlotCardProps {
pathAndNode: PathAndNode;
}

export function HeightPlotCard({ pathAndNode }: HeightPlotCardProps) {
let [drawerOpen, setDrawerOpen] = useState(false);
let [groundHeight, setGroundHeight] = useState<LineSeriesPoint | undefined>(undefined);
let [flightHeight, setFlightHeight] = useState<LineSeriesPoint | undefined>(undefined);

const setFlightHeigthItem = (d: LineSeriesPoint) => {
setFlightHeight(d);
pathAndNode.setCursorNode(d.node);
};

const close = () => {
setDrawerOpen(false);
setGroundHeight(undefined);
setFlightHeight(undefined);
pathAndNode.setCursorNode(undefined);
}

if (pathAndNode.heightPoints === undefined) {
return (<></>);
}

const flightData = [];
const groundData = [];
for (let point of pathAndNode.heightPoints) {
flightData.push({ x: point.distance, y: point.height, node: point });
groundData.push({ x: point.distance, y: point.groundHeight });
}

let flightMarks = [];
let groundMarks = [];
let aglData = []
if (flightHeight !== undefined && groundHeight !== undefined) {
flightMarks.push({
x: flightHeight.x,
y: flightHeight.y,
size: 1
});
groundMarks.push({
x: groundHeight.x,
y: groundHeight.y,
size: 1
});
aglData.push({ x: groundHeight.x, y: groundHeight.y });
aglData.push({ x: flightHeight.x, y: flightHeight.y });
}

return (
<>
<div className="heightPlotButton">
<Button onClick={() => setDrawerOpen(true)} icon={"arrow-up"}>Height Plot</Button>
</div>
<Drawer
icon="info-sign"
onClose={close}
title="Path height plot"
size={"default"}
isOpen={drawerOpen}
className="heightPlotDrawer"
canEscapeKeyClose={true}
canOutsideClickClose={false}
hasBackdrop={false}
position={"bottom"}>
<div className={"heightPlotDrawerBody"}>
<XYPlot height={400} width={window.innerWidth * 0.8} >
<VerticalGridLines />
<HorizontalGridLines />
<XAxis />
<YAxis />
<LineSeries data={flightData} color={"green"} fill={0}
onNearestX={setFlightHeigthItem} />
<LineSeries data={groundData}
color={"red"}
curve={"curveMonotoneX"}
onNearestX={d => setGroundHeight(d)} />
{
groundHeight !== undefined && flightHeight !== undefined ? (
<Crosshair values={[groundHeight, flightHeight]} className={'invisibleCrosshair'}>
<div style={{ background: 'black', minWidth: '80px', maxWidth: '110px' }}>
Height: {Math.round(flightHeight.y)}m<br />
Ground: {Math.round(groundHeight.y)}m<br />
AGL: {Math.round(flightHeight.y - groundHeight.y)}m
</div>
</Crosshair>) : <></>
}
<MarkSeries
strokeWidth={1}
data={flightMarks}
color={"green"}
opacity={0.8}
sizeRange={[0, 5]}
/>
<MarkSeries
strokeWidth={1}
data={groundMarks}
color={"red"}
opacity={0.8}
sizeRange={[0, 5]}
/>
<LineSeries data={aglData}
color={"blue"}
stroke={3} />
</XYPlot>
</div>
</Drawer>
</>
)
}
6 changes: 4 additions & 2 deletions frontend/src/components/SearchComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LatLng } from "leaflet";
import { doSearchFromLocation, nodeInGrid, setPath } from "../utils/utils";
import { computeHeights, doSearchFromLocation, nodeInGrid, setPath } from "../utils/utils";
import { useMap, useMapEvents } from "react-leaflet";
import { GridState, ImageState, PathAndNode, Settings } from "../utils/types";
import { Grid } from "./Grid";
Expand Down Expand Up @@ -29,8 +29,10 @@ export function SearchComponent({ setImageState, settings, setSettings, grid, se

let node = nodeInGrid(e.latlng, grid);
if (node !== undefined) {
setPath(node, grid, pathAndNode);
let nodes = setPath(node, grid, pathAndNode);
pathAndNode.setFixed(true);
let heights = computeHeights(nodes, grid);
pathAndNode.setHeightPoints(heights);
return;
}

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/SettingsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export function SettingsCard({ settings, setSettings, setImageState, setGrid, gr
pathAndNode.setNode(undefined);
pathAndNode.setPath(undefined);
pathAndNode.setFixed(false);
pathAndNode.setHeightPoints(undefined);
pathAndNode.setCursorNode(undefined);
const newSettings = {
...settings,
minGridSize: 30,
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,19 @@ export interface PathAndNode {
path: LatLng[] | undefined;
node: GridTile | undefined;
fixed: boolean;
heightPoints: HeightPoint[] | undefined;
cursorNode: HeightPoint | undefined;
setPath: (path: LatLng[] | undefined) => void;
setNode: (node: GridTile | undefined) => void;
setFixed: (fixed: boolean) => void;
setHeightPoints: (heightPoints: HeightPoint[] | undefined) => void;
setCursorNode: (cursorNode: HeightPoint | undefined) => void;
}

export interface HeightPoint {
location: LatLng;
height: number;
groundHeight: number;
distance: number;
closest_node: GridTile;
}
Loading

0 comments on commit 58230df

Please sign in to comment.