Collision · repose-collision
Shapes & distances
All collision geometry in Repose is built from two primitives. Every query between them returns an exact signed distance.
Primitives
CuSphere { center, radius } | A ball. center: [Length; 3], radius: Length. |
CuCapsule { a, b, radius } | A sphere swept along the segment from a to b: a cylinder with hemispherical caps. A capsule with a == b is a sphere. |
CuCollisionShape | Sphere(CuSphere) or Capsule(CuCapsule). What models, scenes and checks take. |
let m = Length::new::<meter>;
let ball = CuSphere::new([m(0.4), m(0.0), m(0.3)], m(0.05))?;
let post = CuCapsule::new([m(0.6), m(0.2), m(0.0)], [m(0.6), m(0.2), m(0.8)], m(0.04))?;
let shapes = [CuCollisionShape::Sphere(ball), CuCollisionShape::Capsule(post)];The constructors reject non-finite coordinates and negative radii. shape.validate() does the same for shapes you build as struct literals or deserialize.
{"sphere": {"center": [0.4, 0.0, 0.3], "radius": 0.05}}
{"capsule": {"a": [0.6, 0.2, 0.0], "b": [0.6, 0.2, 0.8], "radius": 0.04}}Signed distance
let d = shape_signed_distance(&a, &b); // Length: surface to surfacePositive means a gap of that size, zero means touching, negative means penetration by that depth. The specialised functions sphere_sphere_signed_distance, capsule_sphere_signed_distance and capsule_capsule_signed_distance are what it dispatches to. Capsule-capsule reduces to the closest points between two segments, minus both radii.
shapes_violate_margin(a, b, margin) is the predicate checks use: true when the distance is strictly below margin.
Approximating real geometry
- Links: one capsule from joint to joint, radius covering the housing. Add a second capsule for an offset motor housing.
- Tables and walls: a large sphere far below the surface approximates a plane locally, or tile capsules along the edge you can reach.
- Boxes: capsules along the edges or spheres at the corners, sized so the union encloses the box. Over-approximate: a planner refusing a tight gap is better than a collision.
- Margins: add your positioning uncertainty to the model's
safety_marginrather than inflating every shape.
Shapes on frames
Robot and attached shapes live in a joint frame instead of the world. CuLinkShape { shape, frame } pairs a shape with a frame index (Some(i) for joint frame i, None for the base). CuLinkShape::transform_shape(..) moves a local shape into world coordinates given that frame's transform.