routing.core.design_rules#

class routing.core.design_rules.BoundedAttributeRule(attribute: str, min_value: float | None = None, max_value: float | None = None, distance_multiplier: float = 500.0, name: str = '')[source]#

Bases: ConstraintRule

A class representing a constraint rule with bounded attribute values.

This class inherits from ConstraintRule, and enforces constraints based on whether an attribute value falls within a specified range (min_value, max_value).

Parameters:
  • attribute – The name of the attribute to check.

  • min_value – The optional minimum value for the attribute. Defaults to None.

  • max_value – The optional maximum value for the attribute. Defaults to None.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Defaults to 500.0.

  • name – The name to identify this rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from BoundedAttributeRule between node and neighbor.

Returns 0.0 if the node’s attribute value is within the valid range (as determined by get_function()), otherwise returns distance_multiplier to penalize paths that violate the constraint.

Parameters:
  • node – Current grid node to check attribute value for.

  • neighbor – Neighbor grid node (not used in this implementation).

  • vector – Optional direction vector (not used in this implementation).

Returns:

0.0 if constraint is satisfied, distance_multiplier otherwise.

get_function() Callable[source]#

Get the constraint function as a callable.

Returns a lambda function that checks if an attribute value falls within the specified range: - Both min and max: min_value <= x < max_value - Only min: min_value <= x - Only max: x < max_value - Neither: Always returns True (no constraint)

Returns:

Callable function that takes an attribute value and returns True if the value is within the valid range, False otherwise.

to_voxelized_rule(voxel_size: float) BoundedAttributeRule[source]#

Convert rule to voxelized version with values in voxel units.

Creates a new BoundedAttributeRule with min_value and max_value converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based attribute computations.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert attribute value thresholds from world coordinates to voxel units.

Returns:

New BoundedAttributeRule instance with voxelized value parameters.

class routing.core.design_rules.BoundedCustomLengthRule(attribute: str, min_value: float | None = None, max_value: float | None = None, distance_multiplier: float = 500.0, name: str = '')[source]#

Bases: BoundedAttributeRule

A class representing a constraint rule with bounded custom length attribute values.

This class inherits from BoundedAttributeRule, and enforces constraints based on whether a custom length attribute value falls within a specified range (min_value, max_value).

Parameters:
  • attribute – The name of the custom attribute to check.

  • min_value – The optional minimum value for the attribute. Defaults to None.

  • max_value – The optional maximum value for the attribute. Defaults to None.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Defaults to 500.0.

  • name – The name to identify this rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from BoundedCustomLengthRule between node and neighbor.

Returns 0.0 if the neighbor already has the custom attribute set, or if the node’s attribute length is within the valid range. Otherwise returns distance_multiplier to penalize paths that violate the constraint.

Parameters:
  • node – Current grid node to check attribute length for.

  • neighbor – Neighbor grid node to check for existing attribute.

  • vector – Optional direction vector (not used in this implementation).

Returns:

0.0 if constraint is satisfied, distance_multiplier otherwise.

class routing.core.design_rules.ClampingConstraint(clamp_length: float, clamp_step: float, distance_multiplier: float = 19.0, name: str = '')[source]#

Bases: ConstraintRule

A class representing a constraint rule for clamping requirements.

This class inherits from ConstraintRule, and enforces constraints related to clamping, ensuring pipes maintain appropriate spacing for clamp installation. The rule ensures that pipes can be clamped at regular intervals by penalizing paths that exceed the maximum distance (clamp_step) between clampable locations.

The constraint works by: - Setting a “clampable” attribute on voxels that can accommodate clamps - Tracking the length of pipe segments without clamping - Penalizing paths where the unclamped length exceeds clamp_step

Parameters:
  • clamp_length – The minimum length of pipe segment that requires clamping. This is the length requirement for a clamp to be effective.

  • clamp_step – The maximum distance (in length units) allowed between two clampable locations. Paths exceeding this distance are penalized.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Higher values create stronger penalties. Defaults to 19.0.

  • name – The name to identify this rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from ClampingConstraint between node and neighbor.

Enforces clamping constraints by checking if the path can be clamped at appropriate intervals:

  1. If the neighbor has the “clampable” attribute set: Returns 0.0 (no penalty, can place a clamp here)

  2. If the neighbor is not clampable: Checks the length of the current unclamped segment (stored as “no_clampable” length attribute on the node). - If length <= clamp_step: Returns 0.0 (still within acceptable range) - If length > clamp_step: Returns distance_multiplier (penalty for

    exceeding maximum distance between clamps)

This ensures that pipes maintain appropriate spacing for clamp installation and prevents routing through areas where clamping would be impossible or insufficient.

Parameters:
  • node – Current grid node to check clamp spacing for. The node’s “no_clampable” length attribute tracks how long the current segment has been without a clampable location.

  • neighbor – Neighbor grid node to check for clampable attribute. If this neighbor is clampable, a clamp can be placed here.

  • vector – Optional direction vector (not used in this implementation).

Returns:

0.0 if constraint is satisfied (clampable neighbor or within clamp_step limit), distance_multiplier if constraint is violated (exceeds clamp_step without clampable location).

fast_check(voxels: list[tuple[int, int, int]], voxel_size: float, bool_matrix: ndarray) float[source]#

