Here are two models cube and axes in the render view.
The axes actor had been rotated by 45 degree around Z asix, the cube had been rotated by 45 degree around Y asix after the same process. The following picture shows the final scene. All implementation details are also displayed.

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSTLReader.h>
#include <vtkClipClosedSurface.h>
#include <vtkFillHolesFilter.h>
#include <vtkAxesActor.h>
#include <vtkPlane.h>
#include <vtkTransformFilter.h>
#include <vtkTransform.h>
#include <vtkPlaneCollection.h>
#include <vtkAxesActor.h>
#include <vtkIntersectionPolyDataFilter.h>
#include <vtkProperty.h>
#include <vtkConeSource.h>
#include <vtkBooleanOperationPolyDataFilter.h>
#include <vtkCubeSource.h>
#include <vtkClipPolyData.h>
#include <vtkLineSource.h>

#include "point.hpp"

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

using namespace std;

int main()
{
    vtkSPtrNew( source, vtkCubeSource );
    source->Update();
    auto *pd = source->GetOutput();

    vtkSPtrNew( lineSource, vtkLineSource );
    lineSource->SetPoint1( -3, 3, 0 );
    lineSource->SetPoint2( 3, -3, 0 );
    lineSource->Update();

    vtkSPtrNew( lineMapper, vtkPolyDataMapper );
    lineMapper->SetInputData( lineSource->GetOutput() );

    vtkSPtrNew( lineActor, vtkActor );
    lineActor->SetMapper( lineMapper );
    lineActor->GetProperty()->SetColor( 1, 0, 0 );

    Point vec( 1, -1, 0 );
    vec.Unit();
    cout << "vec: " << vec[0] << ", " << vec[1] << ", " << vec[2] << endl;

    vtkSPtrNew( trans0, vtkTransform );
    trans0->RotateZ( -45 );
    trans0->RotateY( 45 );
    trans0->Update();

    vtkSPtrNew( trans1, vtkTransform );
    trans1->RotateZ( -45 );
    trans1->Update();

    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( pd );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );
    actor->SetUserTransform( trans0 );

    vtkSPtrNew( axesActor, vtkAxesActor );
    axesActor->SetTotalLength( 3, 3, 3 );
    axesActor->SetUserTransform( trans1 );

    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor( actor );
    //renderer->AddActor( lineActor );
    renderer->AddActor( axesActor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();
    return 0;
}

Now I want to scale the cube twice along the rotated axis X which we will represented it as red line in the future.
As we know, the action scale works on the three directions axis X, axis Y and asix Z. So the scaling transform I want to create needs to rotate by 45 degree around asix Z, then apply scale(2, 1, 1). But the new transform will rotate cube surely. How to scale the cube without rotating or translating it?
I marks the red line as target scaling axis \vec{A_1}, represent the axis X in the world coordinate system as \vec{A_0}. I found the transform matrx M_1 from \vec{A_0} to \vec{A_1}, its inverse matrix is M_1^{-1}. I construct a scale transform finalScaleTrans.

    vtkSPtrNew( scaleTrans, vtkTransform );
    scaleTrans->Scale(2, 1, 1);
    scaleTrans->Update();

    vtkSPtrNew( finalScaleTrans, vtkTransform );
    finalScaleTrans->Concatenate( M1 );
    finalScaleTrans->Concatenate( scaleTrans );
    finalScaleTrans->Concatenate( M1_Inv );
    finalScaleTrans->Update();

I want it works as the my simple demo.
The following program scale the cube along vector(1, -1, 0).

.

int main()
{
    vtkSPtrNew( source, vtkCubeSource );
    source->Update();
    auto pd = source->GetOutput();

    vtkSPtrNew( trans0, vtkTransform );
    trans0->RotateZ( -45 );
    trans0->Scale( 2, 1, 1 );
    trans0->RotateZ( 45 );
    trans0->Update();

    vtkSPtrNew( transFilter, vtkTransformFilter );
    transFilter->SetInputData( pd );
    transFilter->SetTransform( trans0 );
    transFilter->Update();

    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( transFilter->GetPolyDataOutput() );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );

    Point testVec( 1, 1, 0 );
    trans0->TransformPoint( testVec.point, testVec.point );

    cout << "testVec: " << testVec[0] << ", " << testVec[1] << ", " << testVec[2] << endl;

    vtkSPtrNew( lineMapper, vtkPolyDataMapper );

    vtkSPtrNew( lineActor, vtkActor );
    lineActor->SetMapper( lineMapper );
    lineActor->GetProperty()->SetColor( 1, 0, 0 );

    vtkSPtrNew( axesActor, vtkAxesActor );

    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor( actor );
    renderer->AddActor( axesActor );
    renderer->AddActor( lineActor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();

    return 0;
}

