Get Element's LevelId

I goal is to get the floor element on which an element lies.
I am trying to use the Element.LevelId property as listed in the Revit API but for some reason it seems Like it isn’t working.
Any idea?

import clr

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

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

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

OUT = element[0].LevelId

Hi,
there are no properties that directly give the Level (object)
here’s a solution, assuming construction planes are levels

import sys
import clr

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument


def findLevel(e):
	assert isinstance(e, DB.ModelCurve), "Element is not a ModelCurve"
	# filter Level
	level = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels)\
											.WhereElementIsNotElementType()\
											.ToElements()\
											.Find(lambda x : x.Name == e.SketchPlane.Name)
	return level

toList = lambda x : x if hasattr(x, '__iter__') else [x]
#Preparing input from dynamo to revit
lstelems = toList(UnwrapElement(IN[0]))

OUT = [findLevel(e) for e in lstelems]
1 Like

Thanks.
Can you explain to me what this is from the API if you say there is no such property?
thanks again

Unfortunately, there is not much documentation on this subject.
I think that as CurveElements are workplane based this property return an ElementId.InvalidElementId (-1)

3 Likes

Hi @zvith
Alternatively, you can use GetNearestLevelId Method if you’re using Revit 2022:

import clr
# Import RevitAPI Classes
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
# Import DocumentManager and TransactionManager

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

#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
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
sdkNumber = int(app.VersionNumber)

toList = lambda x : x if hasattr(x, '__iter__') else [x]
#Preparing input from dynamo to revit
ModelCurves = toList(UnwrapElement(IN[0]))

def GetModelCurveLevel(item):
    assert sdkNumber > 2021,  "This Script is only Compatible with Revit 2022 and higher"
    UIunit = Document.GetUnits(doc).GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()
    Zvalue = item.Location.Curve.Origin.ToPoint().Z*304.8
    convertTo = UnitUtils.ConvertToInternalUnits(Zvalue, UIunit)
    return doc.GetElement(Autodesk.Revit.DB.Level.GetNearestLevelId(doc,UnitUtils.ConvertToInternalUnits(convertTo,UIunit)))


OUT = [GetModelCurveLevel(m) for m in ModelCurves]

3 Likes

Pretty much this. GetLevelId isn’t a method for model curves, but rather is inherited from the Element class, as model curves are a type of element. This method will only return valid results for the element types with a level, and model curves are not such a thing.

Returning the sketch plane and the level below or nearest level as shown is likely the best way forward, but be careful as planes which are not parallel to the global XY plane could cause accuracy issues, in which case returning a ‘null’ value may be preferable.

2 Likes

That’s exactly why I didn’t want to use that command as I would like to be able to pick the level automatically without worrying if it chose a different level…

The problem is model curves don’t have a level.

Imagine a curve from 1 unit below your foundation to one unit above your roof, crossing all 4 levels in between. Which level would you say this is on?

2 Likes

Is there a way to get a level by the level’s name?

You can find a node in the Genius Loci package and other nodes to query the level.
image

So I managed to put a code together which worked great - it singled out the level of object and returned a list of the rest of levels as well.
Then when I created a custom node, for some reason it’s returning me a list of all levels of all elements which isn’t needed.
Seems like the custom node skips a level in which I single out one of the elements so I get the level of that element…
Is there any reason for that to happen?

In the attached pic you can see the contents of the custom node which gives me the singled out level vs. the result of the custom node.

Interestingly enough, I added Var to the input and that seemed to solve the problem!