Ryan Lenihan

Revit 2020.1 Prompts to uninstall when you want to install

This is one I have unfortunately come across too many times, you notice that you can’t access BIM360 in Revit 2020, you check your version and you have plain old 2020 which is before the critical TLS patch was released. Easy, I’ll install the 2020.1 patch.

But Revit says no. Update to 2020.2 right? Well.. no. The project you’re working on for the short term is locked into 2020.1 to keep versions consistent. So what are we going to do?

Well, thankfully there are a lot of helpful people out there on the big wide world of the internet, for this one Tony Michniewicz posted up the solution on the Autodesk Support Forums

Open REGEDIT, you will need admin rights for this one. Even local admin rights will do.

The browse to the following registry key

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\

Once there, right click on the key and select find from the contextual menu and search for Autodesk Revit 2020.1.

When you find the existing registry key, simply delete it and then re-run the 2020.1 installer.

Nested Annotation Symbols 101

Over the years, I’ve seen some interesting Revit content. One of the doozies though always seems to be the use of nested annotations and for whatever reason, these weird and wonderful annotation solutions always seem to be in electrical families.

The idea of nesting an annotation symbol in a 3D family is so you can present both a “real life” display for coordination purposes and a symbolic representation for your drawings.

There is no need to get creative with visibility controls

At their most basic level, nested annotations should be controlled by the coarse/medium fine visibility settings.

Simply select the nested annotation in the 3D family, click the visibility/graphics ovverides button in the properties dialogue and then choose when you want the symbol to appear. Generally at fine mode the symbol would be switched off, coarse and medium you should follow your company standards. As the detail level of the view changes, the visibility of the symbol follows suit.

I’m not here to stifle creativity, far from it. But if you’re setting up families and you feel like you’re having to come up with creative solutions for simple things like the display of symbols, chances are you’re doing it wrong.

Yes/No check boxes instead of detail level. Just don’t do it.

In the above example, the family has an instance based Yes/No visibility parameter. This is painful for not only the the end user to work with, but could you imagine giving a model configured this way to an architect and then explaining to them if they need to coordinate on ceiling equipment they need to turn off a series of instance parameters to do so? Yeah nah.

Maybe the more frustrating thing about this particular example is that the 3D components of the family are not controlled at various detail levels either. If you have the symbol on, both the 3D and 2D content is visible all the time which in turn results in your graphical display on drawing to get a bit weird.

Take this example below, how will a contractor on site be able to tell what this even is once printed as a hard copy?

Unfortunately there is no way to be nice or beat around the bush about this one. Just use the provided built in detail level controls in your families. It’s not even difficult to use!

That old annotation orientation chestnut

As a hydraulic guy, I’m rather jealous of the maintain annotation orientation option that electrical and comms families have so I’m sure you understand when I get a little upset with some content creator’s solution to symbology display in families that need to be oriented differently depending on the particular scenario.

The brilliance of this option is that regardless of the rotation of your family, the symbol will display correctly. Need a power outlet on a wall, in a floor box or on the ceiling? No need for multiple families or content creation trickery! Just tick the box!

Upside down, back to front, sideways, no matter what you’ve got the annotation will always appear correctly!

Movable annotation symbols

I’ve talked about movable annotation symbols a long long time ago, and let’s face it, they’re pretty great. But they have a time and place; usually for power and data outlets and the like.

Where they should never be used are things where the symbol is normally shown at actual object size, and is in fact a detail item, not an annotation symbol. Objects such as pits, lights, air terminals.. that’s all a big no for movable annotation symbols.

Why though? Well sit down, pour yourself a drink, grab some popcorn and let me tell you about a story of terrible coordination..

Flip it round

The last common problem that I have seen with content is the use of flipped and mirrored family symbol variations. This particular example is my favourite as well, you see the symbol is supposed to flip by turning on/off the alternate symbol.. but it looks like someone forgot to do that.

Forgetfulness aside, there is a method that can be used particularly for these 3D families that have consistent geometry built of a revolve.

Adding a flip in the direction it’s required will flip both the annotation symbol and the geometry, so just be careful when you use it. In the above example of the smoke detector, the flip control is no drama but in the instance of something such as a power outlet on a wall, using the flip will flip the geometry into the wall itself.

I would however ask the question, is the flip actually required on the symbol? What value does the flippable symbol add to your template? Avoid adding unnecessary complexity or configuration wherever possible in content, especially where standardisation is key. If there are options available on symbol display, then it’s not standard.

