Skip to main content
se3labs.interface.layout

Layout

Typed declarations for planar initial layouts, realized by Shapely.

Use meters and radians in one table frame. A region constrains the object's reference point; the table boundary constrains its entire footprint.

SE2 declares a fixed pose, RandomPose a distribution, and RelativePose a relationship to an earlier object by ID. These nodes are immutable data. Declare anchors before their dependents and give each object a unique ID. Shapes must have positive dimensions; polygons may be concave and have holes. Polygon rings must form a valid Shapely geometry.

LayoutSpec.sample(seed) resolves a declaration into immutable, concrete poses. It is the only sampling entry point. Save the LayoutSample as well as its seed: changing a declaration or the sampler can change the result for the same seed. Sampling uses its own random generator and never changes Python's global random state.

Call sample.visualize("layout.png") to save a plot of the table, exclusions, and placed objects without opening a window.

Circle​

Circle(radius: float)

Disk approximated by 256 edges, with radial error below 0.008% of radius.

Attributes​

radius: float​#

Rectangle​

Rectangle(width: float, height: float)

Attributes​

width: float​#
height: float​#

Polygon​

Polygon(vertices: tuple[Point, ...], holes: tuple[tuple[Point, ...], ...] = ())

A valid Shapely polygon, with an outer boundary and optional hole rings.

Rings may be concave, must not cross themselves, and need at least three distinct vertices. Closing vertices are optional; either winding is accepted.

Attributes​

vertices: tuple[Point, ...]​#
holes: tuple[tuple[Point, ...], ...] = ()​#

Shape​

Shape: TypeAlias = Circle | Rectangle | Polygon

Point​

Point: TypeAlias = tuple[float, float]

SE2​

SE2(x: float = 0.0, y: float = 0.0, yaw: float = 0.0)

A translation and yaw about the local origin.

parent @ child expresses a child pose in the parent's frame. pose @ shape places a footprint at that pose.

Attributes​

x: float = 0.0​#
y: float = 0.0​#
yaw: float = 0.0​#

Methods​

transform(point: Point) -> Point​#

PlacedShape​

PlacedShape(shape: Shape, pose: SE2 = <factory>)

A footprint in table coordinates; also usable as a sampling region.

Attributes​

shape: Shape​#
pose: SE2 = SE2()​#

Uniform​

Uniform(low: float, high: float)

A continuous uniform distribution between low and high.

Attributes​

low: float​#
high: float​#

RandomPose​

RandomPose(region: PlacedShape, yaw: float | Uniform = <factory>)

Area-uniform position and independent yaw, expressed in the parent frame.

Rotating region rotates the position region, not the yaw distribution. Polygon holes are excluded from the sampling area.

Attributes​

region: PlacedShape​#
yaw: float | Uniform = Uniform(-pi, pi)​#

Frame​

class Frame(Enum)

Attributes​

TABLE = 'table'​#

Translate from the anchor in table axes; offset yaw is absolute.

ANCHOR = 'anchor'​#

Compose with the anchor's pose, rotating both position and yaw.

RelativePose​

RelativePose(
anchor: str,
offset: SE2 | RandomPose = <factory>,
frame: Frame = Frame.ANCHOR,
)

Attributes​

anchor: str​#

ID of an earlier object in the layout.

offset: SE2 | RandomPose = SE2()​#
frame: Frame = Frame.ANCHOR​#

PoseRule​

PoseRule: TypeAlias = SE2 | RandomPose | RelativePose

LayoutObject​

LayoutObject(
id: str,
shape: Shape,
pose: PoseRule,
label: str = '',
instruction: str = '',
)

Attributes​

id: str​#
shape: Shape​#
pose: PoseRule​#
label: str = ''​#
instruction: str = ''​#

Operator guidance for properties outside SE(2), such as 'prongs up'.

PlacedObject​

PlacedObject(id: str, shape: Shape, pose: SE2, label: str = '', instruction: str = '')

Attributes​

id: str​#
shape: Shape​#
pose: SE2​#
label: str = ''​#
instruction: str = ''​#
footprint: PlacedShape​#

Read-only property.

LayoutSpec​

LayoutSpec(
objects: tuple[LayoutObject, ...],
table: PlacedShape = SE2(0.6, 0.325) @ Rectangle(1.2, 0.65),
excluded: tuple[PlacedShape, ...] = (SE2(0.27, 0.55) @ Rectangle(0.18, 0.28), SE2(0.93, 0.55) @ Rectangle(0.18, 0.28)),
edge_clearance: float = 0.03,
clearance: float = 0.01,
)

Root declaration; sample realizes all object poses together.

Defaults describe the RoboDojo Real tabletop: 1.20 x 0.65 m, the two arm exclusions, a 3 cm edge margin, and 1 cm footprint clearance. The origin is the back-left corner, with x to the right and y toward the arms.

Attributes​

objects: tuple[LayoutObject, ...]​#
table: PlacedShape = SE2(0.6, 0.325) @ Rectangle(1.2, 0.65)​#
excluded: tuple[PlacedShape, ...] = (SE2(0.27, 0.55) @ Rectangle(0.18, 0.28), SE2(0.93, 0.55) @ Rectangle(0.18, 0.28))​#
edge_clearance: float = 0.03​#
clearance: float = 0.01​#

Minimum gap between object footprints and from objects to exclusions.

Methods​

sample(seed: int, *, max_attempts: int = 10000, accept: Callable[[LayoutSample], bool] | None = None) -> LayoutSample​#

Reject candidate scenes until one fits, or raise ValueError.

Independent absolute poses are first conditioned on the static workspace. Object collisions and failed relative placements redraw the scene, including anchors, preserving the declared joint distribution conditioned on the placement constraints. Static rejections and scene attempts both count toward max_attempts. accept can impose an additional task-specific initial-state condition. Exhaustion means no scene was found within the budget, not a proof that the declaration is impossible.

LayoutSample​

LayoutSample(
seed: int,
objects: tuple[PlacedObject, ...],
table: PlacedShape,
excluded: tuple[PlacedShape, ...],
)

Attributes​

seed: int​#
objects: tuple[PlacedObject, ...]​#
table: PlacedShape​#
excluded: tuple[PlacedShape, ...]​#

Methods​

__getitem__(object_id: str) -> PlacedObject​#
visualize(path: str | Path) -> None​#

Save the realized layout to a file without displaying a window.

The file extension selects the format, e.g. PNG, SVG, or PDF. Coordinates are meters; +y points down, matching the tabletop diagram. Arrows mark each object's local +x direction. Polygon holes stay empty.