Is it easier than a double sweep with 2 for

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. :wink:
Happy evening everyone
Cordially
christian.stan

2 Likes

Sounds tasty

1 Like

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 :wink::
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