Composition and InversesΒΆ

Use spatial operations to compose poses/transforms, apply poses to points, rotate free vectors, and convert transforms into frameless pose offsets.

In Python, * composes poses/transforms or applies them to points. In TypeScript, use multiply() for composition and apply() for points. Pose * Pose chains frameless poses; Transform * Pose re-expresses a pose in a new frame; Transform * Transform chains stamped transforms when frame ids match (empty ids act as wildcards). inverse() undoes a pose or transform; for Transform the frame ids are swapped as well. as_pose() / asPose() returns the equivalent frameless Pose. Use rotate() for Vector values when translation should not be applied.

from olo.spatial import Point, Pose, Transform, Vector

# Compose frameless poses.
p1 = Pose(Point(x=0.1, y=0.0, z=0.3))
p2 = Pose(Point(x=0.0, y=0.2, z=0.0))

composed = p1 * p2
print(f"{composed = }")

# Apply a pose to a point.
transformed = p1.apply(Point(x=0.05))
print(f"{transformed = }")

# Chain stamped transforms when frame ids match.
world_to_odom = Transform(
    translation=Vector(x=1.0),
    frame_id="world",
    child_frame_id="odom",
)
odom_to_base = Transform(
    translation=Vector(y=2.0),
    frame_id="odom",
    child_frame_id="base_link",
)

world_to_base = world_to_odom * odom_to_base
print(f"{world_to_base = }")

# Invert a transform; frame ids are swapped.
base_to_tool = Transform(
    translation=Vector(z=0.12),
    frame_id="base_link",
    child_frame_id="tool0",
)

tool_to_base = base_to_tool.inverse()
print(f"{tool_to_base = }")

# Drop frame metadata for a frameless pose offset.
tool_offset = base_to_tool.as_pose()
print(f"{tool_offset = }")
import { Point, Pose, Transform, Vector } from "olo/spatial";

// Compose frameless poses.
const p1 = new Pose(new Point(0.1, 0.0, 0.3));
const p2 = new Pose(new Point(0.0, 0.2, 0.0));

const composed = p1.multiply(p2);
console.log(`composed = ${composed}`);

// Apply a pose to a point.
const transformed = p1.apply(new Point(0.05));
console.log(`transformed = ${transformed}`);

// Chain stamped transforms when frame ids match.
const worldToOdom = new Transform({
  translation: new Vector(1.0),
  frameId: "world",
  childFrameId: "odom",
});
const odomToBase = new Transform({
  translation: new Vector(0.0, 2.0),
  frameId: "odom",
  childFrameId: "base_link",
});

const worldToBase = worldToOdom.multiply(odomToBase);
console.log(`worldToBase = ${worldToBase}`);

// Invert a transform; frame ids are swapped.
const baseToTool = new Transform({
  translation: new Vector(0.0, 0.0, 0.12),
  frameId: "base_link",
  childFrameId: "tool0",
});

const toolToBase = baseToTool.inverse();
console.log(`toolToBase = ${toolToBase}`);

// Drop frame metadata for a frameless pose offset.
const toolOffset = baseToTool.asPose();
console.log(`toolOffset = ${toolOffset}`);