Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Get translation and rotation for a FamilyInstance (Export)

13 REPLIES 13
Reply
Message 1 of 14
Anonymous
2177 Views, 13 Replies

Get translation and rotation for a FamilyInstance (Export)

Hello, I'm currently doing some code to export a model from to glTF.
For performance reasons, I need to export each kind of geometry only one time, so my code does that, but something is wrong with it:

 

 

ElementType elementType = CurrentDocument.GetElement(CurrentElement.GetTypeId()) as ElementType;
string meshName = elementType.Name + "[" + elementType.Id + "]";
_mesh.Name = meshName;

//Check if we already have the geometry
Node node = _scene.FindNode(n => n.Mesh.Name == meshName);

//No, it's new, so save it inside a node
if (node == null)
    node = _scene.CreateNode(elementId.IntegerValue.ToString()).WithMesh(_model.CreateMeshes(_mesh)[0]);
	
//We already have a mesh/geometry
else
{
    Transform currentTransform = (CurrentElement as FamilyInstance).GetTransform();

    ElementId id = new ElementId(Convert.ToInt32(node.Name));
    Element firstElementOfType = CurrentDocument.GetElement(id);
    FamilyInstance firstElementOfTypeFamilyInstance = firstElementOfType as FamilyInstance;
    
    Transform firstElementOfTypeTransform = firstElementOfTypeFamilyInstance.GetTransform();

    var currentElementOriginPoint = new XYZ(currentTransform.Origin.Y, currentTransform.Origin.Z, currentTransform.Origin.X);

    var firstElementOfTypeOriginPoint = new XYZ(firstElementOfTypeTransform.Origin.Y, firstElementOfTypeTransform.Origin.Z, firstElementOfTypeTransform.Origin.X);
    var p = new XYZ(currentTransform.Origin.Y - firstElementOfTypeTransform.Origin.Y, currentTransform.Origin.Z - firstElementOfTypeTransform.Origin.Z, currentTransform.Origin.X - firstElementOfTypeTransform.Origin.X);
    
    _scene.CreateNode(elementId.IntegerValue.ToString()).WithMesh(node.Mesh).LocalTransform = new SharpGLTF.Transforms.AffineTransform()
     {
//TODO: Rotation //Rotation = new Vector3((float)(p.Y),(float)(p.X),(float)(p.Z)), Translation = new Vector3((float)(p.Z), (float)(p.X), (float)(p.Y)), Scale = new Vector3(1, 1, 1), }; }



I'm working on this very hard, It should be simple,  can someone provide some tips?
Why is my translation vector wrong?

How can I get the Rotation.

13 REPLIES 13
Message 2 of 14
jeremytammik
in reply to: Anonymous

If your goal is to export the entire model, or the contents of a specific view, the easiest way to go (and the officially recommended way) is to use a custom exporter:

 

https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.1

 

Arnošt Löbel's Custom Exporter to XML is the goto-reference sample for that functionality:

 

https://thebuildingcoder.typepad.com/blog/2013/07/graphics-pipeline-custom-exporter.html#4

 

If you wish to go down the other path of handling elements individually yourself, one reliable source of truth for the task is the Revit SDK sample ElementViewer.

 

You can also take a look at a current project of mine that does something similar:

 

https://github.com/jeremytammik/ExportSymbolInstanceGeo

 

A number of other samples on The Building Coder export geometry meshes to various targets and demonstrate various ways of handling family instances and their possibly nested transformations. Several of them are pointed out in the same article:

 

https://thebuildingcoder.typepad.com/blog/2013/07/graphics-pipeline-custom-exporter.html#3

 

Best regards,

 

Jeremy

 

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 14
Anonymous
in reply to: jeremytammik

Hello Jeremy!
I'm already using the custom exporter.

 

The code I've posted is inside
public void OnPolymesh(PolymeshTopology polymesh)

 

I can't understand why you use 3 vectors for the rotation, for example:

 

Like this: 

https://github.com/jeremytammik/ExportSymbolInstanceGeo 

{ "rotation_matrix": [1,0,0,0,1,0,0,0,1], "translation": [1,2,3], ... }

Look at the rotation matrix, here we have 3 vectors.

On glTF format I only need ONE vector for the rotation, one for transformation and one for scaling.
I understand how the process works for one XYZ for rotation.
But 3 XYZ just for rotation? How does that works?

On other words, how can I make this 3 vectors:
Transform.BasisX,
Transform.BasisY and
Transform.BasisZ

into one? Should I multiply them? (I will try that now)


The translation on the code is just using Transform.Origin (It's one XYZ, good enough for me), but I've already used that without success. I will try again.

 

Probably this question is more math related than revit API, but asking for help doesn't hurt =P


Thanks for the help!

 

Edit:
Viewing the values for the BasisXYZ, they are aways 1... Now I'm more confused, It doesn't make any sense using these... But your code does =/ 
I don't think that code is relevant to my situation, It only exports ONE thing... I need to export all things.
I think that's why the Transformation is aways = basis  on your code, it doesn't need any kind of positioning (because it's just one object...) Back to square one =/

Message 4 of 14
Anonymous
in reply to: jeremytammik

Please understand that the problem is not related with REVIT instances, but glTF mesh instancing.

I've written a response... But the sistem diagnosed as spam and deleted it... WHY JESUS WHY

 

Please, I have already read ALL of the topics you posted but one (https://github.com/jeremytammik/ExportSymbolInstanceGeo), and now I've read and that have no correlation with my problem. (I've explained in detail on my previous post, deleted by the system... You don't do a transformation based on a previous object, your code use XYZ.Basis... if I do that every object will be in the same place)


I don't know what to do, I'm working on this for weeks.

I'm already using the custom exporter, like the samples you provided.

Please, help, please... I'm desperate I don't know what else I can do. I tried EVERYTHING you posted...

Using the symbol tranformation, using instance transformation, using point location, multiplying transformations...

I will try to resume my point, please, please, please try to understand my problem, I don't know what else I can do, that's why I came to the forum to post (as you can see I don't do that much...)

Everything on the view will be exported, not just one object... (That's why I need the transformation).

1 - EXPORT GEOMETRY 
   1.1 - THE GEOMETRY IS ALREADY EXPORTED? 
       1.1.1 - NO - JUST EXPORT IT THEN. (This is what is done in all samples... there's nothing like 1.1 in any of the samples)
       1.1.2 - YES - THEN USE THE ALREADY EXPORTED GEOMETRY AND APPLY THE TRANSFORM TO THE BASE GEOMETRY.

My problem is how do I get the correct transform.

I've tried everything, researched a lot about it but no success so far. I'm reading thebuildingcoder everyday trying different stuff but I've reached a dead end, I need some help =/ 


Please I'm begging, if there is anything is my code bad written I will do my best to explain, that was the nearest I've reached.

I'm really sorry for not being able to achieve the desired results with your content, I never worked so hard on any stuff to fail like this. 

Sorry for the long text I really need help.

Message 5 of 14
jeremytammik
in reply to: Anonymous

The sample by Arnost that I pointed out above demonstrates exactly how to keep track of the required transformations.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 6 of 14
Anonymous
in reply to: jeremytammik

That was my first try, I will try again, thanks Jeremy.

Message 7 of 14
Anonymous
in reply to: Anonymous

I thought that was the collada exporter, I did not see that XML one...

Anyway... Please correct me if I'm wrong, you mean this:

// applying the current transform to a collection of points
    public IList<XYZ> ApplyTransform( IList<XYZ> points )
    {
      IList<XYZ> newPoints = new List<XYZ>( points.Count );

      foreach( XYZ xyz in points )
      {
        newPoints.Add( m_currentTransform.OfPoint( xyz ) );
      }

      return newPoints;
    }

If is this what you meant, It does not help in my case.

I will try to ask with other words:

<MyFile>

    <Nodes>

         <Node Mesh="ChairMesh" Translation="10,10,10" Rotation="0,0,0">

         <Node Mesh="ChairMesh" Translation="20,10,10" Rotation="0,0,0">>

         <Node Mesh="ChairMesh" Translation="30,10,10" Rotation="0,0,0">>

    </Nodes>
     <Meshes>
            <Mesh Name="ChairMesh">

                      (MeshPrimitives)
             </Mesh>
     </Meshes>
<MyFile>

I don't need to transform each point of the mesh to do that.
Am I missing something?

Message 8 of 14
Anonymous
in reply to: Anonymous

The translation I needed was correct all along! 
We can update to a more "simple" way of subtract:

XYZ translation = (meshInstance.First() as GeometryInstance).Transform.Origin.Subtract((meshBase.First() as GeometryInstance).Transform.Origin)

I've changed the variable names to be a little more semantical.

Unfortunatelly my problems with the rotation remains.
I've tried to do the same thing with the rotation (using FacingOrientation), no luck so far.

Message 9 of 14
Anonymous
in reply to: Anonymous

Is there anyone who can help me on this?
I'm still trying to get that rotation quarternion...

Is there anywhere else where I can seek help on this? 

Message 10 of 14
mphelt
in reply to: Anonymous

Hi @Anonymous, have you figured that out? From what I have found Rotation of Node is a quaternion, so a vector4. Have you been able to get it somehow from Revit Transfrom?

Message 11 of 14
jeremy_tammik
in reply to: Anonymous

Another example that is guaranteed to keep correct track of the transformation stack that I referred to above is the Revit SDK ElementViewer sample: 

 

 

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 12 of 14
mhannonQ65N2
in reply to: Anonymous

For rotations, what you are trying to do is transform between two different representations of the 3d rotation group (aka the Special Orthogonal group of dimension 3, SO(3)). Revit provides rotations in the form of a 3x3 matrix whose three columns are the BasisX, BasisY, and BasisZ properties of Transform. This rotates vectors by standard matrix multiplication.

 

However, what you are using in SharpGLTF requires a quaternion. To be precise, it actually requires a unit quaternion, which is a quaternion of length 1. The equation for this is x²+y²+z²+w²=1 (this is identical to the equation of the unit sphere in 4-dimensional space, known as the 3-sphere because its 'surface' is 3-dimensional). Furthermore, the product of two unit quaternions is also a unit quaternion. Unit quaternions rotate 3d vectors in a more mathematically complicated way that is actually faster to compute (I won't get into the details). A significant consequence of how unit quaternions are used to rotate vectors is that multiplying the unit quaternion by -1 does not change how the vector is rotated. As such each 3d rotation can be represented by two different quaternions, q, and -q. As such, the group of unit quaternions is called a 'double cover' of SO(3).

 

Given an axis you wish to rotate about (as a unit vector, v) and the amount you wish to rotate, θ, (in radians), the process of constructing a unit quaternion for that rotation is straight forward. The x, y, and z components of the unit quaternion are the x, y, and z components of v, multiplied by sin(θ/2) and the fourth component is cos(θ/2).

 

If you don't know the axis and angle but only have the rotation matrix (i.e. a Revit Transform), there are algorithms for converting from a 3d rotation matrix to a quaternion, though I won't go into any here. Alternatively, it looks like in the latest version of SharpGLTF, AffineTransform has a constructor that takes a 4x4 matrix. To make such a matrix from a Revit Transform, the first 3 columns should be the BasisX, BasisY, and BasisZ of the Transform, with the fourth member of the column being zero, and the last column should be the Transform's origin, with the fourth member of the column being one.

Message 13 of 14
bnewcombe
in reply to: Anonymous

Quarternion functions added to the Revit api would be great. Quarternion explanations always seem very confusing, the best explanation (primer) video i found was this 10 mins GameDev tips - Quaternions - YouTube hope this helps

 

Message 14 of 14
jeremy_tammik
in reply to: bnewcombe

Thank you for the great pointer. I fully agree, and added both your and Matthew's explanation and pointer to The Building Coder for future reference and posterity:

  

https://thebuildingcoder.typepad.com/blog/2021/11/installer-asset-formit-and-quaterions.html#4

  

Many thanks to you both, @bnewcombe@mhannonQ65N2 !

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Customer Advisory Groups


Rail Community