Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes issue #69 (adds path and next waypoint tracking on map) #155

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
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
74 changes: 51 additions & 23 deletions client/src/components/FlightMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,14 @@ const FlightPlanMap = props => {
let mapRef = createRef()
const [icons, setIcons] = useState({})
const tileRef = useRef(null)

useEffect(() => {

httpget("/uav/commands/export", response => {
let points = response.data.waypoints.map((marker) => {
return { num: marker.num, cmd: marker.cmd, p1: marker.p1, p2: marker.p2, p3: marker.p3 * 3.281, p4: marker.p4, lat: marker.lat, lng: marker.lon, alt: marker.alt * 3.281 } // convert altitude from meters to feet
})
props.setters.path(points)
props.setters.pathSave(structuredClone(points))
})

var MarkerIcon = L.Icon.extend({
options: {
iconSize: [25, 41],
Expand All @@ -86,7 +83,7 @@ const FlightPlanMap = props => {
var NoIcon = L.Icon.extend({
options: {
iconSize: [20, 20],
iconAnchor: [10, 10],
iconAnchor: [10, 10],
iconUrl: "../assets/icon-transparent.svg",
popupAnchor: [0, 0],
tooltipAnchor: [0, 0],
Expand Down Expand Up @@ -119,13 +116,16 @@ const FlightPlanMap = props => {
uav: new VehicleIcon({ iconUrl: "../assets/uav.svg" }),
uavDirection: new DirectionPointerIcon({ iconUrl: "../assets/pointer.svg" }),
uavDirectionOutline: new DirectionPointerIcon({ iconUrl: "../assets/pointer-outline.svg" }),
uavPath: new NoIcon(),
water: new VehicleIcon({ iconUrl: "../assets/water-drop.svg" }),
})

window.addEventListener("offline", () => {
tileRef.current.setUrl("/map/{z}/{x}/{y}.png")
})



checkInternet()

}, [])
Expand All @@ -143,12 +143,12 @@ const FlightPlanMap = props => {
}).catch(() => {
try {
tileRef.current.setUrl("/map/{z}/{x}/{y}.png")
} catch {}
} catch { }
})
} else {
try {
tileRef.current.setUrl("/map/{z}/{x}/{y}.png")
} catch {}
} catch { }
}
}
useInterval(5000, checkInternet)
Expand Down Expand Up @@ -179,8 +179,9 @@ const FlightPlanMap = props => {
props.setters.pathSaved(false)
}


const handleClick = event => {
console.log(props.getters.path)


if (["disabled", "distance"].includes(props.getters.placementMode) || ["jump"].includes(props.getters.placementType)) {
return
Expand Down Expand Up @@ -208,9 +209,9 @@ const FlightPlanMap = props => {
second = get[(i + 1) % get.length]
}

let m = (second.lat - first.lat)/(second.lng - first.lng)
let x0 = (event.latlng.lng/m + event.latlng.lat - second.lat + m*second.lng)/(m + 1/m) // projection of event point on line
let y0 = -(x0 - event.latlng.lng)/m + event.latlng.lat
let m = (second.lat - first.lat) / (second.lng - first.lng)
let x0 = (event.latlng.lng / m + event.latlng.lat - second.lat + m * second.lng) / (m + 1 / m) // projection of event point on line
let y0 = -(x0 - event.latlng.lng) / m + event.latlng.lat

if (m === -Infinity || m === Infinity) {
let d = Math.abs(event.latlng.lng - first.lng)
Expand All @@ -221,7 +222,7 @@ const FlightPlanMap = props => {
let lng = event.latlng.lng
return [d, (lng > first.lng && lng < second.lng) || (lng > second.lng && lng < first.lng)]
} else {
let d = Math.sqrt((x0 - event.latlng.lng)**2 + (y0 - event.latlng.lat)**2)
let d = Math.sqrt((x0 - event.latlng.lng) ** 2 + (y0 - event.latlng.lat) ** 2)
if (x0 > Math.min(first.lng, second.lng) && x0 < Math.max(first.lng, second.lng) && y0 > Math.min(first.lat, second.lat) && y0 < Math.max(first.lat, second.lat)) {
return [d, true]
} else {
Expand Down Expand Up @@ -321,7 +322,7 @@ const FlightPlanMap = props => {
<Popup>
{popupMenu}
</Popup>
: null}
: null}
</Marker>
)
}
Expand All @@ -340,6 +341,17 @@ const FlightPlanMap = props => {
return null;
};

const getTargetWaypoint = () => {

if (props.getters.Awaypoint.length > 0 && props.getters.planePoints.length > 0 && props.getters.path) {

let waypointNum = props.getters.Awaypoint[0].num % props.getters.path.length

return [props.getters.planePoints[props.getters.planePoints.length - 1], props.getters.path[waypointNum]]
}
return []
}

const MarkerPopup = ({ marker, i, datatype }) => {
return (
<div>
Expand Down Expand Up @@ -398,7 +410,7 @@ const FlightPlanMap = props => {
Jump From
<Box style={{ "width": "12em", "margin-right": "4em", "height": "3em" }} editable={false} placeholder={"---"} content={i} onChange={v => positiveSignedIntValidation(v, marker.p0, (k) => {
let path = props.getters.path
props.setters.path([...path.slice(0, i), {...marker, p0: k}, ...path.slice(i + 1)])
props.setters.path([...path.slice(0, i), { ...marker, p0: k }, ...path.slice(i + 1)])
props.setters.pathSaved(false)
})} />
<br />
Expand All @@ -412,7 +424,7 @@ const FlightPlanMap = props => {
Repeat
<Box style={{ "width": "12em", "margin-right": "4em", "height": "3em" }} editable={true} placeholder={"---"} content={marker?.p2} onChange={v => positiveSignedIntValidation(v, marker.p2, (k) => {
let path = props.getters.path
props.setters.path([...path.slice(0, i), { ...marker, p2: k}, ...path.slice(i + 1)])
props.setters.path([...path.slice(0, i), { ...marker, p2: k }, ...path.slice(i + 1)])
props.setters.pathSaved(false)
})} />
</div>}
Expand All @@ -426,13 +438,13 @@ const FlightPlanMap = props => {
if (p.num == j + 2) { // if starting point of jump is at waypoint to be deleted
return null
} else if (p.p1 > j + 1) {
return { ...p, p1: p.p1 - 1, cmd: p.cmd, num: p.num - (p.num > j+1 ? 1 : 0) }
return { ...p, p1: p.p1 - 1, cmd: p.cmd, num: p.num - (p.num > j + 1 ? 1 : 0) }
} else if (p.p1 == j + 1) { // if destination of jump is to waypoint to be deleted
return null // marked for deletion
}
}

return { ...p, num: (p.num > j+1 ? p.num - 1 : p.num) }
return { ...p, num: (p.num > j + 1 ? p.num - 1 : p.num) }
}

const _delete = (_p, k) => {
Expand Down Expand Up @@ -491,7 +503,7 @@ const FlightPlanMap = props => {
/>
<ClickLocation />
<LayersControl position="topright">
{ /* Need for SUAS: geofence, airdrop, uav, waypoint */ }
{ /* Need for SUAS: geofence, airdrop, uav, waypoint */}
<LayersControl.Overlay checked name={props.display.flightBoundary[1]}>
<LayerGroup>
<Polyline positions={circle(props.getters.flightBoundary)} color="#000000" weight={4} />
Expand All @@ -508,6 +520,22 @@ const FlightPlanMap = props => {
})}
</LayerGroup>
</LayersControl.Overlay>
<LayersControl.Overlay checked name={props.display.airdropBoundary[1]}>
<LayerGroup>
<Polyline positions={props.getters.planePoints.slice(-20)} color="#8a2be2" weight={3} />
{props.getters.planePoints.map((marker, index) => {
return popup(marker, index, "uavPath")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should make and use custom datatypes - see how airdropBoundary is defined above. Also, note the name={props.display.airdropBoundary[1]} which solves the previous comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props.display gets you the display name of a certain property. With this comment, I didn't want you to use the airdrop boundary display name for the uav path - I wanted you to create a custom property. You did this, but never gave it a display name and never used it in the name= field. So close!

})}
</LayerGroup>
</LayersControl.Overlay>
<LayersControl.Overlay checked name={props.display.airdropBoundary[1]}>
<LayerGroup>
<Polyline positions={getTargetWaypoint()} color="#FFFFFF" weight={3} />
{props.getters.planePoints.map((marker, index) => {
return popup(marker, index, "uavPath")
})}
</LayerGroup>
</LayersControl.Overlay>
<LayersControl.Overlay checked name={props.display.uav[1]}>
{props.getters.uav.heading == null ? null : (
<LayerGroup>
Expand Down Expand Up @@ -558,10 +586,10 @@ const FlightPlanMap = props => {
return (
<>
<PolylineDecorator layer="Waypoints" positions={[props.getters.path[j], props.getters.path[marker.p1 - 1]]} color="#17e3cb" decoratorColor="#61e8d9" />
{popup({...marker, lng: (props.getters.path[j].lng + props.getters.path[marker.p1 - 1].lng)/2, lat: (props.getters.path[j].lat + props.getters.path[marker.p1 - 1].lat)/2}, marker.num, "jump", (
{popup({ ...marker, lng: (props.getters.path[j].lng + props.getters.path[marker.p1 - 1].lng) / 2, lat: (props.getters.path[j].lat + props.getters.path[marker.p1 - 1].lat) / 2 }, marker.num, "jump", (
<div>
<h5>#{i + 1}: Jump</h5>
{MarkerPopup({marker: marker, i: i, datatype: "jump"})}
{MarkerPopup({ marker: marker, i: i, datatype: "jump" })}
</div>
), false)}
</>
Expand All @@ -570,29 +598,29 @@ const FlightPlanMap = props => {
return popup(marker, marker.num, "unlim", (
<div>
<h5>#{i + 1}: Unlimited Loiter</h5>
{MarkerPopup({marker: marker, i: i, datatype: "unlim"})}
{MarkerPopup({ marker: marker, i: i, datatype: "unlim" })}
</div>
), true)
} else if (marker.cmd === Commands.turnLoiter) {
return popup(marker, marker.num, "turn", (
<div>
<h5>#{i + 1} Turn Loiter</h5>
{MarkerPopup({marker: marker, i: i, datatype: "turn"})}
{MarkerPopup({ marker: marker, i: i, datatype: "turn" })}
</div>
), true)
} else if (marker.cmd === Commands.timeLoiter) {
return popup(marker, marker.num, "time", (
<div>
<h5>#{i + 1}: Time Loiter</h5>
{MarkerPopup({marker: marker, i: i, datatype: "time"})}
{MarkerPopup({ marker: marker, i: i, datatype: "time" })}
</div>
), true)
}

return popup(marker, marker.num, "path", (
<div>
<h6>#{i + 1}: Mission Path Waypoint</h6>
{MarkerPopup({marker: marker, i: i, datatype: "path"})}
{MarkerPopup({ marker: marker, i: i, datatype: "path" })}
</div>
), true)
})}
Expand Down
64 changes: 43 additions & 21 deletions client/src/pages/FlightData/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ TODO: Display list highlighting (and vice versa)

const FlightData = () => {
const [flightBoundary, setFlightBoundary] = useState([
{lat: 38.31729702009844, lng: -76.55617670782419},
{lat: 38.31594832826572, lng: -76.55657341657302},
{lat: 38.31546739500083, lng: -76.55376201277696},
{lat: 38.31470980862425, lng: -76.54936361414539},
{lat: 38.31424154692598, lng: -76.54662761646904},
{lat: 38.31369801280048, lng: -76.54342380058223},
{lat: 38.31331079191371, lng: -76.54109648475954},
{lat: 38.31529941346197, lng: -76.54052104837133},
{lat: 38.31587643291039, lng: -76.54361305817427},
{lat: 38.31861642463319, lng: -76.54538594175376},
{lat: 38.31862683616554, lng: -76.55206138505936},
{lat: 38.31703471119464, lng: -76.55244787859773},
{lat: 38.31674255749409, lng: -76.55294546866578},
{lat: 38.31729702009844, lng: -76.55617670782419}
{ lat: 38.31729702009844, lng: -76.55617670782419 },
{ lat: 38.31594832826572, lng: -76.55657341657302 },
{ lat: 38.31546739500083, lng: -76.55376201277696 },
{ lat: 38.31470980862425, lng: -76.54936361414539 },
{ lat: 38.31424154692598, lng: -76.54662761646904 },
{ lat: 38.31369801280048, lng: -76.54342380058223 },
{ lat: 38.31331079191371, lng: -76.54109648475954 },
{ lat: 38.31529941346197, lng: -76.54052104837133 },
{ lat: 38.31587643291039, lng: -76.54361305817427 },
{ lat: 38.31861642463319, lng: -76.54538594175376 },
{ lat: 38.31862683616554, lng: -76.55206138505936 },
{ lat: 38.31703471119464, lng: -76.55244787859773 },
{ lat: 38.31674255749409, lng: -76.55294546866578 },
{ lat: 38.31729702009844, lng: -76.55617670782419 }
])
const [airdropBoundary, setAirdropBoundary] = useState([
{lat: 38.31442311312976, lng: -76.54522971451763},
{lat: 38.31421041772561, lng: -76.54400246436776},
{lat: 38.3144070396263, lng: -76.54394394383165},
{lat: 38.31461622313521, lng: -76.54516993186949},
{lat: 38.31442311312976, lng: -76.54522971451763}
{ lat: 38.31442311312976, lng: -76.54522971451763 },
{ lat: 38.31421041772561, lng: -76.54400246436776 },
{ lat: 38.3144070396263, lng: -76.54394394383165 },
{ lat: 38.31461622313521, lng: -76.54516993186949 },
{ lat: 38.31442311312976, lng: -76.54522971451763 }
])
const [uav, setUav] = useState({})
const [home, setHome] = useState({})
Expand All @@ -62,6 +62,8 @@ const FlightData = () => {
const [currentDistance, setCurrentDistance] = useState(-1)
const [firstJump, setFirstJump] = useState(-1)
const [firstPoint, setFirstPoint] = useState(-1)
const [planePoints, setPlanePoints] = useState([])
const [Awaypoint, setAwaypoint] = useState([])

const getters = {
flightBoundary: flightBoundary,
Expand All @@ -77,7 +79,9 @@ const FlightData = () => {
defaultAlt: defaultAlt,
currentDistance: currentDistance,
firstJump: firstJump,
firstPoint: firstPoint
firstPoint: firstPoint,
planePoints: planePoints,
Awaypoint: Awaypoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better name? What's the purpose?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work with these getters and setters. However, I'd call Awaypoint something different - maybe toNextWaypoint?

}

const setters = {
Expand All @@ -94,7 +98,9 @@ const FlightData = () => {
defaultAlt: setDefaultAlt,
currentDistance: setCurrentDistance,
firstJump: setFirstJump,
firstPoint: setFirstPoint
firstPoint: setFirstPoint,
planePoints: setPlanePoints,
Awaypoint: setAwaypoint
}

const display = {
Expand All @@ -107,6 +113,7 @@ const FlightData = () => {
time: ["Time Loiter", "Time Loiter"],
jump: ["Jump", "Jump"],
uav: ["UAV", "UAV Location"],
uavPath: ["UAV Path", "UAV Path"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, you should use custom datatypes to populate this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You did in fact implement custom datatypes above (great job!), you just never added display attributes for them. This is what I'm looking for in FlightMap.js.

water: ["Drop", "Bottle Drop Location"]
}

Expand All @@ -127,6 +134,21 @@ const FlightData = () => {
lat: response.data.result.home.lat,
lng: response.data.result.home.lon
})
setPlanePoints(planePoints => [
...planePoints,
{
lat: response.data.result.lat,
lng: response.data.result.lon
}
]);
})
httpget("/uav/stats", response => {

setAwaypoint(Awaypoint => [
{
num: response.data.result.quick.waypoint[0]
}
]);
})
})

Expand Down