QT學習VTK序列: Plane

學習VTK繪製平面

/*
 * ModuleName: 模塊名稱
 * Description:
 * 參考代碼:https://lorensen.github.io/VTKExamples/site/Cxx/GeometricObjects/PlaneSourceDemo/
 * Author: hsw
 * Date: 2020-03-15
 *
*/

// QT
#include <QMainWindow>
#include <QDebug>

// VTK
#include <vtkSmartPointer.h>
#include <vtkPlaneSource.h>
#include <vtkSphereSource.h>
#include <vtkArrowSource.h>
#include <vtkActor.h>
#include <vtkLegendBoxActor.h>
#include <vtkCamera.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkNamedColors.h>
#include <vtkColor.h>
#include <vtkMinimalStandardRandomSequence.h>
#include <vtkAutoInit.h>

// C++
#include <array>
#include <vector>
#include <string>

namespace Ui {
class MainWindow;
}

VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);

// For compatibility with new VTK generic data arrays
#ifdef vtkGenericDataArray_h
#define InsertNextTupleValue InsertNextTypedTuple
#endif

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    vtkSmartPointer<vtkPolyData> createArrow(const double& pdLength,
                                             const std::array<double, 3>& startPoint,
                                             const std::array<double, 3>& endPoint);
private:
    Ui::MainWindow *ui;
private:
    vtkSmartPointer<vtkPlaneSource>       planeSource;
    std::array<double, 6>                 bounds;
    vtkSmartPointer<vtkPolyDataMapper>    planeMapper;
    vtkSmartPointer<vtkActor>             planeActor;
    vtkSmartPointer<vtkSphereSource>      sphereSource;
    vtkSmartPointer<vtkPolyDataMapper>    originMapper;
    vtkSmartPointer<vtkActor>             originActor;
    vtkSmartPointer<vtkPolyDataMapper>    centerMapper;
    vtkSmartPointer<vtkActor>             centerActor;
    vtkSmartPointer<vtkPolyDataMapper>    point1Mapper;
    vtkSmartPointer<vtkActor>             point1Actor;
    vtkSmartPointer<vtkPolyDataMapper>    point2Mapper;
    vtkSmartPointer<vtkActor>             point2Actor;

    vtkSmartPointer<vtkPolyData>          xAxisPolyData;
    vtkSmartPointer<vtkPolyData>          yAxisPolyData;
    vtkSmartPointer<vtkPolyData>          normalPolyData;

    vtkSmartPointer<vtkPolyDataMapper>    xAxisMapper;
    vtkSmartPointer<vtkPolyDataMapper>    yAxisMapper;
    vtkSmartPointer<vtkPolyDataMapper>    normalMapper;

    vtkSmartPointer<vtkActor>             xAxisActor;
    vtkSmartPointer<vtkActor>             yAxisActor;
    vtkSmartPointer<vtkActor>             normalActor;

    std::array<double, 3>                 center;
    std::array<double, 3>                 origin;
    std::array<double, 3>                 normal;
    std::array<double, 3>                 point1;
    std::array<double, 3>                 point2;

    vtkSmartPointer<vtkRenderer>          renderer;
    vtkSmartPointer<vtkLegendBoxActor>    legend;
