Get and Set View Range - Problems with some settings

Hello Dynamo Community!

Getting and setting View Range parameters did work very well in many plans but now i found some viewrange settings that give me errors.

In the first case i think that the nodes can´t handle an “unlimited” setting because it is giving me nulls.

In the second case i don`t even see the Problem. The view range is valid because i got it from another view.

In most cases it´s working just fine.

So can you please give me some help so that i can improve this to handle all kinds of view range settings?

Here is the Python Code for setting the view range

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

v = UnwrapElement(IN[0])
tof = IN[1]
bof = IN[2]
cof = IN[3]
dof = IN[4]
count = 0

TransactionManager.Instance.EnsureInTransaction(doc)

    #getting the viewrange of the view
    viewrange = v.GetViewRange()
    asslvl = v.GenLevel

    #Setting top clip plane of the viewrange
    #	Setting level of topclip plane
    viewrange.SetLevelId(PlanViewPlane.TopClipPlane,asslvl.Id)
    #	setting offset of top clip plane
    viewrange.SetOffset(PlanViewPlane.TopClipPlane,tof)

    #Setting bottom clip plane of the viewrange
    #	Setting level of bottom clip plane
    viewrange.SetLevelId(PlanViewPlane.BottomClipPlane,asslvl.Id)
    #	setting offset of bottom clip plane
    viewrange.SetOffset(PlanViewPlane.BottomClipPlane,bof)

    #	setting offset of cut plane
    viewrange.SetOffset(PlanViewPlane.CutPlane,cof)

    #Setting view depth plane of the viewrange
    #	Setting level of view depth plane
    viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,asslvl.Id)
    viewrange.SetOffset(PlanViewPlane.ViewDepthPlane,dof)


    #Applying the viewrange to the view
    v.SetViewRange(viewrange)
    count = count +1
    TransactionManager.Instance.TransactionTaskDone()

    OUT = '%d view ranges altered' %(count), v

Thank you very much in advance! :slightly_smiling_face:

Your first guess is correct. You are feeding it nulls (unlimited range) so it throws the error.
To get around this try add another step that goes, if null, input = 99999999999
or some very large integer to represent ‘unlimited’ range.

not sure about your second error. can you show what you’re feeing into IN[0].
are you feeding in a view or a view range?

1 Like

Hello Andy, thanks for your help!
I thought there would be some fix like this for problem 1 but i haven´t had the thought to just put in a very large number, i will try that out!

The workflow is alway the same, the GET input is a view and the SET input is a new created duplicate of the view! I´m going to add a graph later!

Hello again,

It took me now hours of testing so i can tell you whats even going on in “problem 2”. Luckily i figured out how i can reproduce or avoid the error, but i have absolutely no idea whats going on.

It seems that the python code can´t handle some cut plane settings, please see these examples:

They are valid because i´m setting them in Revit, but the python script can´t handle them.

Would really appreciate any advice, i´m really stuck here. I´m not sure but i think it did work in Revit 2020.
Enough dynamo for me today!

kind regards

edit:

And i noticed something else, the python code does not set the Levels but it adjusts the offset to the right value. I also didn´t notice that in Revit 2020! Should the python code set the levels?

Hello @gerhard.p

for set an unlimited range replace “asslvl.Id” by “viewrange.Unlimited”

for set a view range in view with up direction (like cellingPlan) you need to set the level for BottomClipPlane and CutPlane (with same values for levelId and Offset)

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

v = UnwrapElement(IN[0])
tof = IN[1]
bof = IN[2]
cof = IN[3]
dof = IN[4]
count = 0

TransactionManager.Instance.EnsureInTransaction(doc)

#getting the viewrange of the view
viewrange = v.GetViewRange()
asslvl = v.GenLevel

#Setting top clip plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.TopClipPlane,viewrange.Unlimited)
viewrange.SetOffset(PlanViewPlane.TopClipPlane,tof)

#Setting bottom clip plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.BottomClipPlane,asslvl.Id)
viewrange.SetOffset(PlanViewPlane.BottomClipPlane,bof)

#	setting offset of cut plane
viewrange.SetLevelId(PlanViewPlane.CutPlane,asslvl.Id)
viewrange.SetOffset(PlanViewPlane.CutPlane,cof)

#Setting view depth plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,viewrange.Unlimited)
viewrange.SetOffset(PlanViewPlane.ViewDepthPlane,dof)

#Applying the viewrange to the view
v.SetViewRange(viewrange)

TransactionManager.Instance.TransactionTaskDone()

OUT = v
2 Likes

Hello c.poupin,

Thank you so much for your help :+1:

I would like to clarify that i want to have a python code that works for all kinds of viewranges and levels. For view direction up and down. For specific associated levels and also for infinite values. Whatever i read out from the template view, it should be set to the target view. Setting the levels to “infinite” is only one case that should work.

I tried it with your python code but i get the same error :frowning: :

If i don´t use the GetViewRange node but write the values manualy, it does work!

Please look at that, if i only use 2 outputs from the GetViewRange node it does work!

So i guess its the GetViewRange node thats messing everything up, maybe the values that should be equal are not equal? Maybe they have more decimal places than we can see here?

yes probably

So, to sum this up in one picture:

Setting the ViewRange parameters to a view does work if i put the numbers in manually.
It does not work with the ViewRange relative node, even so the numbers are the same.

So i think the next step should be to investigate this ViewRange relative node, its from MEPover by the way.

import clr

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

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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
#The inputs to this node will be stored as a list in the IN variables.
if isinstance(IN[0], list):
	views  = UnwrapElement(IN[0])
else:
	views = [UnwrapElement(IN[0])]

def getViewRange(view):
	if view.GetType() == Autodesk.Revit.DB.ViewPlan:
		viewrange = view.GetViewRange()
		try:
			cutId = viewrange.GetLevelId(PlanViewPlane.CutPlane)
			cutlevel = doc.GetElement(cutId)
			cut = viewrange.GetOffset(PlanViewPlane.CutPlane)
		except:
			cut = None
		
		try:
			topId = viewrange.GetLevelId(PlanViewPlane.TopClipPlane)
			toplevel = doc.GetElement(topId)
			topelev = toplevel.Elevation
			top = topelev + viewrange.GetOffset(PlanViewPlane.TopClipPlane)
			top -= cutlevel.Elevation
		except:
			top = None
			
		try:
			bottomId = viewrange.GetLevelId(PlanViewPlane.BottomClipPlane)
			bottomlevel = doc.GetElement(bottomId)
			bottomelev = bottomlevel.Elevation
			bottom = bottomelev + viewrange.GetOffset(PlanViewPlane.BottomClipPlane)
			bottom -= cutlevel.Elevation
		except:
			bottom = None
		
		try:
			depthId = viewrange.GetLevelId(PlanViewPlane.ViewDepthPlane)
			depthlevel = doc.GetElement(depthId)
			depthelev = depthlevel.Elevation
			depth = depthelev + viewrange.GetOffset(PlanViewPlane.ViewDepthPlane)
			depth -= cutlevel.Elevation
		except:
			depth = None

	return depth, bottom,cut,top

depth = []
bottom = []
cut = []
top = []

for view in views:
	try:
		depth.append(getViewRange(view)[0])
		bottom.append(getViewRange(view)[1])
		cut.append(getViewRange(view)[2])
		top.append(getViewRange(view)[3])
	except:
		depth.append(None)
		bottom.append(None)
		cut.append(None)
		top.append(None)
#Assign your output to the OUT variable.
if len(depth) == 1:
	OUT = depth[0], bottom[0], cut[0], top[0]
else:
	OUT = depth, bottom, cut, top

So the first question that gets to mind, why are these outputs blue?

Edit:
I did a test to check if the numbers are equal, they are…
I´m out of ideas

Oh, if someone would be so kind to test it, .dyn-file attached!

ViewRange.dyn (15.0 KB)

1 Like

Problem solved!

by using the python code without the custom node it was inside.
I really hope that´s it and it will work now for all kinds of viewranges. I will keep testing.
But I´m very curious if someone has an idea about what the problem was with the custom node!

Thanks for your help :slight_smile:

Edit:

One question left, would it be possible to get the view range levels from the template view and apply them to the target view?

Found this amazing node from GeniusLoci:

Now i would like to edit the python code to set the viewrange level to the one i give as input:

I tried to add the following, it doesn´t work because i don´t understand python…

The code i need is in this thread:

A tip to compare 2 floats (Double) with Equals .Net method

or with Python

1 Like

Thats very interresting, i will keep that in mind, thanks!

Hello again, good evening!

Good news, get and set viewrange offsets and levels now working almost perfect for all possible values :slightly_smiling_face:

I changed the code of the Get View Range node from GeniusLoci to not convert the units to meter. Then i added the levels to the Set View Range node.

Now there are two steps left to complete this mission.

  • The Get View Range node works with a list of views which is awesom, but the Set View Range node doesn´t work with lists. Thats too hard for me to get this working, would someone please help out and give a little explanation?

  • Still getting nulls for infinite levels, does someone know a smooth solution for that or do i really need to work with an if node? Would appreciate a suggestion for a better solution!

Thanks in Advance!
Code, nodes and .dyn attached!

Get View Range:

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

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

    UIunit = Document.GetUnits(doc).GetFormatOptions(UnitType.UT_Length).DisplayUnits

    views=UnwrapElement(IN[0])

    if not hasattr(views, '__iter__'):
    	views = [views]

    topLevel,top,cutLevel,cut,bottomLevel,bottom,depthLevel,depth,underlayLevel,underlay=[],[],[],[],[],[],[],[],[],[]

    for view in views :
    	viewRange=view.GetViewRange()
    	topLevel.append(doc.GetElement((view.GetViewRange().GetLevelId(PlanViewPlane.TopClipPlane))))
    	top.append((viewRange.GetOffset(PlanViewPlane.TopClipPlane)))
    	cutLevel.append(doc.GetElement((view.GetViewRange().GetLevelId(PlanViewPlane.CutPlane))))
    	cut.append((viewRange.GetOffset(PlanViewPlane.CutPlane)))
    	bottomLevel.append(doc.GetElement((view.GetViewRange().GetLevelId(PlanViewPlane.BottomClipPlane))))
    	bottom.append((viewRange.GetOffset(PlanViewPlane.BottomClipPlane)))
    	depthLevel.append(doc.GetElement((view.GetViewRange().GetLevelId(PlanViewPlane.ViewDepthPlane))))
    	depth.append((viewRange.GetOffset(PlanViewPlane.ViewDepthPlane)))
    	underlayLevel.append(doc.GetElement((view.GetViewRange().GetLevelId(PlanViewPlane.UnderlayBottom))))
    	underlay.append((viewRange.GetOffset(PlanViewPlane.UnderlayBottom)))

    OUT = [topLevel,top,cutLevel,cut,bottomLevel,bottom,depthLevel,depth,underlayLevel,underlay]

Set View Range:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

v = UnwrapElement(IN[0])
tof = IN[1]
bof = IN[2]
cof = IN[3]
dof = IN[4]
ltop = UnwrapElement(IN[5])
lcut = UnwrapElement(IN[6])
lbot = UnwrapElement(IN[7])
ldep = UnwrapElement(IN[8])
count = 0

TransactionManager.Instance.EnsureInTransaction(doc)

#getting the viewrange of the view
viewrange = v.GetViewRange()
asslvl = v.GenLevel

#Setting top clip plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.TopClipPlane,ltop.Id)
viewrange.SetOffset(PlanViewPlane.TopClipPlane,tof)

#	setting offset of cut plane
viewrange.SetLevelId(PlanViewPlane.CutPlane,lcut.Id)
viewrange.SetOffset(PlanViewPlane.CutPlane,cof)

#Setting bottom clip plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.BottomClipPlane,lbot.Id)
viewrange.SetOffset(PlanViewPlane.BottomClipPlane,bof)

#Setting view depth plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,ldep.Id)
viewrange.SetOffset(PlanViewPlane.ViewDepthPlane,dof)

#Applying the viewrange to the view
v.SetViewRange(viewrange)

TransactionManager.Instance.TransactionTaskDone()

OUT = v

GetSetViewRange.dyn (25.3 KB) View Range.dyf (20.5 KB)

1 Like

Now also working with unlimited level inputs :grinning:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

v = UnwrapElement(IN[0])
tof = IN[1]
bof = IN[2]
cof = IN[3]
dof = IN[4]
ltop = UnwrapElement(IN[5])
lcut = UnwrapElement(IN[6])
lbot = UnwrapElement(IN[7])
ldep = UnwrapElement(IN[8])
count = 0

TransactionManager.Instance.EnsureInTransaction(doc)

#getting the viewrange of the view
viewrange = v.GetViewRange()
asslvl = v.GenLevel

#Setting top clip plane of the viewrange
if ltop is None:
	viewrange.SetLevelId(PlanViewPlane.TopClipPlane,viewrange.Unlimited)
else :
	viewrange.SetLevelId(PlanViewPlane.TopClipPlane,ltop.Id)
	
viewrange.SetOffset(PlanViewPlane.TopClipPlane,tof)

#	setting offset of cut plane
viewrange.SetLevelId(PlanViewPlane.CutPlane,lcut.Id)
viewrange.SetOffset(PlanViewPlane.CutPlane,cof)

#Setting bottom clip plane of the viewrange
viewrange.SetLevelId(PlanViewPlane.BottomClipPlane,lbot.Id)
viewrange.SetOffset(PlanViewPlane.BottomClipPlane,bof)

#Setting view depth plane of the viewrange

if ldep is None:
	viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,viewrange.Unlimited)
else :
	viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,ldep.Id)

viewrange.SetOffset(PlanViewPlane.ViewDepthPlane,dof)

#Applying the viewrange to the view
v.SetViewRange(viewrange)

TransactionManager.Instance.TransactionTaskDone()

OUT = v

GetSetViewRange_2.dyn (25.6 KB)

I got it wortking with a list of views, but it does not work with lists of view ranges :confused:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

views = UnwrapElement(IN[0])
tof = IN[1]
bof = IN[2]
cof = IN[3]
dof = IN[4]
ltop = UnwrapElement(IN[5])
lcut = UnwrapElement(IN[6])
lbot = UnwrapElement(IN[7])
ldep = UnwrapElement(IN[8])
count = 0

if not hasattr(views, '__iter__'):
	views = [views]

TransactionManager.Instance.EnsureInTransaction(doc)

for view in views :

	viewrange = view.GetViewRange()
	asslvl = view.GenLevel

	if ltop is None:
		viewrange.SetLevelId(PlanViewPlane.TopClipPlane,viewrange.Unlimited)
	else :
		viewrange.SetLevelId(PlanViewPlane.TopClipPlane,ltop.Id)
	
	viewrange.SetOffset(PlanViewPlane.TopClipPlane,tof)


	viewrange.SetLevelId(PlanViewPlane.CutPlane,lcut.Id)
	viewrange.SetOffset(PlanViewPlane.CutPlane,cof)


	viewrange.SetLevelId(PlanViewPlane.BottomClipPlane,lbot.Id)
	viewrange.SetOffset(PlanViewPlane.BottomClipPlane,bof)


	if ldep is None:
		viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,viewrange.Unlimited)
	else :
		viewrange.SetLevelId(PlanViewPlane.ViewDepthPlane,ldep.Id)

	viewrange.SetOffset(PlanViewPlane.ViewDepthPlane,dof)

	view.SetViewRange(viewrange)

TransactionManager.Instance.TransactionTaskDone()

OUT = views

3 Likes

Hello @gerhard.p
try to use the Python zip function to iterate over both views to define and views to copy

4 Likes

@c.poupin
thanks for the advice, saw this zip function many times and know it has something to do with lists. Will read into this function!

@Alban_de_Chasteigner
Ah! The lacing!
I think your nodes will now meet the needs of everyone who ever wants to get and set view ranges!
I´m going to test that extensively next week.
Thanks for your quick help :grinning: