CouchDB Implementation and GitHub Repository

I more or less completed the research for my cloud-based round-trip 2D Revit model editing project.

I'll describe some parts of that, and also address

Lazy, Simple and Perfect

You will like the first slide of my upcoming tech summit presentation.

I start off with a couple of quotes on three fundamental aspects of software engineering and life in general:

Quotes on three fundamental aspects of software engineering and life

Basically, I demonstrate how easy it is to implement simple model navigation and 2D graphical editing using server-side scripting so that it works on all mobile devices.

So it is all about keeping it simple and easy.

Room Editor Navigation

The last instalment on this topic included a two-minute minimal demo recording illustrating its use and started describing the simplest aspect of the implementation, the server-side generated index.html home page that lists all models and prompts to select one of them.

From there, one navigates through the hierarchy of model > level > room > furniture and equipment. The latter finally reference the symbol objects that determine their geometry.

Now lets move on to the more interesting parts where the inter-related objects need to execute more complex queries to establish their relationships. I still have not covered the juicy part of rendering the SVG model, and the even juicier part of interacting with it, editing it, and updating the database with the changes made, either.

As said, the navigation logic is pretty trivial:

Basically, the entire implementation is all squeezed into one single overgrown index.html file.

Moving on from the home page to the second simplest part of it, we have selected a specific model and list all the levels it contains.

This navigation takes place by invoking the same index.html URL and adding a modelId parameter to it.

This parameter is picked up and used to query the database for all levels in the specified model.

To retrieve only the required ones, I use a CouchDB view mapping model id keys to level documents like this:

  map_model_to_level = {
    map: function (doc) {
      if( 'level' == doc.type ) {
        emit(doc.modelId, doc);
      }
    }
  };

I can specify a key to CouchDB when querying this view, i.e. make a REST API call with a parameter like this:

  .../roomedit/_design/roomedit/_views?key=12345

This will retrieve only those level documents from the database whose modelId value matches the given key.

Here is the part of index.html handling that interaction:

. . .

else if ( paramdict.hasOwnProperty( 'modelid' ) ) {

  //======================================================
  // display a menu of all levels in selected model
  //======================================================

  var mid = paramdict['modelid'];
  db.getDoc( mid,
    function(err,resp) {
      if (err) {
        return alert(JSON.stringify(err));
      }
      var modeldoc = resp;
      db.getView('roomedit',
        'map_model_to_level',
        { key: JSON.stringify(mid) },

        function (err, data) {
          if (err) {
            return alert(err);
          }
          var n = data.rows.length;
          for (var i = 0; i < n; ++i) {
            var doc = data.rows[i].value;
            if( doc.modelId != mid ) {
              alert( 'model ids differ: doc '
                + doc.modelId + ", url " + mid );
            }
            var s = url + '?levelid=' + doc._id;
            $('<li/>')
              .append($('<a>').attr('href',s).text(doc.name))
              .appendTo('#navigatorlist');
          }
          var p = $('<p/>').appendTo('#content');
          p.append( $('<a/>').text('Home').attr('href',url) );
          p.append( document.createTextNode( three_spaces ) );
          p.append( $('<a/>').text('Back').attr('href',url) );

          $('<p/>')
            .text( 'Please select a level in the list below.' )
            .appendTo('#content');

          var table = $('<table/>').appendTo('#content');
          table.append( '<tr><td>' + 'Model:'
            + '</td><td>' + modeldoc.name + '</td></tr>' );

          var prompt = n.toString() + ' level'
            + pluralSuffix( n ) + ' in model ';

          var p = $('<p/>').text( prompt ).appendTo('#content');
          p.append( $('<i/>').text( modeldoc.name ) );
          p.append( document.createTextNode( dotOrColon( n ) ) );
        }
      );
    }
  );
}

As I already mentioned, this is populating an super simple HTML skeleton containing the following nodes:

  <h1>Room Editor</h1>

  <div id="content"></div>

  <ul id="navigatorlist"></ul>