private:
    vtkSmartPointer<vtkNamedColors> namedColors           = vtkSmartPointer<vtkNamedColors>::New();
    vtkColor3d                      backgroundColor       = namedColors->GetColor3d("SlateGray");
    vtkColor3d                      legendBackgroundColor = namedColors->GetColor3d("Black");
    vtkColor3d                      originColor           = namedColors->GetColor3d("Tomato");
    vtkColor3d                      centerColor           = namedColors->GetColor3d("Banana");
    vtkColor3d                      point1Color           = namedColors->GetColor3d("Peru");
    vtkColor3d                      point2Color           = namedColors->GetColor3d("Bisque");
    vtkColor3d                      xAxisColor            = namedColors->GetColor3d("lime");
    vtkColor3d                      yAxisColor            = namedColors->GetColor3d("orange");
    vtkColor3d                      normalColor           = namedColors->GetColor3d("Raspberry");
};

 

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    namedColors           = vtkSmartPointer<vtkNamedColors>::New();
    backgroundColor       = namedColors->GetColor3d("SlateGray");
    legendBackgroundColor = namedColors->GetColor3d("Black");
    originColor           = namedColors->GetColor3d("Tomato");
    centerColor           = namedColors->GetColor3d("Banana");
    point1Color           = namedColors->GetColor3d("Peru");
    point2Color           = namedColors->GetColor3d("Bisque");
    xAxisColor            = namedColors->GetColor3d("lime");
    yAxisColor            = namedColors->GetColor3d("orange");
    normalColor           = namedColors->GetColor3d("Raspberry");

    // vtkPlaneSource: 創建平面
    planeSource = vtkSmartPointer<vtkPlaneSource>::New();
    planeSource->SetOrigin(0.0, 0.0, 0.0);
    planeSource->SetPoint1(1,0, 0);
    planeSource->SetPoint2(0,1.0, 0);
    planeSource->Update();

    // vtkPlaneSource Bounds
    planeSource->GetOutput()->GetBounds(bounds.data());

    // 平面的長邊
    double length = std::max(bounds[1] - bounds[0], bounds[3] - bounds[2]);

    // 平面的Mapper和Actor
    planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    planeMapper->SetInputConnection(planeSource->GetOutputPort());
    planeActor = vtkSmartPointer<vtkActor>::New();
    planeActor->SetMapper(planeMapper);

    // 球(點)
    sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetRadius(length * .04);

    // 原點
    originMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    originMapper->SetInputConnection(sphereSource->GetOutputPort());
    originActor  = vtkSmartPointer<vtkActor>::New();
    originActor->SetPosition(planeSource->GetOrigin());
    originActor->SetMapper(originMapper);
    originActor->GetProperty()->SetDiffuseColor(originColor.GetData());

    // 平面中心點
    centerMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    centerMapper->SetInputConnection(sphereSource->GetOutputPort());
    centerActor  = vtkSmartPointer<vtkActor>::New();
    centerActor->SetPosition(planeSource->GetCenter());
    centerActor->SetMapper(centerMapper);
    centerActor->GetProperty()->SetDiffuseColor(centerColor.GetData());

    // 平面點1
    point1Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    point1Mapper->SetInputConnection(sphereSource->GetOutputPort());
    point1Actor = vtkSmartPointer<vtkActor>::New();
    point1Actor->SetPosition(planeSource->GetPoint1());
    point1Actor->SetMapper(point1Mapper);
    point1Actor->GetProperty()->SetDiffuseColor(point1Color.GetData());

    // 平面點2
    point2Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    point2Mapper->SetInputConnection(sphereSource->GetOutputPort());
    point2Actor  = vtkSmartPointer<vtkActor>::New();
    point2Actor->SetPosition(planeSource->GetPoint2());
    point2Actor->SetMapper(point2Mapper);
    point2Actor->GetProperty()->SetDiffuseColor(point2Color.GetData());

    for (auto i = 0; i < 3; ++i)
    {
        point1[i] = planeSource->GetPoint1()[i];
        point2[i] = planeSource->GetPoint2()[i];
        origin[i] = planeSource->GetOrigin()[i];
        center[i] = planeSource->GetCenter()[i];
        normal[i] = planeSource->GetNormal()[i] * length;
    }

    // x軸
    xAxisPolyData = createArrow(length, origin, point1);
    xAxisMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    xAxisMapper->SetInputData(xAxisPolyData);
    xAxisActor = vtkSmartPointer<vtkActor>::New();
    xAxisActor->SetMapper(xAxisMapper);
    xAxisActor->GetProperty()->SetDiffuseColor(xAxisColor.GetData());

    // y軸
    yAxisPolyData = createArrow(length, origin, point2);
    yAxisMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    yAxisMapper->SetInputData(yAxisPolyData);
    yAxisActor = vtkSmartPointer<vtkActor>::New();
    yAxisActor->SetMapper(yAxisMapper);
    yAxisActor->GetProperty()->SetDiffuseColor(yAxisColor.GetData());

    // z軸
    normalPolyData = createArrow(length, origin, normal);
    normalMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    normalMapper->SetInputData(normalPolyData);
    normalActor = vtkSmartPointer<vtkActor>::New();
    normalActor->SetMapper(normalMapper);
    normalActor->GetProperty()->SetDiffuseColor(normalColor.GetData());

    // 圖例
    legend = vtkSmartPointer<vtkLegendBoxActor>::New();
    legend->SetNumberOfEntries(7);
    legend->UseBackgroundOn();
    legend->SetBackgroundColor(legendBackgroundColor.GetData());
    legend->GetPositionCoordinate()->SetValue(.7, .7);
    legend->GetPosition2Coordinate()->SetValue(.3, .3);

    int entry = 0;
    legend->SetEntry(entry++, sphereSource->GetOutput(), "center", centerColor.GetData());
    legend->SetEntry(entry++, sphereSource->GetOutput(), "origin", originColor.GetData());
    legend->SetEntry(entry++, sphereSource->GetOutput(), "point1", point1Color.GetData());
    legend->SetEntry(entry++, sphereSource->GetOutput(), "point2", point2Color.GetData());
    legend->SetEntry(entry++, xAxisPolyData, "xAxis", xAxisColor.GetData());
    legend->SetEntry(entry++, xAxisPolyData, "yAxis", yAxisColor.GetData());
    legend->SetEntry(entry++, xAxisPolyData, "normal", normalColor.GetData());

    // 渲染器
    renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->SetBackground(backgroundColor.GetData());
    renderer->AddActor(planeActor);
    renderer->AddActor(originActor);
    renderer->AddActor(centerActor);
    renderer->AddActor(point1Actor);
    renderer->AddActor(point2Actor);
    renderer->AddActor(xAxisActor);
    renderer->AddActor(yAxisActor);
    renderer->AddActor(normalActor);
    renderer->AddActor(legend);

    ui->qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
}

