Simple DirectShape on Face, RestSharp, PUT and POST

Last Tuesday, I looked at creating a DirectShape from a face and sketch plane reuse.

I implemented a convoluted method using the picked face reference and its stable string representation returned by the ConvertToStableRepresentation method to navigate the element geometry and determine an appropriate transformation for it into the world coordinate system.

Today, let's take a look at a much simpler approach, and also point to my cloud related work including a significant enhancement to the FireRating sample in the cloud:

Civil – Made in France

Are you civil?

I sincerely hope so!

No, what I really meant, are you interested in civil engineering?

If so, and if you read French, or are happy to use a translator, you might also be interested in the newest addition to the Autodesk blogosphere:

Civil – Made in France

Restez au fait de l'actualité des solutions AEC d'Autodesk pour l'Aménagement du Territoire – Keep up with the news of Autodesk AEC solutions for regional development.

Back to the Revit API:

Simpler DirectShape on Picked Face Using Total Transform

That solution that Frode and I implemented to create a DirectShape on a picked face lives in the DirectShapeFromFace GitHub repository.

Alexander Ignatovich, Александр Игнатович, of Investicionnaya Venchurnaya Companiya took a critical look at that sample and implemented a significant simplification.

He also added a front-end command to enable you to choose which of the three implementations to execute:

Here is a summary of our discussion, which also briefly explains how to create a pull request for a GitHub project:

Alexander: You wrote a post about creating direct shape elements from face a few days ago.

The algorithm to find appropriate transformation is difficult. I was sure, that there is much more simple way to find it, and after several experiments I've found the right way ;-)

I took the initial code and made some slight changes.

First of all, I get total family instance transform:

  var familyInstance = el as FamilyInstance;
 
  var transform = familyInstance != null
    ? familyInstance.GetTotalTransform()
    : Transform.Identity;

I use that when getting the mesh triangle points:

  p1 = transform.OfPoint( p1 );
  p2 = transform.OfPoint( p2 );
  p3 = transform.OfPoint( p3 );

Jeremy: Does your method work correctly for a nested family instance?

I am not sure that mine will either, but at least it tries to!

Imagine the following nested family:

Now if you pick a face of the A instance in the projects, the total transform of the A instance will probably only take the translation from A into account, but not the additional preceding transformation of B within A.

In my algorithm, try to determine both of those transformations and multiply them with each other.

I have not tested it, and my multiplication may well be in the wrong order.

Would you like to try that out?

If you make any changes to the code, would you like to do one of the two following?

Both of these approaches will save me from having to compare the code and reintegrate the changes back manually.

Thank you!

Alexander: I tested nested families and submitted pull request #1 to your repository:

I also added a sample rvt with nested families, both when all are shared and not:

DirectShape test.rvt

Jeremy: I integrated your changes and created DirectShapeFromFace release 2016.0.0.13.

Alexander: Cool commit!

I only tested the idea; thank you for cleaning up the code.

I retested, and everything is still working.

