Select HVAC Zones

I have started this script to ideally allow be to select HVAC Zones but it is not letting me. Any ideas?

from Autodesk.Revit.DB import (
    FilteredElementCollector,
    BuiltInCategory,
    ViewPlan,
    SpatialElementBoundaryOptions,
    GraphicsStyle,
    Transaction,
    ElementId,
    SpatialElement
)
from Autodesk.Revit.UI.Selection import ObjectType, ISelectionFilter
from pyrevit import forms

# Custom selection filter to ensure only HVAC zones are selected
class HVACZoneSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        # Check if the element is an HVAC zone
        if isinstance(element, SpatialElement) and element.Category.Id.IntegerValue == int(BuiltInCategory.OST_HVAC_Zones):
            return True
        return False
    
    def AllowReference(self, reference, position):
        return False

# Get current document
doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument  # Correctly get the active UIDocument

# Get current view (assuming it's a floor plan or ceiling plan)
current_view = doc.ActiveView

# Check if the view is valid for detail lines
if not isinstance(current_view, ViewPlan):
    forms.alert("Please run this script in a Floor Plan or Ceiling Plan view.", exitscript=True)

# Prompt user to select HVAC zones with the custom filter
selected_zone_refs = uidoc.Selection.PickObjects(ObjectType.Element, HVACZoneSelectionFilter(), "Select HVAC Zones")

I am trying this one
image

I have my MEP spaces created and added to a zone


Changing BuiltInCategory.OST_HVAC_Zones to BuiltInCategory.OST_MEPSpaces does allow me to select spaces so I am not sure what else I am missing.

1 Like

this is my original script

from Autodesk.Revit.DB import (
    FilteredElementCollector,
    BuiltInCategory,
    ViewPlan,
    SpatialElementBoundaryOptions,
    GraphicsStyle,
    Transaction,
    ElementId,
    SpatialElement
)
from Autodesk.Revit.UI.Selection import ObjectType, ISelectionFilter
from pyrevit import forms

# Custom selection filter to ensure only HVAC zones are selected
class HVACZoneSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        # Check if the element is an HVAC zone
        if isinstance(element, SpatialElement) and element.Category.Id.IntegerValue == int(BuiltInCategory.OST_MEPSpaces):
            return True
        return False
    
    def AllowReference(self, reference, position):
        return False

# Get current document
doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument  # Correctly get the active UIDocument

# Get current view (assuming it's a floor plan or ceiling plan)
current_view = doc.ActiveView

# Check if the view is valid for detail lines
if not isinstance(current_view, ViewPlan):
    forms.alert("Please run this script in a Floor Plan or Ceiling Plan view.", exitscript=True)

# Prompt user to select HVAC zones with the custom filter
selected_zone_refs = uidoc.Selection.PickObjects(ObjectType.Element, HVACZoneSelectionFilter(), "Select HVAC Zones")

# Exit if the user cancels the selection
if not selected_zone_refs:
    forms.alert("No HVAC zones selected. Exiting script.", exitscript=True)

# Convert selected references to elements
selected_zones = [doc.GetElement(ref.ElementId) for ref in selected_zone_refs]

# Collect all line styles available in the document
line_styles = FilteredElementCollector(doc).OfClass(GraphicsStyle).ToElements()

# Create a dictionary of line style names and their corresponding ElementIds
line_style_dict = {ls.Name: ls.Id for ls in line_styles}

# Sort the line style names alphabetically
sorted_line_styles = sorted(line_style_dict.keys())

# Prompt user to select a line style from the sorted list
selected_line_style_name = forms.SelectFromList.show(sorted_line_styles, title="Select Line Style", button_name="OK")

# Exit if the user cancels the selection
if not selected_line_style_name:
    forms.alert("No line style selected. Exiting script.", exitscript=True)

# Get the selected line style ElementId
selected_line_style_id = line_style_dict[selected_line_style_name]

# Start a transaction
t = Transaction(doc, "Draw HVAC Zone Boundaries")
t.Start()

try:
    for zone in selected_zones:
        # Get the boundary curves for the zone
        boundary_options = SpatialElementBoundaryOptions()  # Instantiate the boundary options
        boundary_segments = zone.GetBoundarySegments(boundary_options)
        
        for segment in boundary_segments:
            for curve in segment:
                # Convert curve to a detail line in the current view with the selected line style
                detail_line = doc.Create.NewDetailCurve(current_view, curve.GetCurve())
                detail_line.LineStyle = doc.GetElement(selected_line_style_id)  # Set the line style
                
finally:
    # Commit the transaction
    t.Commit()

I am attempting to get the zone boundaries to then be able to place detail lines over them.

as of now, it it placing detail lines over any space boundary due to BuiltInCategory.OST_MEPSpaces which i don’t want

1 Like

@Ralph1024 ,

so your filter need a correction,

when i just do this

selected_zone_refs = uidoc.Selection.PickObjects(ObjectType.Element)

it works

here are the correction

class HVACZoneSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        # Check if the element is an HVAC zone
        if element.Category is not None and element.Category.Id.IntegerValue == int(BuiltInCategory.OST_HVAC_Zones):
            return True
        return False

    def AllowReference(self, reference, position):
        return False

# Get current document and active view
doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument

# Check if the view is valid for detail lines
if not isinstance(current_view, ViewPlan):
    forms.alert("Please run this script in a Floor Plan or Ceiling Plan view.", exitscript=True)

