Placing Arrows for each and every sloped pipe to indicate the direction for all levels and especially in basement areas where sanitary pipes are huge in number is a very difficult task for plumbing modelers. Here is a very good solution.
The script does the following:
- Filters pipe length as per requirement and collects all sloped pipes.
- Assigns the right level to pipes even if they have wrong reference levels.
- Places the Arrow family as per level.
Inputs:
- Select Family.
- Assign Pipe length.
- Select level
- Select all the pipes visible in the view
Outputs:
- Arrows placed
Here is the entire code written in Revit Api, Python :
import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import math
import System
from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from Autodesk.Revit.DB.Structure import *
from Autodesk.Revit.DB.Plumbing import *
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]
# Place your code below this line
def ToInternalUnits(number, unittype = None):
if unittype == None:
unittype = UnitType.UT_Length
currentType = doc.GetUnits().GetFormatOptions(unittype).DisplayUnits
return UnitUtils.ConvertToInternalUnits(number, currentType)
def getview(v):
v1 = str(v.ViewType)
if v1=="FloorPlan":
return(v)
else: return("Input is Not a Plan view")
View = UnwrapElement(IN[0])
Length = IN[1]
ft = UnwrapElement(IN[2])
Level = UnwrapElement(IN[3])
#System classification rule filter
Sys_rule = ParameterFilterRuleFactory.CreateEqualsRule(ElementId(-1140325),"Sanitary",True)
#Length rule filter
Length_rule = ParameterFilterRuleFactory.CreateGreaterOrEqualRule(ElementId(-1004005),ToInternalUnits(Length),0)
#C list for filters
Filters = List[FilterRule]()
Filters.Add(Sys_rule)
Filters.Add(Length_rule)
# Parameter Filer
param_filter =ElementParameterFilter(Filters)
# filter collector for pipes
Fec_Pipes = FilteredElementCollector(doc,View.Id).OfClass(Pipe).WherePasses(param_filter).ToElements()
#pipe curves
curves = [pipe.Location.Curve.Direction for pipe in Fec_Pipes ]
#for pipe in Fec_Pipes:
# curves.append(pipe.Location.Curve.Direction)
#pipe directions
vectors = [ curve.IsAlmostEqualTo(XYZ(0,0,1)) for curve in curves ]
#for i in curves:
# vectors.append(i.IsAlmostEqualTo(XYZ(0,0,1)))
#filtering elements parallel to z
filtered_elements = [m for indx,m in enumerate(Fec_Pipes) if vectors[indx] == False]
elementIds = List[ElementId]()
for x in filtered_elements:
elementIds.Add(x.Id)
#Slope rule filter
Slope_rule = ParameterFilterRuleFactory.CreateHasValueParameterRule(ElementId(-1140256))
Element_Filter = ElementParameterFilter(Slope_rule)
# Filtering on the existing element list
Fec_Elements = FilteredElementCollector(doc,elementIds).WherePasses(Element_Filter).ToElements()
# Getting elements have slope
def getelements(y):
elements = []
for e in y:
if e is None:
elements.append(None)
else:
value = e.LookupParameter("Slope").AsDouble()
if value > 0 and value <1:
elements.append(e)
return elements
elems = getelements(Fec_Elements)
# locations
Startpoints = []
Directions = []
Length = []
D_curve = []
for elem in elems:
D_curve.append(elem.Location.Curve.ToProtoType())
Startpoints.append(elem.Location.Curve.Evaluate(0.5, True))
Length.append(elem.Location.Curve.Length)
start_ptz = elem.Location.Curve.GetEndPoint(0).Z
Mid_ptz = elem.Location.Curve.Evaluate(0.5, True).Z
if start_ptz > Mid_ptz:
Directions.append(elem.Location.Curve.Direction)
else:
Directions.append(elem.Location.Curve.Direction.Negate())
#Linebystartpointdirectionandlength
def lineDB_ByStartPointDirectionLength(pt, vector, distance):
vector = vector.Normalize() * distance
return Line.CreateBound(pt, pt + vector)
def PlaceArrows(a):
arrow = doc.Create.NewFamilyInstance(a,ft,Level,StructuralType.NonStructural)
param = arrow.LookupParameter("W")
param_value = param.Set(ToInternalUnits(25))
Arrows.append(arrow)
return Arrows
Lines = []
for i,j,k in zip(Startpoints,Directions,Length):
l = lineDB_ByStartPointDirectionLength(i,j,k)
Lines.append(l)
#Making family active
if not ft.IsActive:
ft.Activate()
TransactionManager.Instance.EnsureInTransaction(doc)
#t = Transaction(doc,"Exception Handling")
Arrows = []
for line in Lines:
try:
Arrows_placed = PlaceArrows(line)
except:
Arrows.append("No elements placed")
TransactionManager.Instance.TransactionTaskDone()
OUT = Arrows_placed