Skip to content

Commit 5d3df26

Browse files
Height Limit Penalty [AARD-1999] (#1230)
Co-authored-by: Alexey Dmitriev <157652245+AlexD717@users.noreply.github.com> Co-authored-by: Brandon Pacewic <92102436+BrandonPacewic@users.noreply.github.com>
2 parents d2df0f2 + a35eb00 commit 5d3df26

File tree

15 files changed

+466
-27
lines changed

15 files changed

+466
-27
lines changed

fission/src/mirabuf/MirabufSceneObject.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,101 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
632632
return box
633633
}
634634

635+
/**
636+
* Gets the maximum dimensions (length, width, height) of the mirabuf object.
637+
*
638+
* @returns An object containing the width (x), height (y), and depth (z) dimensions in meters.
639+
*/
640+
public getDimensions(): { width: number; height: number; depth: number } {
641+
const boundingBox = this.computeBoundingBox()
642+
const size = new THREE.Vector3()
643+
boundingBox.getSize(size)
644+
645+
return {
646+
width: size.x,
647+
height: size.y,
648+
depth: size.z,
649+
}
650+
}
651+
652+
/**
653+
* Calculates the robot's dimensions as if it had no rotation applied.
654+
*
655+
* @returns the object containing the width (x), height (y), and depth (z) dimensions in meters.
656+
*/
657+
public getDimensionsWithoutRotation(): { width: number; height: number; depth: number } {
658+
const rootNodeId = this.getRootNodeId()
659+
if (!rootNodeId) {
660+
console.warn("No root node found for robot, using regular dimensions")
661+
return this.getDimensions()
662+
}
663+
664+
const rootBody = World.physicsSystem.getBody(rootNodeId)
665+
const rootTransform = convertJoltMat44ToThreeMatrix4(rootBody.GetWorldTransform())
666+
667+
const rootPosition = new THREE.Vector3()
668+
const rootRotation = new THREE.Quaternion()
669+
const rootScale = new THREE.Vector3()
670+
rootTransform.decompose(rootPosition, rootRotation, rootScale)
671+
672+
// Create inverse rotation matrix to "undo" the robot's rotation
673+
const inverseRotation = new THREE.Matrix4().makeRotationFromQuaternion(rootRotation.clone().invert())
674+
675+
const unrotatedBox = new THREE.Box3()
676+
677+
this._mirabufInstance.parser.rigidNodes.forEach(rigidNode => {
678+
const bodyId = this._mechanism.getBodyByNodeId(rigidNode.id)
679+
if (!bodyId) return
680+
681+
const body = World.physicsSystem.getBody(bodyId)
682+
const bodyTransform = convertJoltMat44ToThreeMatrix4(body.GetWorldTransform())
683+
684+
const shape = body.GetShape()
685+
const scale = new JOLT.Vec3(1, 1, 1)
686+
const triangleContext = new JOLT.ShapeGetTriangles(
687+
shape,
688+
JOLT.AABox.prototype.sBiggest(),
689+
shape.GetCenterOfMass(),
690+
JOLT.Quat.prototype.sIdentity(),
691+
scale
692+
)
693+
694+
try {
695+
const vertices = new Float32Array(
696+
JOLT.HEAP32.buffer,
697+
triangleContext.GetVerticesData(),
698+
triangleContext.GetVerticesSize() / Float32Array.BYTES_PER_ELEMENT
699+
)
700+
701+
for (let i = 0; i < vertices.length; i += 3) {
702+
const vertex = new THREE.Vector3(vertices[i], vertices[i + 1], vertices[i + 2])
703+
704+
vertex.applyMatrix4(bodyTransform).applyMatrix4(inverseRotation)
705+
706+
unrotatedBox.expandByPoint(vertex)
707+
}
708+
} finally {
709+
JOLT.destroy(triangleContext)
710+
JOLT.destroy(scale)
711+
}
712+
})
713+
714+
// Fallback if no vertices were processed
715+
if (unrotatedBox.isEmpty()) {
716+
console.warn("Could not process physics shapes, using regular dimensions")
717+
return this.getDimensions()
718+
}
719+
720+
const unrotatedSize = new THREE.Vector3()
721+
unrotatedBox.getSize(unrotatedSize)
722+
723+
return {
724+
width: unrotatedSize.x,
725+
height: unrotatedSize.y,
726+
depth: unrotatedSize.z,
727+
}
728+
}
729+
635730
/**
636731
* Once a gizmo is created and attached to this mirabuf object, this will be executed to align the gizmo correctly.
637732
*

fission/src/systems/World.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import PhysicsSystem from "./physics/PhysicsSystem"
66
import DragModeSystem from "./scene/DragModeSystem"
77
import SceneRenderer from "./scene/SceneRenderer"
88
import SimulationSystem from "./simulation/SimulationSystem"
9+
import RobotDimensionTracker from "./match_mode/RobotDimensionTracker"
910

1011
class World {
1112
private static _isAlive: boolean = false
@@ -116,6 +117,8 @@ class World {
116117

117118
World._analyticsSystem?.update(this._currentDeltaT)
118119
World._performanceMonitorSystem?.update(this._currentDeltaT)
120+
121+
RobotDimensionTracker.update(World._sceneRenderer)
119122
}
120123

121124
public static get currentDeltaT(): number {

fission/src/systems/input/InputSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { KeyCode } from "@/systems/input/KeyboardTypes.ts"
2-
import MatchMode, { MatchModeType } from "@/systems/MatchMode"
2+
import MatchMode, { MatchModeType } from "@/systems/match_mode/MatchMode"
33
import { DriveType } from "@/systems/simulation/behavior/Behavior.ts"
44
import { TouchControlsAxes } from "@/ui/components/TouchControls"
55
import Joystick from "../scene/Joystick"

fission/src/systems/DefaultMatchModeConfigs.ts renamed to fission/src/systems/match_mode/DefaultMatchModeConfigs.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { MatchModeConfig } from "@/ui/panels/configuring/MatchModeConfigPanel"
2+
import { convertFeetToMeters } from "@/util/UnitConversions"
23

34
/** The purpose of this class is to store any defaults related to match mode configurations. */
45
class DefaultMatchModeConfigs {
@@ -10,6 +11,9 @@ class DefaultMatchModeConfigs {
1011
autonomousTime: 15,
1112
teleopTime: 135,
1213
endgameTime: 20,
14+
ignoreRotation: true,
15+
maxHeight: Infinity,
16+
heightPenalty: 0,
1317
}
1418
}
1519