Unfortunately the scale axis \vec{A_1} will change after we set userTransform, so we can’t get the correct result.
I find the acctual scale axis and mark it as red line.

    Point vec( 1, -1, 0 );
    vec.Unit();
    cout << "vec: " << vec[0] << ", " << vec[1] << ", " << vec[2] << endl;

    vtkSPtrNew( trans0, vtkTransform );
    trans0->RotateZ( -45 );
    trans0->RotateY( 45 );
    trans0->Update();

    vtkSPtrNew( trans1, vtkTransform );
    trans1->RotateZ( -45 );
    trans1->Update();

    Point crossVec = Point(1, 0, 0) ^ vec;
    auto dotValue = Point(1, 0, 0).Dot( vec );
    auto radius = std::acos( dotValue );
    auto degree = vtkMath::DegreesFromRadians( radius );
    vtkSPtrNew( rotateTrans, vtkTransform );
    rotateTrans->RotateWXYZ( -degree, crossVec.point );
    rotateTrans->Update();

    vtkSPtrNew( rotateTransInv, vtkTransform );
    rotateTransInv->DeepCopy( rotateTrans );
    rotateTransInv->Inverse();
    rotateTransInv->Update();

    vtkSPtrNew( scaleTrans, vtkTransform );
    scaleTrans->Scale( 2, 1, 1 );
    scaleTrans->Update();

    vtkSPtrNew( finalScaleTrans, vtkTransform );
    finalScaleTrans->Concatenate( rotateTrans );
    finalScaleTrans->Concatenate( scaleTrans );
    finalScaleTrans->Concatenate( rotateTransInv );
    finalScaleTrans->Update();

    vtkSPtrNew( transFilter, vtkTransformFilter );
    transFilter->SetInputData( pd );
    transFilter->SetTransform( finalScaleTrans );
    transFilter->Update();

    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( transFilter->GetPolyDataOutput() );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );
    actor->SetUserTransform( trans0 );


    vtkSPtrNew( axesActor, vtkAxesActor );
    axesActor->SetTotalLength( 3, 3, 3 );
    axesActor->SetUserTransform( trans1 );

    // =====> to find the scale axis <======
    vtkSPtrNew( finalTestTrans, vtkTransform );
    finalTestTrans->Concatenate( trans0 );
    finalTestTrans->Concatenate( rotateTrans ); //finalScaleTrans );//rotateTrans );
    finalTestTrans->Update();

    Point testVec( 1, 0, 0 );
    finalTestTrans->TransformVector( testVec.point, testVec.point );
    testVec.Unit();
    Point pt0( (-testVec*3) );
    Point pt1( (testVec*3) );
    vtkSPtrNew( lineSource, vtkLineSource );
    lineSource->SetPoint1( pt0.point );
    lineSource->SetPoint2( pt1.point );
    lineSource->Update();

    vtkSPtrNew( lineMapper, vtkPolyDataMapper );
    lineMapper->SetInputData( lineSource->GetOutput() );

    vtkSPtrNew( lineActor, vtkActor );
    lineActor->SetMapper( lineMapper );
    lineActor->GetProperty()->SetColor( 1, 0, 0 );

So I have to make rotateTrans smarter to counteract userTransform trans0’s effect.
We have to convert the vector \vec{A_1} to a new vector \vec{A_2} which represent it is in trans0’s inverse matrix.

    Point vec( 1, -1, 0 );
    vec.Unit();

    vtkSPtrNew( trans0Inv, vtkTransform );
    trans0Inv->DeepCopy( trans0 );
    trans0Inv->Inverse();
    trans0Inv->Update();
    trans0Inv->TransformVector( vec.point, vec.point );

    cout << "vec: " << vec[0] << ", " << vec[1] << ", " << vec[2] << endl;
    Point crossVec = Point(1, 0, 0)^vec;
    auto dotValue = Point(1, 0, 0).Dot( vec );
    auto radius = std::acos( dotValue );
    auto degree = vtkMath::DegreesFromRadians( radius );

    // ...

