Skip to content
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
2 changes: 1 addition & 1 deletion docs/docs/tab-reference/3d-field/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Mechanism data can be visualized using 2D mechanisms or articulated 3D component

### 2D Mechanisms

To visualize mechanism data logged using a [`Mechanism2d`](https://docs.wpilib.org/en/stable/docs/software/dashboards/glass/mech2d-widget.html), add the mechanism field to an existing robot or ghost object. The mechanism is projected onto the XZ or YZ plane of the robot using simple boxes, as shown below. Click the gear icon or right-click on the field name to switch between the XZ and YZ planes. The robot's origin is centered on the bottom edge of the mechanism.
To visualize mechanism data logged using a [`Mechanism2d`](https://docs.wpilib.org/en/stable/docs/software/dashboards/glass/mech2d-widget.html), add the mechanism field to an existing robot or ghost object. The mechanism is projected onto the XZ or YZ plane of the robot using simple boxes, as shown below. Click the gear icon or right-click on the field name to switch between the XZ, YZ, and XY planes. The robot's origin is centered on the bottom edge of the mechanism.

![2D mechanism](./img/3d-field-2.png)

Expand Down
15 changes: 12 additions & 3 deletions src/hub/controllers/Field3dController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ export default class Field3dController implements TabController {
let components: AnnotatedPose3d[] = [];
let mechanismsXZ: MechanismState[] = [];
let mechanismsYZ: MechanismState[] = [];
let mechanismsXY: MechanismState[] = [];
let visionTargets: AnnotatedPose3d[] = [];
let swerveStates: {
values: SwerveState[];
Expand All @@ -342,7 +343,12 @@ export default class Field3dController implements TabController {
case "mechanism": {
let state = getMechanismState(window.log, child.logKey, time!);
if (state !== null) {
(child.options.plane === "yz" ? mechanismsYZ : mechanismsXZ).push(state);
(child.options.plane === "yz"
? mechanismsYZ
: child.options.plane === "xy"
? mechanismsXY
: mechanismsXZ
).push(state);
}
break;
}
Expand Down Expand Up @@ -446,6 +452,7 @@ export default class Field3dController implements TabController {
}
let mechanismXZ = mechanismsXZ.length === 0 ? null : mergeMechanismStates(mechanismsXZ);
let mechanismYZ = mechanismsYZ.length === 0 ? null : mergeMechanismStates(mechanismsYZ);
let mechanismXY = mechanismsXY.length === 0 ? null : mergeMechanismStates(mechanismsXY);
visionTargets.reverse();
swerveStates.reverse();

Expand All @@ -460,7 +467,8 @@ export default class Field3dController implements TabController {
components: components,
mechanisms: {
xz: mechanismXZ,
yz: mechanismYZ
yz: mechanismYZ,
xy: mechanismXY
},
visionTargets: visionTargets,
swerveStates: swerveStates
Expand All @@ -476,7 +484,8 @@ export default class Field3dController implements TabController {
components: components,
mechanisms: {
xz: mechanismXZ,
yz: mechanismYZ
yz: mechanismYZ,
xy: mechanismXY
},
visionTargets: visionTargets,
swerveStates: swerveStates
Expand Down
3 changes: 2 additions & 1 deletion src/hub/controllers/Field3dController_Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ const Field3dController_Config: SourceListConfig = {
showInTypeName: false,
values: [
{ key: "xz", display: "XZ Plane" },
{ key: "yz", display: "YZ Plane" }
{ key: "yz", display: "YZ Plane" },
{ key: "xy", display: "XY Plane" }
]
}
],
Expand Down
1 change: 1 addition & 0 deletions src/shared/renderers/Field3dRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export type Field3dRendererCommand_GenericRobotObj = {
mechanisms: {
xz: MechanismState | null;
yz: MechanismState | null;
xy: MechanismState | null;
};
visionTargets: AnnotatedPose3d[];
swerveStates: {
Expand Down
2 changes: 1 addition & 1 deletion src/shared/renderers/Field3dRendererImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ export default class Field3dRendererImpl implements TabRenderer {
color: "#000000",
poses: [],
components: [],
mechanisms: { xz: null, yz: null },
mechanisms: { xz: null, yz: null, xy: null },
visionTargets: [],
swerveStates: []
});
Expand Down
13 changes: 11 additions & 2 deletions src/shared/renderers/field3d/objectManagers/RobotManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default class RobotManager extends ObjectManager<
private visionLines: Line2[] = [];
private mechanismLinesXZ: MechanismLineData[] = [];
private mechanismLinesYZ: MechanismLineData[] = [];
private mechanismLinesXY: MechanismLineData[] = [];

private swerveContainer: HTMLElement | null = null;
private swerveCanvas: HTMLCanvasElement | null = null;
Expand Down Expand Up @@ -107,6 +108,7 @@ export default class RobotManager extends ObjectManager<
});
this.mechanismLinesXZ.forEach((entry) => entry.mesh.dispose());
this.mechanismLinesYZ.forEach((entry) => entry.mesh.dispose());
this.mechanismLinesXY.forEach((entry) => entry.mesh.dispose());
while (this.visionLines.length > 0) {
this.visionLines[0].geometry.dispose();
this.visionLines[0].material.dispose();
Expand Down Expand Up @@ -435,7 +437,7 @@ export default class RobotManager extends ObjectManager<
}

// Update mechanism
let updateMechanism = (state: MechanismState | null, lines: MechanismLineData[], plane: "xz" | "yz") => {
let updateMechanism = (state: MechanismState | null, lines: MechanismLineData[], plane: "xz" | "yz" | "xy") => {
if (state === null) {
// No mechanism data, remove all meshes
while (lines.length > 0) {
Expand Down Expand Up @@ -507,10 +509,16 @@ export default class RobotManager extends ObjectManager<
.map((x) => x.pose)
.map((robotPose) => {
this.dummyRobotPose.rotation.setFromQuaternion(rotation3dToQuaternion(robotPose.rotation));
// default plane is xz
if (plane === "yz") this.dummyRobotPose.rotateZ(Math.PI / 2);
if (plane === "xy") this.dummyRobotPose.rotateX(Math.PI / -2);
this.dummyRobotPose.position.set(...robotPose.translation);

this.dummyUserPose.position.set(line.start[0] - state.dimensions[0] / 2, 0, line.start[1]);
this.dummyUserPose.position.set(
line.start[0] - (plane === "xy" ? 0 : state.dimensions[0] / 2),
0,
line.start[1]
);
this.dummyUserPose.rotation.set(0, -angle, 0);
return {
translation: this.dummyUserPose.getWorldPosition(new THREE.Vector3()).toArray(),
Expand All @@ -523,6 +531,7 @@ export default class RobotManager extends ObjectManager<
};
updateMechanism(object.mechanisms.xz, this.mechanismLinesXZ, "xz");
updateMechanism(object.mechanisms.yz, this.mechanismLinesYZ, "yz");
updateMechanism(object.mechanisms.xy, this.mechanismLinesXY, "xy");

// Update swerve canvas (disabled in XR)
if (!this.isXR) {
Expand Down
2 changes: 1 addition & 1 deletion src/xrClient/XRRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ export default class XRRenderer {
color: "#000000",
poses: [],
components: [],
mechanisms: { xz: null, yz: null },
mechanisms: { xz: null, yz: null, xy: null },
visionTargets: [],
swerveStates: []
});
Expand Down