Up, Down, Up, Down.. and left and right.

I often see this in families that contain text in the symbol. Some variation of instance based yes/no visibility check boxes to show a correctly oriented symbol and text.

The example above actually relies on a combination of the left and front visibility check boxes to in turn display the correct symbol. The other more obvious variation of this solution that I’ve seen is the literal up, down, left, right parameters. Either way, it’s what we in the industry call a shemozzle.

As with most of these other creative solutions, there is actually an out of the box solution to handle the orientation of text within symbols.

The keep text readable option does just that, it keeps the text readable in line with standard drafting practices of the text being readable from the bottom or the right hand side of the page.

As you can see in the example, I have created a simple arrow family to clearly display the direction the family itself has been rotated. The symbol itself is a nested annotation with text and linework for the box.

With the annotation family correctly configured with the keep text readable tag, the text always appears correctly without introducing the possibility of human error.

Do you have any other tips on working with nested annotations in Revit families? If so post them in the comments section below

The Drawing Status

The drawing status is maybe overlooked as something simple, but there are many different ways to approach it, some being more cumbersome to mange than others.

Checkboxes

First we have the instance based checkbox. It’s a great method if you have something like Ideate BIMLink available to you, or a well developed Dynamo graph, but if you don’t have either of these then the manual checking of boxes across a project becomes tedious quite quickly.

Even with these tools to speed up your work, setting the status of these titleblocks can become quite the chore if you have a lot of statuses to work with like the above example and you have differing statuses from sheet to sheet.

rows and rows and columns and columns and rows and rows..

Even though you can copy cells in Excel, I wouldn’t want to be the person given the task of ensuring the accuracy of these status stamps.

So how do we improve on this?

Integers

The next approach to managing instance based on/off visibility, the integer. I’ve discussed the use of integers to control visibility in the past and it certainly makes management of visibility much easier.

As you can see in the above example, we have a single integer value controlling the visibility of all the status options. As you can see, we have a series from 1-10 and another series from 21-28, this is differentiate between statuses in different geographical regions. But we can do better than that!

Although it’s slightly more complex and gives an additional integer to define, if you have consistent statuses between regions that need to be displayed differently, then you have the benefit of both regions having the same status code, such as 4 for tender issue.

Sure you need to either have a list in front of you or at least remember what number corresponds to which status, but both of these solutions are much easier to manage in an Excel based workflow as you simply need to export one or two parameters in addition to the sheet number.

Another simple alternative to controlling the region setting is to have the integer as a type based parameter and create a titleblock type per region or office, that way there is no need for the end user to set the integer controlling the region within the titleblock at all.

Checkboxes and Family Types

The family type parameter method is another way to approach this simple task, however it makes things a little trickier as the parameters aren’t easily manipulated with BIMLink.

Often I’ve seen titleblocks using this method to still use yes/no visibility check boxes within the nested family. The nested family types can then be controlled using an instance parameter in the titleblock, which provided that you name your nested family types in a simple easy to understand manner, it gives the end user an easy to understand way to control the status on a per sheet basis.

The Free-for-all Instance Label

An option that is rarely used and probably for good reason is the free-for-all label. This is where the status is controlled by an instance text parameter tied to a label in the nested annotation family. The instance parameter is then linked through another instance parameter to the status family.

As status stamps are something that are standardised and shared parameter labels by their nature are a free for all text box, it’s a good reason to not use a label. However, if you have a good BIM or drafting lead overseeing the project and ensuring the correct standards are being applied, then there is no reason why using labels should be out of the question. There will always be that risk of inconsistency though.

Labels and Family Types

Finally, probably the best option is the nested annotation symbol with a label that is controlled by a type parameter. This method is both easily controllable in an Excel or Dynamo based workflow and is a clean and lightweight option.

Regardless of the method you choose, make sure it’s easy for the end users to adopt and if there is anything at all that needs to be documented, make sure it’s documented clearly and concisely.

From Dynamo to C# – Get and Set Parameters

I’m the kind of guy that uses Dynamo for practical things, an indispensable swiss army knife that I used to manipulate data.

Getting and setting parameters is obviously key. This time around we look at how this is done in Dynamo and then how we can achieve that same thing with code.

In this example I will look at how to build up an asset code based on the level name and the mark parameter, combining those into a single new parameter value.

We will start with the code from the previous Dynamo to C# post where we collected all the AHU families in the model. For convenience, here is the complete code from the previous post:

