I’m working on a script to insert families (Generic Model void) of holes at the intersection of pipes, ducts, and conduits with walls and floors.
As long as there are no intersecting groups of elements, everything is fine. I’d like to solve the problem of creating holes that include groups of closely spaced pipes (as in the example image).
I’ve reached the point where I have lists containing which pipes intersect each pipe, as shown in the image (the intersecting elements it’s not actually the diameter of the pipe, but a family representing its increased diameter).
At this point, I’d like to merge the lists containing common elements to obtain additional lists representing the groups of “nearby” pipes. I’ll use these lists to create a bounding box that will represent the final through hole.
The most straightforward method in my mind requires either a recursive function or a true while loop, both of which would likely require you to use Python. You essentially need to go through each pipe and build up a list of other pipes that intersect it, joining them into a larger combined volume. Continue this process (looping over again every time you add a pipe) until there are no more intersections with your combined group, then move on to the next pipe/group.
You could also try identifying “matches” within your existing groups, which is what it sounds like you’ve been trying so far. For each current group of intersecting pipes, use List.Contains to see which other groups also contain any of the same pipes as the existing group. Collect all those subgroups and join them into a unique list. This can get very messy with list levels but it’s technically possible.
Did something similar recently regarding overlapping ElementId grouping.
Here is a simple function (rejigged a bit) that helped me.
def group_by_overlap(lists):
groups = []
group_order = [] # Track the original list index for each group
for list_idx, lst in enumerate(lists):
# Find which existing groups share items with this list
matching_groups = []
for i, group in enumerate(groups):
if any(item in group for item in lst):
matching_groups.append(i)
if not matching_groups:
# No matches - create new group
groups.append(set(lst))
group_order.append(list_idx)
else:
# Merge all matching groups + current list
merged = set(lst)
earliest_order = list_idx
for i in reversed(matching_groups): # reverse to avoid index issues
merged.update(groups.pop(i))
earliest_order = min(earliest_order, group_order.pop(i))
groups.append(merged)
group_order.append(earliest_order)
# Sort groups by their original appearance order
sorted_groups = sorted(zip(group_order, groups), key=lambda x: x[0])
return [list(group) for _, group in sorted_groups]
lists = IN[0]
OUT = group_by_overlap(lists)
Thank you so much for your reply and for the codes, because I think I also used your code to create a BoundingBox for multiple elements belonging to a list.
But now that I’ve added more Pipes to complicate the test model, I don’t understand why 400198 intersects 400199? (The yellow cylinders are generic models that the script inserts by increasing the overall radius of the Pipe, including any insulation).