We can use vtkParametricTorus to construct a curved 3D arrow. However, during this process, the opening needs to be closed, and the boundary should be preprocessed: merge nearby points, remove duplicate points, and triangulate.

RotationArrow.h

#pragma once

#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkMath.h>
#include <vtkRenderer.h>

#include "Point.hpp"

class RotationArrow
{
public:
    RotationArrow();
    vtkSPtr<vtkPolyData> Generate(double radius = 1.0);

private:
    vtkSPtr<vtkPolyData> CreateArrowBody(double ringRadius = 1.0, double crossSectionRadius = 0.2, double minU = 0, double maxU = 2 * vtkMath::Pi() );
    vtkSPtr<vtkPolyData> CreateCircularArc(double radius, double startAngle, double endAngle, int resolution);
    vtkSPtr<vtkPolyData> CreateArrowHead(const Point& position, const Point& direction, double length);
    vtkSPtr<vtkPolyData> GetDataForShow( vtkSPtr<vtkTransform> trans, vtkSPtr<vtkPolyData> data );
};

RotationArrow.cpp

#include "RotationArrow.h"
#include "BasicMethod.h"
#include "ConnectedEdgeFilter.h"

#include <vtkCleanPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkFillHolesFilter.h>
#include <vtkTubeFilter.h>
#include <vtkAppendPolyData.h>
#include <vtkConeSource.h>
#include <vtkParametricFunctionSource.h>
#include <vtkParametricTorus.h>


vtkSPtr<vtkPolyData> RotationArrow::GetDataForShow( vtkSPtr<vtkTransform> trans, vtkSPtr<vtkPolyData> data )
{
    vtkSPtrNew( transFilter, vtkTransformFilter );
    transFilter->SetTransform( trans );
    transFilter->SetInputData( data );
    transFilter->Update();

    vtkSPtr<vtkPolyData> result = transFilter->GetPolyDataOutput();
    return result;
}

RotationArrow::RotationArrow()
{
}

/*
x = r * cos(θ)
y = r * sin(θ)
for any angle, the derivative of the x and y coordinates with respect to θ are:
dx/dθ = -r * sin(θ)
dy/dθ = r * cos(θ)
*/
vtkSPtr<vtkPolyData> RotationArrow::Generate(double radius)
{
    double angleValue = 270;
    double crossSectionRadius = 0.05*radius;
    auto body = CreateArrowBody(radius, crossSectionRadius, 0, vtkMath::RadiansFromDegrees(angleValue));

    vtkSPtrNew( cleanFilter, vtkCleanPolyData );
    cleanFilter->SetInputData( body );
    cleanFilter->SetTolerance( 1e-6 );
    cleanFilter->PointMergingOn();
    cleanFilter->Update();

    body = cleanFilter->GetOutput();

    vtkSPtrNew( triangleFilter, vtkTriangleFilter );
    triangleFilter->SetInputData( body );
    triangleFilter->SetPassLines( false );
    triangleFilter->SetPassVerts( false );
    triangleFilter->Update();

    body = triangleFilter->GetOutput();
    body->BuildCells();
    body->BuildLinks();

    vtkSPtrNew( edges, vtkCellArray );
    BasicMethod::FindIndependentEdges(edges, body);
    ConnectedEdgeFilter *connectFilter = new ConnectedEdgeFilter();
    connectFilter->Initialise( edges );
    connectFilter->HandleEdges();

    auto listCount = connectFilter->GetListsCount();
    for( int i = 0; i < listCount; i++ )
    {
        auto list = connectFilter->GetList(i);
        if( list->GetNumberOfIds() < 2 )
            continue;
        BasicMethod::CenterPointFillHole( body, list );
    }

    double endAngle = vtkMath::RadiansFromDegrees(angleValue);
    Point arrowPos(radius * cos(endAngle), radius * sin(endAngle), 0);
    Point tangent(-sin(endAngle), cos(endAngle), 0);
    
    auto arrowHead = CreateArrowHead(arrowPos, tangent, crossSectionRadius * 8);
    
    vtkSPtrNew(append, vtkAppendPolyData);
    append->AddInputData(body);
    append->AddInputData(arrowHead);
    append->Update();
    
    return append->GetOutput();
}

vtkSPtr<vtkPolyData> RotationArrow::CreateArrowBody(double ringRadius, double crossSectionRadius, double minU, double maxU)
{
    vtkSPtrNew( source, vtkParametricFunctionSource );

    vtkSPtrNew( func, vtkParametricTorus );
    func->SetMinimumU( minU );
    func->SetMaximumU( maxU );
    func->SetJoinU(false);
    func->SetRingRadius( ringRadius );
    func->SetCrossSectionRadius( crossSectionRadius );

    source->SetParametricFunction( func );
    source->Update();

    vtkSPtrNew(rotateTrans, vtkTransform);
    rotateTrans->RotateWXYZ(-180, 0, 0, 1);
    rotateTrans->Update();

    auto result = GetDataForShow(rotateTrans, source->GetOutput());
    
    vtkSPtrNew(triangleFilter, vtkTriangleFilter);
    triangleFilter->SetInputData(result);
    triangleFilter->PassLinesOff();
    triangleFilter->PassVertsOff();
    triangleFilter->Update();

    return triangleFilter->GetOutput();
}

vtkSPtr<vtkPolyData> RotationArrow::CreateCircularArc(double radius, double startAngle, double endAngle, int resolution)
{
    vtkSPtrNew(points, vtkPoints);
    vtkSPtrNew(cells, vtkCellArray);
    
    double angleStep = (endAngle - startAngle) / (resolution - 1);
    vtkIdType prevId = -1;
    
    for(int i = 0; i < resolution; i++)
    {
        double angle = vtkMath::RadiansFromDegrees(startAngle + i * angleStep);
        double x = radius * cos(angle);
        double y = radius * sin(angle);
        vtkIdType id = points->InsertNextPoint(x, y, 0);
        
        if(prevId >= 0)
        {
            vtkIdType line[2] = {prevId, id};
            cells->InsertNextCell(2, line);
        }
        prevId = id;
    }
    
    vtkSPtrNew(polyData, vtkPolyData);
    polyData->SetPoints(points);
    polyData->SetLines(cells);
    return polyData;
}

vtkSPtr<vtkPolyData> RotationArrow::CreateArrowHead(const Point& position, const Point& direction, double length)
{
    vtkSPtrNew(cone, vtkConeSource);
    cone->SetHeight(length);
    cone->SetRadius(length * 0.6);
    cone->SetResolution(16);
    cone->Update();
    
    auto trans = BasicMethod::RotateVecToSpecialDir(Point(1, 0, 0), direction);

    vtkSPtrNew( finalTrans, vtkTransform );
    finalTrans->Translate(position[0], position[1], position[2]);
    finalTrans->Update();
    finalTrans->Concatenate(trans);
    finalTrans->Update();
    
    return GetDataForShow(finalTrans, cone->GetOutput());
}

Some interfaces of BasicMethod can be found on the websize.


0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Tex To PDF
: convert the Latex file which suffix is tex to a PDF file

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