@@ -21,6 +25,9 @@ class DefaultMatchModeConfigs {
2125
autonomousTime: 15,
2226
teleopTime: 135,
2327
endgameTime: 20,
28+
ignoreRotation: true,
29+
maxHeight: convertFeetToMeters(4),
30+
heightPenalty: 2,
2431
}
2532
}
2633

@@ -32,6 +39,9 @@ class DefaultMatchModeConfigs {
3239
autonomousTime: 15,
3340
teleopTime: 135,
3441
endgameTime: 30,
42+
ignoreRotation: true,
43+
maxHeight: convertFeetToMeters(6.5),
44+
heightPenalty: 5,
3545
}
3646
}
3747

@@ -43,6 +53,9 @@ class DefaultMatchModeConfigs {
4353
autonomousTime: 5,
4454
teleopTime: 15,
4555
endgameTime: 5,
56+
ignoreRotation: true,
57+
maxHeight: Infinity,
58+
heightPenalty: 0,
4659
}
4760
}
4861

fission/src/systems/MatchMode.ts renamed to fission/src/systems/match_mode/MatchMode.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import SimulationSystem from "../simulation/SimulationSystem"
2+
import { MatchModeConfig } from "@/ui/panels/configuring/MatchModeConfigPanel"
3+
import { SoundPlayer } from "../sound/SoundPlayer"
14
import beep from "@/assets/sound-files/beep.wav"
25
import MatchEnd from "@/assets/sound-files/MatchEnd.wav"
36
import MatchResume from "@/assets/sound-files/MatchResume.wav"
7+
import RobotDimensionTracker from "./RobotDimensionTracker"
48
import MatchStart from "@/assets/sound-files/MatchStart.wav"
5-
import { MatchModeConfig } from "@/ui/panels/configuring/MatchModeConfigPanel"
6-
import SimulationSystem from "./simulation/SimulationSystem"
7-
import { SoundPlayer } from "./sound/SoundPlayer"
89

