[solved] How test and manipulate family instance by id?

Hi everybody :slightly_smiling_face:
I ave a lot of little questions that turn around the same theme : Id and FamilyInstance in pure code

I know how to get the Id of a family instance :

new_stuff =  doc.Create.NewFamilyInstance( ... )
The_glory_ID_of_my_new_stuff = new_stuff.Id

But, with an Id from a csv text file, and with a python code(without graph) how to :

  • test if an object whit this Id exist ?
  • define what type of object it is ?
  • select an object whit this id and manipulate it ? (for exemple whit "object.LookupParameter(…))
  • get the coordinate and orientation of an object whit this id ? (and change these value)

I find that in the REVIT API DOC : SelectById
But I don’t found a functionally example code :confused:

Given an element ID from your CSV file, first cast it to an int

Using the Autodesk.Revit.DB namespace, some pseudocode:

id_csv = "123" # Assuming Dynamo interprets input as a string. May not be necessary.
id_int = int(id_csv)
element_id = ElementId(id_int) # This is now a proper ElementId object
element = doc.GetElement(element_id) # Will return null if no element by this Id exists in the doc
1 Like

Great thank ! :smile:

“id_int = int(id_csv)” I suspected that …
“ElementId(id_int)” escape of my radar !

With an instance created like this :

new = doc.Create.NewFamilyInstance(reference,insert_point_XYZ,Direction_vector_XYZ,symbol)

Do you know how to get (an modifing) “insert_point_XYZ” and “Direction_vector_XYZ” ?

Look into the FamilyInstance.FacingOrientation node and Element.GetLocation nodes.

1 Like

Thank

For get information “FacingOrientation” work well but not “GetLocation” (however simply “instance.Location” seem good) :
image

image

now I will look for modifying this value

partial auto-reply :
for change the position of an instance, must make subtraction, add lot of stuff at the begin of code, an be careful of #%@µ! conversion feet/meter :

import clr
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
from Revit.Elements import *
clr.AddReference('System')
from System.Collections.Generic import *
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
# Les entrées effectuées dans ce noeud sont stockées sous forme de liste dans les variables IN.
dataEnteringNode = IN

# Placer votre code au-dessous de cette ligne

destination = XYZ(0, 0, 0)
ret= []
for element in IN[0] :
	id=element.Id
	position=element.Location
	posx=element.Location.X
	posy=element.Location.Y
	desx=destination.X - posx
	desy=destination.Y - posy
	dest= XYZ(desx/304.8, desy/304.8, 0)
	az=element.FacingOrientation
	ret.append([id , position ,desx,desy, az])
	TransactionManager.Instance.EnsureInTransaction(doc)
	moveditems = ElementTransformUtils.MoveElement(doc, ElementId(id), dest)
	TransactionManager.Instance.TransactionTaskDone()

# Affectez la sortie Ă  la variable OUT.
OUT = ret
1 Like

GetLocation() is a method whereas Location is a property. Without the parentheses, you are returning the method itself instead of the value which it is supposed to return. So, you instead need to write:

position = element.GetLocation()
1 Like

Ha ? now “GetLocation” (with and without brackets) working too !
Maybe it’s because of stuff at begin of code …

Now all I need to do is find how to turn change the vector of direction of the elements :slight_smile:

Perhaps with " RotateElement" ? (or not)

Actually, I think the GetLocation without parentheses is imported from Revit.Elements whereas GetLocation() is imported from Autodesk.Revit.DB. When you import modules using from module import * it makes code very difficult to debug since it’s not apparent where different functions, methods, and properties are coming from. You could instead import a module with an alias. In Grasshopper, it’s common practice to use import rhinoscriptsyntax as rs.

To conclude :
I have not found an elegant solution to redefine the direction vector of an instance (if someone has a solution, I take it!)
So we have to exhume Pythagore, be guilty of trigonometry and juggle with different angle reverential (I did not understand everything, but strangely it works)
For memory, my code :

import clr
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
from Revit.Elements import *
clr.AddReference('System')
from System.Collections.Generic import *
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#import math
from math import acos
from math import radians

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
# Les entrées effectuées dans ce noeud sont stockées sous forme de liste dans les variables IN.
dataEnteringNode = IN

# Placer votre code au-dessous de cette ligne
destination = XYZ(2000, -1000, 0)
vec_dir = XYZ(20,15,0)


def XY2rad (x,y) :
	lg= ( x**2 + y**2 )**0.5
	signe = 1
	if y<0 : signe = -1
	return acos(x/lg)*signe
#fin def
	

ret= []


#corection angle 0 (axe y) ==> angle 0 (agle nul instance)
az_cible = XY2rad (vec_dir.X,vec_dir.Y) + radians(90)

for element in IN[0] :
	id=element.Id
	position=element.GetLocation()
	posx=element.Location.X/304.8
	posy=element.Location.Y/304.8
	posz=element.Location.Z/304.8
	posxyz=XYZ(posx,posy,posz)

	# orientation
	p = XYZ(posx, posy, posz)
	z = XYZ(posx, posy, posz + 1)
	axeZ= Line.CreateBound(p, z)

	vec=element.FacingOrientation
	signe = 1
	if vec.Y<0 : signe = -1
	az= acos(vec.X)*signe

	TransactionManager.Instance.EnsureInTransaction(doc)
	rotatitem = ElementTransformUtils.RotateElement(doc, ElementId(id),	axeZ, az_cible - az)
	TransactionManager.Instance.TransactionTaskDone()

	# position
	desx=destination.X/304.8 - posx
	desy=destination.Y/304.8 - posy
	dest= XYZ(desx, desy, 0)
	
	TransactionManager.Instance.EnsureInTransaction(doc)
	moveditem = ElementTransformUtils.MoveElement(doc, ElementId(id), dest)
	TransactionManager.Instance.TransactionTaskDone()

	# traces ...
	ret.append([id , position ,desx,desy, az])	

# Affectez la sortie Ă  la variable OUT.
OUT = ret

I will take care of that … at some point :innocent:

Arf … a last question :

I think i am in this case because I can’t use “element = doc.GetElement(int(id))” and “position=element.GetLocation()” together :

the code :

import clr
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
from Revit.Elements import *
clr.AddReference('System')
from System.Collections.Generic import *
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

#var
moa = []
test = &quot;false&quot;
# ############################### #
# procedure #
# ############################### #
idelem = &quot;15628&quot;

id = ElementId(int(idelem))

element = doc.GetElement(id)

if element :
test = "true"

vec=element.FacingOrientation
position=element.GetLocation

moa.append([element, test])

#Assign your output to the OUT variable.
OUT= moa

Can you give me a functional example please ?

This is actually a bit more nuanced than I thought.

Running a quick test using the following code:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

ele_dyn = IN[0]
ele_rvt = UnwrapElement(ele_dyn)

type_dyn = str(type(ele_dyn))
type_rvt = str(type(ele_rvt))
type_test = type(ele_dyn) == type(ele_rvt)

OUT = type_dyn, type_rvt, type_test

This will yield the following result:

image

which is to say that the Dynamo-owned element and Revit-owned element are both of a type called “FamilyInstance”, but are not actually the same type. While they may have methods and properties by the same name, in many cases they do not. This is illustrated by this test below:

image
type differences.dyn (13.3 KB)

 import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

ele_dyn = IN[0]
ele_rvt = UnwrapElement(ele_dyn)

# Using DS element
get_loc_dyn = ele_dyn.GetLocation()
loc_dyn = ele_dyn.Location
or_dyn = ele_dyn.FacingOrientation

# Using Revit element
# get_loc_rvt = ele_rvt.GetLocation() # Will raise AttributeError
loc_rvt = ele_rvt.Location
or_rvt = ele_rvt.FacingOrientation

OUT = or_dyn, or_rvt

In Dynamo, the FacingOrientation property returns a Vector, but the property by the same name in the Revit API returns an XYZ.

But I want to replace your “IN[0]” by an ID value from a text.csv file :confused:
So something look that GetElement(int(ValueFromCsv))

Archilab has a node to select elements by ID values that can solve that bit. Wire the output into the input on the above python and you’ll likely be in the clear.

… I didn’t express myself well.
I don’t just want to enter a single ID but run a loop with a very large amount of ID from a CSV file (this with a set of tests)

Strangely, with “element = doc.GetElement(id)”, “vec=element.FacingOrientation” working but not “position=element.GetLocation()”

So you select 1,000,000,000 IDs from the csv, select the 1,000,000,000 elements using the Archilab node, and then manipulate them with the python above… Dynamo will handle the looping automatically as long as you have structures your lists correctly.

Is there any functional example anywhere please ?

That is because doc.GetElement(id) is returning a Revit-owned element. The Revit-owned element does not have a “GetLocation()” method. This is why it’s raising an AttributeError.

An object whit orientation(FacingOrientation working) but not position ??? :face_with_raised_eyebrow: