routing.core.geometry#
Routing geometry primitives: the voxel frame (world/grid chart) and shapes that voxelize themselves into it.
- class routing.core.geometry.Box(minimums: ndarray, maximums: ndarray)[source]#
Bases:
RoutingShapeA class to handle boxes in routing context.
- property bounding_box: ndarray#
Box vertices as
[minimums, maximums].
- property center: ndarray#
Box geometric center.
- contains(points: ndarray) ndarray[source]#
Whether each of
points(n, 3)lies in the box, its faces included.
- classmethod cubes_at(centers: ndarray, edge: float, color: tuple = (0.5, 0.5, 0.5), alpha: float = 1.0) list[Solid][source]#
Render one cube solid of side
edgecentred on each ofcenters.- Parameters:
centers – World centres, as any array of
(x, y, z)rows.edge – The side of every cube.
- classmethod from_bounding_box(bounding_box: ndarray) Box[source]#
Create a box from its extreme vertices.
- grown(margin: float | ndarray) Box[source]#
Give the box widened by
marginon each of its six faces, one value per axis or one for all.
- maximums: ndarray#
- meets(boxes: ndarray) ndarray[source]#
Whether each of
boxes,(n, 2, 3)lowest and highest corners, shares a point with this box.
- minimums: ndarray#
- property origin: ndarray#
Box origin (min corner).
- property points: ndarray#
All box’s points.
- property size: ndarray#
Box extent along each axis.
- property size_x: float#
Box extent along x.
- property size_y: float#
Box extent along y.
- property size_z: float#
Box extent along z.
- volmdlr_primitive(color: tuple = (0.5, 0.5, 0.5), alpha: float = 1.0) Solid[source]#
Render this box as a volmdlr CAD solid.
- property volume: float#
The volume of the box.
- voxelize_into(volume: ndarray, frame: VoxelFrame, dilation_radius: float = 0) None[source]#
Fill the index block the box spans, widened by
dilation_radiusand clipped to the grid.- Parameters:
volume – The grid to write into.
frame – The chart
volumeis sampled on.dilation_radius – Extra half-width in voxel units (expands the filled index range).
- class routing.core.geometry.Cylinder(start: ndarray, end: ndarray, radius: float)[source]#
Bases:
RoutingShapeA class to handle cylinders in routing context.
- ball_radius(voxel_size: float, dilation_radius: float = 0) int[source]#
Integer thickening radius in voxels:
ceil(radius + dilation).The thickening ball needs an INTEGER radius: a non-integer yields an even-sized footprint with no centre voxel, so thickening shifts the tube half a voxel off the fiber and brings the skeletonization vanish straight back.
- property bounding_box: ndarray#
Get the bounding box of the cylinder.
- end: ndarray#
- fiber_indices(frame: VoxelFrame) ndarray[source]#
Voxel-snapped Bresenham rasterization of the axis (neutral fiber), clipped to the grid.
- property length: float#
Cylinder axis length.
- radius: float#
- start: ndarray#
- volmdlr_primitive(color: tuple = (0.5, 0.5, 0.5), alpha: float = 1.0) Cylinder[source]#
Render this cylinder as a volmdlr CAD primitive.
- voxelize_into(volume: ndarray, frame: VoxelFrame, dilation_radius: float = 0) None[source]#
Rasterize the axis (neutral fiber) via Bresenham, then thicken it into an exact-Euclidean-ball tube.
- class routing.core.geometry.OrientedBox(origin: ndarray, axes: ndarray, extent: Box)[source]#
Bases:
RoutingShapeA box lying in a frame of its own: the tightest box around points, seen from there.
An oriented box is an aligned one seen from its frame, so it carries that frame and the
Boxit spans in it. A shape lying along a diagonal keeps a tight box, where a world-aligned one would swallow the space around it.- Parameters:
origin – Where the frame sits in the world.
axes – The frame’s three unit axes, as columns.
extent – The box the shape spans in that frame.
- axes: ndarray#
- bounding_box() ndarray[source]#
Axis-aligned bounding box of the eight vertices, as
[minimums, maximums].
- cells(frame: VoxelFrame, dilation_radius: float = 0) ndarray[source]#
Give the cells of
framewhose centre lies in the box, widened bydilation_radiusvoxels.The candidates are read off the aligned block the box spans, so an oblique box costs its own neighbourhood and not the grid.
- contains(points: ndarray) ndarray[source]#
Whether each of
points(n, 3)lies in the box, its faces included.
- classmethod from_points(points: ndarray, origin: ndarray, axes: ndarray) OrientedBox[source]#
Build the tightest box around
pointsin the frame(origin, axes).
- grown(margin: float | ndarray) OrientedBox[source]#
Give the box widened by
marginon each of its six faces, one value per axis or one for all.
- origin: ndarray#
- property points: ndarray#
The box’s eight vertices, in the world.
- voxelize_into(volume: ndarray, frame: VoxelFrame, dilation_radius: float = 0) None[source]#
Fill the cells whose centre lies in the box, widened by
dilation_radiusvoxels.
- class routing.core.geometry.Polyline(points: ndarray)[source]#
Bases:
RoutingShapeAn ordered sequence of points forming a broken line in 3D.
- property bounding_box: ndarray#
Polyline AABB as
[minimums, maximums].
- property length: float#
Sum of segment lengths.
- local_angles(tangent_window: int) ndarray[source]#
Per-vertex bending angle measured over a
tangent_window-step neighborhood.Returns an array of length
len(points). NaN at vertices closer thantangent_windowfrom the endpoints (no back/forward tangent available) or where back/forward is degenerate (zero-length).
- points: ndarray#
- to_cylinders(radius: float = 1e-06) list[Cylinder][source]#
One cylinder per segment, all of
radius; degenerate segments are dropped.- Parameters:
radius – A polyline carries no thickness of its own, so this states the scale it should be seen at; the default draws it as a hairline.
- turn_indices(tangent_window: int, min_turn_angle: float) list[int][source]#
Interior indices where
local_angles()peaks abovemin_turn_angle.Detected turns are at least
tangent_windowapart so a single messy corner yields a single cut.
- voxelize_into(volume: ndarray, frame: VoxelFrame, dilation_radius: float = 0) None[source]#
Rasterize each segment via Bresenham, then dilate over the polyline’s own bounding window.
- class routing.core.geometry.RoutingShape[source]#
Bases:
ABCA class to handle shapes in routing context.
- voxelize(frame: VoxelFrame, dilation_radius: float = 0) ndarray[source]#
Boolean mask of the
framevoxels intersecting the shape, on a grid of its own.
- abstractmethod voxelize_into(volume: ndarray, frame: VoxelFrame, dilation_radius: float = 0) None[source]#
Add this shape’s voxels to
volume, sampled onframe, touching only the cells the shape occupies.
- class routing.core.geometry.VoxelFrame(origin: tuple[float, float, float], voxel_size: float, shape: tuple[int, int, int])[source]#
Bases:
objectWhere a voxel grid sits in space: its origin, its step and its extent.
The one chart between world coordinates and grid indices, shared by everything shaped like a grid — a voxelization’s matrix, a pathfinding grid’s nodes, a region’s fields. Its distinct roundings are distinct operations: the voxel nearest to a point (
nearest_indices()), the exact fractional position (fractional_indices()), and the covering bounds of a world box (floor_indices()/ceil_indices()).- Parameters:
origin – The centre of voxel (0, 0, 0) in world coordinates.
voxel_size – The edge length of a voxel, in world units.
shape – The grid extent in voxels per axis.
- ceil_indices(points: ndarray) ndarray[source]#
Lowest voxel indices at or above world
points— the upper bound of a covering window.
- cells_covered_by(coarser: VoxelFrame, indices: ndarray) ndarray[source]#
Give the cells of this frame whose centre lies in the voxels
indices(N, 3)of thecoarserframe.The multi-scale map anchors its grids on one centre and refines by an odd factor, so a coarse voxel covers a block of cells centred on its own centre; a frame covers itself cell for cell. Not clipped.
- center(index: tuple[int, int, int] | ndarray) tuple[float, float, float][source]#
World centre of the single voxel at
index, as a plain float tuple.
- centers(indices: ndarray) ndarray[source]#
World centres of the voxels at integer or fractional
indices,(3,)or(N, 3).
- contains(points: ndarray) ndarray[source]#
Whether world
points,(3,)or(N, 3), fall inside the grid’s extent — the outer faces of its boundary voxels.
- cylindrical_window(start: ndarray, end: ndarray, half_width: float) tuple[ndarray, ndarray, ndarray][source]#
Dense grid window around the
[start, end]segment, in cylindrical coordinates.Covers the axis-aligned box enclosing the segment inflated by
half_width, clipped to the grid. Radial distances and abscissas are separable along the grid axes, so no per-voxel point array is ever built.- Returns:
Tuple
(lower (3,) int, radial_distances (ni, nj, nk), abscissas (ni, nj, nk))— the window’s lower corner index and, per window voxel, the world distance to the segment’s supporting line and the world abscissa along it (0 atstart). Empty arrays when the window misses the grid.
- floor_indices(points: ndarray) ndarray[source]#
Highest voxel indices at or below world
points— the lower bound of a covering window.
- fractional_indices(points: ndarray) ndarray[source]#
Exact grid position of world
points,(3,)or(N, 3), without rounding to a voxel.
- indices_around(center: ndarray, radius: float) ndarray[source]#
List the grid’s voxels within
radius(in voxels) of the fractional indexcenter, in C order.
- nearest_index(point: tuple[float, float, float] | ndarray) tuple[int, int, int][source]#
Index of the single voxel containing
point, as a plain int tuple.
- nearest_indices(points: ndarray) ndarray[source]#
Convert world
points,(3,)or(N, 3), to the indices of the voxels containing them.
- classmethod of(voxelization: MatrixBasedVoxelization) VoxelFrame[source]#
Read the frame a voxelization is sampled on.
- origin: tuple[float, float, float]#
- shape: tuple[int, int, int]#
- voxel_size: float#