项目场景:
实现IGES文件、点云文件(.txt、.pcd)、STL文件的读取显示、STL模型及点云模型在三维空间中的旋转(这里使用的是使用旋转矩阵)。
将该这些功能集成到QT中。
问题描述:
问题一
有关三维模型文件读取不成功的可能问题:
VTK进行IGES文件读取及显示遇到的文件路径不正确问题的解决方法
问题二
在窗口中进行交互操作时并不是我们常用的交互方式。
常用方式:
鼠标左键按住不动拖动旋转
鼠标右键按住不动拖动移动
鼠标滚轮对模型进行放大
问题三
在将VS中的代码移植到QT Creator中时,因为在VS中添加四个初始化操作,在VS中如果不添加会出现:
Error: no override found for ‘vtkRenderWindow’.
Error: no override found for ‘vtkRenderer’.
Error: no override found for ‘vtkPolyDataMapper’.
这三个错误。
问题四
在我将PCL中的VTK8.1换成我自己编译的VTK8.2后(因为想使用QVTKWidgetPlugin),构建工程的时候报错:
ImmediateModeRenderingOff 不是vtkMapper的成员
原因分析:
问题二
没有添加渲染窗口交互操作的样式导致
问题三
寻找合适的位置放置四个初始化代码
解决方案:
问题二
添加如下代码:
vtkInteractorStyleTrackballCamera *style =
vtkInteractorStyleTrackballCamera::New();
renderWindowInteractor->SetInteractorStyle(style);
问题三
在QT工程文件中的mainwindow.cpp文件中添加如下代码:
同时在.cpp文件最前面添加头文件
#include <vtkAutoInit.h>
问题四
直接双击报错的位置,自动寻找到报错的行数,然后将那几行注释掉即可。
VS全部代码
//#define WNT
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <gp_Sphere.hxx>
#include <Poly_Polygon3D.hxx>
#include <Poly_Triangulation.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <IGESControl_Controller.hxx>
#include <IGESControl_Writer.hxx>
#include <IGESControl_Reader.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>
#include <BRepMesh.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <GCPnts_TangentialDeflection.hxx>
#include <TopExp_Explorer.hxx>
#include <Standard_TypeDef.hxx>
//vtk lib
#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkCellArray.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkAutoInit.h>
//VTK显示坐标轴
#include <vtkAxesActor.h>
#include <vtkLineSource.h>
#include <vtkAxis.h>
#include <vtkAxes.h>
#include <vtkConeSource.h>
#include <vtkCaptionActor2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackball.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkProperty.h>
#include <vtkTriangle.h>
#include <vtkSTLReader.h>
//进行旋转操作所需的头文件
//vtkTransform, vtkTransformFilter, vtkMatrix4x4
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkMatrix4x4.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
Standard_Integer ReadIGES(const Standard_CString& aFileName,
Handle(TopTools_HSequenceOfShape)& aHSequenceOfShape)
{
IGESControl_Reader Reader;
Standard_Integer status = Reader.ReadFile(aFileName);
if (status != IFSelect_RetDone)
{
return status;
}
Reader.TransferRoots();
TopoDS_Shape aShape = Reader.OneShape();
aHSequenceOfShape->Append(aShape);
return status;
}
void BuildMesh(vtkRenderer* render,
const TopoDS_Face& face, double deflection = 0.1)
//这里的0.1是默认参数,如果配合header使用那么只需要在header中写即可,在CPP文件中是不需要的
{
TopLoc_Location location;
//BRepMesh::Mesh(face, deflection);该函数已经弃用
BRepMesh_IncrementalMesh(face, deflection);
Handle_Poly_Triangulation triFace = BRep_Tool::Triangulation(face, location);
Standard_Integer nTriangles = triFace->NbTriangles();
gp_Pnt vertex1;
gp_Pnt vertex2;
gp_Pnt vertex3;
Standard_Integer nVertexIndex1 = 0;
Standard_Integer nVertexIndex2 = 0;
Standard_Integer nVertexIndex3 = 0;
TColgp_Array1OfPnt nodes(1, triFace->NbNodes());
Poly_Array1OfTriangle triangles(1, triFace->NbTriangles());
nodes = triFace->Nodes();
triangles = triFace->Triangles();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
points->Allocate(nTriangles * 3);
cells->Allocate(nTriangles);
int id = 0;
for (Standard_Integer i = 1; i <= nTriangles; i++)
{
Poly_Triangle aTriangle = triangles.Value(i);
aTriangle.Get(nVertexIndex1, nVertexIndex2, nVertexIndex3);
vertex1 = nodes.Value(nVertexIndex1).Transformed(location.Transformation());
vertex2 = nodes.Value(nVertexIndex2).Transformed(location.Transformation());
vertex3 = nodes.Value(nVertexIndex3).Transformed(location.Transformation());
points->InsertNextPoint(vertex1.X(), vertex1.Y(), vertex1.Z());
points->InsertNextPoint(vertex2.X(), vertex2.Y(), vertex2.Z());
points->InsertNextPoint(vertex3.X(), vertex3.Y(), vertex3.Z());
vtkSmartPointer<vtkTriangle> triangle = vtkSmartPointer<vtkTriangle>::New();
triangle->GetPointIds()->SetId(0, id * 3);
triangle->GetPointIds()->SetId(1, id * 3 + 1);
triangle->GetPointIds()->SetId(2, id * 3 + 2);
// Add the triangle to a cell array
cells->InsertNextCell(triangle);
id++;
}
polyData->SetPoints(points);
polyData->SetPolys(cells);
vtkSmartPointer<vtkPolyDataMapper> sourceMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
//setInput函数已经弃用
sourceMapper->SetInputData(polyData);
vtkSmartPointer<vtkActor> sourceActor = vtkSmartPointer<vtkActor>::New();
sourceActor->SetMapper(sourceMapper);
sourceActor->GetProperty()->SetColor(1, 0, 0);
render->AddActor(sourceActor);
}
void createAxes(vtkSmartPointer<vtkRenderer> renderer)
{
//轴
vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
axes->SetTotalLength(150.0, 100.0, 50.0);
axes->SetShaftType(vtkAxesActor::CYLINDER_SHAFT);//设置轴类型圆柱形状
axes->SetCylinderRadius(0.01);
axes->GetXAxisCaptionActor2D()->SetWidth(0.03);
axes->GetYAxisCaptionActor2D()->SetWidth(0.03);
axes->GetZAxisCaptionActor2D()->SetWidth(0.03);
renderer->AddActor(axes);
}
void BuildScene(vtkRenderer *renderer, Handle(TopTools_HSequenceOfShape)& aHSequenceOfShape)
{
Standard_Integer index = aHSequenceOfShape->Length();
TopoDS_Shape theCompSolid = aHSequenceOfShape->ChangeValue(index);
for (TopExp_Explorer faceExp(theCompSolid, TopAbs_FACE); faceExp.More(); faceExp.Next())
{
// The 3d-mesh of the FACE is assembled to form the
// boundary of the SOLID.
const TopoDS_Face& theFace = TopoDS::Face(faceExp.Current());
BuildMesh(renderer, theFace);
}
}
//实现点云的显示
vtkSmartPointer<vtkActor> visualizePointCloud(std::string fileName) {
vtkSmartPointer<vtkPoints> m_Points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); //_存放细胞顶点,用于渲染(显示点云所必须的)
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyDataMapper> pointMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkActor> pointActor = vtkSmartPointer<vtkActor>::New();
//_读进点云数据信息
FILE *fp = NULL;
fp = fopen(fileName.c_str(), "r"); //3DpointDatas.txt
double x = 0, y = 0, z = 0;
int i = 0;
while (!feof(fp))
{
fscanf(fp, "%lf %lf %lf", &x, &y, &z);
m_Points->InsertPoint(i, x, y, z); //_加入点信息
vertices->InsertNextCell(1); //_加入细胞顶点信息----用于渲染点集
vertices->InsertCellPoint(i++);
}
fclose(fp);
polyData->SetPoints(m_Points); //_设置点集
polyData->SetVerts(vertices); //_设置渲染顶点
pointMapper->SetInputData(polyData);
pointActor->SetMapper(pointMapper);
pointActor->GetProperty()->SetColor(0.0, 0.1, 1.0);
pointActor->GetProperty()->SetAmbient(0.5);
pointActor->GetProperty()->SetPointSize(2);
return pointActor;
}
//实现STL模型的显示
vtkSmartPointer<vtkActor> visualizeSTL(std::string aFileName) {
vtkSmartPointer<vtkSTLReader> readerSTL =
vtkSmartPointer<vtkSTLReader>::New();
readerSTL->SetFileName(aFileName.c_str());
// Visualize
//用来代表多边形数据的模型
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(readerSTL->GetOutputPort());
//这里的actor用来表示需要渲染的实体模型
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
/*
setmapper的含义:这是用于将执行组件连接到可视化管道的末尾(即映射器)的方法。
这应该是 vtkMapper 的子类。
render:渲染
*/
actor->SetMapper(mapper);
return actor;
}
//实现IGES模型的显示
void visualizeIGES(const Standard_CString fileName, vtkSmartPointer<vtkRenderer> renderer) {
Handle(TopTools_HSequenceOfShape) aHSequenceOfShape =
new TopTools_HSequenceOfShape();
Standard_Integer status =
ReadIGES(fileName, aHSequenceOfShape);
cout << "return status:" << status << endl;
//向渲染三维空间中添加IGES的渲染对象
BuildScene(renderer, aHSequenceOfShape);
}
#define LINE_LEN .5
int main(void)
{
//新建一个渲染对象所存放的窗口
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
//新建一个用来存放渲染对象的三维空间
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
//创建一个点云的actor对象
std::string pointCloudFileName =
"E:\\Research\\test resource\\STL.txt";
vtkSmartPointer<vtkActor> pointActor =
visualizePointCloud(pointCloudFileName);
/*STL文件的读取*/
std::string aFileName =
"E:\\Research\\test resource\\STL_8836.stl";
vtkSmartPointer<vtkActor> actorSTL =
visualizeSTL(aFileName);
//IGES的读取
//相当于const const char* IGESFileName
const Standard_CString IGESFileName = "E:\\Research\\test resource\\zhizuo_1.igs";
visualizeIGES(IGESFileName, renderer);
//向显示窗口中添加一个渲染对象的三维空间
renderWindow->AddRenderer(renderer);
//设置一个窗口渲染交互的对象并添加到渲染显示窗口中
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//粗配准矩阵和精配准矩阵
double preTrsf[] =
{ 0.154145 ,-0.268736 ,-0.9508 ,90.2438 ,
-0.50864 ,0.803412 ,-0.309539 ,0.332563 ,
0.847068 ,0.531329 ,-0.0128478 ,-155.794 ,
0 ,0 ,0 ,1 };
double ICPTrsf[] =
{ 0.952493 ,0.304157 ,0.0149612 ,-11.551,
-0.30439 ,0.949638 ,0.0744341 ,8.09676,
0.00843305,-0.0754527 ,0.997108 ,5.34397,
0 ,0 ,0 ,1 };
vtkMatrix4x4 *mat = vtkMatrix4x4::New();
double finalTrsf[16];
vtkMatrix4x4::Multiply4x4(ICPTrsf, preTrsf, finalTrsf);//获得最终旋转矩阵
mat->DeepCopy(finalTrsf);
//std::cout << *mat << std::endl;//直接打印出旋转矩阵得到信息
//将某个渲染对象actor右乘一个旋转矩阵mat
//actor->SetUserMatrix(mat);
pointActor->SetUserMatrix(mat);
//相当于在renderer图像中添加了一个actor
renderer->AddActor(actorSTL);
renderer->AddActor(pointActor);
createAxes(renderer);
renderer->SetBackground(1, 1, 1);
// Render and interact
renderWindow->Render();
//无限的执行循环,避免自己去写
vtkInteractorStyleTrackballCamera *style =
vtkInteractorStyleTrackballCamera::New();
renderWindowInteractor->SetInteractorStyle(style);
renderWindowInteractor->Start();
return 0;
}