Get Rooms materials by Wall orientation

Hi everyone. Does anybody know how can I get the rooms materials from the walls according to the cardinal position (North, South, East and West)?
I need the position for a Rooms finish schedule, sorting them by North wall, south wall, etc.
I’m getting the rooms materials using this code in Python Node:

import sys
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager

rooms = UnwrapElement(IN[0])

doc = DocumentManager.Instance.CurrentDBDocument
calculator = SpatialElementGeometryCalculator(doc)

elementMaterial = list()
for room in rooms:
	results = calculator.CalculateSpatialElementGeometry(room)
	roomSolid = results.GetGeometry()
	
	roomMaterial = list()
	for face in roomSolid.Faces:
		for subface in results.GetBoundaryFaceInfo(face):
			if subface.SubfaceType == SubfaceType.Side:
				boundingElement = subface.GetBoundingElementFace()
				elementId = boundingElement.MaterialElementId
				materialName = doc.GetElement(elementId).Name
				roomMaterial.append(materialName)
	elementMaterial.append(roomMaterial)

OUT = elementMaterial

And the workspace (this is only for walls):

Hello @DavidMena
you can try to use FaceNormal Property, faces from roomSolid = results.GetGeometry()
Note from API doc
This property is the “face normal” vector, and thus should return a vector consistently pointing out of the solid that this face is a boundary for (if it is a part of a solid).

then compute (for each faceNormalVector) the dot product with the TrueNorth vector (and the TrueEast) to find the Wall orientation

I’ll help you if you get stuck

1 Like

Thank you @c.poupin, let me try and I’ll tell you how it worked !

Ok @c.poupin this is what I’ve achieved so far (Until I got stuck :frowning: ) :
First I filtered 16 wall faces from a list of 4 rooms with this code:

import sys
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager

rooms = UnwrapElement(IN[0])

doc = DocumentManager.Instance.CurrentDBDocument
calculator = SpatialElementGeometryCalculator(doc)

walls = list()
for room in rooms:
	results = calculator.CalculateSpatialElementGeometry(room)
	geometries = results.GetGeometry()
	
	faces = list()
	for face in geometries.Faces:
		for subFace in results.GetBoundaryFaceInfo(face):
			if subFace.SubfaceType == SubfaceType.Side:
				boundingElement = subFace.GetBoundingElementFace()
				walls.append(boundingElement)			

OUT = walls

Then obtained the FaceNormal for each PlanarFace with this code in another node:

import sys
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager

faces = IN[0]

normals = []
for face in faces:
	vectorNormal = face.FaceNormal
	normals.append(vectorNormal)

OUT = normals

This is my workspace:

But now I can’t find the way to compute these vectors to get the dot product with the True North and East as you told me.
Could you please help me with any hint about it?
Thank you!

Hello @DavidMena
the dot product of 2 normalized vectors varies between -1 and 1, as the vectors normal face point towards the outside of the solid it is thus possible to determine their orientations with North an East.
Some explanation with a graph

try this script

import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

from Autodesk.Revit.DB import *
import Autodesk
from RevitServices.Persistence import DocumentManager

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


def getOrientation(vecTrueNorth, vecTrueEast, solidFace):
	faceNorm = solidFace.FaceNormal
	dotP_N = faceNorm.DotProduct(vecTrueNorth)
	dotP_E = faceNorm.DotProduct(vecTrueEast)
	#0.7 = Pi / 4 or (45°)
	if  dotP_N > 0.7 and abs(dotP_E) <= 0.7:
		return "North"
	elif dotP_N < -0.7 and abs(dotP_E) <= 0.7:
		return "South"
	elif dotP_E > 0.7 and abs(dotP_N) <= 0.7:
		return "East"		
	elif dotP_E < -0.7 and abs(dotP_N) <= 0.7:
		return "West"
	else:
		return None
		
rooms = UnwrapElement(IN[0])

doc = DocumentManager.Instance.CurrentDBDocument
currentLocation = doc.ActiveProjectLocation
origin = XYZ(0, 0, 0)
projectPosition = currentLocation.GetProjectPosition(origin)
angleToNorth = projectPosition.Angle
vecNorth = XYZ.BasisY 
vecEast = XYZ.BasisX 
rotTransf = Transform.CreateRotation(XYZ.BasisZ,  - angleToNorth)
vecTrueNorth = rotTransf.OfVector(vecNorth)
vecTrueEast = rotTransf.OfVector(vecEast)

calculator = SpatialElementGeometryCalculator(doc)

elementMaterial = list()

for room in rooms:
	if calculator.CanCalculateGeometry(room):
		results = calculator.CalculateSpatialElementGeometry(room)

		roomSolid = results.GetGeometry()
		roomMaterial = list()
		for face in roomSolid.Faces:
			for subface in results.GetBoundaryFaceInfo(face):
				if subface.SubfaceType == SubfaceType.Side:		
					boundingElement = subface.GetBoundingElementFace()
					elementId = boundingElement.MaterialElementId
					material = doc.GetElement(elementId)
					if material is not None :
						surfaceDs = face.ToProtoType()
						nameOrient = getOrientation(vecTrueNorth, vecTrueEast, face)
						materialName = material.Name
						roomMaterial.append([face, surfaceDs[0], materialName, nameOrient])
									
						
		elementMaterial.append([room, roomMaterial])
	
OUT =  elementMaterial
2 Likes

To be specific, the dot product varies between -1 and 1. If the angle between two vectors is less than 90° then this will result in a value between 0 and 1 (1 if they are exactly aligned), if they are perpendicular (exactly 90°), then this will be 0, and if the angle between vectors is greater than 90°, then the dot product will be negative, -1 if they are exactly oppositely aligned.

2 Likes

@c.poupin Thank you so much for your dedication and your time! It really worked! . It took me time to rewrite the code to understand it. Now I think I have what I need to work with this information.
Great and very very useful.
Thanks again!