Free “View Parameter for Detail Items” app now available

A few months ago I posted the source code showing how a “View” field could be added to a Detail Item schedule, even though out-of-the-box Revit does not offer View as a schedule-able field. The compiled application can now be downloaded for free at the Autodesk App Store.

Select Intersecting Elements – new free app available for download

In a complicated and crowded model, it can be hard to select the elements you want. This tool helps you select all elements that physically intersect with a specified element.

Select an element and use this tool to select all other elements that intersect with it.

Download it at http://apps.exchange.autodesk.com/RVT/en/Detail/Index?id=appstore.exchange.autodesk.com%3aselectintersectingelements_windows32and64%3aen

SelectIntersectingScreenShot

Free Keynote Reporter now available on Revit App Store

When I asked readers to suggest some small Revit API apps, Nathan suggested:

Something that will highlight any keynotes that have lost their host and show up as blank. Actually a tool that highlights User Keynotes versus the other types would be cool, too. We don’t like User Keynotes in my office, but many people still insist on using them for some reason. Being able to pick out how many there are in a given view would be useful.

Here is the free installer of the Boost Your BIM Keynote Reporter.

You can use the semicolon-delimited list of element IDs along with Revit’s “Select By ID” tool to select groups of tags based on their type or orphan-status.

Sample Output:

KeynoteReportScreenShot

In-N-Out Parameters for Revit 2014 with enhanced unit support

Looking for a quick, easy, and inexpensive way to update family parameters?

I’ve created a 2014 install for In-N-Out Parameters. It is also enhanced so that it works with Length parameters of cm, mm, and other non-foot units. Get it at https://boostyourbim.wordpress.com/products/#InNOutParameters

Topo From Lines now available on the Autodesk App Store

With this new (and free) app you can create Revit toposurfaces by selecting lines that define the contours of the surface.

http://apps.exchange.autodesk.com/RVT/en/Detail/Index?id=appstore.exchange.autodesk.com%3atopofromlines_windows32and64%3aen

TopoFromLinesScreenShot

Record view creation date in a shared parameter

Luke asked if it was possible to use the API to track the history of Revit view creation to a shared parameter. This allows a View List to be sorted by creation date.

Source code available at https://www.udemy.com/revitapi/?couponCode=%2425off-4158ef98

A public Git repository for sharing Revit Macros at BitBucket

With encouragement from Luke that we get together to create “an unlimited store of easily accessible plugins in an open source repository”, I’ve created a public Git repository at https://bitbucket.org/BoostYourBIM/revit_api_public/ that will be open to anyone who wants to contribute code. (BitBucket requires each user to be explicitly given write access, so let me know if you’d like that and I will send you an invite)

In my post at https://boostyourbim.wordpress.com/2013/07/31/what-is-version-control-and-why-should-you-care/ I explained why the products BitBucket and SourceTree from the folks at https://www.atlassian.com/ seem like a good combination. These tools let us back up, track revisions, and share code without having to do the crazy command-line stuff that is sometimes associated with technologies like Git. I hope the video below sheds at least a bit of light on how the pieces fit together.

The idea is that you should be able to install SourceTree, go to this BitBucket repository, click “Check out in Source Tree”

Untitled

Get a repository in SourceTree that looks like this:

Capture

And end up with the code on your computer like this

Untitled2
That creates working macros as shown here
macro manager

If this makes no sense or doesn’t work at all, let me know and we will try to straighten it out.

Extract Subcategory and Material Names from Multiple Families

From a discussion on Twitter last night, I put together an API solution to export the name of every subcategory and material in a group of RFAs.

In this sample it is hard-coded to check every RFA in the C:\ProgramData\Autodesk\RAC 2013\Libraries\US Imperial\Doors folder. The output is written to individual files in the TEMP folder (one file for material info & one file for category info).

The source code is available in my Udemy course on the Revit API

#RTCEUR Wish 5 – Who Created Those Warnings?

To help BIM Managers train or punish their Revit users, I was asked at RTC in Delft if we can use the API to figure out which users are responsible for each warning in your Revit file.

Here’s how that can be done by writing all warnings to a log file and then comparing warnings in the current file with those in the log.

public void RegisterFailureReporter()
{
    Application app = this.Application;
    Document doc = this.ActiveUIDocument.Document;
    if (doc.PathName == "")
    {
        TaskDialog.Show("Error","Please save the file and then repeat this command.");
        return;
    }
    app.FailuresProcessing += FailureReporter;
}

