學習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();
}