Rotate 3D camera view around its own axis/ or workplan

Hello everyone,

Always when i find myself stuck for many days, i come here and i find the solution, thanks to you in advance for helping.
Actually i am creating a Revit dynamo Script to create 3D camera views for each CCTV security camera in the model.
The camera object/family has some parameters like pan/tilt/zoom and i succeeded to extract these values in dynamo for each object and create a 3D perspective camera view and rotate these views left/right and up/down depending on the parameter value for each camera family in my model.

The problem i am facing that i have some families where the camera object is rotating around its own axis, (not only left/right & up/down) as per the below 1st photo, so i need to rotate the 3D Camera perspective view after it is created, around its own axis (align it with the camera object view rotation), i am able to do it manually in Revit so i am sure there is a way in dynamo but i am struggling to find it.

What i have done manually, that i open the 3D camera view and i set the current working plan to the family object reference plane (as per 2nd photo below), then i rotate the view and it is rotated easily.
the idea that i need a dynamo node to rotate the 3D camera perspective view around a certain reference plane, where i already detect this plane in dynamo for each family (in the project environment) with the node “FamilyInstance References”, but still searching to rotate the view with a certain angle with reference to certain plane.

Thanks for any help you can give to me.

I found something but it is not working
i can create a line by start end point, the start point is the 3D camera view eye (x,y,z) and the end point is the 3D camera view target (x,y,z) which is the considered the axis of rotation, and use the ViewPlan.Rotate node from ryhthm package but it is giving me errors that it is not working as per the below photo, any ideas?

The rhythm node requires a viewPlan - so a perspective view will not work
I think one way to handle this to use API ViewOrientation3D class and python
Adding roll to a view is not a trivial task

This will take a view and change the ‘camera’ view

import sys, clr

clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument

perspective = UnwrapElement(IN[0])
EyePosition = IN[1].ToXyz()
UpDirection = IN[2]
ForwardDirection = IN[3]

TransactionManager.Instance.EnsureInTransaction(doc)
NewVO = ViewOrientation3D(EyePosition, UpDirection, ForwardDirection)
perspective.SetOrientation(NewVO)
uidoc.RefreshActiveView()  # Comment out if not using active view
TransactionManager.Instance.TransactionTaskDone()

OUT = perspective

You already have the camera position (Dynamo Point → Revit XYZ class)
Now the issue is how to get the up and forward vectors - your line is the forward vector so create this with Vector.ByTwoPoints (might need to be normalised) and then the up could be obtained by getting the BasisZ of the forward vector and then doing a transform rotate on the X Axis (I think).
Alternately if you know the roll and calcuate the pan and tilt from your vector you could create up and froward with the following

import math

import clr

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import XYZ, Transform

pan = math.radians(IN[0])  # Pan
tilt = math.radians(IN[1])  # Tilt
roll = math.radians(IN[2])  # Roll

X = XYZ(1, 0, 0) # Roll
Y = XYZ(0, 1, 0) # Tilt
Z = XYZ(0, 0, 1) # Pan

transform_roll = Transform.CreateRotation(X, roll)
transform_tilt = Transform.CreateRotation(Y, tilt)
transform_pan = Transform.CreateRotation(Z, pan)

up = transform_pan.OfVector(transform_tilt.OfVector(transform_roll.OfVector(Z)))
forward = transform_pan.OfVector(transform_tilt.OfVector(transform_roll.OfVector(X)))

OUT = up, forward

Not sure if this is the correct way to do a transform of 3 axes
Hope this helps

Thank you Mike for your reply.

i tried your python script, as per shown in below photo, i understand that the 1st input will be the 3D camera perspective view, 2nd input will be the vector created from the eye position point, 3rd input i do not know how to get it, i cannot find something to give me the basisZ of the forward vector, 4th as you said vector by 2 points of my line (starting point = eye, ending point= target).

in addition, i have an error in the python, “AttributeError : 'Vector” object has no attribute ‘ToXyz’[’ File “”, line 16, in\n’], i even try to put IN[1] directly withount being in a list but it give the same error.

for the second python you wrote, i see only 3 inputs (pan, tilt, roll) but i do not see the main input that need to be rotated by these 3 parameters, what exactly i have to insert, is it the 3D view or the vector of my line or what?

Apologies, I should have done a screenshot of my graph to give you context.
You can use a Dynamo Point for IN[1]. .ToXyz() in the script should convert the Vector.
Perhaps add this to the imports

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

Looking into this I think there is an easier way to get the vectors. If the forward vector is F(x,y,z) we can define the ‘right’ vector as R(-y,x,0) which is a 90 degree rotation in the xy plane of the F vector. Then the up vector is the cross product - if we have roll we can rotate with F as the axis

Main python script - I have added a helper function so that the script can accept Dynamo Point or Vector or a Revit XYZ

import sys, clr

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import Vector, Point

clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument

def check_vec(vec):
    if isinstance(vec, (Vector, Point)):
        return vec.ToXyz()
    return vec

perspective = UnwrapElement(IN[0]) if IN[0] else doc.ActiveView
EyePosition = check_vec(IN[1])
UpDirection = check_vec(IN[2])
ForwardDirection = check_vec(IN[3])

TransactionManager.Instance.EnsureInTransaction(doc)
NewVO = ViewOrientation3D(EyePosition, UpDirection, ForwardDirection)
perspective.SetOrientation(NewVO)
uidoc.RefreshActiveView()  # Comment out if not using active view
TransactionManager.Instance.TransactionTaskDone()

OUT = perspective

Rotation of the ‘Up’ vector by the roll angle using the ‘Forward’ vector as the axis

import clr
import math

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import XYZ, Transform

f = IN[0].ToXyz()
u = IN[1].ToXyz()
roll = math.radians(IN[2]) if IN[2] else 0

OUT = Transform.CreateRotation(f, roll).OfVector(u)

Sorry for my late reply, Really Thank you so much Mike for your reply and support.
It works :slight_smile:
In addition, after some times i was exploring in dynamo, i have found a node that is doing exactly the same function from the Package “GeniusiLoci”

image

it has python inside same as what you proposed.

I really want to thank you again.

Have a nice day.

1 Like