Migrating to v2.12#

Version 2.12 is the electrical-harness release: routed cables can now be consolidated into a single optimizable harness (User Guide: Harness Generation). Existing routing code keeps working — the breaking points are the CadMap voxelization API, the Pack API and a handful of removed helpers. Most projects only need the voxel_inside and revoxelize fixes below.

New: harness generation#

The headline addition. One call routes, bundles and optimizes:

from routing.core.harness import HarnessSettings

bundle, history = route_planner.generate_harness(specifications, HarnessSettings())

Nothing in your existing pipeline changes — generate and optimize behave as before. See User Guide: Harness Generation for the pipeline, its settings and its results.

pymoo and scikit-image are new dependencies#

The harness optimizer runs on pymoo (≥ 0.6) and the skeletonization on scikit-image. Both are declared as core dependencies, so pip install -U routing pulls them in. Only projects that pin their transitive dependency set need to act.

voxel_inside was removed from CadMap.from_project_inputs#

Inside-solid routing is declared where the geometry is declared — on the volume, not on the cadmap. RuledVolume.from_volume_model(..., voxel_inside=True) is unchanged; the cadmap parameter is gone:

# Before (v2.11)
cadmap = CadMap.from_project_inputs(
    design_rules=[...], ruled_volumes=[volume], voxel_size=0.02, voxel_inside=True
)
# After (v2.12)
volume = RuledVolume.from_volume_model(volume_model, design_rules=[...], voxel_inside=True)
cadmap = CadMap.from_project_inputs(
    design_rules=[...], ruled_volumes=[volume], voxel_size=0.02
)

See Tutorial: Routing Inside a Closed Volume.

to_matrix_based_voxelization is now revoxelize#

Re-voxelizing a cadmap at another resolution is one call, and it returns a RoomVoxelization:

# Before (v2.11)
voxelization = cadmap.to_matrix_based_voxelization(voxel_size=0.01)
# After (v2.12)
voxelization = cadmap.revoxelize(voxel_size=0.01)

Two related moves:

  • Room voxelization itself now belongs to the volume: RuledVolume.voxelize_room(...).

  • CadMap.update_weights(...) is public — reapplying the design rules to the grid no longer means calling a private method.

RoomVoxelization moved to routing.core.voxels#

The voxel types live in their own module together with VoxelVolume:

# Before (v2.11)
from routing.core.core import RoomVoxelization
# After (v2.12)
from routing.core.voxels import RoomVoxelization

The old import still resolves through a deprecated subclass in routing.core.core, so existing code will not break immediately — update it anyway.

Pack construction and stamping changed#

Packs (the pooled groups returned by collect_packs) were reworked around a fitted cluster axis. Reading a pack is unchanged; building or stamping one is not:

Before (v2.11)

After (v2.12)

Pack(pipe_lines, vector, crossed_voxels=..., parallel=True)

Pack(pipe_lines, vector, axis) — the tray policy is now a subclass, ParallelPack; Pack.from_pipe_line(..., parallel=True) dispatches to it

pack.update_coefficients(...) + pack.update_forbidden_voxels(...)

pack.stamp(coefficients, forbidden_voxels, pipe_type, pooling_rule, room_voxels, clearance_at) — one pass writing both

pack.center_fixed, pack.point_in_bbox, pack.contains_point, pack.point_in_cylinder

Removed. Distances are taken to the pack axis; there is no per-voxel containment test left to call

pack.get_axis_voxels(room_voxels)

Same contract (voxel 4-tuple → representative 4-tuple), re-derived from the occupancy tube. The historical dictionary-based version stays on ParallelPack

Removed helpers#

These methods had no remaining caller inside routing and were deleted. None of them has a one-line replacement; if you relied on one, the geometry it computed is available through the cadmap’s voxel and distance fields.

Removed

Notes

CadMap.is_point_in_voxels

Query the room voxelization directly.

CadMap.to_graph / CadMap.to_trimesh

The routing graph is built by the finders; meshes come from volmdlr.

CadMap.crop_with_bounding_box / CadMap.crop_and_upscale

Cropping is internal to the optimizer windows (Bundle.attach_local_cadmaps) and to CadMap.from_project_inputs(crop_point=...).

CadMap.radii_in_voxel

The per-voxel radii cache is gone with the generic pack’s per-voxel machinery.

RuledVolume.empty_duplicate

Build the volume you need with RuledVolume.from_volume_model.

PipeLine.contains_point_projection

Use the pack axis abscissa or CadMap.clearance_along.

Behaviour changes without an API change#

Code that compiles unchanged but may produce different numbers:

  • WeightingRule lost its offset parameter and no longer freezes its calibration on the first distance field it weights: coeff is recomputed per field, so one rule instance shared by several volumes now calibrates correctly on each. An explicit 0 for min_value / max_length is honored instead of being replaced by a fallback, and a degenerate band yields a flat min_value with a warning instead of an infinite slope.

  • ShapedWeightingRule containment is voxel-overlap based — the shape is voxelized filled on the room lattice instead of being tested with a signed-distance query at each voxel centre. Robust on the non-watertight tessellations that defeated the old test; membership right at a zone boundary can differ.

  • Solution equality is identity — two cables with identical specifications are two physical cables, so == and data_eq no longer report them as equal. Code that de-duplicated solutions by value now keeps both.

  • Solution.input_length / output_length / min_straight_length are plain floats defaulting to 0.0 — an explicit 0 is honored instead of being coalesced to a fallback length.

  • Pooling fields on oblique runs — a pack whose axis leaves the grid directions no longer crenellates its influence field, so cables that used to thread between the “merlons” of a quasi-45° pack are now pooled as intended.

Also new in v2.12#

  • Cadmap steering and replay — CadMap.repel_zone / withdraw_zones add and remove a repulsive zone over a shape; remove_solutions / restore_solutions rebuild the pack state from a recorded solution set. This is what the harness unlock stage uses, and what makes a run replayable (see User Guide: Harness Generation).

  • Continuous clearance API — CadMap.cad_distance_field, clearance_at, clearance_along, traversed_weights: distance to CAD and traversed weights at any world position, not only at voxel centres.

  • Cropped cadmaps — CadMap.from_project_inputs(crop_point=...) keeps only the navigable component containing that point, which cuts memory on large assemblies.

  • Design rules reach the harness — a rule can constrain the bundled geometry through evaluate_on_bundle and declare its form with RuleEnforcement; see Design Rules on the Harness.

See Also#