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

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

It can be pretty hard to track what is visible in a big federated model, and even harder to figure out when something has been changed or updated. Until now…

Check this little node out:

This gets five pieces of information and writes each of them to a View instance parameter. Currently, it works in the context of the currently active view in Revit. The information acquired is as follows:

  • current date / time
  • worksets currently opened
  • RVT links that are visible in the view
  • the file sizes of those links
  • the date modified for those links

The ‘list items’ are converted to a string with line breaks. Then when it is referenced in a Label in a View Title family (on the far right of image above), it basically shows up as a list.

Future applications of this can easily include reading the link status from the view parameter (by converting the string back to a list), comparing it to current link status, and then immediately showing what models have been updated and need to be reloaded…

One of the biggest challenges for many long-time Revit users is that initial ‘starting point’ of getting into Dynamo. It takes a bit of time and effort to make that transition…

Happily, as with Revit, the community is the key. The community is full of people who are providing free packages, definitions, and code, and free advice to new users. But where can we find all of this info? Check out this post on Kyle Martin’s blog. He gives some great tips on how to integrate Dynamo learning into your daily work.

Here are a couple of comments I enjoyed:

  • been using Dynamo for less than a year with no prior visual programming experience and it has made a significant impact on the way I approach production
  • Dynamo adds an additional layer of control to overcome Revit limitations by providing the capability to gather and restructure information and elements in the model, thus creating the potential for repetitive task automation

I added some of the feeds he mentioned to my super aggregator feed at:
http://www.inoreader.com/stream/user/1005975985/tag/REVIT_FEEDS_RSS/view/html

Full post at:
Getting Started with Dynamo — Kyle C Martin

I have also reproduced some of his links here:
… the tutorials on the Learn page of 

the Dynamo website
the Primer 
the Dynamo Blog
The Dynamo Community Forum

 … there are many blogs produced by pure Dynamo enthusiasts that have helped me in my journey. I highly recommend that you check them out if you are looking for answers or inspiration:

Proving Ground (io) & The Proving Ground (org)
Archi-Lab
Buildz
Havard Vasshaug’s blog
Simply Complex
What Revit Wants
Sixty Second Revit
AEC, You and Me
Jostein Olsen’s blog
Revit beyond BIM
Enjoy Revit
Serial_NonStandard
Kyle Morin’s blog
The Revit Kid
The Revit Saver
SolAmour’s extensive list of resources

Listen to the Dynamo Team explain the history and recent popularity of Dynamo on the Designalyze Podcast.

I’ve had a bit of struggle with Package Manager lately, but I’m happy to report I was able to get a new version of Bakery uploaded today. I’m pretty sure my issue was ‘too many backups in the dyfbackup folder’, so that may help you if you are having problems uploading. The new version is 2015.10.291:

Recently, I have made an effort to reduce dependencies, but there are still a couple like archi-lab and Clockwork.

Here is a list of my main nodes, with these comments

  • some have been forked or imported directly from other packages (see note about dependencies above), and full credit goes to those people who made the original versions
  • some are sub-nodes of main parent nodes that I have yet to go through and hide from the library. I have a big habit (bad?) of making nodes to handle one item and then using them in List.Maps.