Here is the current version of the working simplified algorithm:

  UIApplication uiapp = commandData.Application;
  UIDocument uidoc = uiapp.ActiveUIDocument;
  Document doc = uidoc.Document;
  Selection choices = uidoc.Selection;
 
  try
  {
    Reference reference = choices.PickObject(
      ObjectType.Face );
 
    Element el = doc.GetElement(
      reference.ElementId );
 
    Face face = el.GetGeometryObjectFromReference(
      reference ) as Face;
 
    Mesh mesh = face.Triangulate();
 
    var familyInstance = el as FamilyInstance;
 
    if( null != familyInstance )
    {
      var t = familyInstance
        .GetTotalTransform();
 
      mesh = mesh.get_Transformed( t );
    }
 
    using( Transaction trans = new Transaction( doc ) )
    {
      trans.Start( "Create DirectShape from Face" );
 
      TessellatedShapeBuilder builder
        = new TessellatedShapeBuilder();
 
      builder.OpenConnectedFaceSet( false );
 
      List<XYZ> args = new List<XYZ>( 3 );
 
      XYZ[] triangleCorners = new XYZ[3];
 
      for( int i = 0; i < mesh.NumTriangles; ++i )
      {
        MeshTriangle triangle = mesh.get_Triangle( i );
 
        triangleCorners[0] = triangle.get_Vertex( 0 );
        triangleCorners[1] = triangle.get_Vertex( 1 );
        triangleCorners[2] = triangle.get_Vertex( 2 );
 
        TessellatedFace tesseFace
          = new TessellatedFace( triangleCorners,
            ElementId.InvalidElementId );
 
        if( builder.DoesFaceHaveEnoughLoopsAndVertices(
          tesseFace ) )
        {
          builder.AddFace( tesseFace );
        }
      }
 
      builder.CloseConnectedFaceSet();
 
      TessellatedShapeBuilderResult result
        = builder.Build(
          TessellatedShapeBuilderTarget.AnyGeometry,
          TessellatedShapeBuilderFallback.Mesh,
          ElementId.InvalidElementId );
 
      ElementId categoryId = new ElementId(
        BuiltInCategory.OST_GenericModel );
 
      DirectShape ds = DirectShape.CreateElement(
        doc, categoryId,
        Assembly.GetExecutingAssembly().GetType()
          .GUID.ToString(), Guid.NewGuid().ToString() );
 
      ds.SetShape( result.GetGeometricalObjects() );
 
      ds.Name = "MyShape";
 
      trans.Commit();
    }
  }
  catch( Exception ex )
  {
    Debug.Print( ex.Message );
  }

The most up-to-date version, complete Visual Studio solution and add-in manifest is provided by the DirectShapeFromFace GitHub repository.

The version discussed here is release 2016.0.0.13.

Many thanks to Alexander for raising this issue, providing the important simplification and testing!

The CompHound component tracker

I am overdue to prepare for my upcoming conferences this autumn, RTC Europe in Budapest end of October and Autodesk University in Las Vegas in December.

For both of them, I committed to implementing and demonstrating a cloud-based universal component and asset usage analysis, visualisation and reporting:

We describe the nitty-gritty programming details to implement a cloud-based system to analyse, visualise and report on universal component and asset usage. The components could be Revit family instances used in BIM or any other kind of assets in any other kind of system. The focus is on the cloud-based database used to manage the component occurrences, either in global or project based coordinate systems. Searches can be made based on geographical location or keywords. Models are visualised using the Autodesk View and Data API, providing support for online viewing and model navigation.

Besides the web server and database aspects already explored for the FireRating in the cloud sample that I recently discussed here in depth, the new tool will also sport a user interface.

Therefore, I started looking at the React JavaScript library for building user interfaces, implemented and used by none other than Facebook.

I implemented my first JsFiddle, a minimal pre-test version of a FireRating Door List React Component:

I am also taking a new look at the Autodesk View and Data API side of things, and bringing it all together as quickly and painlessly as possible...

This will be a nice project to take with me to the upcoming cloud accelerator in Prague next week!

I christened this project CompHound, for hounding out and tracking down those pesky components   :-)

So far, it consists of two modules:

To keep these two projects nicely packaged together, I created the CompHound GitHub organisation and added them as subprojects to that:

I grabbed the code from the existing fireratingdb web server and FireRatingCloud Revit add-in to quickly achieve the following functionality for CompHound as well:

Note that stepping through all of these tasks for the new CompHound project only took an hour or so in all, from scratch.

It took me several weeks to discover how to achieve all this the first time around, for the FireRating project   :-)

I was once again irritated by the GET, PUT and POST issue I encountered: I have to use POST to create a new record versus PUT to update an existing one.

I finally fixed that problem in the two new projects and published CompHoundWeb 0.0.1 and CompHoundRvt 2016.0.0.0, respectively.

Then I returned to the original FireRating samples to fix it there as well:

FireRating in the Cloud Enhancement

I implemented a significant enhancement to the FireRatingCloud Revit add-in and its cloud-based database counterpart fireratingdb.

Together, they represent a multi-project replacement for the standard Revit SDK FireRating sample, which demonstrates three things:

Last time I looked at this project, there were still two issues left open:

I now resolved them, both for the initial CompHound implementation and for the original FireRating in the cloud project: