Skip to content

Commit

Permalink
Add KeepIn and KeepOut geofence boxes
Browse files Browse the repository at this point in the history
  ## 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.
  • Loading branch information
rSchwartz1 committed Mar 16, 2020
1 parent e82c5e0 commit bae005c
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 90 deletions.
5 changes: 0 additions & 5 deletions src/common/struct/Vehicle.ts
Expand Up @@ -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<VehicleStatus>('status', (value): boolean => {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/mainWindow/map/MapContainer.tsx
Expand Up @@ -318,7 +318,7 @@ export default class MapContainer extends Component<ThemeProps, State> {
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],
Expand Down
163 changes: 120 additions & 43 deletions src/renderer/missionWindow/MissionWindow.tsx
Expand Up @@ -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 = {
Expand Down Expand Up @@ -223,50 +227,98 @@ export default class MissionWindow extends Component<ThemeProps, State> {
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;
Expand Down Expand Up @@ -368,11 +420,18 @@ export default class MissionWindow extends Component<ThemeProps, State> {

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;
Expand Down Expand Up @@ -447,7 +506,10 @@ export default class MissionWindow extends Component<ThemeProps, State> {
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;
}

Expand Down Expand Up @@ -485,11 +547,15 @@ export default class MissionWindow extends Component<ThemeProps, State> {
* (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 (
<div className={`missionWrapper${theme === 'dark' ? '_dark' : ''}`}>
Expand All @@ -516,16 +582,27 @@ export default class MissionWindow extends Component<ThemeProps, State> {
<h1 style={{ marginTop: 0 }}>Options</h1>
<MissionOptions title={title} missionNames={missionNames} options={options} />
</div>
<div className="geofenceContainer">
<h1>Geofencing</h1>
<input className="inputFields" type="number" name="geofenceScanTop" value={checklist.geofenceTop || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Top" />
<div className="geofenceContainerKeepIn">
<h1>Geofencing KeepIn</h1>
<input className="inputFields" type="number" name="geofenceKeepInTop" value={checklist.geofenceKeepInTop || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Top" />
<br />
<input className="inputFields" type="number" name="geofenceKeepInBottom" value={checklist.geofenceKeepInBottom || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Bottom" />
<br />
<input className="inputFields" type="number" name="geofenceKeepInLeft" value={checklist.geofenceKeepInLeft || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Left" />
<br />
<input className="inputFields" type="number" name="geofenceKeepInRight" value={checklist.geofenceKeepInRight || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Right" />
<CreateBoundingBoxButton theme={theme} name="Geofence Keep-In" value="geofenceContainerKeepIn" color="green" />
</div>
<div className="geofenceContainerKeepOut">
<h1>Geofencing KeepOut</h1>
<input className="inputFields" type="number" name="geofenceKeepOutTop" value={checklist.geofenceKeepOutTop || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Top" />
<br />
<input className="inputFields" type="number" name="geofenceBottom" value={checklist.geofenceBottom || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Bottom" />
<input className="inputFields" type="number" name="geofenceKeepOutBottom" value={checklist.geofenceKeepOutBottom || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Bottom" />
<br />
<input className="inputFields" type="number" name="geofenceLeft" value={checklist.geofenceLeft || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Left" />
<input className="inputFields" type="number" name="geofenceKeepOutLeft" value={checklist.geofenceKeepOutLeft || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Left" />
<br />
<input className="inputFields" type="number" name="geofenceRight" value={checklist.geofenceRight || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Right" />
<CreateBoundingBoxButton theme={theme} name="geofence" value="Geofencing" />
<input className="inputFields" type="number" name="geofenceKeepOutRight" value={checklist.geofenceKeepOutRight || ''} disabled={locked.geofence} onChange={this.onChange} placeholder="Right" />
<CreateBoundingBoxButton theme={theme} name="Geofence Keep-Out" value="geofenceContainerKeepOut" color="red" />
</div>
<div className="buttonContainer">
{status === 'ready' && <button type="button" disabled={!unlockStartMissionButton} onClick={this.postStartMissions}>Start Missions</button>}
Expand Down
9 changes: 7 additions & 2 deletions src/renderer/missionWindow/extra/CreateBoundingBoxButton.tsx
Expand Up @@ -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<CreateBoundingBoxButtonProps> {
Expand All @@ -23,9 +28,9 @@ export default class CreateBoundingBoxButton extends PureComponent<CreateBoundin
}

private onClick(): void {
const { name, value } = this.props;
const { name, value, color } = this.props;
ipc.postUnlockParameterInputs(name);
ipc.postCreateBoundingBoxes({ name: value });
ipc.postCreateBoundingBoxes({ name: value, color });
}

public render(): ReactNode {
Expand Down
25 changes: 15 additions & 10 deletions src/renderer/missionWindow/mission.css
Expand Up @@ -6,14 +6,14 @@
height: 100%;
width: 100;
grid-template-areas:
'selector selector selector mapping'
'parameter parameter parameter mapping'
'parameter parameter parameter mapping'
'parameter parameter parameter mapping'
'geofence geofence geofence options'
'geofence geofence geofence options'
'button button button options';
grid-template-rows: 25px 1fr 1fr 0.8fr 1fr 0.3fr 25px;
'selector selector selector mapping'
'parameter parameter parameter mapping'
'parameter parameter parameter mapping'
'parameter parameter parameter mapping'
'geofenceKeepIn geofenceKeepIn geofenceKeepOut options'
'geofenceKeepIn geofenceKeepIn geofenceKeepOut options'
'button button button options';
grid-template-rows: 25px 1fr 1fr 1fr 1fr 0.2fr 25px;
grid-template-columns: repeat(4, 1fr);
}

Expand All @@ -27,8 +27,13 @@
padding-left: 20px;
}

.geofenceContainer {
grid-area: geofence;
.geofenceContainerKeepIn {
grid-area: geofenceContainerKeepIn;
padding-left: 20px;
}

.geofenceContainerKeepOut {
grid-area: geofenceContainerKeepOut;
padding-left: 20px;
}

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/missionWindow/parameter/VTOLSearch.tsx
Expand Up @@ -233,7 +233,7 @@ export class VTOLSearch extends Component<VTOLSearchProps, State> {
<input className="inputFields" type="number" name="quickScanLeft" value={checklist.quickScanLeft || ''} disabled={locked.quickScan} onChange={this.onChange} placeholder="Left" />
<br />
<input className="inputFields" type="number" name="quickScanRight" value={checklist.quickScanRight || ''} disabled={locked.quickScan} onChange={this.onChange} placeholder="Right" />
<CreateBoundingBoxButton theme={theme} name="quickScan" value="Bounding Box" />
<CreateBoundingBoxButton theme={theme} name="quickScan" value="Bounding Box" color="red" />
</div>
);
}
Expand Down

0 comments on commit bae005c

Please sign in to comment.