Purge and Detecting an Empty View

I am behind schedule blogging, working too much on answering cases and participating in the Revit API discussion forum thread while my colleagues are busy at DevCon and AU in Las Vegas.

In spite of that, this is blog number 1600, a nice round number to celebrate.

One topic that keeps cropping up is how to purge different kinds of Revit database elements:

Purge unused

Purge and PostCommand

The topic of purging various elements came up repeatedly in the past:

Two recent Revit API discussion threads re-raise the topic of programmatic access to the purge functionality:

In the latter, Thomas the Coder asks:

Question: So I've read The Building Coder article on determining purgeable elements and the discussion forum thread on writing a purge utility.

They both say that triggering the 'Purge Unused' button under the 'Manage' tab via code isn't possible and that you have to write your own code to handle the not so small task of doing it manually.

Answer by Ali @imaliasad Asad: I've come up with the solution, using PostCommand to launch the built-in Revit command:

  UIApplication uiapp = commandData.Application;

  // Store the ID of desired plugin button,
  // in this case its 'purge unused'

  String s_commandToDisable = "ID_PURGE_UNUSED";
  RevitCommandId s_commandId = RevitCommandId
    .LookupCommandId( s_commandToDisable );

  // This revit button will run at the 
  // end of your application. 

  uiapp.PostCommand( s_commandId );

The limitation I'm facing: I can't run the Revit command button instantly; it runs after the add-in external command terminates.

Question: How do I run the Revit command instantly within my add-in external command, before it terminates?

Answer: PostCommand launches a Revit command. The command cannot run in parallel with your add-in, because there is no multithreading support in the Revit API and the Revit API is never ever thread safe.

Therefore, your add-in must terminate before the next command can run.

You can add another PostCommand to call a second add-in command to be executed afterwards to continue the process, or use other means, such as Idling and external events for modeless access and driving Revit from outside.

Also note Ali's list of PostCommand limitations on StackOverflow.

Detecting Empty Views

On another related topic, my colleague Philipp Kast, Principal Engineer at Autodesk, shared an approach to detect empty views, i.e., views which do not display any visible object, and his research steps leading up to his current approach:

I am working on the Revit Extractor. We are creating so-called master views, which are views for each phase in the Revit model.

Recently we fixed an issue concerning empty views for phases that have no content.

So, we added the following code to detect whether a given view is empty:

  private bool IsEmptyMasterView( View view )
  {
    usingFilteredElementCollector collector 
      = new FilteredElementCollector( doc, view.Id ) )
    {
      return !collector.Any();
    }
  }

That worked well. But then a model came along that had empty views again, because it contained division and curtain elements that are not visible.

So, we adapted this code, basically skipping those categories:

  usingFilteredElementCollector collector 
    = new FilteredElementCollector( doc, view.Id ) )
  {
    var invisibleCategories = new HashSet<ElementId>
    {
       new ElementId(BuiltInCategory.OST_Divisions),
       new ElementId(BuiltInCategory.OST_CurtaSystemFaceManager)
    };
    return collector.All( 
      element => element.Category != null 
      && invisibleCategories.Contains( 
        element.Category.Id ) );
  }

Now again, yet another model includes other invisible elements.

So, I came up with the following check, by experimenting around:

  usingFilteredElementCollector collector 
    = new FilteredElementCollector( doc, view.Id ) )
  {
    return collector.All( 
      element => element.Category != null 
      && !element.Category.get_AllowsVisibilityControl( 
        view ) );
  }

This seems to work, but I’m not sure if it makes sense.

Any comment or input would be appreciated.

Thank you!

And thanks to Philipp for sharing this!

JavaScript Debugging Tips

Philippe @F3lipek Leefsma just pointed out the 14 JavaScript debugging tips you probably didn't know.

They are really helpful, so I'll make a note of them for myself here.

Thanks, Philippe!

Collection from the Past

My son Chris released a music album, collection from the past, by Chris Tammik, saying:

This collection spans my composition catalogue from around 2011 to 2015. This time was mainly centred around me learning to handle digital audio editing and composition tools.

After some months playing around with the Traktor DJ software I started exploring electronic music production with Ableton Live. I started working with sound professionally and made my passion to a job. In between I discovered REAPER as my ideal sound design environment.

Since then I have focused more on the programing side of things and am now creating audio tools for video games. The release of this collection shall serve as a reminder for the stems of my passion for sound and the incredible journey I still find myself on. Hopefully you find something enjoyable here. There are songs in various genres, sound design exercises, and pretty much each track has its own story – :)

Chris Tammik