The code snippet is here.

int main()
{
    vtkSPtrNew( source, vtkCubeSource );
    source->Update();
    auto *pd = source->GetOutput();
    Point center( 2, 2, 1 );


    Point vec( 1, -1, 0 );
    vec.Unit();
    cout << "vec: " << vec[0] << ", " << vec[1] << ", " << vec[2] << endl;


    vtkSPtrNew( trans0, vtkTransform );
    trans0->Translate( center.point );
    trans0->RotateZ( -45 );
    trans0->RotateY( 45 );
    trans0->Translate( center.point );
    trans0->Update();

    vtkSPtrNew( trans1, vtkTransform );
    trans1->RotateZ( -45 );
    trans1->Update();

    vtkSPtrNew( trans0Inv, vtkTransform );
    trans0Inv->DeepCopy( trans0 );
    trans0Inv->Inverse();
    trans0Inv->Update();
    trans0Inv->TransformVector( vec.point, vec.point );


    Point crossVec = Point(1, 0, 0) ^ vec;
    auto dotValue = Point(1, 0, 0).Dot( vec );
    auto radius = std::acos( dotValue );
    auto degree = vtkMath::DegreesFromRadians( radius );
    cout << "degree: " << degree << endl;
    cout << "crossVec: " << crossVec[0] << ", " << crossVec[1] << ", " << crossVec[2] << endl;


    vtkSPtrNew( rotateTrans, vtkTransform );
    rotateTrans->RotateWXYZ( -degree, crossVec.point );
    rotateTrans->Update();


    vtkSPtrNew( rotateTransInv, vtkTransform );
    rotateTransInv->DeepCopy( rotateTrans );
    rotateTransInv->Inverse();
    rotateTransInv->Update();


    vtkSPtrNew( scaleTrans, vtkTransform );
    scaleTrans->Scale( 2, 1, 1 );
    scaleTrans->Update();


    vtkSPtrNew( finalScaleTrans, vtkTransform );
    finalScaleTrans->Concatenate( rotateTransInv );
    finalScaleTrans->Concatenate( scaleTrans );
    finalScaleTrans->Concatenate( rotateTrans );
    finalScaleTrans->Update();


    vtkSPtrNew( finalTrans, vtkTransform );
    finalTrans->Concatenate( trans0 );
    finalTrans->Concatenate( finalScaleTrans );
    finalTrans->Update();


    vtkSPtrNew( transFilter, vtkTransformFilter );
    transFilter->SetInputData( pd );
    transFilter->SetTransform( finalScaleTrans );
    transFilter->Update();


    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( transFilter->GetPolyDataOutput() );


    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );
    actor->SetUserTransform( trans0 );


    vtkSPtrNew( axesActor, vtkAxesActor );
    axesActor->SetTotalLength( 5, 5, 5 );
    axesActor->SetUserTransform( trans1 );


    vtkSPtrNew( lineSource, vtkLineSource );
    Point pt0( -3, 3, 0 ), pt1( 3, -3, 0 ), tmpPt( 0, 0, 0 );
    trans0->TransformPoint( tmpPt.point, tmpPt.point );
    lineSource->SetPoint1( (pt0 + tmpPt).point );
    lineSource->SetPoint2( (pt1 + tmpPt).point );
    lineSource->Update();


    vtkSPtrNew( lineMapper, vtkPolyDataMapper );
    lineMapper->SetInputData( lineSource->GetOutput() );


    vtkSPtrNew( lineActor, vtkActor );
    lineActor->SetMapper( lineMapper );
    lineActor->GetProperty()->SetColor( 1, 0, 0 );


    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor( actor );
    renderer->AddActor( lineActor );
    renderer->AddActor( axesActor );
    renderer->SetBackground( 0, 0, 0 );


    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );


    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );


    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();
    return 0;
}
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments

Content Summary
: Input your strings, the tool can get a brief summary of the content for you.

X
0
Would love your thoughts, please comment.x
()
x