Files
walkersim/sim/mujoco/walker_sim/geometry.py

52 lines
1.3 KiB
Python

"""Geometry helpers mirrored from the web sim source drawing.
These values are copied from linkage.svg extraction and kept here to make
cross-checking with the JS model straightforward.
"""
from __future__ import annotations
from dataclasses import dataclass
from math import hypot
@dataclass(frozen=True)
class Pt:
x: float
y: float
RAW_POINTS = {
"A": Pt(78.468674, 129.90132),
"B": Pt(137.85054, 130.12675),
"O": Pt(108.00143, 129.68732),
"C0": Pt(107.73979, 134.64543),
"D0": Pt(91.864792, 153.45453),
"E0": Pt(123.05698, 152.69731),
"F0": Pt(77.341405, 173.08926),
"G0": Pt(138.20833, 172.9466),
}
def dist(a: Pt, b: Pt) -> float:
return hypot(a.x - b.x, a.y - b.y)
RAW_LEG_LENGTH = dist(RAW_POINTS["C0"], RAW_POINTS["G0"])
TARGET_LEG_LENGTH_CM = 45.0
SCALE_TO_CM = TARGET_LEG_LENGTH_CM / RAW_LEG_LENGTH
def to_meters(cm: float) -> float:
return cm / 100.0
def base_dimensions_cm() -> dict[str, float]:
"""Baseline dimensions matching src/geometry.js normalization."""
return {
"crank": dist(RAW_POINTS["O"], RAW_POINTS["C0"]) * SCALE_TO_CM,
"leg": dist(RAW_POINTS["C0"], RAW_POINTS["G0"]) * SCALE_TO_CM,
"tendon": dist(RAW_POINTS["B"], RAW_POINTS["E0"]) * SCALE_TO_CM,
"body": dist(RAW_POINTS["A"], RAW_POINTS["B"]) * SCALE_TO_CM,
}