Fast constraint check for a list of voxels without full pathfinding.

Performs a quick validation of a path segment to check if it violates clamping constraints. The method:

  1. Converts clamp_step and clamp_length to voxel units

  2. If path is shorter than clamp_step, returns 0.0 (no violation)

  3. Extracts clampable attribute values for all voxels in the path

  4. Splits the path into consecutive segments of clampable/non-clampable voxels

  5. Tracks unclampable segments and checks if they exceed clamp_step

  6. Accumulates total violation length (unclampable segments > clamp_step)

Returns the total violation length in world coordinates, which represents the cumulative distance where clamping constraints are violated. A value of 0.0 means the path satisfies all clamping constraints.

This method is used for early validation of paths before committing to full pathfinding, improving performance by rejecting invalid paths quickly.

Parameters:
  • voxels – List of voxel indices (i, j, k) representing a path segment to check for clamping violations.

  • voxel_size – Size of a voxel in length units. Used to convert clamp_step and clamp_length to voxel units.

  • bool_matrix – Boolean matrix indicating which voxels have the “clampable” attribute set to True. Shape should match the voxel grid.

Returns:

Total violation length in world coordinates. Returns 0.0 if the path satisfies all clamping constraints, otherwise returns the cumulative distance where constraints are violated (in length units).

to_voxelized_rule(voxel_size: float) ClampingConstraint[source]#

Convert rule to voxelized version with lengths in voxel units.

Creates a new ClampingConstraint with clamp_length and clamp_step converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based length computations.

The conversion ensures that clamping constraints are properly scaled for the voxel grid resolution, maintaining the same physical constraints but expressed in voxel units.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert clamp_length and clamp_step from world coordinates to voxel indices.

Returns:

New ClampingConstraint instance with voxelized length parameters.

class routing.core.design_rules.ConstraintRule(attribute: str, distance_multiplier: float = 500.0, name: str = '')[source]#

Bases: DesignRule

A class representing a design rule that enforces constraints based on boolean attributes.

This class inherits from DesignRule, and prevents routing through voxels with a specific boolean attribute set to True. This is used to enforce hard constraints like “no routing near sensitive components” or “must stay in designated zones”.

Parameters:
  • attribute – The name of the boolean attribute that triggers the constraint. Voxels with this attribute set to True will be blocked or heavily penalized.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Higher values create stronger constraints. Defaults to 500.0.

  • name – The name to identify this constraint rule. Defaults to ‘’.

fast_check(voxels: list[tuple[int, int, int]], voxel_size: float, bool_matrix: ndarray) float[source]#

Fast constraint check for a list of voxels.

Base implementation returns 0.0 (no constraint violation). Subclasses can override to provide fast constraint checking without full pathfinding. This is used for early validation of paths.

Parameters:
  • voxels – List of voxel indices to check.

  • voxel_size – Size of a voxel in length units.

  • bool_matrix – Boolean matrix indicating which voxels have the constraint attribute set to True.

Returns:

Constraint violation cost (0.0 means no violation).

class routing.core.design_rules.CostRule(cost: float = 50.0, name: str = '')[source]#

Bases: DesignRule

A base class for design rules that apply a cost penalty.

This class inherits from DesignRule, and provides a constant cost penalty that can be applied during pathfinding. Subclasses like TurnPenalizer extend this to apply costs based on specific conditions.

Parameters:
  • cost – The cost penalty value to apply. Higher values create stronger penalties during pathfinding. Defaults to 50.0.

  • name – The name to identify this cost rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from CostRule between node and neighbor to get to target. Should return 0.

class routing.core.design_rules.DesignRule(name: str = '')[source]#

Bases: DessiaObject

A base class for all design rules used in routing.

This class inherits from DessiaObject, and defines how pipes interact with volumes and space during routing. They can provide weights (preferences), costs (penalties), constraints, and heuristics for pathfinding algorithms.

Parameters:

name – The name to identify this design rule. Defaults to ‘’.

