Get your technology fix here. Stay tuned for general tech trends, news, and articles. Work with Autodesk products? I do too! I like to write VBA, lisp and create a lot of custom tools for general consumption too. You'll find all that here and more!
Looking for ways to automate your installations and customization within Revit or AutoCAD products? Wish you could control the project launch process? Need to maintain Revit project versions without accidental upgrades? Want to customize Revit deployments by studio, delivery group, or Office? Wish you could ensure that all project team members were on the same build and or service pack? Perhaps you just need to master Revit Roofs and would like to explore more than 35 different roof types and how to create them in Revit? I’ve submitted a few classes that will interest you. Vote Now, then attend in November!
AutoCAD Architecture Automation Anywhere!
Automating and Customizing Revit Deployments for the DIY Enthusiast
Revit Project Launch Scripting to Standardize All Studios
I’m bringing some more standards tools to you today. A quick copy and adjust of the original text tools graph resulted in three tools for dimension styles. The first allows the user to select a dimension type and then selects all elements in the current project that use that style. The elements are selected in Revit, so the user can use the type selector to change the type.
The second tool reports all dimension types and writes them to the chosen excel file in a worksheet named dimensions after the category chosen.
The third tool allows the user to choose a dimension type and change the elements selected by the “type” filter and change their family type to the desired type within Dynamo.
Here is a the complete screen capture of the 3 tool graph.
As I was updating existing templates and building some new ones, I wanted a better way to determine what fonts/text styles are in use and where they are being used.
Exploring some existing dynamo graphs and custom nodes, I put the following graph together.
This graph searches the current project, builds a list of graphic views (plan, section, elevation, drafting, legend, and callout) and then builds a list of elements in those views.
The data is then output to an excel file for review. Here is what the output looks like. As you can see, the graph outputs the textnote style and the viewname the text element was found in.
For those of you who want to do it yourself and understand how I reached the working version of the graph, follow along as I describe how I created the graph.
First Step – Insert the White_Dynamo_Graphic_Standard node, edit the custom node and copy all the precreated groups, pasting them into your new home workspace. I edited the file notes contained inside this standard and saved it so I have a ready to use set of groups whenever I need them.
Since we are trying to determine where standard elements are being used in projects and templates, and I know I want to be able to reuse the data in excel, lets get started with the beginning and end in mind. Type excel into the search tool in the Dynamo graph editor and add the Excel.WriteToFile node. This node presents a number of connectors helping us to quickly add the necessary inputs by search.
Add a File Path node, a Categories node, and a Boolean node as we will be able to quickly connect these up as we begin to think through the logic of what the rest of the graph will require. I prefer the the file path node to a string based input, because I can select an excel file by browsing to it. The categories node allows us to select the category to be reviewed (Text Notes). I will add a “String from Object” node and connect it to the Categories node, so I pass in the sheet name directly from my chosen category. The boolean node lets us control whether the data is refreshed and whether the excel file is overwritten. I know that I want to start filling the excel file from column A and Row 1, so I’ll add a code block by double clicking in the editor and preparing to pass out a value of zero. I will connect up the nodes like this:
As you can see in the image above, I have already provided 5 out of the six input nodes required by the Excel.WriteToFile node. So now we tackle the data input. Since I want to figure out where all my text note styles are being used, so I can standardize the text note styles, I’ll next add the Document.Views node from the clockworks package to generate a list of all views contained in the current project. Click on your Excel.WriteToFile node, right click your mouse and freeze this node til we have the data input prepared. Click run to see the output from the Document.Views node.
I added and connected the Lunchbox node: Remove Null Values to the output of the Document.Views node, because I saw some null output after running it the first time. Looking at the list of views provided, I realized that there were many views that would not be of use to me in this process, so I searched for a node that could give me a way to filter out these nodes. Having found no such node, I decided to modify the View.IsTemplateView node from Clockwork for my use. The easiest way, I’ve found is to simply add this node to your graph, then select it and right click choosing to “Edit custom node”. Once the node is open in the editor, copy all the internal nodes to the clipboard and then close the View.IsTemplateView node. Remove it from your graph and click “File” new custom node. When the editor opens, paste the contents of the clipboard to your new custom node. It should look like the following image:
I named my custom node: View.IsGraphicView and added it to the BesideTheCursor Package, I’ll publish it later tonight or tomorrow. In the mean time, you can do what I did and modify the python script as shown in the image below. I added some exclusions of view types to exclude. This results in a view filter that effectively rips out the views that wouldn’t contain graphics.
I modified the original python code very slightly, see the difference view image below:
I used a boolean if else line to accomplish what i needed as seen in the images above. A quick run of the partially completed graphs shows that I am now effectively identifying the views that I do not wish to process. I can use the true false output from my new custom node with the List.FilterByBoolMask to filter out the view types I no longer want to include. I connect my node to the bool input and connect the cleaned output to the list input on the List.FilterByBoolMask node.
I am now ready to pass my list of included views into the Springs.ElementsFromViews node, to begin building the list of elements found in every view. A quick run at this time reveals many thousands of elements. Don’t get worried by the spinning blue wheel. It will run to completion rather quickly.
Now its time to filter for the type of element I’m looking for. We can add a code block and type in the TypeName description for TextNotes. You can see what is required from the Object.Type node. We connect this into the String.Contains node to search our large element list and build a boolean list of true and false. Connect these up to a List.FilterByBoolMask and then flatten the output will complete our data filtering down to just TextNotes as shown below.
Lets add some more nodes. Add Element.OwnerView, Element.Name (Universal), TextNote.Typename and we’ll connect them up and build a new list using List.Create with two input connectors as shown below:
Lets run this graph and take a look at the output from our list to this point. As can be seen in the image below, we are getting two sublists; the first contains the viewnames and the second list contains the textnote typenames. Having worked with the Excel.WriteToFile node in the past, I know from experience that the data input node prefers lists that contain rows and columnar data. Lets add the List.Transpose node to convert our list to this format and connect it into the Excel.WriteToFile data input connector. Now its time to run the graph, so unfreeze the final node and get ready to review your list of textnotes used by view. You can grab a copy of the graph here:, but its always best to build it yourself to gain a better understanding of how Dynamo works.
During the process of writing this blog post, I realized that the path I took was longer than necessary and can actually be accomplished without the custom node created, but what fun would that be? Check back later for an update and a simpler graph to complete the same workflow.
Finally got around to adding the code to modify a great routine published by Harry Mattison back in 2015. I’ve been using the routine to generate the isolated 3D views, but from the first time I ran it, I wanted a way to do workset isolation rather than element level temporary isolation. Using the Harry’s original code, I added a dictionary and the SetWorksetVisibility code segments. The code published below will set the workset visiblity for the view in addition to the element.
public void CreateIsolatedWorksetView()
Document doc = this.ActiveUIDocument.Document;
int max = 100;
// get the 3d view type which is needed when creating 3d views
ViewFamilyType vft = new FilteredElementCollector(doc)
.FirstOrDefault(q => q.ViewFamily == ViewFamily.ThreeDimensional);
using (Transaction t = new Transaction(doc, “workset view isolation”))
// create a dictionary to hold the worksetid and workset name
Dictionary<string, Autodesk.Revit.DB.WorksetId> dict =
new Dictionary<string, Autodesk.Revit.DB.WorksetId>();
// loop through all worksets (but only User worksets)
foreach (Workset wset in new FilteredWorksetCollector(doc).WherePasses(new WorksetKindFilter(WorksetKind.UserWorkset)))
foreach (Workset wset in new FilteredWorksetCollector(doc).WherePasses(new WorksetKindFilter(WorksetKind.UserWorkset)))
// create a 3d view
View3D view = View3D.CreateIsometric(doc, vft.Id);
// set the name of the view to match the name of the workset
view.Name = “WORKSET – ” + wset.Name;
// isolate elements in the view, using a filter to find elements only in this workset
view.IsolateElementsTemporary(new FilteredElementCollector(doc).WherePasses(new ElementWorksetFilter(wset.Id)).Select(q => q.Id).ToList());
for (int i = 0; i < max; i++)
foreach (var pair in dict)
// verify not current workset
if (pair.Key != wset.Name)
Working on some tools to assist the design teams in managing parking spaces. The attached graph contains two tools. The first tool renumbers parking spaces based on a model based spline drawn through the spaces. Refer to the image below for more info.
The instructions to renumber the parking spaces are shown in the blue area in the image and listed below this paragraph. Use the control toggle boolean node to run one graph at a time by setting its value to true and the other node to false.
To renumber existing parking tags based on spline
1.) Draw a model line using the spline tool. If your sketch contains multiple sharp curves, you may need to increase the “Integer Slider” amount to ensure the routine gets all the parking stalls. 400 is a good starting number.
2.) Start in lowest number parking spot, continue spline through parking spots in order ending the spline in the spot you wish to have the highest number.
3.) Use Select Spline (Model line) “Change” button to select the model spline in your project.
4.) Enter desired starting number for in Starting number node.
5.) Enter desired increment amount
Click Run when Ready
The second tool addresses parking spaces on ramps. It requires a custom parameter named SCHEDULE LEVEL. Use the second tool to write data to the parameter. You can use this to filter your parking schedule.
The instructions to update the parameter are shown in the blue area in the image below and are listed below this paragraph.
To Assign Schedule Level
To differentiate between level based parking and ramp associated parking, perform the following steps:
1.) Click Select model elements and window the parking elements that are to be associated with the ramp.
2.) Click True to run this operation or False to run a different operation.
This post will describe a fairly simple graph for offsetting alternating curtain panels in a curtain wall. The idea was generated by a request for a checkerboard rowlock brick wall accent. I’ll break down the dynamo graph for you in pieces.
Prior to getting started, make sure you have installed Dynamo Version 1.2.0 or higher. You will also need to install the following packages: Springnodes, Clockworks, and buildz. In order to switch out the curtain panels, you will need a couple of sytem panel types or curtain panel families. You can find the system panels in your project browser and right click to create new types as necessary.
Once you’ve created the new types, right click the type and set the appropriate properties to create the offset surfaces or alternating patterns to be used.
In this example, I’ve created two new system panel types: Brick_Flush, and Brick_Offset. I also edited the type properties and added a brick rowlock material. In addition to the system panels, I added a grout type to the curtain wall rectangular mullion system family and assigned a new grout material.
The above image is the result of the graph shown below which collected all the curtain panels from the user selected curtain wall. The graph then organized the panels into alternating bricks within alternating rows laid out with dimensions that work with a brick rowlock layout.
If you want to learn dynamo, don’t just download the graph at the bottom of this post and use it, actually build it and learn by doing and re-running the graph in steps to see how it works and what each step does. Ready to learn? Here we go.
Launch Revit and draw a curtain wall. To replicate the brick rowlock checkerboard curtain wall, adjust the properties of the curtain wall to match these settings:
Note: I have already created the Rectangular Mullion Type to represent the 3/8” thick grout between the bricks. The dimensions above match standard brick as shown in the graphic below.
Launch Revit Dynamo from the Addins tab and using the node search function, add the following nodes and connect them together as shown in the image below: Select Model Elements, CurtainPanel.ByElement, and CurtainPanel.Sort. Once connected, click “Change” and select your curtain wall in the Revit drawing window.
Once you’ve connected the nodes together and selected a curtain wall, click Run, then hover over the lower right corner of the sort node to see if you’ve gotten any panels in the data list. The CurtainPanel.Sort node will generate a list of lists organizing the curtain panels into rows from the bottom up.
To see the results of our work, lets add the “FirstItem” node and the “Element.Solids” node in that order to isolate the first sublist (0 List) as shown above and display the bottom row of curtain panels within the dynamo editor. Click Run, your dynamo window should resemble the following image:
Using List.FirstItem and Element.Solids gives us visual feedback within the dynamo editor. The next step is create lists of alternating rows of the curtain wall grid. Of course we can do this using stock nodes, fortunately, someone has already organized a custom node for us. Add the Springs.List.GetEvenOdd and connect it to the CurtainPanel.Sort node. Now click the Odd output connector and connect it to the “List.Firstitem” input connector. Lets run the graph again and look at the results. Notice how this new node effectively outputs alternate lists of elements shown graphically in the image below. Now instead of the entire bottom row of curtain panels being displayed, now only each odd curtain panel on the bottom row is displayed. Switch the output to even and re-run it to see the other panels.
If you bypass the “List.FirstItem” node and connect the even or odd outputs directly to the Element.Solids node, you’ll see exactly what the GetEvenOdd node is doing. It is creating lists of the alternating columns. Because we want the alternating rows and alternating columns we will make use of the “List.Transpose” node along with two more …GetEvenOdd nodes.
In order to generate our checkerboard pattern, we are going to have to build lists of alternate rows as well as lists of alternating panels within each row. Let’s adjust our graph a little further. Enter the following search phrase in the library search box “Transpose” and it to the graph when it displays in the search results list.
Select the List.Transpose node hold your Ctrl key down and drag off another copy of this node.
Now Click to select the “Springs.List.GetEvenOdd” node, hold the Ctrl key down as you drag off a copy of this node. (You can also use copy / paste within the dynamo editor). Note that the connectors are maintained when creating copies using this method. Click to unselect them.
Connect each transpose node to an output connector from the original …GetEvenOdd node, now connect the new …GetEvenOdd input connectors to the output connectors from the transpose nodes as shown in the image below
At this point, if you want to duplicate the solids node another 3 times you can connect them to the four even/odd output connectors to see what each output list contains individually (the download is organized this way for learning purposes). Note, when you click on the Element.Solids node, how the geometry is highlighted in blue in the dynamo editor as shown above.
Since we are alternating only two types of panels in our curtain walls, we will use the List.Create node to recombine the output lists in an organized fashion. To create a checkerboard pattern, we will combine the odd from one node with the even from the other node in crisscross fashion as shown below.
Now that we’ve reorganized our curtain panel lists, its time to change the curtain panel type. Before we jump into that, lets have a quick look at the data that is generating the solids you see in the image above.
As you can see in the image above, the result of our reorganizing has created some very deeply nested data. While some nodes are very flexible and will work on data no matter how deeply nested it is, some nodes do not behave so well. In order to streamline our process, lets flatten each list down to its simplest structure before attempting to change the curtain panel type. Add a “flatten node” for each output. Use the Builtin version of the flatten node to reduce the 4 deep list of lists to a single list of panels as shown below:
Click in the Library search box and enter this keyword: “FamilyInstance”, choose the second one in the list displayed. “CurtainPanel.AsFamilyInstance”. You’ll add two of these and connect them to each of the flatten outputs. Enter “SetType” in the library search box and add two FamilyInstance.SetType nodes as shown in the image below:
Note that the FamilyInstance.SetType node also needs and input of the familyType to be set. Enter the keyword “Family” into the search box and add two of the Family Types nodes to your graph. Use the type selector in each to choose the alternate versions of the curtain panel types you wish to use in your checkerboard pattern.
Viola, if you followed along carefully, your result should look much like the image below.
I hope you were able to follow along and add this workflow to your Dynamo repertoire.
You can download the completed and formatted dynamo graph Here.
Note: this method also works for other curtain panel types:
Thought I’d share with you a little success my son has had with TSA at his highschool. Earlier this school year, he entered the Architectural Design competition at the TSA technology day at the state fair in Georgia. The challenge was to design a garage with workshop. He put together a design plan for a wood working shop inside an enlarged 3 car garage. Here was the design challenge copied from the flyer:
Design Challenge Background:
DIY (Do-it-yourself) is coming back into style. Many home owners are adding separate multi-use buildings to park vehicles and have a workshop as well.
The challenge is to design one of these garage/workshops for a client. Your job is to act as an architect and prepare a pro-posed design for a client who wants to park two cars and have a workshop in the same building, separate from the main house. You do not have to include a main house. The entry needs to be only the garage/workshop. Consideration needs to be made for getting materials into and large projects out of the workshop. Research what machines would be included in the workshop and where they may be placed inside for safe use. Also include some space for storage.
Here is what he submitted:
This design was started as a 2D sketch in Sketchup3D, recreated in Revit 2015, then exported to Lumion3D for rendering and presentation. Here is a photo of his presentation board.
The following images are the rendered images used in his presentation as exported from Lumion. Note, Lumion3D saves in bmp format. These images were converted for presentation on the web.
When he presented his design and was interviewed he ended up winning the blue ribbon – First Place for his efforts. A good effort for a 10th grader with no formal training or any classes in Architectural Design.
View his Lumion3D rendering and panorama model for the TSA Technology Day Architectural Design Competition.
After installing V-Ray for Revit public beta the other day, I rebooted my workstation and found that everytime I launched Revit, there was a delay and V-Ray would error out with a message indicating that no license was available.
Since I knew that I had successfully installed and had ample licenses available, the problem must be in a setting somewhere. I checked the localhost:30304 server and found plenty of unused licenses on the online tab. Since I have an install for Sketchup and 3DSMax, I thought that the new beta may be using an existing mechanism to find the server. I suspected that the 3DSMax license tool was telling Revit to look in the wrong place. Once I reconfigured the original install to use localhost as primary and moved the network ip location to the “Alternate Server 1” slot, Revit was able to pull licenses when launched.
Steps to fix this issue:
Find the chaos group folder under your start menu.
Within the 3DSMax tools find the license administration folder
Right click and choose “Change V-Ray…”
When the V-Ray License Server information dialog box displays, make sure that “localhost” is assigned to the primary license server with 30304 as the connection port. If you were grabbing a license from a dongle attached to another machine(s), just add them in Alternate license server 1 and/or 2.
A designer asked for help this week with a project where they were having difficulty creating shafts on certain levels. On some levels there was no issue, on other levels she was unable to create a shaft to save her life. This was her question:
“Good morning! One of my revit models is giving me trouble when creating a shaft. When I choose to create a new shaft it immediately gives me an error that the top of the opening is lower than the bottom of the opening. It does not allow me to adjust the heights, and I am unable to place a new shaft. I’ve audited but cannot figure this one out…”
When I jumped into their model, activated one of the problem levels and launched the shaft tool, I was greeted with this dialog box just as she described it:
Clicking Delete Element(s) gave me another cryptic message about not being able to delete the element I am unable to create in the first place.
Of course hitting the Cancel button will allow me to exit the sketch mode based shaft command, leaving me right where I started with no shaft!…. It seems my designer has spawned a black hole and now I’ve been swept into the vortex with her! So I try again and this time pay attention to the property palette.
Notice the level based constraints on the shaft and the resulting Unconnected Height. Seeing this, I switch to another level and try creating a shaft and viola no error message, I seem to be able to create the shaft with no problem. So it appears the black hole only exists on the fourth floor.
So I cancel the command and see if I can create a shaft on the offending level four again…much to my chagrin, I still cannot create it, but at least I’m not past the event horizon so I cancel the command again. My next thought is it is a problem with an existing shaft and prepare to find the offending shafts and remove them. But wait, before I go down that rabbit hole, let me think about how Revit works! I know that Revit is always trying to help me by remembering the values I previously used for different commands… so maybe all I have to do is successfully create a shaft that is not tied to an upper constraint. As shown in the image above, with a floor to floor height of 20′-6″ (intermediate level not shown), a base offset of 15′-0″ the result is a shaft of 5′-6″, which is valid. Then it occurs to me, perhaps I shouldn’t have canceled out of the command after all! Since canceling didn’t store the value in the properties palette, I go ahead and try creating a shaft again on the level without the black hole, this time setting the upper constraint to “Unconnected” and clicking the green check mark to successfully complete the process.
Completing the process results in new shaft tool defaults, so when I launch the tool on another level, the properties of the shaft tool will default with the base constraint of that current level, but no upper constraint. My theory is that the tool will not error out.
I try on another level and have success. I try on the offending level and have success.
Ding ding ding, winner winner, chicken dinner!
Once I’ve created a shaft I am able to then create a new one on any level I wish. So next time you’re faced with this vortex of doom, just find a level that works, or create a new level and create a shaft with no top constraint. Then you can delete it and resume creating shafts on levels you want to create them on.
P.S. I am sure that this problem originated as a result of nesting shafts within Model groups and copying them from level to level with “Upper Constraint” properties tied to levels.
Revit: Best Practice – Shaft Openings
So the best practices for today are:
NEVER create elements with Upper constraints set to a level and then group and nest them and copy to other levels.
ALWAYS remove the “Upper Constraint” for elements within Groups and set the upper constraint to “Unconnected” with an explicit height.
Better yet, don’t include level constrained elements inside groups!