Skip to content

Field overlay view layer for keep in/out zones #915

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
59 changes: 39 additions & 20 deletions src/components/field/svg/FieldOverlayRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ class FieldOverlayRoot extends Component<Props, State> {
<FieldImage2024 />
</>
)}


{layers[ViewLayers.Grid] && <FieldGrid></FieldGrid>}
{/* Waypoint mouse capture*/}

Expand Down Expand Up @@ -304,7 +306,6 @@ class FieldOverlayRoot extends Component<Props, State> {
</div>
</Popover>
)}

{layers[ViewLayers.Waypoints] &&
uiState.isNavbarWaypointSelected() && (
<circle
Expand All @@ -326,6 +327,43 @@ class FieldOverlayRoot extends Component<Props, State> {
{layers[ViewLayers.Samples] && layers[ViewLayers.Trajectory] && (
<FieldGeneratedWaypoints></FieldGeneratedWaypoints>
)}
{/* Display field zones */}
{layers[ViewLayers.Zones] &&
doc.pathlist.activePath.params.constraints
.filter((c) => c.enabled)
.map((c) => {
return (
<FieldConstraintDisplayLayer
points={doc.pathlist.activePath.params.waypoints}
constraint={c as IConstraintStoreKeyed<ConstraintKey>}
lineColor={c.selected ? "var(--select-yellow)":"transparent"}
clickable= {c.selected || !(uiState.layers[ViewLayers.Waypoints] &&
uiState.isNavbarWaypointSelected())}
></FieldConstraintDisplayLayer>
);
})}

{!layers[ViewLayers.Zones] && doc.isSidebarConstraintSelected && (
<FieldConstraintDisplayLayer
points={doc.pathlist.activePath.params.waypoints}
constraint={
doc.selectedSidebarItem as IConstraintStoreKeyed<ConstraintKey>
}
lineColor="var(--select-yellow)"
clickable={true}
></FieldConstraintDisplayLayer>
)}
{!doc.isSidebarConstraintSelected &&
doc.isSidebarConstraintHovered && (
<FieldConstraintDisplayLayer
points={doc.pathlist.activePath.params.waypoints}
constraint={
doc.hoveredSidebarItem as IConstraintStoreKeyed<ConstraintKey>
}
lineColor="white"
clickable={false}
></FieldConstraintDisplayLayer>
)}
<FieldEventMarkers></FieldEventMarkers>
{layers[ViewLayers.Waypoints] &&
doc.pathlist.activePath.params.waypoints
Expand Down Expand Up @@ -364,26 +402,7 @@ class FieldOverlayRoot extends Component<Props, State> {
{eventMarkerSelected && (
<FieldEventMarkerAddLayer></FieldEventMarkerAddLayer>
)}
{doc.isSidebarConstraintSelected && (
<FieldConstraintDisplayLayer
points={doc.pathlist.activePath.params.waypoints}
constraint={
doc.selectedSidebarItem as IConstraintStoreKeyed<ConstraintKey>
}
lineColor="var(--select-yellow)"
></FieldConstraintDisplayLayer>
)}

{!doc.isSidebarConstraintSelected &&
doc.isSidebarConstraintHovered && (
<FieldConstraintDisplayLayer
points={doc.pathlist.activePath.params.waypoints}
constraint={
doc.hoveredSidebarItem as IConstraintStoreKeyed<ConstraintKey>
}
lineColor="white"
></FieldConstraintDisplayLayer>
)}
{layers[ViewLayers.Trajectory] && (
<InterpolatedRobot
timestamp={uiState.pathAnimationTimestamp}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@
import KeepOutCircleOverlay from "./KeepOutCircleOverlay";
import { IHolonomicWaypointStore } from "../../../../document/HolonomicWaypointStore";
import KeepInLaneOverlay from "./KeepInLaneOverlay";
import { IConstraintDataStore } from "../../../../document/ConstraintDataStore";

export type OverlayProps<K extends keyof ConstraintDataTypeMap> = {
data: IConstraintStoreKeyed<K>;
start: IHolonomicWaypointStore;
end: IHolonomicWaypointStore;
lineColor: string;
select: ()=>void;
clickable: boolean;
};
export type OverlayElementProps<K extends keyof ConstraintDataTypeMap> = {
data: IConstraintDataStore<K>;
start?: IHolonomicWaypointStore;
end?: IHolonomicWaypointStore;
selected: boolean;
select: ()=>void;
clickable: boolean;
};
const overlays = {
PointAt: (props: OverlayProps<"PointAt">) => (
Expand All @@ -26,37 +37,49 @@
start={props.start}
end={props.end}
lineColor={props.lineColor}
selected={props.data.selected}
select={()=>{props.data.setSelected(true)}}
clickable={props.clickable}
></PointAtOverlay>
),
KeepInCircle: (props: OverlayProps<"KeepInCircle">) => (
<KeepInCircleOverlay
data={props.data.data}
start={props.start}
end={props.end}
lineColor={props.lineColor}
selected={props.data.selected}
select={()=>{props.data.setSelected(true)}}
clickable={props.clickable}
></KeepInCircleOverlay>
),
KeepInRectangle: (props: OverlayProps<"KeepInRectangle">) => (
<KeepInRectangleOverlay
data={props.data.data}
start={props.start}
end={props.end}
lineColor={props.lineColor}
selected={props.data.selected}
select={()=>{props.data.setSelected(true)}}
clickable={props.clickable}
></KeepInRectangleOverlay>
),
KeepInLane: (props: OverlayProps<"KeepInLane">) => (
<KeepInLaneOverlay
data={props.data.data}
start={props.start}
end={props.end}
selected={props.data.selected}
select={()=>{props.data.setSelected(true)}}
clickable={props.clickable}
></KeepInLaneOverlay>
),
KeepOutCircle: (props: OverlayProps<"KeepOutCircle">) => (
<KeepOutCircleOverlay
data={props.data.data}
start={props.start}
end={props.end}
lineColor={props.lineColor}
selected={props.data.selected}
select={()=>{props.data.setSelected(true)}}
clickable={props.clickable}
></KeepOutCircleOverlay>
),
StopPoint: () => <></>,
Expand All @@ -70,6 +93,7 @@
constraint?: IConstraintStoreKeyed<ConstraintKey>;
points: IHolonomicWaypointStore[];
lineColor: string;
clickable: boolean;
};
function FieldConstraintDisplayLayer(props: Props) {
const constraint = props.constraint;
Expand All @@ -82,19 +106,20 @@
data: constraint,
start: constraint.getStartWaypoint(props.points),
end: constraint.getEndWaypoint(props.points),
lineColor: props.lineColor
lineColor: props.lineColor,
clickable: props.clickable
};
if (startIndex === undefined) {
return <></>;
}
return (
<g>
<g key={props.constraint?.uuid ?? "undef"} style={{zIndex: constraint.selected ? "999" : undefined}}>
<FieldConstraintRangeLayer
points={doc.pathlist.activePath.params.waypoints}
start={startIndex}
end={endIndex}
lineColor={props.lineColor}
id="display"
id={"display"+props.constraint?.uuid ?? "undef"}

Check failure on line 122 in src/components/field/svg/constraintDisplay/FieldConstraintDisplayLayer.tsx

View workflow job for this annotation

GitHub Actions / TypeScript compiler

Right operand of ?? is unreachable because the left operand is never nullish.
></FieldConstraintRangeLayer>
{overlays[constraint.data.type](
// @ts-expect-error can't cast the constraint as the proper type.
Expand Down
65 changes: 39 additions & 26 deletions src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import * as d3 from "d3";
import { observer } from "mobx-react";
import React, { Component } from "react";
import { IConstraintDataStore } from "../../../../document/ConstraintDataStore";

Check failure on line 4 in src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx

View workflow job for this annotation

GitHub Actions / Format

'IConstraintDataStore' is defined but never used. Allowed unused vars must match /^_/u
import {
ConstraintKey,

Check failure on line 6 in src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx

View workflow job for this annotation

GitHub Actions / Format

'ConstraintKey' is defined but never used. Allowed unused vars must match /^_/u
DataMap
} from "../../../../document/ConstraintDefinitions";
import { doc } from "../../../../document/DocumentManager";
import { doc, uiState } from "../../../../document/DocumentManager";

Check failure on line 9 in src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx

View workflow job for this annotation

GitHub Actions / Format

'uiState' is defined but never used. Allowed unused vars must match /^_/u
import { IHolonomicWaypointStore } from "../../../../document/HolonomicWaypointStore";

Check failure on line 10 in src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx

View workflow job for this annotation

GitHub Actions / Format

'IHolonomicWaypointStore' is defined but never used. Allowed unused vars must match /^_/u
import { ViewLayers } from "../../../../document/UIData";

Check failure on line 11 in src/components/field/svg/constraintDisplay/KeepInCircleOverlay.tsx

View workflow job for this annotation

GitHub Actions / Format

'ViewLayers' is defined but never used. Allowed unused vars must match /^_/u
import { OverlayElementProps } from "./FieldConstraintDisplayLayer";

const STROKE = 0.1;
const DOT = 0.1;
const SELECT_COLOR = "var(--select-yellow)";
const MOVABLE_COLOR = "green";
const IMMOVABLE_COLOR = "darkseagreen";

type Props<K extends ConstraintKey> = {
data: IConstraintDataStore<K>;
start?: IHolonomicWaypointStore;
end?: IHolonomicWaypointStore;
lineColor: string;
};
class KeepInCircleOverlay extends Component<Props<"KeepInCircle">, object> {
class KeepInCircleOverlay extends Component<OverlayElementProps<"KeepInCircle">, object> {
id = crypto.randomUUID();
rootRef: React.RefObject<SVGGElement> = React.createRef<SVGGElement>();
componentDidMount() {
if (this.rootRef.current) {
Expand All @@ -27,66 +27,79 @@
.on("drag", (event) => this.dragPointTranslate(event))
.on("start", () => {
doc.history.startGroup(() => {});
this.props.select()
})
.on("end", (_event) => doc.history.stopGroup())
.container(this.rootRef.current);
d3.select<SVGCircleElement, undefined>(`#dragTarget-keepInCircle`).call(
dragHandleDrag
);
d3.select<SVGCircleElement, undefined>(
`#dragTarget-keepInCircleDot`
`#dragTarget-keepInCircle` + this.id
).call(dragHandleDrag);
d3.select<SVGCircleElement, undefined>(
`#dragTarget-keepInCircleDot` + this.id
).call(dragHandleDrag);
const radiusHandleDrag = d3
.drag<SVGCircleElement, undefined>()
.on("drag", (event) => this.dragPointRadius(event))
.on("start", () => {
doc.history.startGroup(() => {});
this.props.select();
})
.on("end", (_event) => doc.history.stopGroup())
.container(this.rootRef.current);
d3.select<SVGCircleElement, undefined>(
`#dragRadiusTarget-keepInCircle`
`#dragRadiusTarget-keepInCircle` + this.id
).call(radiusHandleDrag);
}
}

dragPointTranslate(event: any) {
this.props.data.x.set(this.props.data.serialize.props.x.val + event.dx);
this.props.data.y.set(this.props.data.serialize.props.y.val + event.dy);
this.props.data.x.set(this.props.data.serialize.props.x.val + event.dx);
this.props.data.y.set(this.props.data.serialize.props.y.val + event.dy);
}

dragPointRadius(event: any) {
const dx = event.x - this.props.data.serialize.props.x.val;
const dy = event.y - this.props.data.serialize.props.y.val;
const r = Math.sqrt(dx * dx + dy * dy);
const dx = event.x - this.props.data.serialize.props.x.val;
const dy = event.y - this.props.data.serialize.props.y.val;
const r = Math.sqrt(dx * dx + dy * dy);

this.props.data.r.set(r);
this.props.data.r.set(r);
}

getColor() : string {
if (this.props.selected) return SELECT_COLOR;
if (this.props.clickable) return MOVABLE_COLOR;
return IMMOVABLE_COLOR;
}
render() {
const data = this.props.data.serialize as DataMap["KeepInCircle"];
const x = data.props.x.val;
const y = data.props.y.val;
const r = data.props.r.val;
const color = this.getColor();
return (
<g ref={this.rootRef}>
<g ref={this.rootRef} onClick={
() => {
if (this.props.clickable) this.props.select();
}}>
{/* Main Circle */}
<circle
cx={x}
cy={y}
r={r - STROKE / 2}
fill={"green"}
fill={color}
fillOpacity={0.1}
id="dragTarget-keepInCircle"
id={"dragTarget-keepInCircle" + this.id}
pointerEvents={"visibleStroke"}
></circle>
{/* Center Dot */}
<circle
cx={x}
cy={y}
r={r < DOT * 2 ? 0.0 : DOT}
fill={"green"}
fill={color}
fillOpacity={1.0}
id="dragTarget-keepInCircleDot"
id={"dragTarget-keepInCircleDot" + this.id}
pointerEvents={"visible"}
></circle>
{/* Radius Handle */}
<circle
Expand All @@ -95,10 +108,10 @@
r={r - STROKE / 2}
fill={"transparent"}
pointerEvents={"visibleStroke"}
stroke={"green"}
stroke={color}
strokeWidth={STROKE}
strokeOpacity={1.0}
id="dragRadiusTarget-keepInCircle"
id={"dragRadiusTarget-keepInCircle" + this.id}
></circle>
</g>
);
Expand Down
Loading
Loading