LazJS for Revit

I recently receive a beta version of LazJS, a Javascript editor embedded within Revit.

Even if I more fluent with .NET and C#, I find the initiative quite interesting, especially when you have to quickly develop some small routine within Revit.

After installing it, I click on the ParamJS button to start their embedded editor.

LazJS

As an example, I concatenate various parameters of a sheet in the sheet name in order to have them when I print or export it.

I start by selecting a category in the Categories list. Here, you can select multiple categories, but I will only select “Sheets” here. When I click on “Customize”, LazJS displays every editable parameters of our sheets in the “Parameters” list. Since I want to edit the name of my sheet, I select “Sheet Name” and save.

ParamJS

I can now drag and drop parameters from the “Formulas” list to the “Editor” panel. This creates automatically the correct line of code for calling this parameter. I drag some of my sheet parameters, add some “+” to concatenate them, and hit Run. We can see the result of my concatenation just below. I hit save, and my modification are added to my model.

Run

If this is the quickest way to edit parameters, LazJS have also a fully functional editor, which allows us to create more elaborate routines.

I use it to create the same concatenation tool than in my previous example, everything came pretty easily with the auto-completion.

ScreenClip [1]

LazJS also provide a set of already existing scripts for inspiration.

Last but not least, LazJS provides functions for exporting and importing data to Excel. These functions are very easy to use, and can replace any plug-in dedicated to exporting and importing data from Excel.

Even if I will keep my habit with C#, the LazJS plug-in seems quite powerful, and far more easy to use than the Revit macro editor, since you don’t have to handle all the tedious document retrieval and the transaction handling.

The only problem I have to report is an error when I attempt to debug a Revit macro in SharpDevelop after installing LazJS. It is kind of annoying, but I am sure this problem will be addressed when they launch their final version.

Getting started programming Revit – Part 2

Last week, we started creating macros in Revit, we saw how to get the current Revit document, and retrieved every visible walls in the current view.

We will see today how to create a tag on these walls.

To tag an element in Revit, we need the Create.NewTag() function. This function is called from the current document, named here myDocument. But to work properly, this function needs a few things as inputs.

It first requires a view to place our tag: we will just use the active view, named myActiveView.

It also needs an element to place a tag on. To do so, we will select each one of our walls with a for each loop.

foreach (Element myElement in myWalls) {
    //Do something with myElement
}

It means that for every element contained in our list of wall myWalls, we will perform some action, written between the brackets.

A few options have to be set, like the category of our tag, its orientation and its leader.

Finally, it needs a location point to insert our tag. We want our tag to be placed at the center of our wall, so we will retrieve the baseline of our wall, and create a point in the middle of this baseline:

//Get our wall
Wall myWall = myElement as Wall;
//Get its location
LocationCurve myWallLocation = myWall.Location as LocationCurve;
//Get starting point
XYZ myWallStartingPoint = myWallLocation.Curve.GetEndPoint(0);
//Get ending point
XYZ myWallEndingPoint = myWallLocation.Curve.GetEndPoint(1);
//Create the middle point
XYZ myWallCenterPoint =(myWallStartingPoint + myWallEndingPoint)/2;

Know, we have everything we need to create our tag:

  IndependentTag myTag = myDocument.Create.NewTag(
                myActiveView,
                myElement,
                false,
                TagMode.TM_ADDBY_CATEGORY,
                TagOrientation.Horizontal,
                myWallCenterPoint);

To try this, we need to draw some walls, and load in our model a Wall. We hit F8 to build the macro before running it.

But if we run it, we get the following error:

Error

Its means that we are trying to modifying something inside our model without starting what is called a transaction.

Every modification of our model has to be done within a transaction, a group of modifications that can be discarded. If you remember the list of actions we can cancel in the Revit user interface, each one of them is a transaction that had to be started be before modifying anything in our model.

Transactions

So let create a transaction:

We start by defining a scope of our transaction with the keyword using. Every piece of code between the following brackets will use the transaction named tx.

using (Transaction tx = new Transaction(myDocument))
{

}

Now our transaction is created, we can start it, execute our code, and commit these modifications in our transaction:

using (Transaction tx = new Transaction(myDocument))
{
                tx.Start("Add Tags on walls");

                foreach (Element myElement in myWalls) {
                    //Do something with myElement

                    //Get our wall
                    Wall myWall = myElement as Wall;
                    //Get its location
                    LocationCurve myWallLocation =
                             myWall.Location as LocationCurve;
                    //Get starting point
                    XYZ myWallStartingPoint =
                             myWallLocation.Curve.GetEndPoint(0);
                    //Get ending point
                    XYZ myWallEndingPoint =
                             myWallLocation.Curve.GetEndPoint(1);
                    //Create the middle point
                    XYZ myWallCenterPoint =
                        (myWallStartingPoint + myWallEndingPoint)/2;

                    IndependentTag myTag = myDocument.Create.NewTag(
                             myActiveView,
                             myElement,
                             false,
                             TagMode.TM_ADDBY_CATEGORY,
                             TagOrientation.Horizontal,
                             myWallCenterPoint);
                }

                tx.Commit();
}