public void getMechanicalEquipment()
{
	//get current document
	Document doc = this.ActiveUIDocument.Document;
	
	//setup collector and filter
	var collector = new FilteredElementCollector(doc);
	var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);

	//collect all mechanical equipment
	var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();

	//use LINQ to filter for familyInstances containing AHU in the family name
	var ahuEquipment = from fi in allMechanicalEquipment
		where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
		select fi;

	//setup string builder to store data
	StringBuilder displayInfo = new StringBuilder();

	//loop through, collect data
	foreach (FamilyInstance fi in ahuEquipment)
		{
			var elementinfo = string.Format("Family Name: {0} Element Id: {1}", fi.Name, fi.Id);
			displayInfo.AppendLine(elementinfo);
		}

	//display results
	TaskDialog.Show("Watch", displayInfo.ToString());
}

Getting the Level

To do this in Dynamo, you would need to string together the following nodes:

In Dynamo we need to use the Level.Name node to get the actual name. The reason for this is that when we feed Level into the Element.GetParameterByName node, the output is actually an element id. Feeding that element id into the Level.Name node returns the name without any further work required.

So how do we replicate this in C#?

First, we need to focus on the foreach loop, as this is where the work is done for each element that we have selected. We have already done the groundwork to select our elements, but how do we find out what level each element is associated with?

We need to use the level class from the API, this allows us to retrieve the name of the level as you would see it when inspecting the element you’re working with.

Using the level class, we create a variable theLevel which we find from the family instance fi.

Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;

This line is doing half the work of our Level.Name Dynamo node. It is taking the element id of the level that is reported from the Level parameter of the selected AHU family, then selecting the level element.

From there we can simply use theLevel.Name to display the level name.

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
	Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;
	var elementinfo = string.Format("Family Name: {0} Level: {1}", fi.Name, theLevel.Name);
	displayInfo.AppendLine(elementinfo);
}

Note that instead of using the elementinfo variable to display the family name element id of the AHU in the dialogue box as per the previous example, we are now displaying the family name and the associated level name.

Getting the Mark

There isn’t a whole lot of change between the process for picking up the mark parameter in Dynamo compared to the level name; the only real change is that we can drop the Level.Name node.

This is because when we tell the Element.GetParameterValueByName node that we want a parameter named Mark, it returns the result as a string.

In C# we want to use get_Parameter on the family instance fi.

But before we get too far, we need to understand that built in parameters are handled slightly differently in Revit to user defined parameters. Built in parameters are contained within an enumerated list, you can review the list of built in parameters on Revit API Docs.

In the API, the mark parameter is stored as ALL_MODEL_MARK

Retrieving built in parameters this way is more reliable as there is no risk that you will pick up a user defined parameter of the same name.

Now that we know this, our equivalent line of code to read the mark parameter in C# looks like this:

Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

But we still don’t have the parameter value. To retrieve the parameter value, we need to use the AsString method on our paramter theMark which will return the parameter value as a string.

It is important to use the correct method to avoid any potential errors returning the data, for numbers use AsDouble, for integers use AsInteger and element ids use AsElementId.

Our foreach loop should now look like so:

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
	//get the level
	Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;
	//get the mark
	Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

	var elementinfo = string.Format("Family Name: {0} Level: {1}", fi.Name, theLevel.Name);
	displayInfo.AppendLine(elementinfo);
}

Again, adding this to our task dialogue, we end up with the following results.

Building the New String

We can build our new parameter value a few different ways in Dynamo, either by using the String.Concat node, or by using a code block which is my preferred method.

There are also a few different way you can approach building the new string in C# as well. The simplest way is to approach it the same way as we do in the Dynamo code block.

First you define the string, in this example we are naming it newValue and we take our level name theLevel.Name, add the string _AHU_ and the we take our mark value with theMark.AsString().

string newValue = theLevel.Name + "_AHU_" + theMark.AsString();

The other method is to use a string builder which we have been using in our examples to create our dialogue box message. The string builder version would look like so:

var newValue = string.Format("{0}_AHU_{1}", theLevel.Name, theMark.AsString());

Either method is acceptable, but if you’re building more complex strings the string builder is the recommended way to go. Both options give the exact same results:

Setting the New Parameter

In Dynamo, the job here is done by the trusty Element.SetParameterByName node seen above, but in C# there is a tiny bit more to do.

The first thing we need to do to set out parameter is define which parameter we want to set. In this example I’m going to use the built in parameter Comments which is stored in Revit as
ALL_MODEL_INSTANCE_COMMENTS.

