Source code for fabex.utilities.parent_utils

from shapely.geometry import Point
from shapely.strtree import STRtree


[docs] def parent_child_distance(parents, children, o, distance=None): # parenting based on x,y distance between chunks # hierarchy works like this: - children get milled first. if distance is None: dlim = o.distance_between_paths * 2 if o.strategy in ["PARALLEL", "CROSS"] and o.movement.parallel_step_back: dlim = dlim * 2 else: dlim = distance # For small chunk counts brute force is faster than the STRtree build overhead. # Only use the spatial index when the pair count justifies it. use_tree = len(parents) * len(children) > 2500 # ~50×50 break-even if not use_tree: for child in children: for parent in parents: if parent != child and parent.x_y_distance_within(child, cutoff=dlim): parent.children.append(child) child.parents.append(parent) return # Build a spatial index over parents to avoid O(n²) pairwise distance checks. # Each parent polygon is buffered by dlim so a simple bbox query is sufficient # to find all candidates; the exact check is still done by x_y_distance_within. indexed_parents = [] parent_geoms = [] for parent in parents: if parent.poly is None: parent.update_poly() if parent.poly is not None: indexed_parents.append(parent) parent_geoms.append(parent.poly.buffer(dlim)) if not indexed_parents: # Fall back to brute force when no polygons are available for child in children: for parent in parents: if parent != child and parent.x_y_distance_within(child, cutoff=dlim): parent.children.append(child) child.parents.append(parent) return tree = STRtree(parent_geoms) for child in children: if child.poly is None: child.update_poly() if child.poly is None: # No polygon — fall back to checking all indexed parents for this child for parent in indexed_parents: if parent != child and parent.x_y_distance_within(child, cutoff=dlim): parent.children.append(child) child.parents.append(parent) continue for hit_idx in tree.query(child.poly): parent = indexed_parents[hit_idx] if parent != child and parent.x_y_distance_within(child, cutoff=dlim): parent.children.append(child) child.parents.append(parent)
[docs] def parent_child(parents, children, o): # connect all children to all parents. Useful for any type of defining hierarchy. # hierarchy works like this: - children get milled first. for child in children: for parent in parents: if parent != child: parent.children.append(child) child.parents.append(parent)
[docs] def parent_child_poly(parents, children, o): # hierarchy based on polygons - a polygon inside another is his child. # hierarchy works like this: - children get milled first. for parent in parents: if parent.poly is None: parent.update_poly() for child in children: if child.poly is None: child.update_poly() if child != parent: parent_x = parent.poly.bounds[0] parent_z = parent.poly.bounds[2] child_x = child.poly.bounds[0] child_z = child.poly.bounds[2] if parent_x <= child_x and parent_z >= child_z: if parent.poly.contains(child.poly.representative_point()): parent.children.append(child) child.parents.append(parent)