910
export enum MatchModeType {
1011
SANDBOX = 0,
@@ -17,6 +18,9 @@ export enum MatchModeType {
1718
export const DEFAULT_AUTONOMOUS_TIME = 15
1819
export const DEFAULT_TELEOP_TIME = 135
1920
export const DEFAULT_ENDGAME_TIME = 20
21+
export const DEFAULT_IGNORE_ROTATION = true
22+
export const DEFAULT_MAX_HEIGHT = Infinity
23+
export const DEFAULT_HEIGHT_PENALTY = 2
2024

2125
class MatchMode {
2226
private static _instance: MatchMode
@@ -39,6 +43,9 @@ class MatchMode {
3943
autonomousTime: DEFAULT_AUTONOMOUS_TIME,
4044
teleopTime: DEFAULT_TELEOP_TIME,
4145
endgameTime: DEFAULT_ENDGAME_TIME,
46+
ignoreRotation: DEFAULT_IGNORE_ROTATION,
47+
maxHeight: DEFAULT_MAX_HEIGHT,
48+
heightPenalty: DEFAULT_HEIGHT_PENALTY,
4249
}
4350

4451
private constructor() {}
@@ -50,6 +57,7 @@ class MatchMode {
5057

5158
setMatchModeConfig(config: MatchModeConfig) {
5259
this._matchModeConfig = config
60+
RobotDimensionTracker.setConfigValues(config.ignoreRotation, config.maxHeight, config.heightPenalty)
5361
}
5462

5563
startTimer(duration: number, functionCall: () => void, updateTimeLeft: boolean = true) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
2+
import { MiraType } from "@/mirabuf/MirabufLoader"
3+
import SceneRenderer from "../scene/SceneRenderer"
4+
import MatchMode from "./MatchMode"
5+
import SimulationSystem from "@/systems/simulation/SimulationSystem"
6+
7+
const BUFFER_HEIGHT = 0.1
8+
9+
class RobotDimensionTracker {
10+
private static _robotLastFramePenalty: Map<number, boolean> = new Map()
11+
private static _ignoreRotation: boolean = true
12+
private static _maxHeight: number = Infinity
13+
private static _heightPenalty: number = 0
14+
15+
public static setConfigValues(ignoreRotation: boolean, maxHeight: number, heightPenalty: number) {
16+
this._ignoreRotation = ignoreRotation
17+
this._maxHeight = maxHeight
18+
this._heightPenalty = heightPenalty
19+
}
20+
21+
public static update(sceneRenderer: SceneRenderer): void {
22+
if (!MatchMode.getInstance().isMatchEnabled()) return
23+
24+
const robots = [...sceneRenderer.sceneObjects.values()].filter(
25+
(obj): obj is MirabufSceneObject => obj instanceof MirabufSceneObject && obj.miraType === MiraType.ROBOT
26+
)
27+
28+
robots.forEach(robot => {
29+
const dimensions = this._ignoreRotation ? robot.getDimensionsWithoutRotation() : robot.getDimensions()
30+
31+
if (dimensions.height > this._maxHeight + BUFFER_HEIGHT) {
32+
if (!(this._robotLastFramePenalty.get(robot.id) ?? false)) {
33+
SimulationSystem.robotPenalty(robot, this._heightPenalty, "Height Expansion Limit")
34+
}
35+
this._robotLastFramePenalty.set(robot.id, true)
36+
} else {
37+
this._robotLastFramePenalty.set(robot.id, false)
38+
}
39+
})
40+
}
41+
}
42+
43+
export default RobotDimensionTracker

0 commit comments

Comments
 (0)