Placing Cad Families through Revit Api, Python

#Placing Ceiling based families through RevitAPI, Python

Sometimes after placing one set of families and while running for another set of families through Dynamo, the first set of families disappear in Revit. This is a major problem the automation engineers are facing with dynamo.

The solution is converting the entire script to python using RevitAPI docs and the problem is solved completely.
Inputs:

  1. Cad data extraction for block names, x points, y points, and rotation values.
  2. Level information for elements to be placed
    3.3d View
  3. Family types
  4. Above Level.
  5. Index of the unique family to be placed.

Below is the Entire code and script attached which can be used to run the script.

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 *
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]
list1 = IN[0] #Excel data
Level = UnwrapElement(IN[1]) #Levels
elevation = Level.Elevation
view = UnwrapElement(IN[2]) # Views
UIunit = Document.GetUnits(doc).GetFormatOptions(UnitType.UT_Length).DisplayUnits
#pt = UnwrapElement(IN[1]).ToRevitType()
ft = UnwrapElement(IN[3])
Level2 = UnwrapElement(IN[4])
list2 = []
number = IN[5]
def transpose(list1, list2):
    # iterate over list to the length of an item
    for i in range(len(list1[0])):
        row =[]
        for item in list1:
            # appending to new list with values and index positions
            # i contains index position and item contains values
            row.append(item[i])
        list2.append(row)
    return list2
Transpose_list = transpose(list1, list2)
# deleting first item of every index
for j in range (len(Transpose_list)):
    del Transpose_list[j][0]
#deleted list
deleted = Transpose_list
# index list as input
Index_list0 = Transpose_list[0]
Index_list1 = Transpose_list[1]
Index_list2 = Transpose_list[2]
Index_list3 = Transpose_list[3]
# Getting unique items
Unique_list = []
for x in Index_list0:
	if x not in Unique_list:
		Unique_list.append(x)
#selcting item as per index
ID_list = tolist(Unique_list[number])
indexes = []
for k in Index_list0:
	for l in ID_list:
		if k==l: 
			indexes.append(True)
		else:	
			indexes.append(False)
filtered_names = [m for indx,m in enumerate(Index_list0) if indexes[indx] == True]

filtered_xpoints = [float(n) for indx,n in enumerate(Index_list1) if indexes[indx] == True]
filtered_ypoints = [float(o) for indx,o in enumerate(Index_list2) if indexes[indx] == True]
filtered_rotation = [float(r) for indx,r in enumerate(Index_list3) if indexes[indx] == True]

#d_points = [ XYZ(pt1, pt2, 0) for pt1, pt2 in zip(filtered_xpoints,filtered_ypoints)]
# Dynamo points ceiling and floor
Point_c = [Autodesk.DesignScript.Geometry.Point.ByCoordinates(pt1,pt2,Level.Elevation*304.8) for pt1, pt2 in zip(filtered_xpoints,filtered_ypoints)]
Point_f = [Autodesk.DesignScript.Geometry.Point.ByCoordinates(pt1,pt2,Level.Elevation*304.8+300) for pt1, pt2 in zip(filtered_xpoints,filtered_ypoints)]
# Converting dynamo points to revit points
rvtPoints_c = [XYZ(UnitUtils.ConvertToInternalUnits(a.X,UIunit),UnitUtils.ConvertToInternalUnits(a.Y,UIunit),UnitUtils.ConvertToInternalUnits(a.Z,UIunit)) for a in Point_c ]
rvtPoints_f = [XYZ(UnitUtils.ConvertToInternalUnits(b.X,UIunit),UnitUtils.ConvertToInternalUnits(b.Y,UIunit),UnitUtils.ConvertToInternalUnits(b.Z,UIunit)) for b in Point_f ]

#Convertinig to revit points ceiling and floor
##Revitpts_f = [ ptf.ToRevitType() for ptf in Point_f]

TransactionManager.Instance.EnsureInTransaction(doc)
#category filtes for floors and ceilings
catfilter_c = ElementCategoryFilter(BuiltInCategory.OST_Ceilings)
catfilter_f = ElementCategoryFilter(BuiltInCategory.OST_Floors)
#Reference intersector for ceilings and floors
ri_c = ReferenceIntersector(catfilter_c,FindReferenceTarget.Element,view)
ri_f = ReferenceIntersector(catfilter_f,FindReferenceTarget.Element,view)
#targets = ri_c.GetTargetElementIds()
#filter = ri_c.GetFilter()

ri_c.FindReferencesInRevitLinks = True
ri_f.FindReferencesInRevitLinks = True
refs_c = [ ri_c.FindNearest(c, XYZ.BasisZ) for c in rvtPoints_c]
refs_f = [ ri_f.FindNearest(f, XYZ.BasisZ) for f in rvtPoints_f]
distances = []
link_elements = []
pts =[]
hitpts = []
families = []
empty =[]
values = []
offset = []

direction = XYZ.BasisZ
#check for null values
Reflist = [True if (ref_c is not None) else False for ref_c in refs_c ]
#Getting index for false values
index = [b for b,val in enumerate(Reflist) if val==False]
#Getting index elements
idx_values = [ refs_f[a] for a in index]
#insert
for d in range(len(index)):
    refs_c[index[d]] = idx_values[d]
# Remove null values
allrefs = [ ]
for z in refs_c:
	if (z is None):
		continue
	allrefs.append(z)

#Getting Attributes	
for e in allrefs:
	if e==None:
		distances.append(None)
	else:
		try:
			distances.append(math.ceil(e.Proximity))
			ref = e.GetReference()
			linkinstance = doc.GetElement(ref.ElementId)
			ele = linkinstance.GetLinkDocument().GetElement(ref.LinkedElementId)
			link_elements.append(ele)
			refp = e.GetReference().GlobalPoint
			z_values = refp.Z
			offset.append(z_values-elevation)
			hitpts.append(refp)
			pts.append(Autodesk.DesignScript.Geometry.Point.ByCoordinates(UnitUtils.ConvertFromInternalUnits(refp.X,UIunit),UnitUtils.ConvertFromInternalUnits(refp.Y,UIunit),UnitUtils.ConvertFromInternalUnits(refp.Z,UIunit)))
		except:
			empty.append("No elements")	
#Making family active			
if not ft.IsActive:
	ft.Activate()
TransactionManager.Instance.EnsureInTransaction(doc)

k = 0
for hitptc in hitpts:
	family = doc.Create.NewFamilyInstance(hitptc,ft,Level,StructuralType.NonStructural)
	param = family.LookupParameter("Elevation from Level")	
	di = offset[k]
	values.append(param.Set(di))
	families.append(family)
	k = k+1
![cad data|363x500](upload://nxIL5f5MKNZEk6zTPewCrOG0xAt.png)

TransactionManager.Instance.TransactionTaskDone()
OUT = families



Fixtures placement-NonHosted API.dyn (25.5 KB)

I reformatted the block of text containing your code for you, but you might want to confirm it’s accurate. In the future, please use the preformatted text option (</>) when posting code.

Dynamo will use element binding by default. That’s the thing that’s causing multiple runs of your graph to “update” rather than place new elements. Python is probably the easiest way to get around element binding within a graph. You can however just use Dynamo Player to force a new graph execution with each run and avoid this as well.

2 Likes

Thanks for reformatting the code…!! Dynamo player, however, solves the problem but sometimes if the script is too heavy player will automatically close and the script won’t run. This problem I faced in the past and so the best may solution is writing the code in python, Revit API.

I haven’t heard of Player handling large graphs any different than Dynamo, but python would certainly be the way to lighten things up.