From bae005cedbd73dfb54fd69dd01f94dea64bcd513 Mon Sep 17 00:00:00 2001 From: rSchwartz1 <55598798+rSchwartz1@users.noreply.github.com> Date: Fri, 13 Mar 2020 12:55:39 -0700 Subject: [PATCH] Add KeepIn and KeepOut geofence boxes ## Why is this being changed? This is being changed because of Northrop's requirement of having a KeepIn and KeepOut box for all vehicles. The KeepIn area is an area that all vehicles must stay inside of, and will be about the size of the mission field/runway. The KeepOut area is an area that all vehicles must stay outside of, and will be the location of all student/Northrop observers. ## What was changed to address this problem? In order to address the problem, two geofence buttons were created inside of the missionWindow UI tah tallows the GCS operator to dynamically create the two boxes individually, separating them by color. ## How was this change tested? This change was tested with npm test. --- src/common/struct/Vehicle.ts | 5 - src/renderer/mainWindow/map/MapContainer.tsx | 2 +- src/renderer/missionWindow/MissionWindow.tsx | 163 +++++++++++++----- .../extra/CreateBoundingBoxButton.tsx | 9 +- src/renderer/missionWindow/mission.css | 25 +-- .../missionWindow/parameter/VTOLSearch.tsx | 2 +- src/types/message.ts | 57 +++--- 7 files changed, 173 insertions(+), 90 deletions(-) diff --git a/src/common/struct/Vehicle.ts b/src/common/struct/Vehicle.ts index 1b3e9e2e..dfe355a7 100644 --- a/src/common/struct/Vehicle.ts +++ b/src/common/struct/Vehicle.ts @@ -260,11 +260,6 @@ export default class Vehicle { this.sendMessage({ type: 'start', jobType, - geofence: { - topLeft: [0, 0], - botRight: [0, 0], - keepOut: true, - }, }); this.updateEventHandler.addHandler('status', (value): boolean => { diff --git a/src/renderer/mainWindow/map/MapContainer.tsx b/src/renderer/mainWindow/map/MapContainer.tsx index 0e4e5b8f..38e45cf1 100644 --- a/src/renderer/mainWindow/map/MapContainer.tsx +++ b/src/renderer/mainWindow/map/MapContainer.tsx @@ -318,7 +318,7 @@ export default class MapContainer extends Component { boundingBoxes.forEach((boundingBox): void => { if (!newBoundingBoxes[boundingBox.name]) { newBoundingBoxes[boundingBox.name] = { - color: boundingBox.color || 'red', + color: boundingBox.color || 'black', bounds: boundingBox.bounds || (viewport.center && { top: viewport.center[0], bottom: viewport.center[0], diff --git a/src/renderer/missionWindow/MissionWindow.tsx b/src/renderer/missionWindow/MissionWindow.tsx index c625ce73..98941e59 100644 --- a/src/renderer/missionWindow/MissionWindow.tsx +++ b/src/renderer/missionWindow/MissionWindow.tsx @@ -54,13 +54,17 @@ const title: { [missionName in MissionInformation.MissionName]: string } = { uuvRescue: 'UUV Rescue', }; -type GeofenceChecklistType = 'geofenceTop' | 'geofenceLeft' | 'geofenceRight' | 'geofenceBottom'; +type GeofenceChecklistType = 'geofenceKeepInTop' | 'geofenceKeepInLeft' | 'geofenceKeepInRight' | 'geofenceKeepInBottom' | 'geofenceKeepOutTop' | 'geofenceKeepOutLeft' | 'geofenceKeepOutRight' | 'geofenceKeepOutBottom'; const checklistCache: { [check in GeofenceChecklistType ]: number | undefined} = { - geofenceTop: undefined, - geofenceLeft: undefined, - geofenceRight: undefined, - geofenceBottom: undefined, + geofenceKeepInTop: undefined, + geofenceKeepInLeft: undefined, + geofenceKeepInRight: undefined, + geofenceKeepInBottom: undefined, + geofenceKeepOutTop: undefined, + geofenceKeepOutLeft: undefined, + geofenceKeepOutRight: undefined, + geofenceKeepOutBottom: undefined, }; type Locked = { @@ -223,50 +227,98 @@ export default class MissionWindow extends Component { const name = event.target.name as GeofenceChecklistType; const value = parseInt(event.target.value, 10) || 0; switch (name) { - case 'geofenceTop': + case 'geofenceKeepInTop': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep-In', bounds: { top: value, - bottom: checklist.geofenceBottom as number, - left: checklist.geofenceLeft as number, - right: checklist.geofenceRight as number, + bottom: checklist.geofenceKeepInBottom as number, + left: checklist.geofenceKeepInLeft as number, + right: checklist.geofenceKeepInRight as number, }, }); break; - case 'geofenceLeft': + case 'geofenceKeepInLeft': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep-In', bounds: { - top: checklist.geofenceTop as number, - bottom: checklist.geofenceBottom as number, + top: checklist.geofenceKeepInTop as number, + bottom: checklist.geofenceKeepInBottom as number, left: value, - right: checklist.geofenceRight as number, + right: checklist.geofenceKeepInRight as number, }, }); break; - case 'geofenceRight': + case 'geofenceKeepInRight': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep-In', bounds: { - top: checklist.geofenceTop as number, - bottom: checklist.geofenceBottom as number, - left: checklist.geofenceLeft as number, + top: checklist.geofenceKeepInTop as number, + bottom: checklist.geofenceKeepInBottom as number, + left: checklist.geofenceKeepInLeft as number, right: value, }, }); break; - case 'geofenceBottom': + case 'geofenceKeepInBottom': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep-In', bounds: { - top: checklist.geofenceTop as number, + top: checklist.geofenceKeepInTop as number, bottom: value, - left: checklist.geofenceLeft as number, - right: checklist.geofenceRight as number, + left: checklist.geofenceKeepInLeft as number, + right: checklist.geofenceKeepInRight as number, + }, + }); + break; + + case 'geofenceKeepOutTop': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep-Out', + bounds: { + top: value, + bottom: checklist.geofenceKeepOutBottom as number, + left: checklist.geofenceKeepOutLeft as number, + right: checklist.geofenceKeepOutRight as number, + }, + }); + break; + + case 'geofenceKeepOutLeft': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep-Out', + bounds: { + top: checklist.geofenceKeepOutTop as number, + bottom: checklist.geofenceKeepOutBottom as number, + left: value, + right: checklist.geofenceKeepOutRight as number, + }, + }); + break; + + case 'geofenceKeepOutRight': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep-Out', + bounds: { + top: checklist.geofenceKeepOutTop as number, + bottom: checklist.geofenceKeepOutBottom as number, + left: checklist.geofenceKeepOutLeft as number, + right: value, + }, + }); + break; + + case 'geofenceKeepOutBottom': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep-Out', + bounds: { + top: checklist.geofenceKeepOutTop as number, + bottom: value, + left: checklist.geofenceKeepOutLeft as number, + right: checklist.geofenceKeepOutRight as number, }, }); break; @@ -368,11 +420,18 @@ export default class MissionWindow extends Component { boundingBoxes.forEach((boxpoint): void => { switch (boxpoint.name) { - case 'Geofencing': - checks.geofenceTop = boxpoint.bounds.top; - checks.geofenceRight = boxpoint.bounds.right; - checks.geofenceLeft = boxpoint.bounds.left; - checks.geofenceBottom = boxpoint.bounds.bottom; + case 'geofenceContainerKeepIn': + checks.geofenceKeepInTop = boxpoint.bounds.top; + checks.geofenceKeepInRight = boxpoint.bounds.right; + checks.geofenceKeepInLeft = boxpoint.bounds.left; + checks.geofenceKeepInBottom = boxpoint.bounds.bottom; + break; + + case 'geofenceContainerKeepOut': + checks.geofenceKeepOutTop = boxpoint.bounds.top; + checks.geofenceKeepOutRight = boxpoint.bounds.right; + checks.geofenceKeepOutLeft = boxpoint.bounds.left; + checks.geofenceKeepOutBottom = boxpoint.bounds.bottom; break; default: break; @@ -447,7 +506,10 @@ export default class MissionWindow extends Component { private unlockParameterInputs(waypointType: string): void { const { locked: newLocked } = this.state; - if (waypointType === 'geofence') { + if (waypointType === 'geofenceContainerKeepIn') { + newLocked.geofence = false; + } + if (waypointType === 'geofenceContainerKeepOut') { newLocked.geofence = false; } @@ -485,11 +547,15 @@ export default class MissionWindow extends Component { * (and no mission is running). */ - const unlockStartMissionButton = information[missionName].parameters !== undefined - && checklist.geofenceTop !== undefined - && checklist.geofenceBottom !== undefined - && checklist.geofenceLeft !== undefined - && checklist.geofenceRight !== undefined; + const unlockStartMissionButton : boolean = information[missionName].parameters !== undefined + && checklist.geofenceKeepInTop !== undefined + && checklist.geofenceKeepInBottom !== undefined + && checklist.geofenceKeepInLeft !== undefined + && checklist.geofenceKeepInRight !== undefined + && checklist.geofenceKeepOutTop !== undefined + && checklist.geofenceKeepOutBottom !== undefined + && checklist.geofenceKeepOutLeft !== undefined + && checklist.geofenceKeepOutRight !== undefined; return (
@@ -516,16 +582,27 @@ export default class MissionWindow extends Component {

Options

-
-

Geofencing

- +
+

Geofencing KeepIn

+ +
+ +
+ +
+ + +
+
+

Geofencing KeepOut

+
- +
- +
- - + +
{status === 'ready' && } diff --git a/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx b/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx index b0d76365..ee0e0582 100644 --- a/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx +++ b/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx @@ -13,6 +13,11 @@ export interface CreateBoundingBoxButtonProps extends ThemeProps{ * Name of the box itself, when it shows up on the map. */ value: string; + + /** + *Color of the box as it appears on the map. + */ + color: string; } export default class CreateBoundingBoxButton extends PureComponent { @@ -23,9 +28,9 @@ export default class CreateBoundingBoxButton extends PureComponent {
- +
); } diff --git a/src/types/message.ts b/src/types/message.ts index 1e518a76..ba80238d 100644 --- a/src/types/message.ts +++ b/src/types/message.ts @@ -18,9 +18,7 @@ interface MessageBase { */ type: string; } - -// Definitions for all messages from GCS to vehicles. - +// Definitions for all messages from GCS to vehicles export interface StartMessage extends MessageBase { type: 'start'; @@ -28,28 +26,6 @@ export interface StartMessage extends MessageBase { * Name of job to perform. */ jobType: JobType; - - /** - * Geofencing coordinates in the form of a rectangle, and geofence type sent with start message. - */ - geofence: { - - /** - * Top Left coordinate of geofencing rectangle, in form of latitude, longitude. - */ - topLeft: [number, number]; - - /** - * Bottom right coordinate of geofencing rectangle, in form of latitude, longitude. - */ - botRight: [number, number]; - - /** - * Boolean to specify whether geofence is keep out type (true), or keep in type (false). - */ - keepOut: boolean; - }; - } /** @@ -103,6 +79,28 @@ export interface StopMessage extends MessageBase { type: 'stop'; } +export interface GeofenceMessage extends MessageBase { + type: 'geofence'; + + /** + * Geofencing coordinates in the form of a rectangle. + */ + geofence: { + 'keepOut': [number, number][], + 'keepIn': [number, number][] + } +} + +/** + * Type guard for Geofence Message. + */ +function isGeofenceMessage(message: Message): boolean { + return message.type === 'geofence' + && message.geofence !== undefined + && Array.isArray(message.geofence.keepIn) + && Array.isArray(message.geofence.keepIn); +} + /** * Type guard for Stop Message. */ @@ -280,9 +278,10 @@ export function isBadMessage(message: Message): boolean { /** * All types of messages sent to and from the GCS. */ -export type Message = StartMessage | AddMissionMessage | PauseMessage | ResumeMessage | StopMessage -| ConnectionAckMessage | UpdateMessage | POIMessage | CompleteMessage | ConnectMessage -| AcknowledgementMessage | BadMessage; + +export type Message = | StartMessage | AddMissionMessage | PauseMessage | ResumeMessage | +StopMessage | GeofenceMessage | ConnectionAckMessage | UpdateMessage | POIMessage | CompleteMessage +| ConnectMessage | AcknowledgementMessage | BadMessage; /** * Simply checks if the message has a valid type field. This is different from the type @@ -298,6 +297,7 @@ export function isMessage(message: { [key: string]: any }): boolean { 'pause', 'resume', 'stop', + 'geofence', 'connectionAck', 'update', 'poi', @@ -348,6 +348,7 @@ export const TypeGuard = { isPauseMessage, isResumeMessage, isStopMessage, + isGeofenceMessage, isConnectionAcknowledgementMessage, isUpdateMessage, isPOIMessage,