MainWindow::~MainWindow()
{
    delete ui;
}

vtkSmartPointer<vtkPolyData> MainWindow::createArrow(const double &pdLength,
                                                     const std::array<double, 3> &startPoint,
                                                     const std::array<double, 3> &endPoint)
{
    // Create an Arrow
    vtkSmartPointer<vtkArrowSource> arrowSource = vtkSmartPointer<vtkArrowSource>::New();
    arrowSource->SetShaftRadius(pdLength * 0.01);
    arrowSource->SetShaftResolution(20);
    arrowSource->SetTipLength(pdLength * 0.1);
    arrowSource->SetTipRadius(pdLength * 0.05);
    arrowSource->SetTipResolution(20);

    // Compute a basis
    std::array<double, 3> normalizedX;
    std::array<double, 3> normalizedY;
    std::array<double, 3> normalizedZ;

    // The X axis is a vector from start to end
    // X軸 = endPoint - startPoint
    vtkMath::Subtract(endPoint.data(), startPoint.data(), normalizedX.data());
    double length = vtkMath::Norm(normalizedX.data());
    vtkMath::Normalize(normalizedX.data());

    // The Z axis is an arbitrary vector cross X
    // Z軸爲同X軸垂直的任意方向
    vtkSmartPointer<vtkMinimalStandardRandomSequence> rng = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
    rng->SetSeed(8775070); // For testing.

    std::array<double, 3> arbitrary;
    for (auto i = 0; i < 3; ++i)
    {
        rng->Next();
        arbitrary[i] = rng->GetRangeValue(-10, 10);
    }
    vtkMath::Cross(normalizedX.data(), arbitrary.data(), normalizedZ.data());
    vtkMath::Normalize(normalizedZ.data());

    // The Y axis is Z cross X
    vtkMath::Cross(normalizedZ.data(), normalizedX.data(), normalizedY.data());
    vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();

    // Create the direction cosine matrix
    matrix->Identity();
    for (auto i = 0; i < 3; i++)
    {
        matrix->SetElement(i, 0, normalizedX[i]);
        matrix->SetElement(i, 1, normalizedY[i]);
        matrix->SetElement(i, 2, normalizedZ[i]);
    }

    // Apply the transforms
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->Translate(startPoint.data());
    transform->Concatenate(matrix);
    transform->Scale(length, length, length);

    // Transform the polydata
    vtkSmartPointer<vtkTransformPolyDataFilter> transformPD = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    transformPD->SetTransform(transform);
    transformPD->SetInputConnection(arrowSource->GetOutputPort());
    transformPD->Update();

    return transformPD->GetOutput();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章