Big messy Dynamo graph? Can’t see through the jungle?
- View – Connectors – Show Connectors OFF
- View – Background 3D Preview – Show Grid OFF
What Revit Wants
I came across this link to a Dynamo seminar by Sol Amour delivered in Wellington about a month ago. I have had a bit of contact with Sol over the years and he is a Dynamo pro. Cool to see that Dynamo Nodes got mentioned too.
Check out the seminar here.
As you can tell by his headshot, he means business 🙂
There is some more information about the event at this link.
The official build of Dynamo 2.0 is here. There are some big changes, so here are my key takeaways:
Download at this link
Read the official post at this link
The Revit API is actually something pretty special. People will go on and on about how Revit needs this feature or that feature, but the fact is that you can build almost any feature you like with the API. Recently, I have been running quite a few batch operations from the scope of a federated Revit model: so I will have one RVT file, with hundreds of Revit links, and I will process them from that main federated model.
On one recent project, we had to deliver to a Client a linked dataset, with Revit link file paths resolving correctly. As you know, people work in many different IT environments, and the pathing of Revit links may vary widely.
I set up an ‘approved’ list of Revit file paths, that looked something like this:
I knew that in Dynamo with Python I could get a lot of information about linked files using the ExternalFileReference class. What I discovered during this process is that there is a TransmissionData API class that let’s you do some pretty interesting things…
You see, I was thinking I would have to set up a batch method to open this files, change the file paths, and close them. But the TransmissionData class is basically what is implemented in eTransmit for Revit – it allows you to ‘lightly touch’ the Revit file and simply change the Revit link paths, and also set a switch saying ‘this file has been transmitted’. This puts the file in an appropriate state for re-opening in the new path environment. Pretty cool huh?
Once I figured out how to implement those TransmissionData actions in Python, I just had to build a node that, running from the federated model:
I did this in the hacky way of a “counter with List.Map” in Dynamo. In the future I’ll probably fix it up to be a ‘proper’ Python script but this works for now. In about an hour it fixed the linked file paths of 600 Revit links, all with the click of a single button 🙂
You can download the main definition here:
You can get the supporting nodes from GitHub here:
As usual, please use with care. And it is probably worth backing up your files before running something like this.
It is kinda more Python than Dynamo but hey, you get the picture 🙂
In fact, here is the Python code:
import clr clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * # Import RevitAPI clr.AddReference("RevitAPI") import Autodesk from Autodesk.Revit.DB import * clr.AddReference("RevitServices") import RevitServices from RevitServices.Persistence import DocumentManager from RevitServices.Transactions import TransactionManager from System.Collections.Generic import * clr.AddReference('RevitNodes') import Revit clr.ImportExtensions(Revit.Elements) clr.ImportExtensions(Revit.GeometryConversion) from System import Guid import System import sys pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib' sys.path.append(pyt_path) import os.path doc = DocumentManager.Instance.CurrentDBDocument uiapp = DocumentManager.Instance.CurrentUIApplication app = uiapp.Application tempvalue = IN approvedFilenames = IN approvedFilepaths = IN targetfilepath = IN def stripquotes(string): string = string[1:-1] return string transData = TransmissionData.ReadTransmissionData(tempvalue) erefids = transData.GetAllExternalFileReferenceIds() refdata =  for x in erefids: refdata.append(transData.GetDesiredReferenceData(x)) currentpaths, currenterefType, currenterefPath, pstr = , , ,  for e in refdata: currentpaths.append(ExternalFileReference.GetAbsolutePath(e)) currenterefType.append(e.ExternalFileReferenceType) currenterefPath.append(e.PathType) for s in currentpaths: pstr.append(ModelPathUtils.ConvertModelPathToUserVisiblePath(s)) filenames =  for p in pstr: templist = os.path.split(p) filenames.append(templist) newpath =  indices =  failpath =  origcounter = 0 matchrefs =  newpathtypes, newbools = ,  pathtypevar = IN for f in filenames: tempindex = approvedFilenames.index(f) if f in approvedFilenames else -1 indices.append(tempindex) if tempindex == -1: failpath.append(origcounter) pass else: newpath.append(ModelPathUtils.ConvertUserVisiblePathToModelPath(stripquotes(approvedFilepaths[tempindex]))) matchrefs.append(erefids[origcounter]) newpathtypes.append(pathtypevar) newbools.append(True) origcounter = origcounter + 1 currentfilepathstring=ModelPathUtils.ConvertModelPathToUserVisiblePath(targetfilepath) elementcount = len(erefids) hostfile = currentfilepathstring * elementcount currentdata =  #currentdata.append(transData) currentdata.append(hostfile) currentdata.append(erefids) currentdata.append(refdata) currentdata.append(currentpaths) currentdata.append(currenterefType) currentdata.append(currenterefPath) currentdata.append(pstr) currentdata.append(filenames) newdata =  newdata.append(indices) newdata.append(newpath) newdata.append(matchrefs) newdata.append(newpathtypes) newdata.append(newbools) setlength = len(newpath) setcounter = range(setlength) successreport =  setdata = IN if setdata: for s in setcounter: try: transData.SetDesiredReferenceData(matchrefs[s], newpath[s], newpathtypes[s], newbools[s]) successreport.append("Success setting data") except: successreport.append("Failure setting data") else: successreport.append("You need to set the switch to True") if setdata: try: transData.IsTransmitted = True transData.WriteTransmissionData(targetfilepath, transData) successreport.append("Success WRITING data") except: successreport.append("Failure WRITING data") #Assign your output to the OUT variable. OUT = successreport, currentdata, newdata
If you want to read more about the API methods used:
If you try to build a connector to get some Revit data to a database like MySQL, you may hit an issue where some strings that are allowed in Revit will do funny things to your SQL instructions, like this:
What to do? We need to ‘escape’ these characters during our data export or INSERT to create something that the database engine can consume. There are some exotic ways to get around this (like encode your text in base-64), but in my case I just wanted to replace the problem character with the escaped version. Ideally, we would use characters that we know will never be found in Revit Type or Family Names.
Revit does not allow these characters in most type and family names:
Looks like a backslash could work, as this is an escape character in MySQL, and it is not allowed by Revit as above.
You can do this a lot of ways in various coding languages, but an easy way is with a String Replace in Dynamo, like:
This workaround doesn’t handle every situation – like if you are pulling parameters out of Revit that contain all kind of characters, you may have to look at a more reliable text cleanup or encoding solution. But this helps with the Type and Family names at least 🙂
The form creation engine in Revit does not really know about flat vertical zero thickness surfaces. However, with DirectShape, we can make almost any type of mesh geometry. One interesting idea coming out of the RTC ANZ event this year was creating these flat surfaces to display grids in 3D. This lets us do things like dimension easily in Navisworks or Revizto. I wanted to use them to add some flat datum lines to a construction setout point family.
Here is the Dynamo Script that I used (Download Make Flat DirectShape From Line):
Basically, you select a Detail (Symbolic) Line and run the script. In action:
Playing around with the lines a bit, I built this geometry for use in the project:
There have been different ways of accomplishing this over the years. Now, with Dynamo, I would use this simple two step process:
It is super easy with Dynamo. Here is how you make the unique types (GUID from Bakery, Duplicate Type from Springs, SetType from Clockwork):
Then, just push the random values in, like this (the Set List node is in Bakery too):
My last attempt at this was here.
Big day yesterday in Revit updates, particularly with Revit 2017 Update 1 bringing some really cool enhancements, and the Dynamo Player! Here are some links and other information:
Revit 2017 Update 1
Direct Download Link
Autodesk blog post
showing these top new features:
Revit 2016 R2 Update 7
Direct Download Link
People have been asking for a way to run their scripts more easily and transparently, and now you can. Simply install Revit 2017 Update 1, ensure you have Dynamo installed, and you will have a new option on your Ribbon…
It comes preconfigured to point at a samples folder:
You can point this at your own “Player” folder containing DYNs.
Press Play button to Run, and Edit button to open the DYN in Dynamo.
It remains to be seen how inputs will be handled?
Pick Objects and Dynamo Player
Interesting thoughts over on the forum, about how if you use a DYN with a Select Node, it will still ‘work’ — this opens up some great possibilities!
Dynamo Player on Revit Help
Associated discussion over here.
So, you are modelling this awesome conceptual design with Dynamo and Revit, and you realise “hey, what we need is access to the Star Wars API in here…”
Yes? Well, thanks to Jostein Berger Olsen, you can just open up your Package Manager and install SWAPI package:
Nice work @jos_ols 🙂
Check out the original post:
Revit Dynamite and Ammo: Star Wars API and Dynamo
Heaps of presentation and sample file goodness at each link from here, thanks to Håvard Vasshaug:
Workshops | Havard Vasshaug