Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions gcs/src/components/mapComponents/missionItems.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ import MarkerPin from "./markerPin"
import MidpointInsertButton from "./midpointInsertButton"

// Tailwind styling
import { midpoint, point } from "@turf/turf"
import { circle, midpoint, point } from "@turf/turf"
import { Layer, Source } from "react-map-gl"
import resolveConfig from "tailwindcss/resolveConfig"
import tailwindConfig from "../../../tailwind.config"
import { selectWaypointRadius } from "../../redux/slices/paramsSlice"

const tailwindColors = resolveConfig(tailwindConfig).theme.colors

export default function MissionItems({ missionItems }) {
export default function MissionItems({ missionItems, waypointRadius = null }) {
const dispatch = useDispatch()
const currentPage = useSelector(selectCurrentPage)
const editable =
Expand Down Expand Up @@ -210,6 +212,36 @@ export default function MissionItems({ missionItems }) {
).geometry.coordinates
}

const waypointRadiusFromStore = useSelector(selectWaypointRadius)

const waypointRadiusMeters = useMemo(() => {
const valueToUse =
waypointRadius !== null && waypointRadius !== undefined
? waypointRadius
: waypointRadiusFromStore
const parsedValue = Number(valueToUse)
const radiusMeters =
Number.isFinite(parsedValue) && parsedValue > 0 ? parsedValue : 2
return radiusMeters
}, [waypointRadius, waypointRadiusFromStore])

const waypointRadiusGeoJson = useMemo(() => {
if (displayedMissionItems.length === 0) return null

return {
type: "FeatureCollection",
features: displayedMissionItems.map((item) =>
circle([intToCoord(item.y), intToCoord(item.x)], waypointRadiusMeters, {
steps: 64,
units: "meters",
properties: {
stroke: "#ffffff",
},
}),
),
}
}, [displayedMissionItems, waypointRadiusMeters])

return (
<>
{/* Show mission item LABELS */}
Expand All @@ -228,6 +260,20 @@ export default function MissionItems({ missionItems }) {
)
})}

{waypointRadiusGeoJson && (
<Source type="geojson" data={waypointRadiusGeoJson}>
<Layer
id="waypoint-radius-border-layer"
type="line"
paint={{
"line-color": "#ffffff",
"line-width": 2,
"line-dasharray": [4, 4],
}}
/>
</Source>
)}