Parameter theComments = fi.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);

The next step is to start a transaction. Every time you want to change something in a Revit file via the API, you need to make the changes inside a transaction. If you have ever looked into Dynamo nodes containing Python code, you would have seen something similar to this before.

//set the parameter
using(Transaction t = new Transaction(doc, "Set Parameter"))
{
	t.Start();
	//do stuff here
	t.Commit();
}

We define a new transaction t which is being performed in the current document doc which will appear in the undo/redo list as Set Parameter.

Inside our transaction, we set the parameter by using the Set method on our parameter theComments.

//set the parameter
using(Transaction t = new Transaction(doc, "Set Parameter"))
{
	t.Start();
	
	theComments.Set(newValue);
	
	t.Commit();
}

And that’s it! We have successfully pulled information from multiple parameters, generated new string data and set another parameter using C#.

The complete code is below:

public void getsetParameters()
{
//get current document
Document doc = this.ActiveUIDocument.Document;

//setup collector and filter
var collector = new FilteredElementCollector(doc);
var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);

//collect all mechanical equipment
var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();

//use LINQ to filter for familyInstances containing AHU in the family name
var ahuEquipment = from fi in allMechanicalEquipment
	where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
	select fi;

//setup string builder to store data
StringBuilder displayInfo = new StringBuilder();

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
	{

		//get the level
		Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;

		//get the mark
		Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

		//get the comments
		Parameter theComments = fi.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);

		var newValue = string.Format("{0}_AHU_{1}", theLevel.Name, theMark.AsString());

		var elementinfo = string.Format(newValue);
		displayInfo.AppendLine(elementinfo);

		//set the parameter
		using(Transaction t = new Transaction(doc, "Set Parameter"))
		{
			t.Start();

			theComments.Set(newValue.ToString());

			t.Commit();
		}

	}

}

Revit Bulk Unit Conversion Addin

One of the most downloaded files here at Revit.AU is the metric conversion journal script. Despite the obvious downsides of journal scripting, it works about 98.27% of the time.

Based on feedback, the problems with the current journal conversion script are mostly due to user error, but occasionally even when the user followed the steps correctly, a problem would crop up that would stop the process in it’s tracks.

Because of this, one of my goals when learning how to use the Revit API has been to replace this journal script with a fully fledged addin. In my opinion, the biggest benefits seen by developing an addin to perform unit conversions are:

  • User-friendly interface
  • Ability to convert to both metric and imperial in the same tool
  • Automatically closes most popup dialogues
  • Handles sub-folders of files without issue
  • Much, much faster

Benchmarking

If I’m honest, I regret my choice of benchmarking method, a much smaller dataset would have done the job.

I rounded up 500 families totaling 169mb and ranging in size from 248kb to 1.5mb comprising of both 2D annotation and detail items as well as 3D components from architecture and MEP disciplines. I ran the same set of families through both the journal file conversion method and the addin conversion method, recording the total elapsed time for each.

I also used two different hardware configurations were in the benchmark tests; an i5 8400H with 32gb RAM and a 512gb NVME SSD and a i7 7820HK with 64gb RAM and a 1tb NVME SSD. The tests were run on Revit 2018.3 on both machines.

I hit the go button and decided to get some breakfast. This is going to take a while.

2 hours and 3 minutes later on the i5 8400H, the journal script failed on family 366. Repeating the same test on the i7 7820HK reached the failure point in around 1 hour and 40 minutes.

The addin, on the other hand, churned through all 500 families without error in 14 minutes on the i5 and 12 minutes on the i7.

Call it commitment or call it stupidity, but I also decided to time how long it would take to change the content in a single family manually to really showcase the power of automation, even if it’s on a tiny scale.

Manually updating a single family to change everything that the addin changes took 7 minutes and 18 seconds.

Of course, you normally wouldn’t change everything that the addin does, but we all love an apples to apples comparison. If you’re feeling like you need some extra excitement in your life, based on 7 minutes and 18 seconds to change a single family, manually updating 500 families will keep you busy for almost 61 hours!

Reliability

So far, I have processed close to 5000 different families from a range of different sources across all versions of Revit from 2017 to 2020 without a single error.

And let’s face it, although 365 of 500 families were processed with the journal, I couldn’t complete my automation without an error.

Couple the reliability of the addin with its ease of use and as an end user, you should have a vastly improved experience compared to the journal script.

Download

So if converting files between metric and imperial is something that you do, you can download the addin for free here:

