I am working on a script to detect clashes between tags and modeled elements. One struggle I have come across are duct and pipe tags. These types of tags have this imaginary reference leader that always point to the duct and pipe and therefore gets detected as a clash between whatever falls on that path of this line. what could be done to avoid this imaginary line from being detected as a leader?
this is boundary box around tags i am generating to compare for clashes
here is the bit of code i am working on:
# pyRevit script
# Detect Tag overlap with modeled elements in active view
# Highlights overlapping tags in bright red
# Now uses Tag's bounding box with vertical shrink to exclude ghost leaders
# User is prompted to select categories to compare against from actual model content
__title__ = 'Detect Tag Overlaps'
from Autodesk.Revit.DB import *
from pyrevit import revit, DB, forms, output
from System.Collections.Generic import List
from System import Enum
doc = revit.doc
uidoc = revit.uidoc
view = doc.ActiveView
# Start output
out = output.get_output()
# Get all elements in view and find their categories
element_collector = FilteredElementCollector(doc, view.Id).WhereElementIsNotElementType()
category_map = {}
for el in element_collector:
cat = el.Category
if cat and cat.Id.IntegerValue < 0: # Built-in categories only
if cat.Name not in category_map:
category_map[cat.Name] = cat.BuiltInCategory
if not category_map:
forms.alert("No valid model categories found in view.", title="Tag Overlap Detection", warn_icon=True)
script.exit()
# Prompt user to select from only categories in the view
selected_names = forms.SelectFromList.show(sorted(category_map.keys()), title="Select Categories to Clash With Tags", multiselect=True)
if not selected_names:
forms.alert("No categories selected. Exiting.", title="Tag Overlap Detection", warn_icon=True)
script.exit()
selected_categories = [category_map[name] for name in selected_names]
# Collect all tags in active view
tag_collector = FilteredElementCollector(doc, view.Id)\
.OfClass(IndependentTag)\
.WhereElementIsNotElementType()
tags = tag_collector.ToElements()
# Create LogicalOrFilter for selected categories
category_filters = [ElementCategoryFilter(cat) for cat in selected_categories]
multi_category_filter = LogicalOrFilter(category_filters)
# Collect model elements matching selected categories
model_collector = FilteredElementCollector(doc, view.Id)\
.WhereElementIsNotElementType()\
.WherePasses(multi_category_filter)
models = model_collector.ToElements()
def bounding_boxes_intersect(bb1, bb2):
"""Check if two bounding boxes intersect in 2D (XY plane)."""
if not bb1 or not bb2:
return False
# Check X overlap
if bb1.Max.X < bb2.Min.X or bb1.Min.X > bb2.Max.X:
return False
# Check Y overlap
if bb1.Max.Y < bb2.Min.Y or bb1.Min.Y > bb2.Max.Y:
return False
return True
def get_filtered_tag_boundingbox(tag, view, shrink_factor=0.1):
"""Get bounding box of tag and shrink Z axis to ignore ghost leader effects."""
bb = tag.get_BoundingBox(view)
if not bb:
return None
min_pt = bb.Min
max_pt = bb.Max
# Shrink Z axis tightly (ignore long ghost lines vertically)
new_min = XYZ(min_pt.X, min_pt.Y, (min_pt.Z + max_pt.Z) / 2.0 - shrink_factor)
new_max = XYZ(max_pt.X, max_pt.Y, (min_pt.Z + max_pt.Z) / 2.0 + shrink_factor)
new_bb = BoundingBoxXYZ()
new_bb.Min = new_min
new_bb.Max = new_max
return new_bb
# Store overlaps
overlapping_tags = []
for tag in tags:
if not isinstance(tag, IndependentTag):
continue
tag_bb = get_filtered_tag_boundingbox(tag, view)
if not tag_bb:
continue
for model in models:
model_bb = model.get_BoundingBox(view)
if not model_bb:
continue
if bounding_boxes_intersect(tag_bb, model_bb):
overlapping_tags.append((tag, model))
# Prepare override settings
highlight_ogs = OverrideGraphicSettings()
highlight_ogs.SetProjectionLineColor(Color(255, 0, 0)) # Bright red lines
highlight_ogs.SetCutLineColor(Color(255, 0, 0)) # Red cut lines
highlight_ogs.SetSurfaceForegroundPatternColor(Color(255, 0, 0)) # Red surface hatch
highlight_ogs.SetHalftone(False)
# Report
if overlapping_tags:
out.print_md("## Overlapping Tags Found:\n")
# Start a Transaction for highlighting
with revit.Transaction("Highlight Overlapping Tags"):
for tag, model in overlapping_tags:
# Report
out.print_md("Tag: {} overlaps with Model: {}".format(
out.linkify(tag.Id),
out.linkify(model.Id)
))
out.print_md("---")
# Highlight the tag
view.SetElementOverrides(tag.Id, highlight_ogs)
else:
forms.alert("No overlapping tags detected!", title="Tag Overlap Detection", warn_icon=False)```