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:

  • examines each link for the links inside of it
  • replaces erroneous paths with the correct file path
  • sets the new paths to the file

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:

External References FINAL

You can get the supporting nodes from GitHub here:

https://github.com/LukeyJohnson/BakeryForDynamo/tree/master/nodes

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[0]
approvedFilenames = IN[1]
approvedFilepaths = IN[2]
targetfilepath = IN[5]

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[1])
	
newpath = []
indices = []
failpath = []
origcounter = 0
matchrefs = []
newpathtypes, newbools = [], []
pathtypevar = IN[3]
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[4]
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:

TransmissionData

ModelPathUtils

ExternalFileReference

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:

  1. Create a unique type for each Planting or Entourage element (as Height is a Type parameter)
  2. Randomize a list of values and write them into the Height parameter

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
Readme
Release Notes 
Autodesk blog post
showing these top new features:

 

Revit 2016 R2 Update 7
Direct Download Link
Readme
Release Notes

Dynamo Player
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!

pickobjects.png

Help:
Dynamo Player on Revit Help

Forum:
Associated discussion over here.

I had a good time at RTC back in 2016, it was awesome to catch up with the usual BIM crew and see what they are all up to. Hopefully I’ll get a chance to post in more detail about a few things I learned this time around… but for now, here are my 2016 presentations for you to check out.

My keynote presentation slides (why BIM is broken and how to fix it…)

My Dynamo presentation slides:

And the Revizto session that I ran with Michael Clothier:

Presentation and handout resources (including Dynamo dataset) are available in the folder here:
https://drive.google.com/folderview?id=0B1dGdRkpk2beZ3VRRUpiYVctakU&usp=sharing

Quite a momentous day!

You can download it at:
http://dyn-builds-data.s3-us-west-2.amazonaws.com/DynamoInstall1.0.0.exe

(or you can wait for the auto update 🙂

dynamoVersion1.png

 

location.png

Readme:
### 1.0.0 ###

– API Stabilization:  1.0.0 is a commitment to stable code that allows for smoother and more reliable movements from one version to another.  To more clearly express this, we have been moving to “semantic versioning” to illustrate the nature of changes in each release. We will be using the fairly standard version naming with an x.y.z system, where x incrementing represents breaks to the API (requiring developer refactors), y indicates changes that are still backwards compatible, and z are smaller bug fixes.  Package creators and maintainers are encouraged to assess changes to the previous code, which can be found here

https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Node-Changes

https://github.com/DynamoDS/Dynamo/wiki/API-Changes
– Graphics performance enhancements:  see this post for details
https://github.com/DynamoDS/Dynamo/pull/6356
– Documentation: Along with new sections of the DynamoPrimer (http://DynamoPrimer.com), we have started an online documentation of the Dynamo API with a searchable index of public API calls for core functionality. This will be expanded to include regular nodes and Revit functionality.  http://dynamods.github.io/DynamoAPI/
– Licensing:  Dynamo Studio is now using a new version of the Autodesk installer that allows for easier access to network and token flex licensing tools
– Install:  we have created a separate installation for “core” Dynamo functionality, those tools used by all implementations of Dynamo, and Revit, and Studio installations.  This allows for the sharing of a common core of Dynamo code and packages.
– List Management:  Changes to “replication” or automated matching of different data streams in nodes and Code Block nodes eliminates the need for List.Map and List.Combine in many situations
– Send to Web: formerly known as Share Workspace, we have improved the ability to view and interact with Dynamo online with Customizers
– File Export:  Users can now author DWG files in the Translation section of Dynamo Studio.
– Direct Shape:  Dynamo in Revit 2017 can now take advantage of faster and more sophisticated direct shape creation.  In most cases, solid and surface geometry can be sent directly into the Revit environment as smooth (rather than tesselated) surfaces and solids, categorized to whatever is needed.  In the cases where a smooth element cannot be created, a tesselated (mesh) object is created, as was the case previously.

Bug Fixes
– An extensive list can be found here: http://dynamobim.org/incoming-bug-fixes-for-dynamo-1-0-0

Known Issues
– Listed here: https://github.com/DynamoDS/Dynamo/wiki/Known-Issues

1180.png

Also:
Dynamo Builds

For a while here on What Revit Wants, I was a bit worried I was writing about Dynamo too much… “Hey, Dynamo isn’t Revit, its just an addin!”

But guess what?

Now Dynamo is Revit, its right there on the Visual Programming panel, Manage Ribbon.

dynamo2017.png

If you were running Dynamo 0.9.2 prior to installing Revit 2017 (perhaps as part of Building Design Suite Ultimate 2017), you won’t immediately see Dynamo on the Manage Ribbon. After installing Revit 2017, re-run the Dynamo install package, and ensure that Revit 2017 is selected:

addin.png

Next time you launch Revit 2017, Dynamo should be in its rightful place, right there on the Manage ribbon, ready for you to jump in and start winning.