Think this tool is worth something? Consider donating to support the operation of the site and the development of further tools in the future.

From Dynamo to C# – All Elements of Category

I had a few comments in response to my post on using the API to clear out a problem line pattern, mostly that the API is over the average user’s head. While this may be the case, there are other users out there that have been using Dynamo for a while now and are looking to take their solutions to the next level.

So I thought it might be useful to show comparisons between what some basic tasks in Dynamo look like, and then what they look like in code. And as I myself am still learning, if you’re a more experienced coder, feel free to correct me if I’ve made any mistakes or if I have taken an around-about method that could be simplified.

It is worth noting that the code examples provided below are from macros, not loadable addins. There are slight differences between the requirements of macros and addins that you can read on Harry Mattison’s blog BoostYourBIM

The first example is getting all families of the mechanical equipment family category. In Dynamo, you would achieve this with the following nodes:

In C# there is a little bit of groundwork that is required first. You need to tell Revit to work with the active open document. To do this you use

//set the active document
Document doc = this.ActiveUIDocument.Document;

In this line, doc is a variable that you are setting and can use later throughout your code to call the active document.

The next step is to create a FilteredElementCollector to collect all the mechanical equipment families in the model.

//setup collector and filter
var collector = new FilteredElementCollector(doc);
var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);
 
 
//collect all mechanical equipment
var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();

We are filtering our families by the built in category OST_MechanicalEquipment. The variable fi represents every family in the model of the mechanical equipment category.

You can however filter any other family category, there is a list of built in categories in the Revit API documentation, the online version of this documentation is here.

But say you wanted to filter further? Selecting the mechanical equipment in the model is far too broad. What about filtering by the family type name? In Dynamo you would achieve this with the following nodes:

As you can see, I’m filtering the families to see if they contain the string “AHU”

In C# we need to take our allMechanicalEquipment variable and filter the list of mechanical equipment families by using a LINQ query to find elements that contain the word AHU.

//filter for ones containing AHU in the name
var ahuEquipment = from fi in allMechanicalEquipment
                   where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
                   select fi;

You can read more about LINQ queries on the Microsoft website:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq

You will also notice here that when we take the family name using fi.Symbol.FamilyName we have added ToUpper(). The reason for this is that some families may have been named inconsistently such as Ahu or ahu. Converting the family name to uppercase means we catch everything with AHU in the name regardless of text case.

So now that we have all of our AHU families, what about replicating that watch node? In Revit we can use the TaskDialog to display information back to the user.

When we want to do something with each of the AHU families, such as getting their name and element id, we need to use a foreach loop which repeats the same process to each selected element.

//example foreach loop
foreach (FamilyInstance fi in ahuEquipment)
{
//do stuff here
}

So we are going to collect the names and element ids for each family instance fi in our list ahuEquipment

First we need to do a little groundwork by defining an empty stringbuilder to populate with information. We do this with the following code:

//setup string builder to store data
StringBuilder displayInfo = new StringBuilder();

Then inside the foreach loop, we need to collect the information on our families and add them to a variable (var) named elementinfo.

We build each line in our string with fi.Name which takes the name of our family instance as well as fi.Id which is the element id of our family.

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
    var elementinfo = string.Format("Family Name: {0} Element Id: {1}", fi.Name, fi.Id);
    displayInfo.AppendLine(elementinfo);
}

To display this information, we need to add the following line outside the foreach loop.

TaskDialog.Show("Watch",displayInfo);

The result is the following dialogue box displayed in Revit

Don’t forget to add spaces around your strings like I did

So to wrap everything up, our final code dropped into our macro looks like so:

//get current document
Document doc = this.ActiveUIDocument.Document;
 
//setup collector and filter
var collector = new FilteredElementCollector(doc);
var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);
 
//collect all mechanical equipment
var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();
 
//use LINQ to filter for familyInstances containing AHU in the family name
var ahuEquipment = from fi in allMechanicalEquipment
                   where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
                   select fi;
 
//setup string builder to store data
StringBuilder displayInfo = new StringBuilder();
 
//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
    var elementinfo = string.Format("Family Name: {0} Element Id: {1}", fi.Name, fi.Id);
    displayInfo.AppendLine(elementinfo);
}
 
//display results
TaskDialog.Show("Watch", displayInfo.ToString());

And yes, I admit coding is a big jump from stringing together some Dynamo nodes, but just like learning Dynamo the more you dive into it the simpler it becomes.

Is DWF Better than PDF?

