Align elements to walls rotation

Hello.

I have been searching and trying many ways to do this and still couldn’t find a good option to get what I want… What I’m trying is to rotate elements intersecting with a wall regarding wall’s normal vector.
Main problem I’m facing is when getting walls rotation, since they can be mirrored modeled and I’m getting 0 or 180 for parallel faces, even if they are interior or exterior ones. That makes my fixtures not to rotate as they should.

1 - linked walls, 1’ rotation
2 - fixture elements, 2’ rotation

I thought of another way of reaching this rotation, as I use spaces’ faces in my script: That would consist on intersecting the spheres with solids from walls surfaces. Once I get it, I couldn’t find any node or way to get its rotation.

So, I’m kind of stuck and I can’t assign a proper rotation to my elements list. Could I get some help there?

Thank you in advance

A think to keep in mind is that the direction a Wall is modelled (i.e right to left) determines the angle.
0 degrees or 180 degrees.

Walls don’t really have a rotation (think of a curved wall with a sweep from 0 to 359.9999 degrees - how is that rotated?), so pulling that is not likely to be very robust. Instead I recommend getting the elements which intersect your sphere, getting their location (should be a line), getting the parameter of the center of the sphere on that line (Curve.ParamterAtPoint) and then getting the normal at that parameter (Curve.NormalAtParameter) to find what vector is perpendicular to the wall. Then rotate your family instances about the Z axis by that direction.

This may have issues if your source model isn’t built from standard Revit walls (IFC imports or wall by face). In those cases you’d want to get the closes point on the solid to the center of the sphere, get the host face of the solid which that point intersects, convert to a surface, find the parameter of that surface that the point is on, get the normal of that point, and set the family instance’s facing direction accordingly.

How you’ve built your model(s) matters quite a bit, so it’s not something we can build directly.

Isn’t that partial true though?

Why does the node give you a rotation though?
How would you determine a walls angle related to another object.

I know about vectors, but they are not allways (that) useful either (imo).

Also a few questions;

  1. Are vectors that much different then rotations?
  2. Are vector different based on the direction a wall is modelled (i.i left to right or right to left)?
  3. Is the same true for detail lines (compared to walls)?

Asking for a friend :wink:.

Joke. I am working on something and i want (need) to group the walls
by if they are horizontal, vertical or diagonal (any angle).
I don’t know what is the best way to go about that. Get the rotations or vectors.

PS
I don’t wanna hijack this topic :see_no_evil:, but i think bit more insight
on the matter would also benefit the OP.

Can’t say without checking the source code, and this is a node I don’t have in my library at the moment. Walls do not have a ‘GetRotation’ method or ‘Rotation’ property in the API. Perhaps they are getting the ‘Orientation’ property, which is returning the vector (as an XYZ) which I noted before, not a rotation (as a double).

Significantly, as they are much more useful. Vectors are 3D, while rotations are not. Vectors can be transformed by other coordinate systems, and therefore mirrored and otherwise edited. Vectors have length allowing for use in analysis and other things which rotations just don’t have. Vectors force you to define the rotation axis, which can be difficult, but if you have to look at the ‘angle between two items not defined on the same sketch plane you’re stuck. All of that said, if your content is simple enough, than sure a rotation will do, and there is no need to complicate things. But in my experience they rarely hold up to the complexity presented by real projects where content is not constrained to one plane.

Assuming the wall isn’t flipped, yes. If they are flipped then rotation based on the direction the wall’s curve is generated might not be correct if you want the exterior or interior side.

Detail components are locked to a plane, and as such you don’t need to use a vector, though you certainly can.

Certainly doable with vectors - in fact the Rhythm node you’re using leverages vectors for the bulk of it’s work. RhythmForDynamo/src/RhythmRevit/Revit/Elements/Wall.cs at 9c7caa2023c26452ef85a5ff96e5335e6b08fe18 · johnpierson/RhythmForDynamo · GitHub

1 Like

Thanks for your insight (again).