{insertionMidpoints.map((midpointItem) => (
<MidpointInsertButton
key={midpointItem.afterId}
Expand Down
6 changes: 5 additions & 1 deletion gcs/src/components/missions/missionsMap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function MapSectionNonMemo({
rallyItems,
onDragstart,
onOpenElevationGraph,
waypointRadius,
}) {
// Redux
const dispatch = useDispatch()
Expand Down Expand Up @@ -405,7 +406,10 @@ function MapSectionNonMemo({
dragEndCallback={updatePolygonVertex}
/>

<MissionItems missionItems={missionItems} />
<MissionItems
missionItems={missionItems}
waypointRadius={waypointRadius}
/>

<FenceItems fenceItems={fenceItems} />

Expand Down
43 changes: 43 additions & 0 deletions gcs/src/missions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { useCallback, useEffect, useRef, useState } from "react"

// 3rd Party Imports
import { useDebouncedCallback } from "@mantine/hooks"
import { ResizableBox } from "react-resizable"
import { v4 as uuidv4 } from "uuid"

Expand Down Expand Up @@ -67,6 +68,11 @@ import {
setMissionProgressModal,
setPlannedHomePosition,
} from "./redux/slices/missionSlice"
import {
emitGetWaypointRadius,
emitSetWaypointRadius,
selectWaypointRadius,
} from "./redux/slices/paramsSlice"
const tailwindColors = resolveConfig(tailwindConfig).theme.colors

const coordsFractionDigits = 7
Expand Down Expand Up @@ -108,6 +114,15 @@ export default function Missions() {
const unwrittenChanges = useSelector(selectUnwrittenChanges)
const missionProgressModalOpened = useSelector(selectMissionProgressModal)
const missionProgressModalData = useSelector(selectMissionProgressData)
const waypointRadius = useSelector(selectWaypointRadius)
const [waypointRadiusInput, setWaypointRadiusInput] = useState(
waypointRadius ?? 2,
)

const debouncedUpdateWaypointRadius = useDebouncedCallback((value) => {
if (!connected || isInvalidInputNumber(value)) return
dispatch(emitSetWaypointRadius(value))
}, 500)

// Need to keep a reference to the active tab to avoid stale closures
const activeTabRef = useRef(activeTab)
Expand Down Expand Up @@ -140,9 +155,16 @@ export default function Missions() {
}
}, [tabsListRef.current])

useEffect(() => {
if (waypointRadius !== null && waypointRadius !== undefined) {
setWaypointRadiusInput(waypointRadius)
}
}, [waypointRadius])

// Send some messages when file is loaded
useEffect(() => {
dispatch(emitGetTargetInfo())
dispatch(emitGetWaypointRadius())
}, [currentPage])

useEffect(() => {
Expand Down Expand Up @@ -540,6 +562,26 @@ export default function Missions() {
<p className="font-bold">Mission statistics</p>
<MissionStatistics />
</div>

<Divider className="my-1" />

<div className="flex flex-col gap-2">
<NumberInput
label="WP radius (m)"
value={waypointRadiusInput}
onChange={(val) => {
setWaypointRadiusInput(val)
debouncedUpdateWaypointRadius(val)
}}
onBlur={() => {
if (isInvalidInputNumber(waypointRadiusInput)) {
setWaypointRadiusInput(waypointRadius ?? 2)
}
}}
min={1}
hideControls
/>
</div>
</div>
</ResizableBox>

Expand All @@ -552,6 +594,7 @@ export default function Missions() {
missionItems={missionItems}
fenceItems={fenceItems}
rallyItems={rallyItems}
waypointRadius={waypointRadiusInput}
onOpenElevationGraph={openElevationGraph}
/>
</div>
Expand Down
14 changes: 14 additions & 0 deletions gcs/src/redux/middleware/emitters.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ import {
import {
emitExportParamsToFile,
emitGetParams,
emitGetWaypointRadius,
emitRebootAutopilot,
emitRefreshParams,
emitSetMultipleParams,
emitSetWaypointRadius,
setParamsWriteProgressModalOpen,
} from "../slices/paramsSlice"
import {
Expand Down Expand Up @@ -547,6 +549,18 @@ export function handleEmitters(socket, store, action) {
store.dispatch(setReadFileProgress(null)) // Reset progress when starting new download
},
},
{
emitter: emitGetWaypointRadius,
callback: () => socket.socket.emit("get_waypoint_radius"),
},
{
emitter: emitSetWaypointRadius,
callback: () => {
socket.socket.emit("set_waypoint_radius", {
value: action.payload,
})
},
},
]

for (const { emitter, callback } of emitHandlers) {
Expand Down
27 changes: 27 additions & 0 deletions gcs/src/redux/middleware/socketMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ import {
emitRefreshParams,
resetParamsWriteProgressData,
setAutoPilotRebootModalOpen,
setWaypointRadius,
setFetchingParam,
setFetchingVars,
setFetchingVarsProgress,
Expand Down Expand Up @@ -171,6 +172,8 @@ const DroneSpecificSocketEvents = Object.freeze({
onNavRepositionResult: "nav_reposition_result",
onGetLoiterRadiusResult: "nav_get_loiter_radius_result",
onSetLoiterRadiusResult: "nav_set_loiter_radius_result",
onGetWaypointRadiusResult: "get_waypoint_radius_result",
onSetWaypointRadiusResult: "set_waypoint_radius_result",
})

const ParamSpecificSocketEvents = Object.freeze({
Expand Down Expand Up @@ -1085,6 +1088,30 @@ const socketMiddleware = (store) => {
},
)

socket.socket.on(
DroneSpecificSocketEvents.onGetWaypointRadiusResult,
(msg) => {
if (msg.success) {
store.dispatch(setWaypointRadius(msg.data))
} else {
showErrorNotification(msg.message)
}
},
)

socket.socket.on(
DroneSpecificSocketEvents.onSetWaypointRadiusResult,
(msg) => {
if (msg.success) {
showSuccessNotification(msg.message)
store.dispatch(setWaypointRadius(msg.data.param_value))
store.dispatch(updateParamValue(msg.data))
} else {
showErrorNotification(msg.message)
}
},
)

/*
Missions
*/
Expand Down
13 changes: 13 additions & 0 deletions gcs/src/redux/slices/paramsSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const paramsSlice = createSlice({
fetchParamsWarningModalOpen: false,
rebootPromptModalOpen: false,
pendingFetchAction: null,
waypointRadius: null,
},
reducers: {
setRebootData: (state, action) => {
Expand Down Expand Up @@ -133,6 +134,7 @@ const paramsSlice = createSlice({
state.rebootData = {}
state.searchValue = ""
state.rebootPromptModalOpen = false
state.waypointRadius = null
},
setHasFetchedOnce: (state, action) => {
state.hasFetchedOnce = action.payload
Expand Down Expand Up @@ -175,11 +177,17 @@ const paramsSlice = createSlice({
state.pendingFetchAction = action.payload
},

setWaypointRadius: (state, action) => {
state.waypointRadius = action.payload
},

// Emitters (empty objects to be captured in the middleware)
emitRebootAutopilot: () => {},
emitGetParams: () => {},
emitRefreshParams: () => {},
emitSetMultipleParams: () => {},
emitGetWaypointRadius: () => {},
emitSetWaypointRadius: () => {},
emitExportParamsToFile: () => {},
},
selectors: {
Expand Down Expand Up @@ -210,6 +218,7 @@ const paramsSlice = createSlice({
state.fetchParamsWarningModalOpen,
selectRebootPromptModalOpen: (state) => state.rebootPromptModalOpen,
selectPendingFetchAction: (state) => state.pendingFetchAction,
selectWaypointRadius: (state) => state.waypointRadius,
},
})

Expand Down Expand Up @@ -241,10 +250,13 @@ export const {
setFetchParamsWarningModalOpen,
setRebootPromptModalOpen,
setPendingFetchAction,
setWaypointRadius,
emitRebootAutopilot,
emitGetParams,
emitRefreshParams,
emitSetMultipleParams,
emitGetWaypointRadius,
emitSetWaypointRadius,
emitExportParamsToFile,
} = paramsSlice.actions
export const {
Expand All @@ -270,6 +282,7 @@ export const {
selectFetchParamsWarningModalOpen,
selectRebootPromptModalOpen,
selectPendingFetchAction,
selectWaypointRadius,
} = paramsSlice.selectors

export default paramsSlice
Loading
Loading