If you ask anyone in the building services industry what they use to markup drawings, I can almost guarantee that no one will answer with Design Review. The large majority will say Bluebeam, a few will say Acrobat and then the luddites will say pen and paper.

Unlike Bluebeam and Acrobat, Design Review doesn’t implement a printer on your system to generate the files it needs, it doesn’t review PDF files and you can’t use it as a dodgy photoshop as some seem to use it for. Design Review as the name implies is made to do one thing and one thing and it does that one thing rather well.

Many had thought that Design Review had been abandoned by Autodesk, with no releases since 2013. Then Design Review 2018 happened.

Check out the process either here on REVIT.AU or watch a demo just below on Youtube.

Exporting Sheets as DWF

To get started, we need to export a DWF from Revit. That’s right, DWF files are used for more than just CostX. In this example we will be using the trusty rac_basic_sample_project.rvt

We’re also using Revit 2019 in this example, if you’re using a previous version of Revit you need to click on the Application Menu (the big R) rather than the file menu.

Just like using the default printing or DWG interfaces, select the views and sheets that you want to export

There are additional options that can be set and applied to the DWF export it’s always great to have a bit of extra metadata within your files, but only fill out if required. There is no point in providing information just because the technology allows you to.

Save your DWF in a convenient location, ready to send off to your friendly local engineer

The Design Review Interface

On opening the file you’re presented with a series of thumbnails on the left hand side of the screen which represent each of the drawing sheets and views exported from the model.

There are also additional tabs that allow you to review sheets and views in a list mode, list your markups and also and exported model views.

Navigating between sheets is as simple as a single click on the sheet in the list. This isn’t Internet Explorer, no double clicking here baby-boomers! Those extra mouse clicks are just precious time that’s wasted!

The right-hand side of the screen provides you with handy tabulated information regarding the open sheet or view. These tabs can be pinned or set to auto-hide depending on your preference.

Markup and Measure Tools

Design Review includes all the makrup and measurement tools that you need to get the job done.

In addition to the usual suite of 2D markup and measurement tools, there are a series of handy tools that can be used in 3D views so you can take sections through the model assist in the markup process.

To further assist with the markup and review process, there is a sheet compare functionality which allows you to compare drawings between two DWF files.

But what about symbols? Most engineers I’ve spoken to say that they can’t give up Bluebeam because “it has symbols”. Acrobat also has symbols. Just saying.

Design Review doesn’t rely on the set of American symbols you found on the internet, or that Bob stole from his previous company for Bluebeam.

Design Review is able to import 2D symbols directly from a DWF file. What this means is that your specific company standard of block or family libraries can be exported from AutoCAD or Revit and imported directly into Design Review.

Remember the markup tab from earlier? As you generate markups, they are listed out within the markup tab and sorted by drawing sheet.

Each markup has additional information attached, reflecting any notes on the markup and the markup history.

Wait. What? The markup history? That’s right, Design Review offers a full round trip functionality.

Why we should all be using Design Review

Have you ever noticed that DWF Markup button in Revit and wondered what it is all about?

It’s only been there for almost forever.

It’s all about Design Review.

For the longest time, we have had the ability to link in DWF markups directly to Revit and it’s a good sign that Autodesk won’t abandon Design Review.

When linking in a DWF markup file, Revit will display the sheets that include markups. Any sheets without markups will not be loaded.

When the markups come in, they overlay on each sheet.

All the information from the DWF markup flows through into Revit, making it easier for markups to be actioned quicker and hopefully more accurately.

Markups can be completed in most instances by activating the current Revit view and making changes on the spot.

As work is progressed, modellers can change the status of the markup which will highlight it as complete.

There is also opportunity for the modeller to add their own notes to the markup for when it is returned to the engineer.

Once all the markups have been completed, the drawings can be exported as DWF again for the engineer to review.

And the Best Part?

Design Review is free

https://www.autodesk.com.au/products/design-review/overview

Build Your Own Unassisted PowerShell Uninstallers

A fair chunk of what I do these days in the office is around testing software prior to packaging and deployment.

If you have ever had to install and uninstall Autodesk software for testing purposes, or you just wanted to get rid of an old version of the software you’d know that it’s not as simple as it probably should be. Rather than just uninstall Revit, you need to uninstall Revit and a whole host of other applications.

Yep.. that’s a lot of clicking

A while ago, I posted a solution for how to uninstall the 2015 Building Design Suite with PowerShell, the problem is however that this solution no longer works with the current Powershell; it was written for v2.x and Windows 10 is deployed with v5.x