compute_cost(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute cost from DesignRule between node and neighbor.

Base implementation returns 0.0. Subclasses should override to provide actual cost computation for pathfinding.

Parameters:
  • node – Current grid node

  • neighbor – Neighbor grid node

  • vector – Optional direction vector

Returns:

Cost value (default: 0.0)

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from DesignRule between node and neighbor to get to target.

Base implementation returns 0.0. Subclasses should override to provide heuristic estimates for A* pathfinding.

Parameters:
  • node – Current grid node

  • neighbor – Neighbor grid node

  • vector – Optional direction vector

Returns:

Heuristic value (default: 0.0)

compute_weights(distances: ndarray) ndarray[source]#

Compute weights from distance matrix.

Base implementation returns zeros. Subclasses should override to provide actual weight computation based on distances to volumes.

Parameters:

distances – Distance matrix or array from which to compute weights

Returns:

Weight array of same shape as distances (default: zeros)

property forbids_zones: bool#

Check if current rule is forbidding some zones.

set_port_nodes(source: tuple[float, float, float], target: tuple[float, float, float]) None[source]#

Set port node positions for rule computation.

Base implementation does nothing. Subclasses can override to use port positions in their computations.

Parameters:
  • source – Source port coordinates

  • target – Target port coordinates

to_voxelized_rule(voxel_size: float) DesignRule[source]#

Convert rule to voxelized version.

Creates a copy of the rule with distances converted to voxel units.

Parameters:

voxel_size – Size of a voxel in length units

Returns:

New DesignRule instance with voxelized parameters

class routing.core.design_rules.DistanceAttributeToggler(attribute: str, min_distance: float = 0.0, max_distance: float = 1e+16, name: str = '')[source]#

Bases: DesignRule

A class representing a design rule that toggles a boolean attribute based on distance.

This class inherits from DesignRule, and sets a boolean attribute on voxels within a distance range. This is used by ConstraintRule to define regions where constraints apply.

Parameters:
  • attribute – The name of the boolean attribute to set on voxels.

  • min_distance – The minimum distance (in length units) where attribute is True. Defaults to 0.0.

  • max_distance – The maximum distance (in length units) where attribute is True. Defaults to _MAX_VALUE.

  • name – The name to identify this rule. Defaults to ‘’.

get_all_nodes_value(distances: ndarray) ndarray[source]#

Get boolean array indicating which voxels have the attribute set to True.

Returns a boolean array where True indicates voxels with distances in the range [min_distance, max_distance). These voxels will have the attribute set to True, which can be used by ConstraintRule to enforce constraints.

Parameters:

distances – Distance array to check against min_distance and max_distance.

Returns:

Boolean array of same shape as distances, True where distances are in the range [min_distance, max_distance).

to_voxelized_rule(voxel_size: float) DistanceAttributeToggler[source]#

Convert rule to voxelized version with distances in voxel units.

Creates a new DistanceAttributeToggler with min_distance and max_distance converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based distance computations.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert distance thresholds from world coordinates to voxel indices.

Returns:

New DistanceAttributeToggler instance with voxelized distance parameters.

class routing.core.design_rules.GravityRule(min_value: float | None = None, max_value: float | None = None, distance_multiplier: float = 500.0, name: str = '')[source]#

Bases: BoundedAttributeRule

A class representing a constraint rule for gravity-based routing.

This class inherits from BoundedAttributeRule, and enforces slope constraints for gravity systems, ensuring pipes maintain appropriate downward slopes between source and target ports.

Parameters:
  • min_value – The optional minimum slope value (negative for gravity systems). Defaults to None.

  • max_value – The optional maximum slope value. Defaults to None.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Defaults to 500.0.

  • name – The name to identify this rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from GravityRule between node and neighbor.

Enforces gravity/slope constraints for routing: - Penalizes upward moves (vector[2] > 0) with distance_multiplier - Computes slope from source to neighbor position - Checks if slope is within [min_value, max_value] range - Allows downward moves when slope constraints are satisfied

The rule ensures pipes maintain appropriate downward slopes for gravity-fed systems.

Parameters:
  • node – Current grid node (not directly used, but direction may be checked).

  • neighbor – Neighbor grid node to compute slope to.

  • vector – Direction vector of the move (3D index: [i, j, k]). vector[2] > 0 indicates upward move (penalized).

Returns:

0.0 if move satisfies gravity constraints, distance_multiplier otherwise.

set_port_nodes(source: tuple[float, float, float], target: tuple[float, float, float]) None[source]#

Set source and target port positions for gravity constraint.

Sets the source and target coordinates and validates feasibility. The source should be above the target for gravity systems.

Parameters:
  • source – Source port coordinates as (x, y, z) array.

  • target – Target port coordinates as (x, y, z) array.

Returns:

None

Raises:

ValueError – If gravity constraint is not feasible (target above source).

to_voxelized_rule(voxel_size: float) GravityRule[source]#

Convert rule to voxelized version with values in voxel units.

Creates a new BoundedAttributeRule with min_value and max_value converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based attribute computations.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert attribute value thresholds from world coordinates to voxel units.

Returns:

New BoundedAttributeRule instance with voxelized value parameters.

class routing.core.design_rules.PoolingMode(name: str, description: str, default_coeff: float, valid_range: tuple[float, float])[source]#

Bases: DessiaObject

A class defining different modes of pooling with configurable coefficients.

This class inherits from DessiaObject, and defines modes with a description, default coefficient, and valid range for coefficient values. Coefficients determine how pipes can be grouped: - coeff == 0: no pooling allowed - coeff < 1: pooling allowed - coeff == 1: pipe can pass without modification - coeff > 1: permissive segregation

Parameters:
  • name – The name identifying this pooling mode.

  • description – The description of the pooling mode.

  • default_coeff – The default coefficient value for this mode.

  • valid_range – The valid range for coefficient values as (min, max) tuple.

property coeff: float#

Getter for coeff.

classmethod custom(name: str, description: str, default_coeff: float, valid_range: tuple[float, float]) PoolingMode[source]#

Create a custom pooling mode instance with specified parameters.

Allows creation of custom pooling modes with user-defined name, description, default coefficient, and valid range. Useful for domain-specific pooling requirements.

Parameters:
  • name – Name identifier for the custom mode.

  • description – Human-readable description of the mode’s behavior.

  • default_coeff – Default coefficient value for this mode.

  • valid_range – Valid range for coefficient values as (min, max) tuple.

Returns:

PoolingMode instance with custom settings.

classmethod expert_mode() PoolingMode[source]#

Create an expert mode instance.

Expert mode allows any coefficient value from 0 to infinity, giving full control to the user. The default is 0 (strict segregation), but users can set any value within the valid range.

Returns:

PoolingMode instance with expert mode settings (unrestricted range).

classmethod intermediate_pooling() PoolingMode[source]#

Create an intermediate pooling mode instance.

Intermediate pooling mode has coeff=0.75, indicating weak preference for grouping pipes. This allows some pooling but is closer to neutral behavior than strict pooling.

Returns:

PoolingMode instance with intermediate pooling settings.

is_intermediate() bool[source]#

Check if this mode represents intermediate pooling.

Returns True if 0.5 < coeff < 1, indicating moderate preference for grouping pipes. This is between strict pooling and neutral.

Returns:

True if 0.5 < coeff < 1 (intermediate pooling), False otherwise.

is_permissive() bool[source]#

Check if this mode represents permissive segregation.

Returns True if coeff > 1, indicating that pipes can pass through each other’s zones but should not be actively grouped. This is a softer constraint than strict segregation.

Returns:

True if coeff > 1 (permissive segregation), False otherwise.

is_pooling() bool[source]#

Check if this mode allows pooling.

Returns True if 0 < coeff < 1, indicating that pipes can be grouped together. Lower coefficient values indicate stronger preference for pooling.

Returns:

True if pooling is allowed (0 < coeff < 1), False otherwise.

is_segregating() bool[source]#

Check if this mode represents segregation (no pooling or permissive segregation).

Returns True if coeff == 0.0 (strict segregation) or coeff > 1 (permissive segregation). In both cases, pipes should not be grouped together.

Returns:

True if mode is segregating (coeff == 0 or coeff > 1), False otherwise.

is_strict_pooling() bool[source]#

Check if this mode represents strict pooling.

Returns True if coeff <= 0.5, indicating strong preference for grouping pipes together. This is the strongest pooling mode.

Returns:

True if coeff <= 0.5 (strict pooling), False otherwise.

is_strong_segregation() bool[source]#

Check if this mode represents strong segregation.

Strong segregation means coeff == 0, indicating that no pooling is allowed between pipes. This is the strictest constraint.

Returns:

True if coeff == 0 (strict segregation), False otherwise.

classmethod moderate_pooling() PoolingMode[source]#

Create a moderate pooling mode instance.

Moderate pooling mode has coeff=0.5, indicating moderate preference for grouping pipes. This is a balanced approach between strict pooling and neutral behavior.

Returns:

PoolingMode instance with moderate pooling settings.

classmethod permissive_segregation() PoolingMode[source]#

Create a permissive segregation mode instance.

Permissive segregation mode has coeff=10, indicating that pipes can pass through each other’s zones but should not be actively grouped. This is a softer constraint than strict segregation, allowing more flexibility while still discouraging pooling.

Returns:

PoolingMode instance with permissive segregation settings.

reset() None[source]#

Reset coefficient to its default value.

Restores the coefficient to the default_coeff value specified when the PoolingMode was created. Useful for reverting custom modifications.

Returns:

None

classmethod segregation() PoolingMode[source]#

Create a segregation mode instance.

Segregation mode has coeff=0, meaning no pooling is allowed between pipes. This is the strictest constraint, requiring pipes to maintain minimum distances and never be grouped together.

Returns:

PoolingMode instance with strict segregation settings.

classmethod strong_pooling() PoolingMode[source]#

Create a strong pooling mode instance.

Strong pooling mode has a very low coefficient (1e-14), indicating strong preference for grouping pipes together. This mode encourages maximum pooling while still allowing some flexibility.

Returns:

PoolingMode instance with strong pooling settings.

classmethod weak_pooling() PoolingMode[source]#

Create a weak pooling mode instance.

Weak pooling mode has coeff=0.99, indicating very weak preference for grouping pipes. This is almost neutral, allowing minimal pooling but preferring separate paths.

Returns:

PoolingMode instance with weak pooling settings.

class routing.core.design_rules.PoolingRule(pooling_specs: list[PoolingSpecification] | None = None, min_distance: float = 0.0, distance_multiplier: float = 500.0, volume_indices: list[int] | None = None, name: str = '')[source]#

Bases: ConstraintRule

A class representing a rule that defines constraints for pooling types in the routing process.

This class inherits from ConstraintRule, and is used to enforce constraints based on the history attribute and the specified pooling types, coefficients, and distances.

Parameters:
  • pooling_specs – The optional list of PoolingSpecification objects defining pooling rules for specific pipe types. Defaults to None.

  • min_distance – The minimum distance used for the pooling rule in case no Pooling mode is set between two pipe types, in which case the pipes segregate by default. Defaults to 0.0.

  • distance_multiplier – The multiplier for the distance attribute. Defaults to 500.0.

  • volume_indices – The optional list of volume indices to apply this rule to. Defaults to None.

  • name – The name of the rule. Defaults to ‘’.

DEFAULT_POOLING_COEFF = 0.0001#
DEFAULT_STRONG_SEGREGATION_COEFF = 0#
property all_types: list[str]#

Get all pipe types covered by pooling specifications.

Aggregates all pipe type identifiers from all PoolingSpecification objects in pooling_specs. May contain duplicates if a type appears in multiple specifications.

Returns:

List of all pipe type identifiers (strings) in all specifications.

build_pooling_matrices(types: list[str]) None[source]#

Build pooling coefficient and distance matrices for all pipe type combinations.

Creates two matrices (coefficients and distances) that define how pipes of different types interact: - coefficients: Pooling coefficients for each type pair (affects routing costs) - distances: Minimum distances required between each type pair

The method: 1. Collects all types from specifications and input list 2. Creates square matrices for all type combinations 3. Fills matrices from PoolingSpecification objects 4. Sets default values (1.0 for coefficients, min_distance for distances) 5. Stores results in self.coefficients and self.distances dictionaries

This must be called before using pooling features in routing.

Parameters:

types – List of pipe type identifiers to include in matrices. Types from pooling_specs are automatically added. “None” type is added if not present.

Returns:

None

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from PoolingRule between node and neighbor.

Currently returns 0.0 (disabled). The commented code shows the intended behavior: checking history attributes to determine if paths should be penalized based on existing pipe placement. When enabled, it would: - Return 0.0 if node has no history - Return 0.0 if node and neighbor have matching history - Return 0.0 if history length exceeds threshold and neighbor has no history - Return distance_multiplier otherwise

Parameters:
  • node – Current grid node to check history for.

  • neighbor – Neighbor grid node to compare history with.

  • vector – Optional direction vector (not used in current implementation).

Returns:

Currently always returns 0.0 (heuristic disabled).

static exceeds_history_min_length(node: SmartGridNode) bool[source]#

Check if the history length exceeds the threshold.

get_min_distance(types: tuple[str, str]) float[source]#

Get the minimum distance required between two pipe types.

Returns the minimum distance from the PoolingSpecification if one exists for the given types, otherwise returns the default min_distance from the PoolingRule.

Parameters:

types – Tuple of two pipe type identifiers.

Returns:

Minimum distance value in length units.

get_pooling_coefficient(types: tuple[str, str]) float[source]#

Get pooling coefficient value for given pipe types.

Returns the coefficient from the PoolingSpecification if one exists for the given types. If no specification matches: - Same types (type1, type1): Returns DEFAULT_POOLING_COEFF (0.0001) - Different types: Returns DEFAULT_STRONG_SEGREGATION_COEFF (0)

Parameters:

types – Tuple of two pipe type identifiers.

Returns:

Pooling coefficient value (0 = strict segregation, < 1 = pooling allowed).

static has_history(node: SmartGridNode) bool[source]#

Check if the node has a history attribute set.

Returns True if the node has a “history” attribute in its custom_attr dictionary and the attribute value is truthy. History indicates that the node is part of a previously routed pipe path.

Parameters:

node – SmartGridNode to check for history attribute.

Returns:

True if node has history attribute set, False otherwise.

static has_matching_history(node: SmartGridNode, neighbor: SmartGridNode) bool[source]#

Check if the node and its neighbor have matching history values.

Returns True if both nodes have the same history attribute value. Matching history indicates they belong to the same pipe path or pack, which can affect pooling decisions.

Parameters:
  • node – Current SmartGridNode.

  • neighbor – Neighbor SmartGridNode to compare with.

Returns:

True if both nodes have the same history value, False otherwise.

is_parallel(types: tuple[str, str]) bool[source]#

Check if pooling for given types should use parallel grouping.

Returns True if the types can be pooled AND the PoolingSpecification has parallel=True. Parallel grouping uses agglomerative clustering with support surface constraints, while non-parallel uses standard proximity-based grouping.

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if parallel grouping should be used, False otherwise.

is_pooling(types: tuple[str, str]) bool[source]#

Verify if given PipeTypes types corresponds to a pooling rule.

Parameters:

types – PipeType types for pooling rule.

Returns:

bool.

is_segregation(types: tuple[str, str]) bool[source]#

Check if the given pipe types must be segregated.

Returns True if any PoolingSpecification enforces segregation for these types. If a specification allows pooling, returns False. If no specification matches, returns the inverse of is_pooling().

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if segregation is required for these types, False otherwise.

is_strong_segregation(types: tuple[str, str]) bool[source]#

Check if the given pipe types have strong segregation enforced.

Returns True if any PoolingSpecification enforces strong segregation (coeff == 0) for these types. If a specification allows pooling for these types, returns False. If no specification matches and types are different, returns True (default segregation).

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if strong segregation is enforced for these types, False otherwise.

type_in_parallel(type_: str) bool[source]#

Check if a pipe type is configured for parallel pooling.

Returns True if the pipe type is in a PoolingSpecification that has parallel=True. Parallel pooling uses agglomerative clustering with support surface constraints.

Parameters:

type – Pipe type identifier to check.

Returns:

True if type is configured for parallel pooling, False otherwise.

update_history_zones(types: tuple[str, str], pooling_range: ndarray, pooling_zone: ndarray, forbidden_zone: ndarray) None[source]#

Update history zones for tracking pipe placement.

Placeholder method for updating history zones that track where pipes have been placed. This information is used to influence future routing decisions based on existing pipe locations.

Currently not implemented (pass). Future implementation would update pooling_zone and forbidden_zone arrays based on pipe placement history.

Parameters:
  • types – Tuple of two pipe type identifiers.

  • pooling_range – Boolean array indicating voxels in pooling influence zone.

  • pooling_zone – Array to update with pooling zone information.

  • forbidden_zone – Array to update with forbidden zone information.

Returns:

None

update_weights(global_weights: ndarray, types: tuple[str, str], pooling_range: ndarray, no_room_voxels: list[tuple[int, int, int]]) ndarray[source]#

Update weights with pooling rules’ coefficient.

Applies pooling coefficients to voxels in the pooling range and sets weights to 0.0 for voxels that are not in the room (non-traversable). The pooling coefficient modifies routing costs to encourage or discourage grouping pipes based on the pooling mode.

Parameters:
  • global_weights – 3D weight array to update (same shape as room_voxels.matrix).

  • types – Tuple of two pipe type identifiers to get pooling coefficient for.

  • pooling_range – Boolean array indicating voxels in the pooling influence zone.

  • no_room_voxels – List of voxel indices (i, j, k) that are not traversable.

Returns:

Updated weight array with pooling coefficients applied.

class routing.core.design_rules.PoolingSpecification(types: list[str], pooling_mode: PoolingMode, min_distance: float, parallel: bool = False, name: str = '')[source]#

Bases: DessiaObject

A class defining pooling rules for specific pipe types.

This class inherits from DessiaObject, and defines pooling rules that determine how pipes of specific types can be grouped together during routing.

Parameters:
  • types – The list of pipe types this pooling rule applies to.

  • pooling_mode – The mode determining how pipes can be grouped.

  • min_distance – The minimum distance for pooling mode to be applied.

  • parallel – Flag indicating whether pooling should use agglomerative or parallel approach. Defaults to False.

  • name – The name to identify this pooling specification. Defaults to ‘’.

contains_types(types: tuple[str, str]) bool[source]#

Check if given types are covered by this pooling specification.

Returns True if both pipe types in the tuple are present in this specification’s types list. For same-type pairs (type1, type1), requires the type to appear twice in the types list.

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if both types are covered by this specification, False otherwise.

is_pooled_with(type_: str) bool[source]#

Check if a pipe type can be pooled with types in this specification.

Returns True if the pooling mode allows pooling AND the given type is in this specification’s types list. This indicates that pipes of the given type can be grouped with pipes of types in this specification.

Parameters:

type – Pipe type identifier to check.

Returns:

True if the type can be pooled with types in this specification, False otherwise.

is_pooling(types: tuple[str, str]) bool[source]#

Check if this specification allows pooling for the given types.

Returns True if the types are covered by this specification AND the pooling mode allows pooling (0 < coeff < 1).

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if pooling is allowed for these types, False otherwise.

is_segregated_with(type_: str) bool[source]#

Check if a pipe type must be segregated from types in this specification.

Returns True if the pooling mode enforces segregation AND the given type is in this specification’s types list. This indicates that pipes of the given type must maintain separation from pipes of types in this specification.

Parameters:

type – Pipe type identifier to check.

Returns:

True if the type must be segregated from types in this specification, False otherwise.

is_segregating(types: tuple[str, str]) bool[source]#

Check if this specification enforces segregation for the given types.

Returns True if the types are covered by this specification AND the pooling mode is segregating (coeff == 0 or coeff > 1). This includes both strict segregation and permissive segregation.

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if segregation is enforced for these types, False otherwise.

is_strong_segregation(types: tuple[str, str]) bool[source]#

Check if this specification enforces strong segregation for the given types.

Returns True if the types are covered by this specification AND the pooling mode is strong segregation (coeff == 0). This means no pooling/mutualization is allowed between these pipe types.

Parameters:

types – Tuple of two pipe type identifiers to check.

Returns:

True if strong segregation is enforced for these types, False otherwise.

class routing.core.design_rules.ShapedWeightingRule(shape: Solid | VolumeModel, coefficient: float = 0.5, zone_type: str = 'attractive', cut_ports: bool = False, name: str = '')[source]#

Bases: DesignRule

A design rule that applies weights based on shape containment.

This class inherits from DesignRule, and defines how routing costs are modified based on whether voxels are inside an arbitrary 3D shape. Supports four zone types:

  • ‘attractive’: Multiply weights by coefficient (0 < coeff < 1) inside shape, reducing path cost to favor passage through the zone.

  • ‘repulsive’: Multiply weights by coefficient (coeff > 1) inside shape, increasing path cost to discourage passage through the zone.

  • ‘forbidden’: Set weight to 0 inside shape, completely blocking passage.

  • ‘forced’: Very low weight inside, very high weight outside, forcing path through the zone.

The shape can be any volmdlr Solid or VolumeModel with triangulation capability. Point-in-shape testing uses igl.signed_distance for efficient vectorized computation.

Parameters:
  • shape – The 3D shape defining the zone. Can be any volmdlr Solid or VolumeModel with triangulation capability.

  • coefficient – The weight modification strength. Interpretation depends on zone_type: - attractive: 0 < coeff < 1 (lower = more attractive) - repulsive: coeff > 1 (higher = more repulsive) - forbidden/forced: ignored (uses internal defaults)

  • zone_type – The type of zone behavior. One of: ‘attractive’, ‘repulsive’, ‘forbidden’, ‘forced’. Defaults to ‘attractive’.

  • name – The name to identify this rule. Defaults to ‘’.

ZONE_TYPES = ('attractive', 'repulsive', 'forbidden', 'forced')#
apply_weights(weights: ndarray, voxelization: MatrixBasedVoxelization) ndarray[source]#

Apply shaped weighting rule to weight tensor.

This method should be called AFTER all other weight computations to apply the shape-based weight modifications. It modifies weights based on whether each voxel center is inside or outside the shape.

Parameters:
  • weights – 3D weight array (width x height x depth) representing the routing cost at each voxel.

  • voxelization – MatrixBasedVoxelization with grid parameters (min_grid_center, voxel_size) for coordinate conversion.

Returns:

Modified weight array with shape-based weights applied.

classmethod attractive_zone(shape: Solid | VolumeModel, strength: float = 0.1, name: str = '') ShapedWeightingRule[source]#

Create an attractive zone that reduces path cost inside the shape.

Paths are more likely to pass through attractive zones because of reduced weight/cost values inside the shape.

Parameters:
  • shape – The 3D shape defining the attractive zone.

  • strength – Attraction strength as weight multiplier (0 < strength < 1). Lower values create stronger attraction. Defaults to 0.5.

  • name – Optional name for the rule.

Returns:

ShapedWeightingRule configured as attractive zone.

cut_port_extension(extension_coords: ndarray, port_name: str) int | None[source]#

Cut port extension when it is inside forbidden zone and cut_port is True.

classmethod forbidden_zone(shape: Solid | VolumeModel, cut_ports: bool = False, name: str = '') ShapedWeightingRule[source]#

Create a forbidden zone that blocks paths inside the shape.

No paths can pass through forbidden zones as the weight is set to zero, making the voxels non-traversable. Use this for hot zones, vibration areas, or other strict constraints.

Parameters:
  • shape – The 3D shape defining the forbidden zone.

  • cut_ports – Whether to cut ports outside the forbidden zone. If True, the port extension will be cut at the first voxel that is outside the forbidden zone. If False, an error will be raised if the port extension is outside the forbidden zone. Defaults to False.

  • name – Optional name for the rule.

Returns:

ShapedWeightingRule configured as forbidden zone.

property forbids_zones: bool#

Check if current rule is forbidding some zones.

classmethod forced_zone(shape: Solid | VolumeModel, name: str = '') ShapedWeightingRule[source]#

Create a forced zone that requires paths to pass through the shape.

Paths are strongly encouraged to pass through forced zones by setting very low weights inside and very high weights outside. Use this for imposed or predefined passage points.

Parameters:
  • shape – The 3D shape defining the forced zone.

  • name – Optional name for the rule.

Returns:

ShapedWeightingRule configured as forced zone.

property mesh: tuple[ndarray, ndarray]#

Get triangulated mesh from shape for signed_distance computation.

Lazily computes and caches the mesh vertices and faces from the shape. The mesh is used by igl.signed_distance to determine point containment.

Returns:

Tuple of (vertices, faces) arrays where vertices has shape (N, 3) and faces has shape (M, 3) with integer indices.

Raises:

ValueError – If the shape does not support triangulation.

classmethod repulsive_zone(shape: Solid | VolumeModel, strength: float = 10.0, name: str = '') ShapedWeightingRule[source]#

Create a repulsive zone that increases path cost inside the shape.

Paths are less likely to pass through repulsive zones because of increased weight/cost values inside the shape. This is useful for zones that are undesirable but not strictly forbidden.

Parameters:
  • shape – The 3D shape defining the repulsive zone.

  • strength – Repulsion strength as weight multiplier (> 1). Higher values create stronger repulsion. Defaults to 2.0.

  • name – Optional name for the rule.

Returns:

ShapedWeightingRule configured as repulsive zone.

to_voxelized_rule(voxel_size: float) ShapedWeightingRule[source]#

Convert rule to voxelized version.

For ShapedWeightingRule, the shape already uses world coordinates and point-in-shape testing is done in world space, so no conversion is needed. Returns a new instance with the same parameters but cleared mesh cache.

Parameters:

voxel_size – Size of a voxel in length units (not used for this rule).

Returns:

New ShapedWeightingRule instance with same parameters.

class routing.core.design_rules.StraightLengthRule(min_value: float = -1e+16, distance_multiplier: float = 500.0, name: str = '')[source]#

Bases: BoundedAttributeRule

A class representing a constraint rule for minimum straight length before turns.

This class inherits from BoundedAttributeRule, and enforces a minimum straight length constraint, ensuring pipes maintain a straight segment before making turns.

Parameters:
  • min_value – The minimum straight length value before a turn is allowed. Defaults to _MIN_VALUE.

  • distance_multiplier – The multiplier for computing constraint cost based on distance. Defaults to 500.0.

  • name – The name to identify this rule. Defaults to ‘’.

compute_heuristic(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Compute heuristic from StraightLengthRule between node and neighbor.

Returns 0.0 if: - The node’s straight_length >= min_value (minimum straight segment achieved), OR - The direction is unchanged (node.direction == vector, continuing straight)

Otherwise returns distance_multiplier to penalize turns that occur before the minimum straight length is reached.

Parameters:
  • node – Current grid node to check straight_length for.

  • neighbor – Neighbor grid node (not used in this implementation).

  • vector – Direction vector of the move. If same as node.direction, indicates continuing straight (no penalty).

Returns:

0.0 if constraint is satisfied, distance_multiplier otherwise.

to_voxelized_rule(voxel_size: float) StraightLengthRule[source]#

Convert rule to voxelized version with length in voxel units.

Creates a new StraightLengthRule with min_value converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based length computations.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert minimum straight length from world coordinates to voxel units.

Returns:

New StraightLengthRule instance with voxelized min_value.

class routing.core.design_rules.TurnPenalizer(cost: float = 50.0, name: str = '')[source]#

Bases: CostRule

A class representing a design rule that penalizes turns during routing.

This class inherits from CostRule, and applies a cost penalty when the path changes direction, encouraging straighter paths and reducing the number of bends.

Parameters:
  • cost – The cost penalty to apply when the path changes direction. Higher values create stronger preference for straight paths. Defaults to 50.0.

  • name – The name to identify this turn penalizer. Defaults to ‘’.

compute_cost(node: SmartGridNode, neighbor: SmartGridNode, vector: tuple[int, int, int] | None = None) float[source]#

Get cost from TurnPenalizer between node and neighbor.

Returns 0.0 if direction is unchanged, otherwise returns the turn cost penalty.

Parameters:
  • node – Current grid node

  • neighbor – Neighbor grid node

  • vector – Direction vector of the move

Returns:

0.0 if no turn, self.cost if direction changes

to_voxelized_rule(voxel_size: float) DesignRule[source]#

Convert rule to voxelized version.

For TurnPenalizer, returns a copy with the same cost since turn penalties are independent of voxel size. The cost is applied per turn regardless of voxel resolution.

Parameters:

voxel_size – Size of a voxel in length units (not used for TurnPenalizer).

Returns:

New TurnPenalizer instance with same cost.

class routing.core.design_rules.WeightingRule(function: str = 'linear', min_length: float = 0.0, max_length: float | None = None, min_value: float = 0.0, max_value: float | None = None, name: str = '')[source]#

Bases: DesignRule

A class representing a design rule that applies weights based on distance to volumes.

This class inherits from DesignRule, and defines how routing costs vary with distance to a volume. Supports linear, square root, and constant functions. Weights are applied during pathfinding to prefer or avoid certain distances.

Parameters:
  • function – The weight function type. Options: ‘linear’, ‘lin’, ‘affine’ for linear interpolation; ‘sqrt’, ‘square root’, ‘square_root’ for square root interpolation; ‘constant’, ‘const’ for constant weight. Defaults to ‘linear’.

  • min_length – The minimum distance (in length units) where rule applies. Defaults to 0.0.

  • max_length – The maximum distance (in length units) where rule applies. If None, applies to all distances >= min_length. Defaults to None.

  • min_value – The minimum weight value applied at min_length distance. Defaults to 0.0.

  • max_value – The maximum weight value applied at max_length distance. If None, computed automatically from function. Defaults to None.

  • name – The name to identify this weighting rule. Defaults to ‘’.

build(distances: ndarray) None[source]#

Build the weighting function by computing all internal parameters.

This method must be called before using get_function() or compute_weights(). It computes: - max_length: Maximum distance for the function (if not explicitly set) - coeff: Slope coefficient for linear/sqrt functions - max_value: Maximum weight value (if not explicitly set) - offset: Vertical offset for function calibration

These parameters are computed from the distance array and the rule’s configuration (function type, min_length, max_length, min_value, max_value).

Parameters:

distances – Distance array used to compute max_length if needed.

Returns:

None

compute_weights(distances: ndarray) ndarray[source]#

Compute weights from distance array using the weighting function.

Applies the weighting function to distances within the valid range [min_length, max_length). Distances outside this range receive zero weight.

The method: 1. Initializes weights array with zeros 2. Identifies voxels in the valid distance range 3. Builds the weighting function (computes coeff, offset, etc.) 4. Applies the function to distances in range

Parameters:

distances – Distance array from which to compute weights.

Returns:

Weight array of same shape as distances, with non-zero values only for distances in the valid range [min_length, max_length).

get_boolean_range(distances: ndarray) ndarray[source]#

Get boolean mask for distances within the valid range.

Returns a boolean array where True indicates distances that are within the valid range [min_length, max_length). Voxels outside this range will not have weights applied by this rule.

Parameters:

distances – Distance array to check.

Returns:

Boolean array of same shape as distances, True where distances are in the valid range [min_length, max_length).

get_function() Callable[source]#

Get the weighting function as a callable.

Returns a lambda function that computes weight from distance based on the function type: - Constant: Returns min_value for all distances - Linear: coeff * (x - min_length) + min_value - Square root: coeff * sqrt(x - min_length) + min_value

The function must be called after build() to ensure coeff and offset are properly computed.

Returns:

Callable function that takes distance and returns weight.

to_voxelized_rule(voxel_size: float) WeightingRule[source]#

Convert rule to voxelized version with distances in voxel units.

Creates a new WeightingRule with min_length and max_length converted from world coordinates to voxel units by dividing by voxel_size and rounding up. This allows the rule to work directly with voxel-based distance computations.

Parameters:

voxel_size – Size of a voxel in length units. Used to convert distance thresholds from world coordinates to voxel indices.

Returns:

New WeightingRule instance with voxelized distance parameters.