I’ll let you know what package the node is from when i have access to Dynamo again
(which is tomorrow).

The reason i like(d) getting the rotation(s) over vector(s) is i only have to deal with one number instead of and XYZ.

I get the desire, and for your use case that might be the simplest way for you, and it works. But taking the wall’s orientation as a vector and using Vector.AngleWithVector from say the X axis (though Y works just as well) and taking the modulo of 180 (remainder after dividing) might be easier for grouping ‘north south’ (would be 0), ‘east west’ (would be 90) and “angled” walls (would be anything else).

It is from GeniusLoci.

#Alban de Chasteigner 2020
#twitter : @geniusloci_bim
#geniusloci.bim@gmail.com
#https://github.com/albandechasteigner/GeniusLociForDynamo

import clr
import math
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

items = UnwrapElement(IN[0]) if isinstance(IN[0],list) else [UnwrapElement(IN[0])]

def GetRotation(item):
	# Dynamo lines
	if hasattr(item, "Explode"):
		vector = item.ToRevitType().Direction
		rotationAngle = math.degrees(vector.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))
	# CropBox	
	elif item.Category == None :
		view=item.Document.GetElement(item.get_Parameter(BuiltInParameter.ID_PARAM).AsElementId())
		line=view.GetCropRegionShapeManager().GetCropShape()
		vector = [l.Direction for l in line[0]]
		rotationAngle = math.degrees(vector[1].AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))
	elif hasattr(item, "Location"):
		loc = item.Location
		if loc:	
			# Generic Annotation, importInstance and linkInstance
			if hasattr(item, "GetTotalTransform"):
				trans=item.GetTotalTransform()
				rotationAngle = math.degrees(trans.BasisX.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))
				rotationAngle=abs(rotationAngle-360)
			# point-based elements (e.g. most loadable families)
			elif isinstance(loc,LocationPoint):
				if hasattr(loc, "Rotation"):
					rotationAngle = math.degrees(loc.Rotation)
				# Group, assembly
				else:rotationAngle = 0
			elif isinstance(item,MEPCurve):
				for c in item.ConnectorManager.Connectors :
					rotationAngle = math.asin(c.CoordinateSystem.BasisY.X) * 180/math.pi
			elif isinstance(item,Grid):
				vector = item.Curve.Direction
				rotationAngle = abs(math.degrees(vector.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))-180)
			elif isinstance(item,ReferencePlane):
				doc=item.Document
				view = doc.ActiveView
				for crv in item.GetCurvesInView(DatumExtentType.ViewSpecific,view):
					vector = crv.Direction
				rotationAngle = abs(math.degrees(vector.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))-360)
			# line-based elements (e.g. walls)
			elif isinstance(loc,LocationCurve):
				vector = loc.Curve.Direction
				rotationAngle = abs(math.degrees(vector.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ))-360)
			else:
				# sketch-based elements (ceiling, floor and roof)
				if hasattr(item, "FindInserts"):
					for ref in HostObjectUtils.GetTopFaces(item):
						geomFace=item.GetGeometryObjectFromReference(ref)
						#Get BoundingBox max UV point
						maxUV = geomFace.GetBoundingBox().Max
						#Get transform
						trans=geomFace.ComputeDerivatives(maxUV)
						if isinstance(item,Ceiling):
							rotationAngle = math.degrees(abs(trans.BasisZ.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ)-2*math.pi))
						else:
							rotationAngle = math.degrees(abs(trans.BasisY.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ)-math.pi))
				else:
					rotationAngle=0
		else:
			rotationAngle=0
	if round(rotationAngle,3)==360:
		rotationAngle=0
	return round(rotationAngle,3)
	
rotations = [GetRotation(x) for x in items]

if isinstance(IN[0], list): OUT = rotations
else: OUT = rotations[0]

Looks like this fails to account for the exterior face and wall flips, meaning direction drawn matters entirely. Also vector based but simplified for reporting, possibly causing issues elsewhere.