To get the job done in Windows 10, first we want to get a list of all the installed applications on the machine, I just want the name of each package so we need to type the following at the PowerShell prompt. Of course make sure that you’re running PowerShell as an administrator.

Get-WmiObject -Class Win32_Product -Computer . | select-object Name | Export-CSV -path c:\ListSoftwareResults.csv -notypeinformation

This produces a handy little *.csv file with a list of all the installed applications

You can actually pull more information than just the name, it’s as simple as separating the properties with a comma

Get-WmiObject -Class Win32_Product -Computer . | select-object IdentifyingNumber,Name,Vendor,Version,Caption,LocalPackage | Export-CSV -path c:\ListSoftwareResults.csv -notypeinformation

From here we need to wrap the names of our software into this handy little script.

# Remove applications if installed.
$programs = @(
"Software Name 1",
"Software Name 2"
)
foreach($program in $programs){
Write-Host "Looking for $program."
$app = Get-WmiObject -Class Win32_Product ` -filter "Name = '$program'"
if ($app -ne $Null) {
Write-Host "Uninstalling $program."
$app.Uninstall()
Write-Host "$program uninstalled."
}
else
{
Write-Host "$program not found."
}
}

So for example, if we just wanted to uninstall Revit 2019 and it’s associated packages, we would use the following

# Remove Revit 2019 applications if installed.
$programs = @("Autodesk Revit 2019.2",
"Autodesk Revit 2019.1",
"Autodesk BIM 360 Revit 2019 Add-in 64 bit",
"Autodesk Revit Infraworks Updater",
"FormIt Converter For Revit 2019",
"Revit 2019",
"Autodesk Revit 2019 MEP Fabrication Configuration - Metric",
"Autodesk Advanced Material Library Base Resolution Image Library 2019",
"Batch Print for Autodesk Revit 2019",
"Autodesk Collaboration for Revit 2019",
"Autodesk Material Library Medium Resolution Image Library 2019",
"Worksharing Monitor for Autodesk Revit 2019",
"Autodesk Revit 2019 MEP Fabrication Configuration - Imperial",
"Autodesk Material Library Low Resolution Image Library 2019",
"Autodesk Revit Model Review 2019",
"Autodesk Advanced Material Library Low Resolution Image Library 2019",
"Autodesk Workflows 2019",
"Autodesk Material Library Base Resolution Image Library 2019",
"eTransmit for Autodesk Revit 2019",
"Autodesk Material Library 2019",
"Revit IFC 2019",
"Autodesk Revit Content Libraries 2019",
"BIM Interoperability Tools for Revit 2019",
"Autodesk Advanced Material Library Medium Resolution Image Library 2019")
foreach($program in $programs){
Write-Host "Looking for $program."
$app = Get-WmiObject -Class Win32_Product ` -filter "Name = '$program'"
if ($app -ne $Null) {
Write-Host "Uninstalling $program."
$app.Uninstall()
Write-Host "$program uninstalled."
}
else
{
Write-Host "$program not found."
}
}

Before you run any of these scripts though, you will need to change your execution policy. You can do this just for the current PowerShell instance rather than permanently allow scripts to be run on the system. To do this, it is as simple as

Set-ExecutionPolicy unrestricted

To run the script you need to include the full location of the script, even if you are running it from the current folder. For example

.\Uninstall_Revit2019.ps1

If you are specifically dealing with Revit software, you can take your uninstall a step further and clean out the associated files along with it. To do this, just add the following to the end of your script.

# Remove Revit 2019 user data.
Write-Host "Cleaning Revit 2019 User Data"
Write-Host "Backing up old user profile"
Move-Item -Path "C:\Users\$env:UserName\AppData\Roaming\Autodesk\Revit\Autodesk Revit 2019" -Destination "C:\Users\$env:UserName\AppData\Roaming\Autodesk\Revit\Autodesk Revit 2019_OLD"
Write-Host "Deleting temp files"
Remove-Item -Path $env:temp -Force -Recurse
Write-Host "Deleting user profile temp files"
Remove-Item -Path "C:\Users\$env:UserName\AppData\Local\Temp" -Force -Recurse
Write-Host "Deleting user profile Revit cache files"
Remove-Item -LiteralPath "C:\Users\$env:UserName\AppData\Local\Autodesk\Revit\Autodesk Revit 2019\CollaborationCache" -Force -Recurse
Write-Host "Deleting local machine Revit cache files"
Remove-Item "C:\Users\$env:UserName\AppData\Local\Autodesk\Revit\Autodesk Revit 2019\CollaborationCache" -Force -Recurse
Write-Host "Deleting Revit journal files"
Remove-Item -Path "C:\Users\$env:UserName\AppData\Local\Autodesk\Revit\Autodesk Revit 2019\Journals" -Force -Recurse

