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..2ffbec41 100644 --- a/src/renderer/missionWindow/MissionWindow.tsx +++ b/src/renderer/missionWindow/MissionWindow.tsx @@ -54,23 +54,22 @@ 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 = { - geofence: boolean; -}; - -const lockedCache: Locked = { - geofence: true, -}; +type Locked = { geofenceKeepIn: boolean, geofenceKeepOut: boolean }; +const lockedCache: Locked = { geofenceKeepIn: true, geofenceKeepOut: true }; interface State { /** @@ -223,50 +222,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: 'Geofence Keep In', + bounds: { + top: value, + bottom: checklist.geofenceKeepInBottom as number, + left: checklist.geofenceKeepInLeft as number, + right: checklist.geofenceKeepInRight as number, + }, + }); + break; + + case 'geofenceKeepInLeft': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep In', + bounds: { + top: checklist.geofenceKeepInTop as number, + bottom: checklist.geofenceKeepInBottom as number, + left: value, + right: checklist.geofenceKeepInRight as number, + }, + }); + break; + + case 'geofenceKeepInRight': + ipc.postUpdateBoundingBoxes(true, { + name: 'Geofence Keep In', + bounds: { + top: checklist.geofenceKeepInTop as number, + bottom: checklist.geofenceKeepInBottom as number, + left: checklist.geofenceKeepInLeft as number, + right: value, + }, + }); + break; + + case 'geofenceKeepInBottom': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep In', + bounds: { + top: checklist.geofenceKeepInTop as number, + bottom: value, + 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.geofenceBottom as number, - left: checklist.geofenceLeft as number, - right: checklist.geofenceRight as number, + bottom: checklist.geofenceKeepOutBottom as number, + left: checklist.geofenceKeepOutLeft as number, + right: checklist.geofenceKeepOutRight as number, }, }); break; - case 'geofenceLeft': + case 'geofenceKeepOutLeft': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep Out', bounds: { - top: checklist.geofenceTop as number, - bottom: checklist.geofenceBottom as number, + top: checklist.geofenceKeepOutTop as number, + bottom: checklist.geofenceKeepOutBottom as number, left: value, - right: checklist.geofenceRight as number, + right: checklist.geofenceKeepOutRight as number, }, }); break; - case 'geofenceRight': + case 'geofenceKeepOutRight': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep Out', bounds: { - top: checklist.geofenceTop as number, - bottom: checklist.geofenceBottom as number, - left: checklist.geofenceLeft as number, + top: checklist.geofenceKeepOutTop as number, + bottom: checklist.geofenceKeepOutBottom as number, + left: checklist.geofenceKeepOutLeft as number, right: value, }, }); break; - case 'geofenceBottom': + case 'geofenceKeepOutBottom': ipc.postUpdateBoundingBoxes(true, { - name: 'Geofencing', + name: 'Geofence Keep Out', bounds: { - top: checklist.geofenceTop as number, + top: checklist.geofenceKeepOutTop as number, bottom: value, - left: checklist.geofenceLeft as number, - right: checklist.geofenceRight as number, + left: checklist.geofenceKeepOutLeft as number, + right: checklist.geofenceKeepOutRight as number, }, }); break; @@ -368,11 +415,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 'Geofence Keep In': + checks.geofenceKeepInTop = boxpoint.bounds.top; + checks.geofenceKeepInRight = boxpoint.bounds.right; + checks.geofenceKeepInLeft = boxpoint.bounds.left; + checks.geofenceKeepInBottom = boxpoint.bounds.bottom; + break; + + case 'Geofence Keep Out': + checks.geofenceKeepOutTop = boxpoint.bounds.top; + checks.geofenceKeepOutRight = boxpoint.bounds.right; + checks.geofenceKeepOutLeft = boxpoint.bounds.left; + checks.geofenceKeepOutBottom = boxpoint.bounds.bottom; break; default: break; @@ -447,8 +501,11 @@ export default class MissionWindow extends Component { private unlockParameterInputs(waypointType: string): void { const { locked: newLocked } = this.state; - if (waypointType === 'geofence') { - newLocked.geofence = false; + if (waypointType === 'geofenceKeepIn') { + newLocked.geofenceKeepIn = false; + } + if (waypointType === 'geofenceKeepOut') { + newLocked.geofenceKeepOut = false; } this.setState({ locked: newLocked }); @@ -486,10 +543,14 @@ export default class MissionWindow extends Component { */ const unlockStartMissionButton = information[missionName].parameters !== undefined - && checklist.geofenceTop !== undefined - && checklist.geofenceBottom !== undefined - && checklist.geofenceLeft !== undefined - && checklist.geofenceRight !== 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 +577,27 @@ export default class MissionWindow extends Component {

Options

-
-

Geofencing

- +
+

Geofence Keep In

+ +
+ +
+ +
+ + +
+
+

Geofence Keep Out

+
- +
- +
- - + +
{status === 'ready' && } diff --git a/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx b/src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx index b0d76365..d47f2bc2 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..e8e4b9d0 100644 --- a/src/types/message.ts +++ b/src/types/message.ts @@ -28,28 +28,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; - }; - } /** @@ -110,6 +88,34 @@ function isStopMessage(message: Message): boolean { return message.type === 'stop'; } +export interface GeofenceMessage extends MessageBase { + type: 'geofence'; + + /** + * Geofencing coordinates in the form of a polygon. + */ + geofence: { + /** + * geofence.keepOut and geofence.keepIn are defined as an array of tuples( [[number, number]] ). + * Each tuple consists of [ [latitude, longitude] ]. + */ + 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.keepOut) + && message.geofence.keepIn.every((pair) => pair.length === 2 && typeof pair[0] === 'number' && typeof pair[1] === 'number') + && message.geofence.keepOut.every((pair) => pair.length === 2 && typeof pair[0] === 'number' && typeof pair[1] === 'number'); +} + export interface ConnectionAckMessage extends MessageBase { type: 'connectionAck'; } @@ -280,10 +286,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 * guards from types/missionInformation and types/task. @@ -298,6 +304,7 @@ export function isMessage(message: { [key: string]: any }): boolean { 'pause', 'resume', 'stop', + 'geofence', 'connectionAck', 'update', 'poi', @@ -348,6 +355,7 @@ export const TypeGuard = { isPauseMessage, isResumeMessage, isStopMessage, + isGeofenceMessage, isConnectionAcknowledgementMessage, isUpdateMessage, isPOIMessage,