Hello, i’m trying to get the layer of the walls that delimitate a room, inquiring the faces of the wall. All works well excpt for the wall where membrane layer is set. In that case the method get only the finish layer before the membrane. There is a way to get the membrane instead?
Hi Pietro, welcome
Please take time to read the following post How to get help on the Dynamo forums
Can you provide more information? Are you using python? Can you provide a screen shot of your graph?
My guess is that it is something to do with a wall type core and shell layers, however it is very difficult to diagnose the issue without additional information
Hi,
After several attempts, I think the only solution is to analyze the layers of the internal wall structure with CompoundStructure
code (tested with IronPython2 or 3)
import sys
import clr
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
room = UnwrapElement(IN[0])
debug = []
#
calculator = SpatialElementGeometryCalculator(doc)
results_data_room = []
if calculator.CanCalculateGeometry(room):
results = calculator.CalculateSpatialElementGeometry(room)
roomSolid = results.GetGeometry()
roomMaterial = list()
for face in roomSolid.Faces:
bbx_face = face.GetBoundingBox()
minPt_face = face.Evaluate(bbx_face.Min)
for subface in results.GetBoundaryFaceInfo(face):
if subface.SubfaceType == SubfaceType.Side:
boundingElement = subface.GetBoundingElementFace()
lnkelemId = subface.SpatialBoundaryElement
materialId = boundingElement.MaterialElementId
material = doc.GetElement(materialId)
print(f"material : {material.Name}")
elem = doc.GetElement(lnkelemId.HostElementId )
if isinstance(elem, Wall):
comp_structure = elem.WallType.GetCompoundStructure()
# get ordered layers exterior to interior
layers = list(comp_structure.GetLayers())
# if the 1st or the last item is a membrane
if layers[0].Function == MaterialFunctionAssignment.Membrane or layers[-1].Function == MaterialFunctionAssignment.Membrane:
#
# compute interior line and exterior line
line_location = elem.Location.Curve
offset_ext = comp_structure.GetOffsetForLocationLine(WallLocationLine.FinishFaceExterior)
offset_int = comp_structure.GetOffsetForLocationLine(WallLocationLine.FinishFaceInterior)
# reverse offsets if wall is flipped
if elem.Flipped :
offset_ext *= -1
offset_int *= -1
line_exterior = line_location.CreateOffset(offset_int, XYZ.BasisZ)
line_interior = line_location.CreateOffset(offset_ext, XYZ.BasisZ)
#
# obtenir la couche la plus proche de la face de la pièce
pairs_line_layer = [[line_exterior, layers[0]], [line_interior, layers[-1]]]
pairs_line_layer.sort(key = lambda x : x[0].Project(minPt_face).Distance )
# get material
material = doc.GetElement(pairs_line_layer[0][1].MaterialId)
surfaceDs = face.ToProtoType()
results_data_room.append([surfaceDs[0], elem, material.Name])
results.Dispose()
OUT = results_data_room
Hi, thanks for the reply. My idea was the same, but i did all with nodes with a lot of workaround. This means that it’s very difficult to control it. So i’ll try you code asap.
The goal of my script is to popolate the room’s information about walls in a building with more the 1000 rooms…
Edit: I looked at your code and maybe (I am not a programmer) your code is not distinguishing the right side. Let me explain: a wall separating two rooms might have a membrane of one type on one side and a membrane of another type on the other. Or it might have no membrane at all on one side. That’s why, in the sequence I’ve set up, I check to see if the surface it has identified for that room is on the outside or inside, and then I try to check if there is a membrane on that side (I do a -1 or +1 depending on whether it’s before or after 3).
Can you upload a sample RVT file with your wall types? I’ll check it out.
Hi, I cannot upload because i’m new, if you know how to do, please tell me. I can screenshoot an example:
In this case my script work, but is a dirty code and i cannot check it in more complex situation
I’m updating your trust level so you should be able to post files soon, but you can also use a 3rd party service such as Dropbox, Google Drive, Box, OneDrive, Etc…
Thank you!
Here my script and a simple rvt
tess.rvt (5.6 MB)
Test Room 1.dyn (41.0 KB)
I’ve tested my code with your RVT, it works fine, but my solution may fail with other complex walls.
Can you send me your script. I would like to mix it up with mine
It was provided here: GetBoundingElementFace and Membrane Layer - #3 by c.poupin
Here is an update version for a list of rooms at input
code IronPython2 or 3 (Possible with CPython3 see comments in code)
import sys
import clr
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
def get_room_finish_materials(calculator, room):
roomMaterials = []
if calculator.CanCalculateGeometry(room): # if you use CPython3 / PythonNet use .Net Reflection
results = calculator.CalculateSpatialElementGeometry(room) # if you use CPython3 / PythonNet use .Net Reflection
roomSolid = results.GetGeometry()
for face in roomSolid.Faces:
bbx_face = face.GetBoundingBox()
minPt_face = face.Evaluate(bbx_face.Min)
for subface in results.GetBoundaryFaceInfo(face):
if subface.SubfaceType == SubfaceType.Side:
boundingElement = subface.GetBoundingElementFace()
lnkelemId = subface.SpatialBoundaryElement
materialId = boundingElement.MaterialElementId
#
material = doc.GetElement(materialId)
elem = doc.GetElement(lnkelemId.HostElementId )
if isinstance(elem, Wall):
comp_structure = elem.WallType.GetCompoundStructure()
# get ordered layers exterior to interior
layers = list(comp_structure.GetLayers())
# if the 1st or the last item is a membrane
if layers[0].Function == MaterialFunctionAssignment.Membrane or layers[-1].Function == MaterialFunctionAssignment.Membrane:
#
# compute interior line and exterior line
line_location = elem.Location.Curve
offset_ext = comp_structure.GetOffsetForLocationLine(WallLocationLine.FinishFaceExterior)
offset_int = comp_structure.GetOffsetForLocationLine(WallLocationLine.FinishFaceInterior)
# reverse offsets if wall is flipped
if elem.Flipped :
offset_ext *= -1
offset_int *= -1
line_exterior = line_location.CreateOffset(offset_int, XYZ.BasisZ)
line_interior = line_location.CreateOffset(offset_ext, XYZ.BasisZ)
#
# obtain the layer closest to the part face
pairs_line_layer = [[line_exterior, layers[0]], [line_interior, layers[-1]]]
pairs_line_layer.sort(key = lambda x : x[0].Project(minPt_face).Distance )
# get material and override the variable
material = doc.GetElement(pairs_line_layer[0][1].MaterialId)
roomMaterials.append(material)
results.Dispose()
return roomMaterials
toList = lambda x : x if hasattr(x, "__iter__") and not isinstance(x, (str, System.String)) else [x]
rooms = toList(UnwrapElement(IN[0]))
#
calculator = SpatialElementGeometryCalculator(doc)
OUT = rooms, [get_room_finish_materials(calculator, room) for room in rooms]
OK, that sounds just what I need. However, when I copy-paste your code into a python node I get an error and I don’t understand why.
I will paste the screenshot
as I mention in my post use Ironpython engine (2 or 3), or if you are an advanced user of Python and .Net try to use .Net Reflection (it can be a good exercise)
Thank you! I just select the right engine and now works.
Now I have to implement the rest of the code and try it in a complex situation. I would like to test how it works when “null” is found.
If it is useful for the community, I can post the final result when it is finished. The goal now is both to write the material in the room (I would like to make a check) and to export the whole list into excel
Thanks to @c.poupin , I created this script that creates three sheets for me in Excel: 1) Wall coverings 2) Doors 3) Windows divided by room.
It remains to figure out how to get the ceiling as I have not found the way yet.
I attach the file here if anyone may need it.
Room Informations in Excels.dyn (87.7 KB)
I tried but:
- I dind’t understand how to create a single list with all the elements that I need
or - I didn’t understand how to say to write differents worksheet for every list.
So i choose the shorter way: 3 x output in excels!
P.S. do u have any tips about false cieling tupe in the rooms?
Perhaps you need to modify the process (to obtain the membrane layer), by recovering the associated geometric surface for each layer, I haven’t tried this.