Here is the result in a model named 'Roombook' containing a single level 'Fondations':

Room editor list of levels

Nested Asynchronous Database Call-back Functions

One challenge for me in the room editor CouchDB implementation was understanding how the asynchronous database call-back functions work, and how I can nest them to retrieve all the results I need.

In the case above, the situation is still very simple: I need to perform two database queries:

Both the getDoc and getView functions take an asynchronous call-back function as an argument.

I found out the hard way that I can nest these within each other to ensure that I have all up-to-date results before I display my page.

This gets a bit more hairy as the number of queries and thus the number of nested functions grows...

Roomedit – My First GitHub Project

Anyway, I have it all happily running now, and published the roomedit CouchDB application implementing this as my first ever GitHub project.

Debugging JavaScript with FireFox FireBug

Everybody makes errors. In my HTML and JavaScript code, these sometimes caused my index.html not to display anything at all.

Often this was due to some trivial JavaScript typo that would have been really hard to chase down.

Enter Firebug, thank God.

This is a great tool that I have started to rely on greatly to help me out of tight corners.

The Firebug debugging console is integrated in FireFox and includes support for examining and debugging all kinds of aspects of a web page.

You can open the Firebug console on any web page through Tools > Web Developer > Firebug > Open Firebug. That displays a new panel at the bottom of the browser with tabs for

I use Console and Script, mostly.

The former displays the location of a JavaScript error and jumps to it when loading the file. It also lists the URLs visited and stuff like that, which is very useful for analysing the REST API calls being made.

The script tab provides a JavaScript debugger allowing you to set breakpoints and analyse variable values etc.

There are lots of tutorials and documentation available on this feature, such as these ones on Firebug and JavaScript debugging, so I will not trouble you any further with my description.

To tell the truth, though, I never looked at any of them.

The thing just worked for me, is incredibly valuable, and I am grateful.

Screen Snapshots on Mobile Devices

Here is a quick guide how to create a screen snapshot on various types of mobile devices:

Open Source Components used by Autodesk

A colleague pointed out this open source repository containing all open source components used in AutoCAD, Map 3D and other Autodesk products.

I was actually surprised how short the list is. Anyway, it might be useful to know about.

Retrieve Slabs Above Certain Walls

Let's wrap this up with a standard Revit API question:

Question: I want to determine the slab above the walls of a particular room.

How can retrieve those using the Revit API, please?

Answer: As so often in Revit, there are a number of different possibilities, and it depends in part upon how the building has been modelled.

In a structural model, you may be able to query the analytical support data. I have no idea whether this information is included there, but my naive assumption would be that this should be possible.

Much more generally, you can analyse and query the geometry in a number of different ways.

The two possibilities that immediately spring to mind are:

The discussion on determining the columns supporting a beam demonstrates several different variations of the latter. Earlier blog posts include examples of the former as well.

Response: I was able to use the functionality for finding the supporting columns for beams from your link to solve my issue as well.

In my case, beam.GetGeneratingElementIds returns the desired supported floors.

I also tested using an ElementIntersectsSolidFilter to retrieve all walls that intersect the floor using the floor solid geometry object:

  Solid solid = null;
  ElementFilter slabIntersectFilter
    = new ElementIntersectsSolidFilter( solid );
 
  FilteredElementCollector walls
    = new FilteredElementCollector( doc )
      .WhereElementIsNotElementType()
      .OfClass( typeof( Wall ) )
      .WherePasses( slabIntersectFilter );

This also solved my issue. It can be the alternative when beams are not there.


Cloud and Mobile

Debugging Asynchronous CouchDB Callbacks & Snapshots

By Jeremy Tammik.

I more or less completed the research for my cloud-based round-trip 2D Revit model editing project.

Here are the main items in my discussion of that and one or two other cloud and mobile related topics: