On most of my projects, I have to spend a lot of time trimming the viewport title’s line to match the length of the text and centering that title underneath the viewport. Does anybody know of a script that could do this for me on all views in the model? See below for example of what I want done.
which Revit version are you in? This was officially added to the API in Revit 2022
I’m in Revit 2022. I’m new to Dynamo so I really have no idea what I’m doing, or where to start.
Ok, that makes sense. Well, welcome to the forum!
I really suggest working through the primer when you have a chance. But, let me break down the thought process around this idea. (Apologies if any of this is review, I just want to be thorough)
Also, it is worth noting, that this might be considered more of an advanced workflow because of some of the weirdness with how dynamo handles units. Some are paper space, some are model space, etc. It is actually quite frustrating to me even, and I have been fighting with Dynamo for a few years now.
1. Initial Collecting of Revit Elements
With Dynamo you generally start with needing to select/collect what you are working with. In your case, that is viewports. So we have a few options here. (Note: all OOTB ¹ collection methods are under Revit>Selection)
In your case, you mentioned “All Views” so a categorical² selection is probably the correct way to go. (This might need to be more specific if you have odd views on the sheets).
2. Working with Certain Classes³ of Revit Elements
Since you mentioned viewports, all of the relevant nodes are going to be under Revit > Elements > Viewport. Luckily in 2022, OOTB nodes encompass what you would like to do.
3. The logic involved.
In this case, for viewport titles, the label outline will report the total size including the line. So I think in order to get the text, minimizing the line, measuring, then setting it to that value should do. (This is a bit more intermediate/advanced, but the logic is there.
as you can see, the bubble is accounted for as well. you could add additional math to fix this
4. Centering under the viewport
Taking this new view title line, we should be able to reconstruct a new location of this title.
The summary of what is happening below is,
a. we are obtaining the center of the viewport with the outline max and min points. this is for our x value
b. We are also getting the bottom left point for our y value
c. using those values we are constructing a centered location below the viewport.
5. Final Result + Finished Graph
SetViewportLabelToTextWidth.dyn (68.5 KB)
Disclaimers
I made this post mostly to work out the logic required when getting going with Dynamo. I can’t gurantee that the attached graph will work for your exact use-case, but I do find this workflow intriguing and will probably add nodes to Rhythm for it and make a full tutorial video on it.
Terms Used in Post
¹Out of the box² Categorical collections are typically “placed” elements
³ Classes of elements in Revit are their object types. Walls, Floors, etc.
Thank you so much for your in-depth response! I’m going to give this a shot once I get some other things done and I’ll let you know how it goes!
John, thank you again for providing me the steps you took to write this script. This is going to save my sector so much time since I often have to trim these lines manually for hundreds of sheets. I have one more question. Would it be possible to add a north arrow at the end of the label line? Would I just need to grab the right end of the bounding box of the label, add a few units to the right, and tell Dynamo to place the north arrow there within the same script?
Of course!
Yes, I believe that would be how I would go about that as well
John,
I stumbled upon this script and revised it to only grab the active views and to place the title on the right hand side of the viewport. It works great for one viewport, but when I run it on a sheet of details the titles tend to be placed above and below the bottom right of the viewport. Any ideas?
Here is how I revised it to grab the viewports in the active view–>
Here is how I revised the script to get it at the right hand corner, right below the viewport →
Thanks
I really think it is freaking out because of the darn units. If we do it in python it seems to behave.
ViewportCentering.dyn (8.3 KB)
and the python:
Gotcha, it’s crazy how much cleaner a script can become using Python. I have started learning it, and I know about revitapidocs, but this is a bit overwhelming for me.
I’m assuming I will need to revise this section of the script if I want them to align with the right side and not the center
I tried eliminating the section #viewport box center for X value and then under #build new location I replaced CalculatedCenter variable with bottomRight = viewport.GetBoxOutline().MaximumPoint . So then the newLocation = XYZ(bottomRight, offset, 0). That spaced them out really far.
The periods also confused me some because I have not gotten to that yet in my learning.
If you could provide some direction that would be great.
Sidenote question → When I was in in Revit APIdocs I believe I was able to find the API you were referencing here, although it was a bit tougher to track down then expected, but how do you use it for Python since it is not one of the 3 languages provided there?
Yeah, I think you would be taking the MaximumPoint’s X value minus the MinimumPoints X value to get the far right corner.
So pseudo code would be:
xValue = MaximumPoint.X - MinimumPoint.X
newPoint = XYZ(xValue,offset,0)
Yeah for the periods
those will generally show you the different properties available on the target element. In python you can also do:
OUT = dir(ElementGoesHere)
to see all the properties available on any given element.
I tend to use ApiDocs.co as it has code lookup in it too. But aside from that, I really recommend installing RevitLookup too. This allows you to inspect the elements for those API calls. Beside that, I do tend to mockup some of this stuff in visual studio with C# because the IntelliSense helps so much.
I did work on this a bit more yesterday for an upcoming post too.
But here is the python:
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import Viewport, XYZ
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
def CenterViewTitle(viewport, offset = 0, location = "Center"):
TransactionManager.Instance.EnsureInTransaction(doc)
# set label line length to 0 to get approximate length by bounding box
viewport.LabelOffset = XYZ.Zero
viewport.LabelLineLength = 0
labelOutline = viewport.GetLabelOutline()
width = labelOutline.MaximumPoint.X - labelOutline.MinimumPoint.X
# set the label line to the length
viewport.LabelLineLength = width
#viewport box center for X value
boxCenter = viewport.GetBoxCenter()
bottomLeft = viewport.GetBoxOutline().MinimumPoint
topRight = viewport.GetBoxOutline().MaximumPoint
#build new location
calculatedCenter = boxCenter.Subtract(bottomLeft)
newLocation = XYZ(0,offset,0)
if location == "Left":
newLocation = XYZ(0,offset,0)
if location == "Center":
newLocation = XYZ(calculatedCenter.X,offset,0)
if location == "Right":
rightX = topRight.X - bottomLeft.X - width
newLocation = XYZ(rightX,offset,0)
viewport.LabelOffset = newLocation
TransactionManager.Instance.TransactionTaskDone()
return viewport
#Preparing input from dynamo to revit
items = UnwrapElement(IN[0])
offset = IN[1]
location = IN[2]
# return the results
if isinstance(IN[0], list): OUT = [CenterViewTitle(x,offset,location) for x in items]
else: OUT = CenterViewTitle(items,offset,location)
and the location is now controlled with this node:
I came back to this script today and tried to setup a Data-Shapes UI. It’s not working. I tried adjusting levels because that was an issue I have had in the past, but that didn’t work and I can’t seem to figure out what is the issue.
By running it through Data-shapes or pulling out the place holders did I change the property of what I’m sending into Python?