52 lines
1.3 KiB
Python
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,
|
|
}
|