Anyhow, here they are:
Boolean Input to Variable String Output
Bruteforce Get Elem ID and Two Parameters and Make List of Strings
Bruteforce Get Parameter Value by Name
Bruteforce Get Parameter Values when Multiple Entries
Bruteforce Get Parameter via String Split for Single element
Bruteforce Get Parameter via String Split V2
Bruteforce Get Two Parameters and Join to One String
Built In Name Lister
Check DYF folder for Dependencies in Package Folders
Check for Duplicate Parameter Values and Make Selection Set
Check for SetParameter Nulls and Report Info on Elements
Check if Elements are Inplace ( In-place Families )
Check Project Shared Parameter against benchmark GUID
Check Reference Level Offsets against a Tolerance Input
Check Specific Shared Parameter has correct GUID
Clean List of Indices to Remove Negative Values
Clean Warning Types from Error Report HTML
Collect all FamilyInstance using Element Types
Collect All Tags in Project
Collect Elements from List of Category Names
Collect Elements in Rooms and Show Detailed List
Collect from Link using Category and Parameter Value
Collect Tag Elements in Specific View and Send Ids to Clipboard
Combine Column from Three Excel Files into One Long Column
Compare Two Columns From Excel and Report Differences
Compare Two Lists by Item and Return Item Differences
Compare View Filters added to Two Views or Templates
Convert Category Name to Built In Category Name
Convert List into List of Strings with Line Breaks
Convert String with Line Breaks into List of Strings
Copy Parameter to Parameter in List of Elements
Copy Parameters Node for Nesting Process
Copy Property to Parameter for List of Elements
Copy Workset Name to Target Parameter
Create Floors From Rooms v1
Create Floors From Rooms v2
Cycle Entries of one List by List of Lengths
Cycle One Item Into List to Match Length of Other List
Design Option Summary
Design Option and Design OptionSet
Document Design Option Sets
Document Design Options
Document Phases
Does this Document Contain Category
Duplicate View and Isolate Elements
Duplicate View and Rename and Isolate Elements
Duplicate View and Rename and Isolate for System Types
Element List check for Inplace Families
Element Name Universal
Element Type for Element Lists
Element Type for Linked File Element Lists
Element Type for Linked File Large Lists
Enumerate Worksharing Display Modes for Document
Example FFE Category List for a project
Export Family and Type Name with One Type Parameter to Excel
Export Images using many input variables
Export to Image using Directory and View Parameter
Extract Specific Tag Entries from XML as Unique List
File List from File Path showing Files in SubDirs
File List from File Path
File Size in MB from File Path
Filter a List by a Given Value with second list passthrough
Filter Element List by Parameter Value
Filter Element List by Type Parameter Value
Filter Items in List by String Contains and Return List and Unmatched
Filter One List by String Search in Another List
Filter Revit Selection to View Crop Elements and Names
Filter Views with Two Criteria and Return Views
Find Nearest Revit Level for a Given Z value
Find Pipe Insulation on Workset – Get Host Pipes – Save to Selection
Find Revit Level for Points by Elevation
Find Sheets and Views Where an Element is Visible
Find Worksets that contain Revit Link Instances
Flat List to List of Strings
Flatten List and Replace Null with NULL VALUE
From File Path into RVT Build Information
Get Actual Elements from Linked Tag Ids
Get All Revisions
Get All Revit Links as Element List
Get Boundary Curve for One Room by Perimeter
Get Boundary Curves from Room List
Get Build Number and Worksharing from RVT file
Get Build Number from All RVTs in a Folder
Get Categories from Elements
Get Categories with Builtins
Get Categories
Get Design Option Element by Set Name and Option Name
Get Element Parameters and Split to Names and Values
Get Element Position Rotate Mirror
Get Element Room parameter from API
Get Elements and Types for Certain Categories in Links
Get Elements from Link Document Using Category
Get Elements in Link using Name Search and Category
Get Elements Parameter List and Show Unique Values
Get Family and Type List for Project
Get Family from Element
Get Family List for this project
Get Host Pipe ID from Pipe Insulation
Get Indices of Null Values
Get Info from a Linked Element Tag
Get Link Document from Link Instance Id
Get Linked Element from Element Id and Doc
Get Linked RVT Documents
Get List of Elements at OriginalNestingLevel
Get list of GUIDs for a Specific Shared Parameter Name
Get List of Linked Elements from Id and Doc
Get Open Worksets and Write to View Parameter
Get Open Worksets
Get Project Location Details
Get Pure Filename from Revit Link Name String
Get Revit Link Names from an Element List
Get Revit Selection and Delete
Get Room Geometry and Filter by Level Elevation
Get RVT Link Filenames with Element and Type Workset Info
Get Sheet Element from View
Get Standard Views as single list
Get System Related Properties of Element
Get Tagged Linked Element Id
Get Two Parameters and Join to One String
Get Type Parameter for Tagged Linked Element
Get View Dependency as Internal not String
Get View Parameter and Parse for Locate32 Search
Get View Template for View
Get Viewport Elements Using View Name Search
Get Workset Info for RVT files without opening
Get Worksets with all Properties
If Equal Return Index using IndexOf
ImageSettings Export Ranges
ImageSettings File Types
ImageSettings Fit Direction Type
ImageSettings Image Resolution
ImageSettings Zoom Fit Type
Inplace Family Check Faster
Is Family Instance InPlace
Join Two single Strings to One single String
List All Views
List Design Option Information
List Detailed View Information for a List of Views
List Duct and Pipe Related Elements
List DWG Link Information
List Elements in View across Revit Links
List Groups
List Import Information
List Nodes in DYFs for an Entire Folder
List of Duct and Pipe Categories as Built in names
List of float double to list of Int
List of Model Elements simplified with Annotation removed
List of Model Elements simplified
List of System Related Categories
List Parameter Info with Shared Parameter GUIDs
List Phase Information
List Revit Link Instances Visible in Active View
List Revit Links Visible in View
List Room Names from API and show failures
List Shared Parameter GUIDs only
List the View Worksets of All Tags in Project
List Unique Categories Present in Set of Elements
List View Filter Information for View or Template
List Views not on Sheets
List.RemoveItemsFromOtherList
Load Selection Set as Elements
Make Unique Identifier and Set it to Parameter
Match Link Level with Level in Host using Elevation
Mirror an Element
Mirror Element Using Origin and Normal Vector
One Face to Polycurve Outline
one Room to its PolyCurves
Parse and Split String to a List
Parse CSV Text of Elem IDs to Actual Revit Elements
Parse Error Report and Provide Summary List
Parse IFC File
Parse Revit Error Report HTML and Output Summary
Parse Revit Journal File
Place Family by Point Cloud
Place Free Instances to Match Project by Category
Polycurve to Nearest Revit Level by Elevation
Process Family Type Excel Sheet and Get a Value To Write
Project Base Point Details
Read CSV to Flat List
Remove Characters from end of single String
Remove Chars from End of Single String
Remove Empty Strings from List
Remove Equal Items from List and Preserve Counts
Remove First and Last Characters from String
Remove First Revision from Each Sheet
Remove List from List by Item not Value
Remove Revision From Sheet subnode for listMap
Rename Families by Replacing Prefix
Rename Families with a Prefix
Rename View by Replacing Prefix
Rename Views by Appending Selected Suffix
Report Dynamo Package Details by Folder
Report on Inplace Families
Report Revit Link Worksets
Report RVT Links Visible in Views on Sheets
Room to Element Geometry Test for Preflight
Rooms to PolyCurves
Rotate Families Around Origin by Angle
RVT Information for All RVTs in a Folder
Search for Certain Build Number in Folder of RVTs
Search for Generic Annotation on Sheet and Copy Id to Clipboard
Search for Type Parameter Value in List of Elements and Return Elements
Search One List Based on Second List and Get Values
Select based on a single builtin name
Send Element IDs to Clipboard
Set Design Option by View Parameter
Set Instance Parameter by Type Parameter
Set List of Values to List of Elements for One Parameter
Set One Parameter to Many Elements
Set OriginalNesting Level Parameter for all FamilyInstances
Set OriginalNestingLevel Parameter to Element
Set Parameter of View based on a Character in Sheet Number
Set Visible RVT Links to Parameter for Current View
Set Workset for a Single Element
Set Worksharing Display Mode for View
Show Dependency Nodes for one DYF
Show Element Workset as Internal db name
Show List of Revit Links that are never visible on Sheets
String Replace using RegEx
String Search All Element.Parameters for a Single Element
Summary and Node Search for a Folder of DYFs
Summary of Selected Parameter Values for Duct and Pipe Elements
Summary of System Related Elements
Summary of Unique Values present in List
Transpose Data within Excel Sheet
UUID GUID Generator for Lists
View Statistics
View Templates for View List
Write Empty Linked Tag Information to Excel
Write Parameters from One Element List to Another
Write Shared Parameter Check to Excel
Write to Excel using only Data and File Path Inputs

