How to rotate around pivot

mmaenz

CAD practitioner
Hi,

I don't understand how to make multiple transformations or how to rotate around a pivot to get a valid result. I'm not sure if it is a problem with the order in which it should happen or am I misunderstanding things how it is meant to work. The gp_Trsf seems to make one transformation at a time and therefor multiple gp_Trsf must be chained to get the result.

As per documentation of opencascade (https://dev.opencascade.org/doc/overview/html/occt_user_guides__modeling_data.html#occt_modat_5_1) I need to create a gp_Trsf for every transformation and chain them using TopLoc_Location.Multiplied().

This is what I do so far:

C++:
TopLoc_Location rotate(TopLoc_Location& world, double angle, int axis, gp_XYZ rotationPosition) {
    gp_Quaternion RX(gp::DX(), 0.);
    gp_Quaternion RY(gp::DY(), 0.);
    gp_Quaternion RZ(gp::DZ(), 0.);

    switch (axis) {
        case 1: RX.Set(gp_Quaternion(gp::DX(), angle / 180 * M_PI)); break;
        case 2: RY.Set(gp_Quaternion(gp::DY(), angle / 180 * M_PI)); break;
        case 3: RZ.Set(gp_Quaternion(gp::DZ(), angle / 180 * M_PI)); break;
    }

    gp_Quaternion RA(RZ * RY * RX);
    
    gp_Trsf compoundTransform = gp_Trsf(world);
    TopLoc_Location result;

    gp_XYZ compoundPosition = gp_XYZ(compoundTransform.TranslationPart());
    gp_XYZ distanceToPivot = compoundPosition.Subtracted(rotationPosition);

    // 0
    TopLoc_Location compoundPositionLocation = TopLoc_Location(world);

    // 1
    // Bring object which should be rotated to actual rotate position
    gp_Trsf rotationPositionTrsf;
    rotationPositionTrsf.SetTranslation(rotationPosition);
    TopLoc_Location rotationPositionLocation(rotationPositionTrsf);

    // 2
    // The rotation itsself
    gp_Trsf rotationTrsf;
    RA.Multiply(compoundTransform.GetRotation());
    rotationTrsf.SetRotation(RA);
    TopLoc_Location rotationLocation(rotationTrsf);

    // 3
    // Objekt auf die Differenz schieben vom eigentlichen Drehpunkt damit wieder auf Originalposition
    gp_Trsf rotationCompoundDifferenceTrsf;
    rotationCompoundDifferenceTrsf.SetTranslation(distanceToPivot);
    TopLoc_Location rotationCompoundDifferenceLocation(rotationCompoundDifferenceTrsf);

    result = compoundPositionLocation * rotationPositionLocation * rotationLocation * rotationCompoundDifferenceLocation;
    
    return result;
}

This is the process in screenshots, the red arrow points to the pivot and the yellow to 0,0,0:
before-rotate.png
it works and looks like this when turning 90 degree on the pivot (25, 758, 33) and looks like this:
one-part-works.png

When doing the same with the opposite bracket assembly is won't work:
other-bracket-rotated.png
It already has a rotate information which I'm multiplying with when doing the rotate but the offset is not working. I tried quite a few different ways but it does not end in the location where it should be. I also suspect that I didn't understand how the rotation works?

I already had that question on occ forum but digged a little deeper since. If I've got an answer I will reply to both.

Any help or hint is appreciated...

Thanks!
 

natalia

Moderator
Staff member
Hi mmaenz,

Sorry that did not answer so long…
At last, I understand what your case is and what might be the solution for you.

Example of rotating AIS_Shape around a pivot exists in a ready presentation AIS_Manipulator in OCCT. When you investigate the code of it, I think, you find the solution. The pivot is the position given to the manipulator. Your case is ‘AIS_MM_Rotation’ processing.

The logic that you need to implement (if follow this way) is the next:
1. Preparing gp_Trsf that contains the location and angle. The lines of interest here are:
C++:
    case AIS_MM_Rotation:
    {
      const gp_Pnt aPosLoc   = myStartPosition.Location();
      const gp_Ax1 aCurrAxis = getAx1FromAx2Dir (myStartPosition, myCurrentIndex);
      ...
      gp_Trsf aNewTrsf;
      aNewTrsf.SetRotation (aCurrAxis, anAngle);
      ...
    }
2. Combine this transformation with the transformation of TopoDS_Shape/AIS_Shape. In your model (on attached snapshots), the brackets have own transformation, so you need to combine it with the new transformation. In AIS_Manipulator the code that relates to it is:
Code:
 void AIS_Manipulator::Transform (const gp_Trsf& theTrsf)
 {
   const Handle(AIS_InteractiveObject)& anObj = anObjIter.ChangeValue();
   const gp_Trsf& anOldTrsf = aTrsfIter.Value();
   ...
   anObj->SetLocalTransformation (theTrsf * anOldTrsf);
   ...
 }
Here, if you need to have this transformation in TopoDS_Shape, use setting location of it.

Sample, how the manipulator works, you may found in DRAW of OCCT, or in repository ‘https://gitlab.com/ssv/lessons/-/tree/viewerManipulator’. It’s discussed in ‘http://analysissitus.org/forum/index.php?threads/youtube-lessons.3/page-2#post-1201’.

Concerning preparing TopLoc_Location, we usually do not make it by ourselves manually. It is generated by using some of OCCT methods inside. You may think about this class like as a chain of gp_Trsf, you understand it correctly. Here, if you need not the history of the transformations (by some custom reasons), you may prepare only one gp_Trsf and give it to TopoDS_Shape.

Best regards
 
Top