Hello, I managed (with great difficulty) to classify elements by their Z coordinates (between 2 levels)
but to classify the elements > to the last elevation, is there a way to make a more efficient script
python script:
# Incoming
lniv=IN[0]
nniv=IN[1]
totest=IN[2]
#Buffer container
transit=[]
#container
cont=[]
#code
#1st sweep to get the elements between levels
for j in range(0,len(lniv)-1):
for i in totest:
if i>lniv[j] and i<=lniv[j+1]:
transit.append(True)
else:
transit.append(False)
cont.append(transit)
transit=[]
#2nd scan to get elements > Z last level
for j in range(len(lniv)-1,len(lniv)):
for i in totest:
if i>lniv[j]:
transit.append(True)
else:
transit.append(False)
cont.append(transit)
transit=[]
#results output
OUT = cont
Cordially
christian.stan
I would make a bounding box of the min/max X and Y values, with the Z classified by each level pairing. From there you can do a bounding box containment test on each point.
This same technique can also be used to fine which quadrant of the level each location point is in.
2 Likes
Are you working from the geometry to recover the locationl?
For the column I find a Z of 0 but as it is wedged in relation to this basic level (R+2 at a z of 543cm), it makes sense, I think.
So, I try another procedure.
Cordially
christian.stan
Was thinking ‘get location’, convert linear locations to points by midpoint, and use that point collection.
1 Like
Thank you for your availability, it’s time to go grill the duck fillets
I’ll dig into your proposal during the week.
Happy evening everyone
Cordially
christian.stan
2 Likes
I’m tempted to make a food section now… perhaps integrating it into a future forum challenge…
3 Likes
Hi,
using @jacob.small 's idea + element bounding boxes to deal with elements at the end of levels
keeping in mind that an element can be on several levels
import clr
import sys
import System
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import net library
from System.Collections.Generic import List, IList, Dictionary
#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 is_model(e):
if e.Category is not None and not isinstance(e, (ViewSheet, SpatialElement, CurveElement)):
if e.Category.CategoryType == CategoryType.Model:
bbx = e.get_BoundingBox(None)
if bbx is not None and abs(bbx.Min.Z - bbx.Max.Z) > 0.01:
return True
return False
#
# get all element in the model
filterCategoryType = System.Predicate[System.Object](is_model)
all_elems = List[DB.Element](FilteredElementCollector(doc).WhereElementIsNotElementType().ToElements()).FindAll(filterCategoryType)
#
allbbx = [x.get_BoundingBox(None) for x in all_elems]
minX = min(allbbx, key = lambda b : b.Min.X).Min.X
minY = min(allbbx, key = lambda b : b.Min.Y).Min.Y
maxX = max(allbbx, key = lambda b : b.Max.X).Max.X
maxY = max(allbbx, key = lambda b : b.Max.Y).Max.Y
#
all_levels = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType().ToElements()
out = []
# sort levels
all_levels = sorted(all_levels, key = lambda x : x.ProjectElevation)
for idx, lvl in enumerate(all_levels):
# filter elements under the first level
if idx == 0:
filterZ = System.Predicate[System.Object](lambda x : x.get_BoundingBox(None).Min.Z < lvl.ProjectElevation )
temp = all_elems.FindAll(filterZ)
out.append(["< {}".format(lvl.Name), temp])
#
# filter elements between 2 consecutive levels (intersection and inside)
else:
lvl_down = all_levels[idx - 1]
z_down = lvl_down.ProjectElevation
z_up = lvl.ProjectElevation
myOutLn = Outline(XYZ(minX, minY, z_down), XYZ(maxX, maxY, z_up))
#create LogicalOrFilter with BoundingBox
filterBbxInside = BoundingBoxIsInsideFilter(myOutLn)
filterBbxInters = BoundingBoxIntersectsFilter(myOutLn)
filterBbx = LogicalOrFilter(filterBbxInside, filterBbxInters)
#
filterZ = System.Predicate[System.Object](lambda x : filterBbx.PassesFilter(x))
temp = all_elems.FindAll(filterZ)
out.append(["{} -> {}".format(lvl_down.Name, lvl.Name) , temp])
#
# filter elements above last level
if idx + 1 == len(all_levels):
filterZ = System.Predicate[System.Object](lambda x : x.get_BoundingBox(None).Max.Z > lvl.ProjectElevation)
temp = all_elems.FindAll(filterZ)
out.append(["> {}".format(lvl.Name), temp])
OUT = out
2 Likes
Thank you so much
Cordially
christian.stan
1 Like
For exercise, same process using PLINQ extension (via IronPython)
The FilteredElementCollector implements the IEnumerable interface which allows it to work with other .NET framework facilities that can use it.
import clr
import sys
import System
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#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
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
def is_model(e):
if e.Category is not None and not isinstance(e, (ViewSheet, SpatialElement, CurveElement)):
if e.Category.CategoryType == CategoryType.Model:
bbx = e.get_BoundingBox(None)
if bbx is not None and abs(bbx.Min.Z - bbx.Max.Z) > 0.01:
return True
return False
my_collector = FilteredElementCollector(doc).WhereElementIsNotElementType()
#
allbbx = my_collector.Where(is_model).Select(lambda x : x.get_BoundingBox(None))
#
minX = allbbx.Select(lambda bb : bb.Min.X).Min()
minY = allbbx.Select(lambda bb : bb.Min.Y).Min()
maxX = allbbx.Select(lambda bb : bb.Max.X).Max()
maxY = allbbx.Select(lambda bb : bb.Max.Y).Max()
#
all_levels = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType().OrderBy(lambda x : x.ProjectElevation).ToList()
out = []
for idx, lvl in enumerate(all_levels):
# filter elements under the first level
if idx == 0:
temp = my_collector.Where(lambda x : is_model(x) and x.get_BoundingBox(None).Min.Z < lvl.ProjectElevation ).ToList()
out.append(["< {}".format(lvl.Name), temp])
#
# filter elements between 2 consecutive levels (intersection and inside)
else:
lvl_down = all_levels[idx - 1]
z_down = lvl_down.ProjectElevation
z_up = lvl.ProjectElevation
myOutLn = Outline(XYZ(minX, minY, z_down), XYZ(maxX, maxY, z_up))
#create LogicalOrFilter with BoundingBox
filterBbxInside = BoundingBoxIsInsideFilter(myOutLn)
filterBbxInters = BoundingBoxIntersectsFilter(myOutLn)
filterBbx = LogicalOrFilter(filterBbxInside, filterBbxInters)
#
temp = my_collector.WherePasses(filterBbx).Where(is_model).ToList()
out.append(["{} -> {}".format(lvl_down.Name, lvl.Name) , temp])
#
# filter elements above last level
if idx + 1 == len(all_levels):
temp = my_collector.Where(lambda x : is_model(x) and x.get_BoundingBox(None).Max.Z > lvl.ProjectElevation).ToList()
out.append(["> {}".format(lvl.Name), temp])
OUT = out
2 Likes
Hi,
Thanks for sharing knowledge :
The enumerate() class
bb filters
the logical filter with or
The Outline class (the bb with edges)
Predicate: I’m going to have to take ownership (it seems very powerful to me)
I manage to strip down and understand the process (I progress step by step, not putting the cart before the horse)
But to give birth alone to such a script will I have to sign a lease closer to the gestation of 1…n elephant(s: chances are n).
As we are well received here it is not disturbing.
Cordially
christian.stan
2 Likes