The Building Coder

Warning Swallower and Roomedit3d Viewer Extension

I continue my work on the roomedit3dv3 sample connecting the desktop with the cloud by enabling a real-time round-trip modification of the BIM via the Forge viewer, mention a neat solution enabling a Revit add-in to swallowing warning messages, and point out the Forge webinar session on the Forge Viewer later today:

Warning Swallower

Adam Krug and Wolfgang Weh provide a neat warning swallower solution in the Revit API discussion forum thread on a general warning swallower:

Question: In my solution I'm opening a lot of families from within a project. Sometimes some popups appear during opening a family. I enclosed the opening process inside a transaction in which I handle warnings via IFailuresPreprocessor. I noticed that:

About 90% warnings can be suppressed with the following:

  FailuresAccessor a;
  a.DeleteAllWarnings();
  return FailureProcessingResult.Continue;

But the remaining 10% won't get suppressed with such treatment, whereas they do get suppressed with:

  FailuresAccessor a;
  IList<FailureMessageAccessor> failures = a.GetFailureMessages();
  a.ResolveFailures( failures );
  return FailureProcessingResult.ProceedWithCommit;

Is there a general way to check with what kind of treatment current warning can get suppressed? I don't want to go into a switch case block because the warnings are really various and it'd take ages before I covered them all. Another issue is that it doesn't matter so much how I treat the warnings because I don't resave the families in my solution - I just close them without saving.

Answer: I am not aware of any generic warning swallower within the Revit API.

The solution you have already seems pretty good to me.

For something yet more generic, all I can suggest is a Windows dialogue handler, e.g., JtClicker.

The Building Coder provides an entire topic group on the subject of Detecting and Handling Dialogues and Failures.

Answer 2: The solution suggested in the thread on suppressing warning pop-ups works fine for me.

Response: Indeed, the Severity is what I was looking for. My solution seems to be working fine now. Here is the code:

FailureProcessingResult PreprocessFailures( 
  FailuresAccessor a )
{
  IList<FailureMessageAccessor> failures 
    = a.GetFailureMessages();

  foreachFailureMessageAccessor f in failures )
  {
    FailureSeverity fseverity = a.GetSeverity();

    if( fseverity == FailureSeverity.Warning )
    {
      a.DeleteWarning( f );
    }
    else
    {
      a.ResolveFailure( f );
      return FailureProcessingResult.ProceedWithCommit;
    }
  }
  return FailureProcessingResult.Continue;
}

Many thanks to Adam and Wolfgang for sharing this solution!

I added it to The Building Coder samples release 2017.0.130.1 in the module CmdPreprocessFailure.cs.

Roomedit3dv3 Transform Viewer Extension

I am implementing the roomedit3dv3 sample connecting the desktop with the cloud based on Philippe Leefsma's Forge node.js boilerplate samples.

I now added a viewer extension enabling the user to select and translate a BIM element in the Forge viewer.

Roomedit3dv3 transform extension

With that up and running, the next step will be to communicate back that modification to update the source Revit BIM.

I am basing the roomedit viewer transform tool on Philippe's Viewing.Extension.Transform viewer extension, from his huge library of JavaScript viewer extensions.

You can see it in action in the Forge React gallery.

It took me several steps, lots of advice from Philippe, and some small enhancements to his underlying base boilerplate code to actually get it up and running:

To add the transform extension to the viewer client, first load the three.js script before loading the viewer.

This is implemented in the layout.

Copy the four files viewing extension into your app.

I placed them in the src/client/Components/Viewer/extensions subfolder.

Load the transform extension by importing the main extension file.

Done in ViewerPanel.js.

The extension will register itself, and activateTool activates either the translate or rotate tool.

The translate tool is derived from event emitter.

It can therefore notify clients about its work by emitting events using this.emit.

At this point, you can add the dbid of the selected element to the transmitted data package. From dbid you can get the external id, which corresponds to the Revit UniqueId.

In the extension constructor, you can subscribe to the events fired by the tool:

  import ServiceManager // cf. sample in App.js

  translateTool.on('transform.translate', (data) => {
    
    viewer.getProperties(data.dbId, callback...)
      
    var socketSvc = ServiceManager.getService('SocketSvc')

    socketSvc.broadcast('your-msgid', {some data ...})
    
  })

Question: I loaded the extension as described, but the call to loadExtension call is not yet working.

Initially, I hooked it up to a load button and added this code:

  var loadBtn = document.getElementById('loadBtn');

  loadBtn.addEventListener("click", function(){
    this.viewer.loadExtension(
      'Viewing.Extension.Transform')
  });

But when I click the button, 'this.viewer' is no longer valid, because this refers to the ViewerPanel instance.

When I try to call

  this.viewer.loadExtension('Viewing.Extension.Transform')

directly without using a button click, nothing happens either.

Answer: This code is correct. However, as ALWAYS in JavaScript, you need to be careful to what this is pointing to. Inside an event handler, it will not be the same as in the calling context.

An easy way to fix your code is to use arrow function => instead, which has the characteristic of implicitly binding this to the calling context.

Response: Yes, the call works now, and loadExtension is called successfully, cf. the diff 0.0.8 to 0.0.9.

However, the extension is still not loaded successfully, neither with or without the button click.

In both cases, calling loadExtension triggers this error message in the js console:

Uncaught TypeError: Cannot read property 'parentControl' of undefined

What could be causing that?

Answer: Simply pass an empty options object to the extensions, e.g., a default argument:

  viewer.loadExtension('extid...', {})

Alternatively, you can pass a parentControl object, which is a viewer UI control to host the extension controls:

  viewer.loadExtension('extid...', {
    parentControl: yourCustomControl
})

Response: Thank you, yes, perfect, it works.

The result now looks like this:

Roomedit3dv3 extension lacks icons

Am I missing some icon resources?

Answer: You need font-awesome for the icons to show up. I just added it to package.json and in the code in my latest commit.

The Roomedit3dv3 transform extension is up and running right now in my local build, as shown above.

I have not tested deploying to Heroku yet, though, and, as said, I still need to add the code to communicate the modifications back to the desktop BIM.

Plus, today is the deadline to submit my material for the RTCEU Revit Technology Conference Europe in Porto next month.

Forge Webinar Series

Today, Jaime Rosales Duque presents the fourth session in the ongoing Forge webinar series, on the Viewer.

Here are the recordings, presentations and support material of the sessions held so far:

Upcoming sessions continue during the remainder of the Autodesk App Store Forge and Fusion 360 Hackathon until the end of October:

Quick access links:

Feel free to contact us at forgehackathon@autodesk.com at any time with any questions.

Forge – build the future of making things together