# Prompt user to select HVAC zones with the custom filter
try:
    selected_zone_refs = uidoc.Selection.PickObjects(ObjectType.Element, HVACZoneSelectionFilter(), "Select HVAC Zones")
    selected_zones = [doc.GetElement(ref) for ref in selected_zone_refs]
    forms.alert("Selected {} HVAC Zones.".format(len(selected_zones)))
except Exception as e:
    forms.alert("Selection cancelled or error occurred: {}".format(str(e)))

@andreasd811 hmm, i guess HVAC Zones are not spatial elements.

so after implementing this into the main script, it works.

I have a little debugging to do but i would like some input on my error i am getting

from Autodesk.Revit.DB import (
    FilteredElementCollector,
    BuiltInCategory,
    ViewPlan,
    SpatialElementBoundaryOptions,
    GraphicsStyle,
    Transaction,
    ElementId,
    SpatialElement
)
from Autodesk.Revit.UI.Selection import ObjectType, ISelectionFilter
from pyrevit import forms

# Custom selection filter to ensure only HVAC zones are selected
class HVACZoneSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        # Check if the element is an HVAC zone
        if element.Category is not None and element.Category.Id.IntegerValue == int(BuiltInCategory.OST_HVAC_Zones):
            return True
        return False

    def AllowReference(self, reference, position):
        return False

# Get current document and active view
doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument

# Get current view (assuming it's a floor plan or ceiling plan)
current_view = doc.ActiveView

# Check if the view is valid for detail lines
if not isinstance(current_view, ViewPlan):
    forms.alert("Please run this script in a Floor Plan or Ceiling Plan view.", exitscript=True)

# Prompt user to select HVAC zones with the custom filter
try:
    selected_zone_refs = uidoc.Selection.PickObjects(ObjectType.Element, HVACZoneSelectionFilter(), "Select HVAC Zones")
    selected_zones = [doc.GetElement(ref) for ref in selected_zone_refs]
    forms.alert("Selected {} HVAC Zones.".format(len(selected_zones)))
except Exception as e:
    forms.alert("Selection cancelled or error occurred: {}".format(str(e)))

# Exit if the user cancels the selection
if not selected_zone_refs:
    forms.alert("No HVAC zones selected. Exiting script.", exitscript=True)

# Convert selected references to elements
selected_zones = [doc.GetElement(ref.ElementId) for ref in selected_zone_refs]

# Collect all line styles available in the document
line_styles = FilteredElementCollector(doc).OfClass(GraphicsStyle).ToElements()

# Create a dictionary of line style names and their corresponding ElementIds
line_style_dict = {ls.Name: ls.Id for ls in line_styles}

# Sort the line style names alphabetically
sorted_line_styles = sorted(line_style_dict.keys())

# Prompt user to select a line style from the sorted list
selected_line_style_name = forms.SelectFromList.show(sorted_line_styles, title="Select Line Style", button_name="OK")

# Exit if the user cancels the selection
if not selected_line_style_name:
    forms.alert("No line style selected. Exiting script.", exitscript=True)

# Get the selected line style ElementId
selected_line_style_id = line_style_dict[selected_line_style_name]

# Start a transaction
t = Transaction(doc, "Draw HVAC Zone Boundaries")
t.Start()

try:
    for zone in selected_zones:
        # Get the boundary curves for the zone
        boundary_options = SpatialElementBoundaryOptions()  # Instantiate the boundary options
        boundary_segments = zone.GetBoundarySegments(boundary_options)
        
        for segment in boundary_segments:
            for curve in segment:
                # Convert curve to a detail line in the current view with the selected line style
                detail_line = doc.Create.NewDetailCurve(current_view, curve.GetCurve())
                detail_line.LineStyle = doc.GetElement(selected_line_style_id)  # Set the line style
                
finally:
    # Commit the transaction
    t.Commit()

As part of the script, i also have it prompt a selection for detail lines but the prompt shows me a lot more that aren’t line styles for detail lines

Revit

I have tried to filter them out to only line styles for detail lines but have not been successful. any suggestions/

@Ralph1024 ,

i think you have select model and detailline before… line style is indemented, because you can convert always lines… which line do you need i thought you only grab Zones.

i’m only wanting the detail lines to show up as selection options, not the model lines.

@Ralph1024

you can implement a if toggle

let me look into this

@Ralph1024

lines = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Lines).WhereElementIsNotElementType().ToElements()

detail_lines = [ i for i in lines if i.Name.Contains("Detail")]
model_lines = [ i for i in lines if i.Name.Contains("Model")]

print("you have {} detail lines".format(len(detail_lines)))
print("you have {} model lines".format(len(model_lines)))

it works well, next step find the right place in your script :wink:

grafik

so that did help a lot. it was showing me 5000+ detail lines :face_with_spiral_eyes:

but it helped resolve it by using this:

# Filter the collected styles to include only those that:
# - Belong to a subcategory under the 'Lines' category (i.e., detail line styles)
# - Are of the 'Projection' type, which is the typical type for detail lines in Revit
detail_line_styles = [
    style for style in collector
    if style.GraphicsStyleCategory.Parent is not None and
    style.GraphicsStyleCategory.Parent.Id.IntegerValue == int(BuiltInCategory.OST_Lines) and 
    style.GraphicsStyleType == GraphicsStyleType.Projection

Thank you for the support @andreasd811

1 Like