Element Bounding Box midpoint shows far away from element

bb = element.get_BoundingBox(None)
   if bb:
      midpt = ((bb.Min + bb.Max) / 2).ToPoint()

Above code shows bb mid point far away from element categories(windows, electrical fixtures, etc…) which has witness lines or dimension reference lines, how to get BB midpoint of element ignoring these?

@mmkkmmv ,

check out this topic

could also be that your family is not clean modeled. thats essential to keep the box “skinfit” to your element.

KR

Andreas

@Draxl_Andreas
Not working for element or family instance which has witness lines, I am using Dynamo python script node for this, but how to ignore element witness lines for bounding box midpoint to be on element itself?

Are you trying to get the midpoint of a linked model element?

First generate a new view, then disable the lines categories in that view. Use that view when pulling the bounding box and it should omit the curves. Once the bounding box is taken you can delete the new view.

@pyXam not from linked model element, from direct model element

I take it back - you can’t just hide the linework, but rather need to pull the bounding box from the solid geometry.

There is a code sample here in C#, which you should be able to translate without much issue: Solved: Revit API get bounding box around door geometry (excluding swing) - Autodesk Community

@jacob.small I am using revit dynamo python script node for this

Yes. You will want to translate the C# code into Python. Not a two second task, but not insurmountable.

# Load the Python Standard and DesignScript Libraries
import clr
import sys
import itertools
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import System
from System import Array
from System.Collections.Generic import *

clr.AddReference('ProtoGeometry')###REMOVED FOR error, 2 lines only
from Autodesk.DesignScript.Geometry import *


clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
from Revit.Elements import Element

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 *

clr.AddReference('DSCoreNodes')
from DSCore.List import Flatten


doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

# The inputs to this node will be stored as a list in the IN variables.
inputElements = IN[0]
view1 = doc.ActiveView

opt=Options()
opt.ComputeReferences = False
opt.IncludeNonVisibleObjects = False
#opt.View = view1

def get_bb_mid(ele):
	bb1 = None
	geo = ele.get_Geometry(opt)
	for a in geo:
		geoInst = a.GetInstanceGeometry()
		for g in geoInst:
			if isinstance(g, Solid):
				bb1 = g.GetBoundingBox()
				if bb1:
					break

	return bb1


centroid_lst = []
for ele1 in inputElements:
	#ele_typ_id = ele.GetType()
	ele = UnwrapElement(ele1)
	pt1 = get_bb_mid(ele)
	centroid_lst.append(pt1)
# Assign your output to the OUT variable.
OUT = centroid_lst

tried above
getting boundingboxXYZ, i need one mid point on element

Your previous code for the middle of the bounding box should work now.

That said, keep in mind that the middle of the bounding box may not fall inside of the solid geometry.

@jacob.small I need one near midpoint on element itself not outside of element geometry, any suggestions?

Would need a sample of the geometry to see the best path forward. Post the RVT with one or two instances in it and I’ll have a look later.

Sending Rvt file may take time, but i observed that, if I move witness lines near to element, bounding box midpoint is near to element & this may work for me, majority elements are familyInstances which has this issue, how to ignore these witness lines to get element BB midpoint?

Review the C# code previously provided. Or filter out non-solids from the list of geometry, union the remaining solids into a single solid, and pull the bounding box from the single solid.

Hi,

a solution by summing the bounding boxes of the solids

import clr
import sys
import System
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

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

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

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

def get_midBBX_byGeometry(elem):
    # sub function
    def get_solid_bbx(solid):
        box = solid.GetBoundingBox()
        origin = box.Transform.Origin
        box.Min = box.Min.Add(origin)
        box.Max = box.Max.Add(origin)
        return box
    # main function
    opt=Options()
    opt.ComputeReferences = False
    opt.IncludeNonVisibleObjects = False
    boxes = []
    geoSet = elem.get_Geometry(opt)
    for geo in geoSet:
        if isinstance(geo, GeometryInstance):
            for gi in geo.GetInstanceGeometry():
                if isinstance(gi, Solid) and gi.Volume > 0.01:
                    boxes.append(get_solid_bbx(gi))
        elif isinstance(geo, Solid) and geo.Volume > 0.01:
            boxes.append(get_solid_bbx(geo))
        else:
            pass
    geoSet.Dispose()
    minx = min(boxes, key = lambda x : x.Min.X).Min.X
    miny = min(boxes, key = lambda x : x.Min.Y).Min.Y
    minz = min(boxes, key = lambda x : x.Min.Z).Min.Z
    maxx = max(boxes, key = lambda x : x.Max.X).Max.X
    maxy = max(boxes, key = lambda x : x.Max.Y).Max.Y
    maxz = max(boxes, key = lambda x : x.Max.Z).Max.Z
    midpoint = XYZ((minx + maxx) / 2.0, (miny + maxy) / 2.0, (minz + maxz) / 2.0)
    return midpoint

elem = UnwrapElement(IN[0])

OUT = get_midBBX_byGeometry(elem).ToPoint()
2 Likes

Thanks, will check

Hi there,
I recommend using the Archilab Package GetCentroid method; it worked for me when I encountered the same issue.
Edit-
Supplying the model elements directly to this node will do the job and no need to get the bounding box from Element.

1 Like

Can i select element automatic with this centroid whether element present or not in python node?

@NIRMAL

i cant answer directly ... i cant find in the API GetCentroid

import clr
import sys 

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

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('System')
from System.Collections.Generic import List

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#functions
def tolist(x):
    if hasattr(x,'__iter__'): return x
    else: return [x]



#Preparing input from dynamo to revit
elements = UnwrapElement(tolist(IN[0]))

output = []

for i in elements:
	output.append(i.get_Geometry(Options()))

	
OUT = output

i get this just with Centroid


#functions
def tolist(x):
    if hasattr(x,'__iter__'): return x
    else: return [x]


elements = UnwrapElement(tolist(IN[0]))

output = []

for i in elements:
	output.append(i.Centroid)

	
OUT = output

KR

Andreas

1 Like