Convert XYZ to Point?

I am working on a script that will subdivide a list of elements based upon the elements’ location within the Revit project. I am having an issue with getting my python script behave properly. It provides the following warning message:

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed. 
Traceback (most recent call last):
  File "<string>", line 48, in < module >
TypeError: expected Point, got XYZ

How would I go about converting XYZ values into Point Values?

Here is my full script:

# Enable Python support and load DesignScript library
import clr

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
    
clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *

clr.AddReference("RevitServices")
from RevitServices import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
# The inputs to this node will be stored as a list in the IN variables.
taktNames = IN[0]		#All Names of TAKT Areas in Project. Via ScopeBox
elemsScBoxs = IN[1]		#All Elements of ScopeBox in Project
boundBoxScope = IN[2]	#All ScopeBoxes convert to BoundingBox
elemsFabPrt = IN[3]		#All Fabrication Parts in the Document
fabBBMidPnt = []		#Centroid of all Fabrication Parts' BoundingBox
ReturnElems = []		#[0] of sublist is name of TAKT, followed by elems in that TAKT
tuple = taktNames
# Place your code below this line
elements = UnwrapElement(elemsFabPrt)
fabBBMidPnt =[]
for e in elements:
	bb = e.get_BoundingBox(None)
	if not bb is None:
		center = bb.Min+(bb.Max-bb.Min)/2
		fabBBMidPnt.append(center)

max=[]
min=[]
for x in boundBoxScope:
	max.append(x.BoundingBox.MaxPoint)
	min.append(x.BoundingBox.MinPoint)

#OUT = [max, min]


LIST=[]
for x in boundBoxScope:
	for i in fabBBMidPnt:
		if x.BoundingBox.Contains(i) == true:
			OUT = i
		
		
# Assign your output to the OUT variable.
OUT = LIST
#OUT = [taktNames, elemsScBoxs, boudBoxScope, elemsFabPrt, fabBBMidPnt]
#OUT = "Sure"

Hi t.large,

Try changing

if x.BoundingBox.Contains(Revit.Point.Create.i) == true:

to

if x.BoundingBox.Contains(Revit.Point.Create(i)) == true:
1 Like

It has returned an error message:

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed. 
Traceback (most recent call last):
  File "<string>", line 48, in <module>
AttributeError: attribute 'Point' of 'namespace#' object is read-only

I apologize, the original line that results in the top error message is as such:

if x.BoundingBox.Contains(i) == true:

You should use the Point.Create(XYZ) function to convert and XYZ to a point.

Link to API docs to function: https://www.revitapidocs.com/2020/fcc27c7e-5491-fea0-9adc-98db9e27076c.htm

I hope it works

1 Like

Funny enough, when I use Point.Create(XYZ) I get this error…

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed. 
Traceback (most recent call last):
  File "<string>", line 48, in <module>
TypeError: expected Point, got Point

Full Python script:

# Enable Python support and load DesignScript library
import clr

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript import *

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
    
clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *

clr.AddReference("RevitServices")
from RevitServices import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
# The inputs to this node will be stored as a list in the IN variables.
taktNames = IN[0]		#All Names of TAKT Areas in Project. Via ScopeBox
elemsScBoxs = IN[1]		#All Elements of ScopeBox in Project
boundBoxScope = IN[2]	#All ScopeBoxes convert to BoundingBox
elemsFabPrt = IN[3]		#All Fabrication Parts in the Document
fabBBMidPnt = []		#Centroid of all Fabrication Parts' BoundingBox
ReturnElems = []		#[0] of sublist is name of TAKT, followed by elems in that TAKT
tuple = taktNames
# Place your code below this line
elements = UnwrapElement(elemsFabPrt)
fabBBMidPnt =[]
for e in elements:
	bb = e.get_BoundingBox(None)
	if not bb is None:
		center = bb.Min+(bb.Max-bb.Min)/2
		fabBBMidPnt.append(center)

max=[]
min=[]
for x in boundBoxScope:
	max.append(x.BoundingBox.MaxPoint)
	min.append(x.BoundingBox.MinPoint)

#OUT = [max, min]


LIST=[]
for x in boundBoxScope:
	for i in fabBBMidPnt:
		if x.BoundingBox.Contains(Point.Create(i)) == true:
			OUT = i
		
		
# Assign your output to the OUT variable.
OUT = LIST
#OUT = [taktNames, elemsScBoxs, boudBoxScope, elemsFabPrt, fabBBMidPnt]
#OUT = "Sure"

Do you want to create a point in Revit (like in an adaptive component) or a point in Dynamo?

I’ve retrieved the centroid of each Fabrication Element, and am trying to use the BoundingBox.Conatins command to then group all of the Fabrication Elements dependant upon whether or not the Element’s Centroid is located within a Bounding Box. But it doesn’t like the Centroid format. It asks for a Point, and actually now when I feed it a Point value it says it is still wrong format.

BoundingBox.Contains is a method specific to DesignScript, and therefore also requires a DesignScript Point. However, you are supplying an Autodesk.Revit.DB.Point object. Here is an example of the different cases:

import clr
clr.AddReference('RevitAPI')
import Autodesk.Revit.DB as DB

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

bbox = IN[0][0]
ds_point = IN[1]
db_xyz = DB.XYZ(0, 0, 0)
db_point = DB.Point.Create(db_xyz)

# Convert Autodesk.Revit.DB.XYZ to DesignScript Point
db_xyz_converted = db_xyz.ToPoint()

# Works properly
bbox.Contains(ds_point)

# Raises TypeError
bbox.Contains(db_xyz)

# Raises TypeError
bbox.Contains(db_point)

# Works properly
bbox.Contains(db_xyz_converted)

In short, you need to import the Revit.GeometryConversion extension by adding this line after import Revit:

clr.ImportExtensions(Revit.GeometryConversion)

This will then allow you to take your centroid (bb.Min+(bb.Max-bb.Min)/2) and convert it to the proper DesignScript equivalent using the ToPoint() method. Change this line:

fabBBMidPnt.append(center)

to this:

fabBBMidPnt.append(center.ToPoint())

Then, you can change this line:

if x.BoundingBox.Contains(Point.Create(i)) == true:

to this:

if x.BoundingBox.Contains(i):

Note that it is not necessary to say if BoundingBox.Contains(point) == True since BoundingBox.Contains already returns a boolean. Essentially, this would be saying if True == True: which then evaluates to if True:.

I would also recommend using more descriptive variable names so that it is easier to keep track of what each variable actually represents.

2 Likes