private void FailureReporter(object sender, Autodesk.Revit.DB.Events.FailuresProcessingEventArgs args)
{
    FailuresAccessor fa = args.GetFailuresAccessor();
    Document doc = fa.GetDocument();

    using (StreamWriter sw = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Warning Creation Log.csv"), true))
    {
        foreach (FailureMessageAccessor fma in fa.GetFailureMessages(FailureSeverity.Warning))
        {
            sw.Write(DateTime.Now + "," + fa.GetDocument().Application.Username + ",");
            sw.Write(fma.GetDescriptionText().Replace(Environment.NewLine,"") + "," );
            foreach (ElementId id in fma.GetFailingElementIds())
            {
                // use UniqueId instead of ElementId because the UniqueId is stable across Save To Central while the ElementId property may change.  
                sw.Write(doc.GetElement(id).UniqueId + ",");
            }
            sw.Write(Environment.NewLine);
        }
    }
}

public void CheckCurrentWarningsInLog()
{
    Document doc = this.ActiveUIDocument.Document;
    if (doc.PathName == "")
    {
        TaskDialog.Show("Error","Please save the file and then repeat this command.");
        return;
    }    
    using (StreamReader warningsHTMLReader = new StreamReader(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileNameWithoutExtension(doc.PathName) + "_Error Report.html")))
    {
        string line = "";
        while ((line = warningsHTMLReader.ReadLine()) != null)
        {
            if (!line.Contains(": id "))
                continue;

            string[] row = System.Text.RegularExpressions.Regex.Split(line, "id ");

            string id1 = row[1].Split(' ')[0];
            string uniqueId1 = doc.GetElement(new ElementId(int.Parse(id1))).UniqueId;
            string uniqueId2 = null;
            if (row.Count() == 3) // there are two element ids in this row
            {
                string id2 = row[2].Split(' ')[0];
                uniqueId2 = doc.GetElement(new ElementId(int.Parse(id2))).UniqueId;
            }

            using (StreamReader warningLogReader = new StreamReader(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Warning Creation Log.csv")))
            {
                string lineLog = "";
                while ((lineLog = warningLogReader.ReadLine()) != null)
                {
                    if (lineLog.Contains(uniqueId1) || (uniqueId2 != null && lineLog.Contains(uniqueId1) && lineLog.Contains(uniqueId2)))
                    {
                        using (StreamWriter sw = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Current Warnings With User Info.csv"), true))
                        {
                                   sw.WriteLine(lineLog);
                        }
                        break;
                    }
                }
            }
        }
    }
}

#RTCEUR Wish 4 – Find Native and RVT Link Penetrating Elements

This sample shows how the BoundingBoxIntersectsFilter can be used to find elements that penetrate ceilings in the model.

The host file contains 2 ceilings, 2 columns, and a RVT link that contains 3 Generic Model elements. There are also 3 shaft openings in the ceiling so that there is no interference between the ceilings and the elements going through them.

This API code analyzes the bounding box of each ceiling and finds all elements in all files (including the current RVT and links) whose bounding box intersects the ceiling’s bounding box. The results are shown in a dialog and written to a parameter of the ceiling category.

public void FindPenetrations()
{
    Document hostDoc = this.ActiveUIDocument.Document;
    string data = "";

    LogicalOrFilter columnGenericModelfilter = new LogicalOrFilter(new ElementCategoryFilter(BuiltInCategory.OST_Columns), new ElementCategoryFilter(BuiltInCategory.OST_GenericModel));

    using (Transaction t = new Transaction(hostDoc, "Find Penetrations"))
    {
        t.Start();

        foreach (Ceiling ceiling in new FilteredElementCollector(hostDoc).OfClass(typeof(Ceiling)))
        {
            data += "--- Ceiling - " + ceiling.Name + " (id = " + ceiling.Id + ") ---\n";

            // define an Outline based on the Bounding Box of this ceiling
            Outline outline = new Outline(ceiling.get_BoundingBox(null).Min, ceiling.get_BoundingBox(null).Max);

            string paramData = "";

            // search for penetrations in all open documents which will include RVT Links and native geoemtry in this RVT
            foreach (Document doc in this.Application.Documents)
            {
                // find elements that pass the Column/Generic Model filter and whose Bounding Box intersects the outline of this Ceiling
                foreach (Element e in new FilteredElementCollector(doc).WherePasses(columnGenericModelfilter).WherePasses(new BoundingBoxIntersectsFilter(outline)))
                 {
                    data += e.Category.Name + " - " + e.Name + " - " + Path.GetFileName(e.Document.PathName) + " - " + e.Id.IntegerValue + "\n";
                    paramData += e.Name + " - " + Path.GetFileName(e.Document.PathName) + " - " + e.Id.IntegerValue + "\n";
                 }
            }

            ceiling.get_Parameter("Penetrating Elements").Set(paramData);
            data += "\n";
        }
        t.Commit();    
    }
    TaskDialog.Show("Intersections",data);
}

How do you want to see Revit connected to the cloud?

Autodesk is offering some great prizes to the developers who create the best “cloud” apps for AutoCAD, Revit, and Inventor.

The theme of the event is “Connecting Autodesk to the Cloud” – and this is open to creative interpretation. Perhaps you can think of a way to wire our software into your favorite social media network or make use of infinite cloud computing to carry out CPU-intensive tasks. Or maybe you have a way to help users better visualize and share their ideas using a web browser.

Build a standalone app for an AutoCAD, Revit, Inventor or BIM 360 Glue product. Or build an app that takes advantage of the integration capabilities of BIM 360 Glue with either of the 3 other products families: AutoCAD, Revit and Inventor!

How would you like to see Revit connected to the cloud?

The deadline for me to submit a description of the app is October 11.