View the figure from a slight elevation and refine the leg-machine rollers

The default camera pitches down 10 degrees, so the floor reads as a
plane (drawn as a rectangle) and near/far contacts straddle it.
Elevation is pure presentation - IK pins solve in the flat authored
view and the posed body tilts, the same pattern as the orbit, so
authored canvas targets never go out of reach. The leg-extension
roller moves up onto the shin above the ankle and the leg-curl roller
tucks under the heel. Fixtures and reference test values regenerated
for the pitched camera.

Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
This commit is contained in:
2026-07-06 21:20:07 -04:00
parent 5e4980f0d7
commit b82054b81a
108 changed files with 838 additions and 778 deletions
+18 -13
View File
@@ -34,24 +34,27 @@ struct ExerciseMotionTests {
let frame = MotionSolver.normalize(resources.motion.frames[0])
let (resolved, geo) = MotionSolver.frameGeometry(frame, prof: resources.profile, cam: cam)
// Pins solve in the flat authored view, then the posed body tilts through the
// default camera pitch so drawn hands straddle the floor plane around their
// authored canvas targets (x exact, y shifted by each hand's depth).
let handR = try #require(geo.limbs[.armR]?.last)
#expect(abs(handR.x - 111) < 1e-3)
#expect(abs(handR.y - 154) < 1e-3)
#expect(abs(handR.x - 111) < 1e-2)
#expect(abs(handR.y - 151.391) < 1e-2)
let handL = try #require(geo.limbs[.armL]?.last)
#expect(abs(handL.x - 105) < 1e-3)
#expect(abs(handL.y - 152) < 1e-3)
#expect(abs(handL.x - 105) < 1e-2)
#expect(abs(handL.y - 153.211) < 1e-2)
#expect(abs(geo.headCenter.x - 86.195568) < 1e-4)
#expect(abs(geo.headCenter.y - 95.140457) < 1e-4)
#expect(abs(geo.headCenter.y - 95.305438) < 1e-4)
// The right arm is the far member here, so its angles solve against the
// offset target; the drawn hand still lands on the authored pin above.
// offset target; the drawn hand still lands on the authored pin (flat view).
#expect(geo.shade[.armR] == .far)
#expect(geo.shade[.armL] == .near)
#expect(abs(resolved.shoulderR.flexion - 73.289190) < 1e-4)
#expect(abs(resolved.elbowR.flexion - 17.443758) < 1e-4)
// Shoulders are wider than hips, so the arms bracket the depth order.
#expect(geo.order == ["arm_r", "leg_r", "spine", "leg_l", "arm_l", "head"])
#expect(abs(resolved.shoulderR.flexion - 73.384213) < 1e-4)
#expect(abs(resolved.elbowR.flexion - 17.076663) < 1e-4)
// Depth-sorted under the elevated camera (arm attach points are the widest).
#expect(geo.order == ["arm_r", "leg_r", "leg_l", "spine", "arm_l", "head"])
}
/// Mid-tween of resolved frames 12: a hand pinned in BOTH frames stays planted
@@ -67,12 +70,14 @@ struct ExerciseMotionTests {
#expect(mid.pins["hand_l"] == nil)
let (_, geo) = MotionSolver.frameGeometry(mid, prof: resources.profile, cam: cam)
let (_, geo0) = MotionSolver.frameGeometry(r0, prof: resources.profile, cam: cam)
let plantedHand = try #require(geo.limbs[.armR]?.last)
#expect(abs(plantedHand.x - 111) < 1e-3)
#expect(abs(plantedHand.y - 154) < 1e-3)
let plantedHand0 = try #require(geo0.limbs[.armR]?.last)
#expect(hypot(plantedHand.x - plantedHand0.x, plantedHand.y - plantedHand0.y) < 1e-3)
let releasedHand = try #require(geo.limbs[.armL]?.last)
#expect(hypot(releasedHand.x - 105, releasedHand.y - 152) > 1)
let releasedHand0 = try #require(geo0.limbs[.armL]?.last)
#expect(hypot(releasedHand.x - releasedHand0.x, releasedHand.y - releasedHand0.y) > 1)
}
/// Prop-free bodyweight motions slowly orbit the camera while looping; motions with