Small subset of family-instance subcomponents out of place with custom exporter

Small subset of family-instance subcomponents out of place with custom exporter

corybarrJCA7L
Participant Participant
309 Views
3 Replies
Message 1 of 4

Small subset of family-instance subcomponents out of place with custom exporter

corybarrJCA7L
Participant
Participant

Hello,

 

I'm wrapping up a custom exporter. It's my first deep dive into using the API. Overall, it was very nice. Now I'm working through a few, final loose ends.

 

It was all working great, but an issue popped up when I added instancing to the exporter. Specifically, I did away with this line in OnPolymesh:

 

pts = pts.Select( p => t.OfPoint( p ) ).ToList();

 

Instead I kept the raw pts vector and add the transform to the export in OnInstanceEnd. This works in almost all cases. For example, it seems all but the canopy ribs in the Snowden example work. I'm trying to fix the exceptions but am getting stumped.

 

I reduced the issue down to a basic case: a default wall and a default window. Here's the export in Blender:

corybarrJCA7L_0-1719858234785.png

 

As you can see, the "with Sill" type is transformed incorrectly. I examined various FamilyInstance properties such as HandFlipped, HandOrientation, FacingFlipped,and FacingOrientation. I don't see anything special about "with Sill." This is the code I currently have:

 

 

Autodesk.Revit.DB.Transform transform = transformStack.Pop();

double rx = transform.BasisX.X;
double ry = transform.BasisY.X;
double rz = transform.BasisZ.X;
double ux = transform.BasisX.Y;
double uy = transform.BasisY.Y;
double uz = transform.BasisZ.Y;
double lx = transform.BasisX.Z;
double ly = transform.BasisY.Z;
double lz = transform.BasisZ.Z;
double px = transform.Origin.X;
double py = transform.Origin.Y;
double pz = transform.Origin.Z;

currentNode.Matrix = new List<double>
{
rx, ry, rz, 0,
ux, uy, uz, 0,
lx, ly, lz, 0,
px, py, pz, 1.0
};

 

 

Thinking that I needed to account for FacingFlipped and HandFlipped, I tried the solution from here: https://thebuildingcoder.typepad.com/blog/2012/05/family-instance-element-coordinate-system.html However, the results are the same.

 

To simplify things, no elements were parented to any other element except for the root node (with no transformation). There shouldn't be any issues of nested transformations.

 

Does anyone have insights into what transformation "with Sill" is using?

 

Asking the question "How exactly is Transform.OfPoint?" working might be an equivalent question. It doesn't seem to be straight matrix multiplication.

0 Likes
310 Views
3 Replies
Replies (3)
Message 2 of 4

jeremy_tammik
Alumni
Alumni

Glad to hear of your positive experiences. Sorry about the loose ends. Where exactly does that line 1 with t.OfPoint that you mention come from? Some Revit SDK sample, or what? Who or what defines OnPolymesh? Without that info, your question cannot be answered.

 

For the custom exporter, Arnost's sample seems most reliable and complete: 

  

  

In order to compare the custom exporter results with the results obtained from simply traversing all elements and their geometry, you can also take a look at the ElementViewer SDK sample:

  

  

Afaik, those two both handle all required transformations properly.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 4

corybarrJCA7L
Participant
Participant

 

 

Thanks for the quick response, Jeremy.

 

Arnost's sample is a model for my exporter. The structure is essentially identical. Arnost's code is fundamentally this:

    public void OnPolymesh( PolymeshTopology polymesh )
    {
...
      Transform currentTransform = transformationStack.Peek();
      for( int iPoint = 0; iPoint < polymesh.NumberOfPoints; ++iPoint )
      {
        point = polymesh.GetPoint( iPoint );
        point = currentTransform.OfPoint( point );
        streamWriter.Write( "{0:0.0000} {1:0.0000} {2:0.0000}\n", point.X, point.Y, point.Z );
      }
...
    }

 

Mine's the same, but using Linq. I'll remove the t variable for clarity:

    public void OnPolymesh( PolymeshTopology polymesh )
    {
...
            var pts = polymeshTopology.GetPoints();
            pts = pts.Select(p => CurrentTransform.OfPoint(p)).ToList();
...
    }

 

To be clear, when I use the above code, everything works correctly. It's when I forgo calling CurrentTransform.OfPoint(p) that the small subset of elements end up out of place. Of course the points still need to be multiplied by the transform, but the transform is stored on the element's node in the output file:

 public void OnInstanceEnd(InstanceNode instanceNode) {
...
               topStackTransform = instanceNode.GetTransform();
                
               if (!topStackTransform.IsIdentity)
               {
                   currentNode.Matrix = new List<double>
                   {
                       topStackTransform.BasisX.X, topStackTransform.BasisY.X, topStackTransform.BasisZ.X, 0.0,
                       topStackTransform.BasisX.Y, topStackTransform.BasisY.Y, topStackTransform.BasisZ.Y, 0.0,
                       topStackTransform.BasisX.Z, topStackTransform.BasisY.Z, topStackTransform.BasisZ.Z, 0.0,
                       topStackTransform.Origin.X, topStackTransform.Origin.Y, topStackTransform.Origin.Z, 1.0
                   };
               }
...
}                

 

As an example of the output, here is where instanceNode.GetTransform() for the Window element ends up in the output file (which is glTF):

 

"name": "Windows: Window-Fixed: 36\" x 48\"",
"mesh": 1,
"matrix": [
-1.0,
2.4682178902866922E-18,
0.0,
0.0,
-2.4682178902866922E-18,
-1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
-6.0000000000000107,
2.0433040615609088E-15,
0.0,
1.0
],

 

 

"with Sill" also exports with the same matrix that leads to correct results when doing CurrentTransform.ofPoint(p). I verified in a log file and also the glTF:

            "name": "Generic Models: Trim-Window-Exterior-Flat: with Sill",
            "mesh": 2,
            "matrix": [
                1.0,
                0.0,
                2.4682178902866922E-18,
                0.0,
                2.4682178902866922E-18,
                0.0,
                -1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                -0.33333333333333126,
                7.0000000000000346,
                1.0
            ],

However, the above matrix multiplied by the raw PolymeshTopology points don't equal the points obtained when using CurrentTransform.OfPoint(p).

 

I'm bypass storing the transformed points of the PolymeshTopology because then everything exported has the identity matrix. This means I can't detect duplicate meshes and enable GPU instancing.

 

I thought that CurrentTransform.OfPoint(p) would be equivalent to CurrentTransform * p (as in a straight multiplication of the transformation matrix), but it looks like OfPoint is doing something else in some cases--in particular the case of "with Sill". Any ideas why CurrentTransform.OfPoint(p) would be not equivalent to CurrentTransform * p in some situations?

0 Likes
Message 4 of 4

corybarrJCA7L
Participant
Participant

Could it be that up-axis and/or handedness isn't being handled correctly? I don't see how that could be the case, but at least in the case of the filled "with Sill" type, a 180-degree rotation (about two potential axes) fixes the issue. When exporting geometry, are the coordinates left-handed z-up? It states here that

 

Revit uses two coordinate systems:

  • The global or model space coordinates where the building exists
  • The viewing coordinate system.

but it's unclear to me if that means what type of coordinate system the exporter operates in.

0 Likes