We run it and every walls are tagged.

Walls

Getting started programming Revit

I recently had some questions on how to start programing in Revit, so I will present here a simple macro created with the embedded macro editor, SharpDevelop.

As an example, I will create a macro for tagging all wall in a given view. Even if this function already exist through the Tag All command, you will see all the possibilities for creating it with a macro.

This week, we will see how to create a macro and retrieve elements draw in our model.

Let’s start it by clicking on the Macro Manager on the Manage tab:

Macro Manager

This is where you create new function in Revit, called “Macro”. These macro are lines of code, conveniently stored in a “Module”.

Macro Manager Interface

After creating a new module, and creating a new macro in this module, Revit starts its embedded code editor, called SharpDevelop. This is where we are going to spend most of our time developing Revit macro.

SharpDevelop

We can see the name of our macro just after “public void” and before a pair of brackets. We will write all our code between these brackets.

Every action done within Revit are made within a document, generally a .rvt or .rfa file. We have to explain this in our macro by retrieving the current document

Let’s write this:

Document myDocument;

With this line, I explain to Revit that something, a variable, called “myDocument” is a Revit Document.

Don’t forget the trailing “;”, it means the end of the line and has to be placed after every instruction line in a Revit macro.

Then, we write this:

myDocument = this.ActiveUIDocument.Document;

With this line, we explain than myDocument is actually the active document, the Revit document I am currently working with. “this” mean here “this Revit application”.

To be able to annotate every walls in a view, we have to select this view. Here, we call our view myActiveView and set it to the currently active view, the one you are looking at right now.

View myActiveView = myDocument.ActiveView;

Now than our Revit document and the view are selected, we have to retrieve walls to be able to annotate them. The Revit API provide us with a great function, the ability to filter element by category, type, class, … well, pretty much everything.

First, let’s create our filter, with the keyword “new”:

FilteredElementCollector filter 
= new FilteredElementCollector(myDocument,myActiveView.Id);

This “filter” will search for every element contained in “myDocument” and visible in the view “myActiveView”. The “.Id” after “myActiveView” mean that we use the unique identifier of the view instead of the view itself to create our filter.

We can now use this filter to actually catch some walls. Let’s write that:

List<Element>myWalls 
= filter.OfCategory(BuiltInCategory.OST_Walls).ToList();

We create a list of Revit element named myWalls and retrieve every element of the category Wall (“BuiltInCategory.OST_Walls”). The trailing “.ToList()” convert our filter into an actual list of elements.

Before going any further, we try this. Back in Revit, we draw four walls and run our macro by selecting it in the Macro Manager and hitting “Step Into”. This sends us back to SharpDevelop, with slight changes in the interface, and a yellow highlight on the first line of our macro. This highlight show us which line of our macro is currently executed. Hit “F11” two times to pass the first line.

If we pass our cursor on “myDocument”, a hint appear, showing us than “myDocument” is actually a document.

Document Hint

Let’s hit “F11” a few time to pass the last line. Stop right after it. If we pass our cursor on “myWalls” and click on the small “+” in the highlight, we see the list of walls retrieved by our filter. Everything works as expected, so far.

Walls Hint

We hit “F5” to run in a single stroke the remaining line of code and go back into SharpDevelop.

Next week, we will see how to use this list of walls to create a tag for every one of them.

AutoCAD Civil 3D to Revit

I recently worked with AutoCAD Civil 3D and explored the various possibilities for creating toposurfaces in Revit from Civil 3D objects.

My first impulse was to import the surface as a DWG, and use it to create my toposurface. But a Civil 3D surface object is not identified when imported in Revit.

I use the Extract Object surface function in AutoCAD Civil 3D to transform every surface contour in a 3D polyline.

Extract Contour

Back in Revit, I import my surface as a set of 3D polylines following contours in my AutoCAD Civil Surface.

In the Toposurface tools, I select the imported DWG, and check the layers containing these polylines.

ImportFromDWG

Revit creates a surface point along every surface contour, and rebuilts our surface.

If you are a Subscription customer, you have access to the LandXML import from Site Designer, recently added to Revit. Start by exporting your AutoCAD Civil 3D surface in LandXML.

ScreenClip [2]

Then use the Site Designer to import it back in Revit.

ImportLandXML

The resulting Revit toposurface contains ten times less points than the version created from contour lines, which can be game-changing, especially if your are dealing with large or complex surfaces.

I didn’t found any free plug-in to import directly LandXML in your Revit model, but if you are of the DIY type, you can use the example of code provided by Jeremy Tammik on his blog.

You can also import AutoCAD Civil 3D points directly in Revit. To do so, you first have to change the style of your surface to display all its points.

ScreenClip [4]

Then, extract these points as simple AutoCAD points and convert them to COGO points. Here, make sure to set the Prompt for Description to Automatic, or you will have to type a description for every one of these point, which can be somehow tedious for thousands of points.

Edit Point Creation oprions

Now, you can export the coordinates of these COGO point as a Comma Separated text file, and use this file to create your toposurface in Revit.

ImportPoints

This option is a nice workaround if you don’t have the possibility to import directly LandXML in your Revit model.