Update… v2 has been published in Bakery package as:
Create Floors From Rooms v2.dyf

All kinds of weirdness with Package Manager at the moment, so I am sharing my entire ‘packages’ folder including Bakery and dependencies for 0.8.2 at this link:
https://drive.google.com/open?id=0B1dGdRkpk2beekFydmdCZTVhc0k

It uses a two different methods to get Room Boundary outlines: first try is with a Clockwork node, next try is by Element.Geometry. It also sets the Room Number to the newly created Floor Comments parameter.

Just letting you all know that this new node has just been published in the Bakery package:
Create Floors From Rooms v1.dyf

The scope:
This ‘version 1’ node takes the Room elements, converts to Element.Geometry, grabs the face at the host level, gets the curves from the face, uses Konrad Sobon’s Group Curves node to assist with making the Polycurves, then matches the right Polycurve with the outer boundary using a bounding box method. Then, it feeds the outline to a Floor creation node (after matching link Level-host Level if necessary), and then sets Element Id, Room Number and Room Name as one string to the parameter you select.

You can use it across links with some other Bakery nodes too, which would look something like this:

Unfortunately, sometimes the builtin Element.Geometry node will fail to convert the Room to a solid. This warrants further investigation, but only affected about 15 rooms of 718 in this particular test. In the meantime, I simply report which rooms fail in the ‘geometry failure’ output:

Future improvements needed:

  • handle Element.Geometry failures with some other method
  • cut out Floor Openings where voids are present in the Room space
  • match Base Offsets by moving created floors to correct height
  • get approximate Room Height by Volume and drive or report desired Floor Thickness

Here is the 1 minute demo:

And the dyn:
http://gdurl.com/cWYz

If you are on Dynamo 0.9 or newer, you may want to check out Marcello’s Direct Shape method over at:
Simply Complex: Create 3D Rooms in Revit Using DynamoBIM

Let’s say you have a Generic Annotation family with about 60 different view states controlled by visibility Yes/No checkboxes. These visibility states are linked to Sheets, and the Generic Annotation families themselves are placed in the Sheet views in Revit. I’m sure you are thinking “why??” at this point, but let’s skip past that part…

Can we drive the Annotation family visibility states based on its ‘host Sheet’ in Revit? Not really.

Can we create a mapping table in Excel, Dynamo-push a single integer value into the Annotation instances based on the host Sheet, and drive the visibility by formula that way? Yep.

Here’s the basic steps:

  1. I used dir and Notepad++ to make the list, one column in Excel for the lookup value (I used Sheet Number), and one for the parameter I want to get and use
  2. This relied on having the Family parameter list sorted Ascending in the Family Editor

  3. The Excel sheet looked a bit like this – notice how the driving parameter is an Integer?

  4. This is the work in progress in Dynamo – getting the Generic Annotation families, matching them up and getting the related Excel integer value

  5. This is the completed dyn, with the push back into the Element Parameter to drive the visibility – see how the string has to get converted ToNumber before pushing into the Integer parameter?

  6. And here is one instance in the project

  7. After running this once, all visibility states are set properly throughout the project

Yet another example of @dynamobim making the Revit-impossible, possible 🙂