Just make sure that if you remove the user data as part of your script that you need to run it from that user’s profile, not from your administrator profile.

Removing Revit Line Patterns with C# Macros

Sometimes you might encounter an element within Revit giving you grief.

Recently for me it was a line pattern that had been transferred across from an old template. I didn’t want to spend the time to re-create all the old line patterns in a new template, but that time ended up being lost troubleshooting a fatal error.

Lucky for me that the line patterns were named so inconsistently in the old template or I wouldn’t have even discovered the problem; an unexpected benefit to others not being as meticulous as I can be I suppose.

One by one, I check each line pattern I had imported and discovered there was just one causing the problem. I couldn’t change the pattern definition. I couldn’t rename it. I couldn’t delete it. No matter what I did, Revit would crash.

An audit? No. What about a purge? Still no love.

So what do you do in this situation? I ended up turning to the API to obliterate the pesky line pattern. Dynamo is great but you can make a fantastic toolset based around C# macros and it’s a great way to learn the basic of coding with the API.

public void DeleteLinePattern()
{
//Get the current document
	
UIDocument uidoc = this.ActiveUIDocument;
Document doc = uidoc.Document;
			
/*
my problem line pattern started with a certain prefix, 
so the method i am using is to search for line patterns with that prefix
update your code to prefix that you're looking for
*/
		
var collector = new FilteredElementCollector(doc)
	.OfClass(typeof(LinePatternElement))
	.Where(i => i.Name.StartsWith("PREFIX")).ToList();
			
	List<ElementId> ids = new List<ElementId>();

//Start the transaction that will modify your document
			
	using(Transaction t = new Transaction(doc,"Delete LinePatterns"))
		{
		t.Start();
			
		try
		{
			foreach (ElementId id in ids)
			{
				doc.Delete(id);
			}
		}
		catch (Exception)
				
	t.Commit();
	TaskDialog.Show("Delete LinePatterns","Deletion complete");
	}
}

I’m still waiting to hear back from Autodesk as to if I am still at risk of the model becoming corrupt in the future, but in the current state I’m pretty happy as I can continue working without issue.

As you can probably tell, this is quite a simple macro and the API is capable of doing much more. If you’re interested in learning the Revit API, check out these resources on the web

Harry Mattson’s Boost Your BIM
https://boostyourbim.wordpress.com/

Harry’s Udemy Courses
https://www.udemy.com/revitapi/
https://www.udemy.com/revitapi2/
https://www.udemy.com/revit-api-materials/

Danny Bentley’s Channel on Youtube
https://www.youtube.com/channel/UC1Dx-jGyRbvvHzZ8ZyGWF5w

Jeremy Tammik’s Building Coder
https://thebuildingcoder.typepad.com/

Revit API Docs Online
http://www.revitapidocs.com/

Autodesk “My First Revit Plugin”
https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/simplecontent/content/my-first-revit-plug-overview.html

Free C# Courses
https://www.learncs.org/
https://www.sololearn.com/Course/CSharp/

ItzAdam5X on Youtube for learning general C# concepts
https://www.youtube.com/channel/UC9pq4hre8qZI132O4cok5vA

Creating Annotation Tag Variations

Are you new to Revit and starting to create customised content for your models? You have all the pipework and fittings and now you’re onto the annotation tags.

You’ve come to a tag that you need a few different variations, a few instance based yes/no parameters are what you need right?

Well, not quite.

For starters, using instance based parameters to control the visibility of tags is just going to be a pain to manage in your project. Just imagine each time you need to click various options on and off. No thanks.

It’s not a problem you will encounter anyway, as instance parameters aren’t presented to you in the way that you’re expecting them to be. They’re not displayed in the properties dialogue like they are in other families. Lucky for whoever was expected to click hundreds of yes/no checkboxes in your model.

This particular example, the user wanted to set a variation of their family using a family type drop down set as an instance parameter, but there is of course no way to access this once you place the tag into Revit.

The correct way to approach (shown in the image) this is to have parameters set to types in your family and define family types (steps 1 & 2).

Make sure that you set all the relevant parameters for each type, then once in Revit, select the tag type that you want to apply (step 3).