前言

本文不适合0基础的VTK开发者,需要提前了解VTK可视化管线和渲染引擎的概念和流程,建议先阅读《VTK图形图像开发进阶》这本书稍微了解一下,并且根据里面的学习案例对VTK有一些了解。 VTK真的不是装好就能上手用的,相比之下OpenCV这种图像处理库真的好用。
本文主要参考文献【1】基于 VTK 和 QT 的层状地质体三维建模及可视化研究—姜弢、陈振振、徐学纯
【2】基于VTK技术的三维地层可视化研究_刘玉芳

目前,地质体三维数据模型总体上可分为线模型 、 表面模型 、 实体模型 、 面向对象的三维数据模型及混合数据模型五大类型 。 线模型的优点是集合关系明确,缺点是对于实体间关系表达及实现交 、并等叠加操作较困难 。 表面模型的优点是便于边界约束 、 显示和数据更新,缺点是空间分析难以进行 。实体模型的优点是便于空间操作和分析,缺点是占用空间较大,计算速度也较慢 。 面向对象的三维数据模型和混合数据模型分别综合了线 、 表面 、 实体模型的优缺点,但实现算法复杂 。[1]基于 VTK 和 QT 的层状地质体三维建模及可视化研究—姜弢、陈振振、徐学纯
本文采用表面模型和体模型混合建模的方式进行地质体三维建模 。采用面模型和体模型混合建模的原因是只有面模型不能够准确地描述层状地质体内部的信息,但是面模型可以对层状地质体的边界进行约束。其次,对每个地层顶面和底面用体模型进行填充,常用的体模型有四面体、三棱柱和六面体,其中四面体模型可以构造非常复杂的地层模型,但是由于四面体数据拓扑结构复杂,数据冗余量大,运算负荷大,对计算机的要求较高,故使用广义三棱柱进行填充。[1]基于 VTK 和 QT 的层状地质体三维建模及可视化研究—姜弢、陈振振、徐学纯

一、构建不规则三角网(TIN)

三棱柱构模原理是由上下两个不平行的两个TIN三角形面和三个竖直侧面四边形面所组成的空间单元。【2】
一般使用Delaunay三角剖分算法对空间中不规则的三维散点集合进行三角剖分。
VTK的vtkDelaunay2D类实现了二维三角剖分。该类的输入数据为一个vtkPointSet或其子类表示的三维空间点集,其输出是一个三角网格vtkPolyData数据。虽然输入的是三维数据,但是算法仅使用XY平面数据进行平面三角剖分,而忽略Z轴的数据。当然,也可以为vtkDelaunay2D设置投影变换从而在新的投影平面上进行三角剖分。

1.1 构建模拟的地层数据

由于手上没有实际测量得到的地层表面散点数据,故只能自己构建一些点来建立地层模型。
这里构建的散点都是规则的点,即确定地层表面在X和Y方向上的点数Nx,Ny,形成规则格网,即等间隔矩形网格,通过格网线之间的间隔来描述或定义,同一个坐标轴上格网线间隔值相同,不同轴向上的格网线间隔值可以不同。通过定义开始点及每个坐标方向上的增量来显示指定坐标。【2】。对于实际测量得到的地层表面数据,可以对其进行离散点格网化,就是对每一个岩层层面离散点进行格网剖分,每个数据点记录了剖分后格网点的平面坐标及高程,共三列,依次记录坐标X,坐标Y,高程Z。
使用插值算法将离散点,如反距离加权插值算法、克里金插值算、最小曲率方法等,具体的我也还没开始研究,因为现在手上没有实际的测量数据。

构建一层地层,包括上表面和下表面:

 vtkSmartPointer<vtkPoints> points=vtkSmartPointer<vtkPoints>::New();unsigned int GridSize_X = 10,GridSize_Y=10;//10*10个等间距的点,也可以使X和Y方向上的点间隔不同unsigned int id=0,num=0;double z=0;//先生成上表面点数据,在生成下表面点数据for(int i =0;i<2;i++){std::cout<<"level : "<<i<<endl;for (unsigned int x = 0; x < GridSize_X; x++){for (unsigned int y = 0; y < GridSize_Y; y++){z=i*(-5) + vtkMath::Random(0,1);id=points->InsertNextPoint(x, y, z);}}std::cout<<std::endl;}std::cout<<points->GetNumberOfPoints()<<std::endl;

把两个界面的数据用vtkPoints对象points存放。注意:顶面和底面数据点的x 和y值相同,不同的只有z值,通过Z值可以区分不同地层之间的距离以及是否存在尖灭。

1.2 Delaunay三角剖分

使用VTK的vtkDelaunay2D类实现了对地层表面散点数据二维三角网剖分,为什么使用二维?因为这里的顶面和底面数据点的x和y相同(其实就算不同也可以不用考虑Z,不过要分开两个面进行三角剖分),不同的是Z值,我们要的结果是把这些点数据相互连接生成三角形拓扑,而我们使用三角形作为三棱柱的两个三角面,故生成三角形实际与Z值高程无关,只需要使用x和y值就行,最后再连接起该点形成三角形.
。由于使用的是三棱柱作为体元,使用顶面中生成的三角形作为三棱柱体元的上三角形,对应底面中生成的三角形作为三棱柱体元的下三角形,把这两个三角形拓扑关系所对应的散点数据进行连接,即可构成一个三棱柱模型。

对于同一地层的顶面和底面数据点要分开进行Delaunay三角剖分,这里是在上下两个面的点数据X和Y相同的情况下,如果不分开进行三角剖分的话,可能只会对顶面或底面进行三角剖分;倘若是上下两个面的点数据X和Y不同的情况,那就更容易出问题了,因为Dealunay2D只对XY平面进行三角剖分,即算法此时可能会把上下两个面的点当成是一个面的,然后进行三角剖分,则上下两个面的点就连接成三角形了。

 //分离地层的顶部和底部地层表面数据点,本质是拷贝数据点到ceil和bottomvtkSmartPointer<vtkPoints> ceil = vtkSmartPointer<vtkPoints>::New();for (int i = 0; i < GridSize_X*GridSize_Y; ++i){auto point = points->GetPoint(i);ceil->InsertNextPoint(point);cout<<"ceil   point = "<<point[0]<<","<<point[1]<<","<<point[2]<<endl;}vtkSmartPointer<vtkPoints> bottom = vtkSmartPointer<vtkPoints>::New();for (int i = GridSize_X*GridSize_Y; i < points->GetNumberOfPoints(); ++i){auto point = points->GetPoint(i);bottom->InsertNextPoint(point);cout<<"bottom    point = "<<point[0]<<","<<point[1]<<","<<point[2]<<endl;}// Add the grid points to a polydata objectvtkSmartPointer<vtkPolyData> polydata=vtkSmartPointer<vtkPolyData>::New();polydata->SetPoints(points);vtkSmartPointer<vtkPolyData> ceil_polydata =vtkSmartPointer<vtkPolyData>::New();ceil_polydata->SetPoints(ceil);vtkSmartPointer<vtkPolyData> bottom_polydata =vtkSmartPointer<vtkPolyData>::New();bottom_polydata->SetPoints(bottom);// Triangulate the grid pointsvtkSmartPointer<vtkDelaunay2D> ceil_delaunay =vtkSmartPointer<vtkDelaunay2D>::New();ceil_delaunay->SetInputData(ceil_polydata);ceil_delaunay->Update();vtkSmartPointer<vtkDelaunay2D> bottom_delaunay =vtkSmartPointer<vtkDelaunay2D>::New();bottom_delaunay->SetInputData(bottom_polydata);bottom_delaunay->Update();//上下三角网combine two poly datavtkSmartPointer<vtkAppendPolyData> appendfilter = vtkSmartPointer<vtkAppendPolyData>::New();appendfilter->AddInputConnection(ceil_delaunay->GetOutputPort());appendfilter->AddInputConnection(bottom_delaunay->GetOutputPort());vtkSmartPointer<vtkPolyDataMapper> meshMapper =vtkSmartPointer<vtkPolyDataMapper>::New();meshMapper->SetInputConnection(appendfilter->GetOutputPort());

此时把meshMapper送入渲染引擎,便可以看到上下两个面三角剖分后的结果。

二、构建地质三棱柱体模型

1.生成三棱柱体元

目前按我查到的资料来看,构建三棱柱都需要用到插入点数据到vtkPoints对象时返回的ID值,id=points->InsertNextPoint(x, y, z); 返回该点在points中的索引。但是我比较迷惑,就是例如下面这种情况:

    unsigned int GridSize = 10;for (unsigned int x = 0; x < GridSize; x++){for (unsigned int y = 0; y < GridSize; y++){points->InsertNextPoint(x, y, vtkMath::Random(0,1));//返回该point的ID}}vtkSmartPointer<vtkWedge> wedge =vtkSmartPointer<vtkWedge>::New();//SetID的顺序必须是三棱柱的上三角形的三个点ID和下三角形的三个点IDwedge->GetPointIds()->SetId(0, 0);//第一个参数是三棱柱的6个点序号,第二个参数是vtkPoints对象中的点ID,就是插入是返回的那个wedge->GetPointIds()->SetId(1, 2);wedge->GetPointIds()->SetId(2, 20);wedge->GetPointIds()->SetId(3, 1);wedge->GetPointIds()->SetId(4, 3);wedge->GetPointIds()->SetId(5, 21);

注意:这里我比较迷惑的是为什么SetId()里的第二个参数就只用一个数字来表示ID就可以了,那系统是怎么确定这个数字代表的是哪个vtkPoints对象的点ID?经过我的实验发现,这个数字代表的ID貌似指定的是距离SetId()最近的在它之前插入vtkPoints对象的点的ID,那就类似与就近原则?那假设当前代码中有多个vtkPoints对象,我想利用前面几个vtkPoints对象的ID点来构建三棱柱怎么办?这个我暂时还没搞到答案,群里问了半天也没人回答,有大佬知道的可以评论一下,VTK的点ID管理,网上是真的找不到啥资料,这个问题折腾了我好久了。
而且由于这个问题没有得到解决,使用Delaunay2D生成的三角形我也没有办法知道每个三角形对应的点ID是多少,所以我构建三棱柱用的点ID就是vtkPoints对象中点插入后返回的ID。

这里我构建三棱柱就是按照这种“就近原则”,把构建三棱柱的代码紧跟在vtkPoints对象的点插入之后。ID是按点插入的顺序来确定的,构建三棱柱时需要注意,构造三棱柱的6个点的id都是我推理计算出来的。

/*** MakeWedge必须紧跟在地层表面数据生成或读入之后,然后利用其ID来构建三棱柱,同时对地层表面数据读入或生成的顺序有要求,先Y后X* 这个函数构建的是三棱柱集合* */
vtkSmartPointer<vtkUnstructuredGrid> MakeWedge(vtkSmartPointer<vtkPoints> points,unsigned int GridSize_X,unsigned int GridSize_Y)
{vtkSmartPointer<vtkUnstructuredGrid> ug =vtkSmartPointer<vtkUnstructuredGrid>::New();ug->SetPoints(points);vtkIdType p=0;//设置一个ID编号//每列GridSizeY-1个矩形格子,每行GridSizeX-1个矩形格子for(int i=1;i<GridSize_X;i++)//从矩形格子开始统计,一个矩形格子可以划分为两个三角形,{for(int j=1;j<GridSize_Y;j++){//先构造矩形格网的左下三棱柱//SetID的顺序必须是三棱柱的上三角形的三个点ID和下三角形的三个点IDvtkSmartPointer<vtkWedge> wedge1 =vtkSmartPointer<vtkWedge>::New();wedge1->GetPointIds()->SetId(0, p);wedge1->GetPointIds()->SetId(1, p+1);wedge1->GetPointIds()->SetId(2, p+GridSize_Y);//下三角形IDwedge1->GetPointIds()->SetId(3, GridSize_X*GridSize_Y+p);wedge1->GetPointIds()->SetId(4, GridSize_X*GridSize_Y+p+1);wedge1->GetPointIds()->SetId(5, GridSize_X*GridSize_Y+p+GridSize_Y);//添加三棱柱//if(p==4)ug->InsertNextCell(wedge1->GetCellType(), wedge1->GetPointIds());//先构造矩形格网的左下三棱柱vtkSmartPointer<vtkWedge> wedge2 =vtkSmartPointer<vtkWedge>::New();wedge2->GetPointIds()->SetId(0, p+1);wedge2->GetPointIds()->SetId(1, p+GridSize_Y+1);wedge2->GetPointIds()->SetId(2, p+GridSize_Y);//下三角形IDwedge2->GetPointIds()->SetId(3, GridSize_X*GridSize_Y+p+1);wedge2->GetPointIds()->SetId(4, GridSize_X*GridSize_Y+p+GridSize_Y+1);wedge2->GetPointIds()->SetId(5, GridSize_X*GridSize_Y+p+GridSize_Y);//if(p==-3)ug->InsertNextCell(wedge2->GetCellType(), wedge2->GetPointIds());p++;if(j==GridSize_Y-1)//点ID到达矩形网格最上边界之后,直接跳转到下一个IDp++;}}return ug;
}int main(int, char *[])
{vtkSmartPointer<vtkPoints> points=vtkSmartPointer<vtkPoints>::New();unsigned int GridSize_X = 10,GridSize_Y=10;unsigned int id=0,num=0;double z=0;//先生成上表面点数据,在生成下表面点数据for(int i =0;i<LEVEL;i++){std::cout<<"level "<<i<<endl;for (unsigned int x = 0; x < GridSize_X; x++){for (unsigned int y = 0; y < GridSize_Y; y++){z=i*(-5) + vtkMath::Random(0,1);//z=(i-0.5)*(GridSize_X-x);id=points->InsertNextPoint(x, y, z);}}std::cout<<std::endl;}std::cout<<points->GetNumberOfPoints()<<std::endl;//构建三棱柱集合vtkSmartPointer<vtkUnstructuredGrid> wedgeArray=MakeWedge(points,GridSize_X,GridSize_Y);

到这里这一层地层的不规则三角形(TIN)面和三棱柱体元就建立好了。想要在窗口中显示出来,还需要配置VTK的可视化管线和渲染引擎。

 vtkSmartPointer<vtkUnstructuredGrid> wedgeArray=MakeWedge(points,GridSize_X,GridSize_Y);// VisualizevtkSmartPointer<vtkNamedColors> WedgeColor =vtkSmartPointer<vtkNamedColors>::New();//三棱柱映射vtkSmartPointer<vtkDataSetMapper> wedgeMapper = vtkSmartPointer<vtkDataSetMapper>::New();wedgeMapper->SetInputData(wedgeArray);vtkSmartPointer<vtkActor> wedgeActor=vtkSmartPointer<vtkActor>::New();wedgeActor->SetMapper(wedgeMapper);wedgeActor->GetProperty()->SetColor(WedgeColor->GetColor3d("Banana").GetData());wedgeActor->GetProperty()->EdgeVisibilityOn();//显示三角形的边vtkSmartPointer<vtkRenderer> renderer =vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(wedgeActor);//显示三棱柱体元renderer->SetBackground(colors->GetColor3d("Mint").GetData());vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(renderer);vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =vtkSmartPointer<vtkRenderWindowInteractor>::New();renderWindowInteractor->SetRenderWindow(renderWindow);renderWindow->Render();renderWindowInteractor->Start();

总结

我是第一次使用VTK建模,完成这一层地层建模就花了我差不多两个多星期,虽然完成了,但是还是有很多疑惑还是没有解决,在查找问题的过程中我也发现,CSDN上VTK对应的文章挺多的,但是都不怎么系统,遇到一些问题,想问问别人却几年都没有回应,VTK贴吧更是冷清,在QQ上找了个vtk开发群700多个人,在线的不到100,会帮忙回答问题的更是少之又少。这一点和OSG那边真的形成鲜明对比,OSG那边好像是有个专门的使用OSG开发的国内公司在管理,群里面也是他们在帮忙解答一些问题,而且群里人很多,问一个问题基本马上就有回复,还有出一些中文教程。唉,要是VTK也有这样的组织就好了。

VTK实现三维地质建模相关推荐

  1. 利用计算机绘制地质图的思路和方法,基于平面地质图的三维地质建模方法研究...

    摘要: 平面地质图综合了地质野外勘察工作成果与地质专家知识,揭示了地区的岩石.地层和地质构造等信息,是人们了解区域地质最易获取和最直接的数据源.研究基于平面地质图的三维地质体建模方法,能够有效地解决缺 ...

  2. 三维地质建模数据处理

    三维地质建模计算在地质工程.地球物理.矿产勘查等领域获得了广泛的应用,常用软件包括GOCAD.Surpac.XModel.DMine等.通过三维地质建模,既可以表达空间几何对象,也可以表现空间属性分布 ...

  3. GOCAD 2009 完整版功能强大的三维地质建模软件

    为什么80%的码农都做不了架构师?>>>    GOCAD 2009 完整版功能强大的三维地质建模软件 GOCAD(Geological Object Computer Aided ...

  4. 基于点、线数据三维地质建模方法

    ** 基于点.线数据三维地质建模方法 ** 1.前言   作者本人计算机出身,近一年多负责公司地质建模项目项目工作,项目关联计算机.采矿行业相关技术.本文章主要介绍采矿行业地质建模及模型更新相关数字化 ...

  5. 三维地质建模基本原理、实现流程、应用领域

    三维地质建模计算在地质工程.地球物理.矿产勘查等领域获得了广泛的应用,常用软件包括GOCAD.Surpac.XModel.DMine等.通过三维地质建模,既可以表达空间几何对象,也可以表现空间属性分布 ...

  6. ProEssentials实时绘制三维地质建模、科学领域三维建模仅需毫秒

    ProEssentials实时绘制3D/2D图适用于Winforms 图表, WPF 图表, C++/MFC/VCL 图表. 用过的客户都说图表快速.稳定.强健且简单.官方称应用人工智能的渲染技术.专 ...

  7. 三维地质建模系统-整体思路

    <script type="text/JavaScript"></script> <script src="http://a.alimama ...

  8. 菜鸟编三维地质建模系统-国外资源概览(网格化部分)

    三维地质建模系统主要分为三大块: 一 三维可视化(利用OPENGL实现),包括拓扑关系分析.3D交互修改编辑 二 三维建模(建模的方式多种多样,2d.2.5d.3d...) 三 网格化(网格生成,包括 ...

  9. 基于QGIS与畅图云进行三维地质建模及云发布

    1. 剖面数据处理 原始勘探设计AutoCAD数据 导入QGIS中进行分层处理 2.三维地质建模 输入钻孔数据.shp剖面数据. Import_well导入钻孔数据:Import_profile2d导 ...

  10. 菜鸟编三维地质建模系统-整体思路

    接手三维地质建模系统编制的项目时,我只是一个很菜鸟的业余编程爱好者,但我对于这个项目很感兴趣,不管结果如何,参与这个项目的过程就很有意思. 语言选择:c++.选择c++是考虑到c++可以向下兼容c,同 ...

最新文章

  1. 微型计算机步进电机控制,步进电机的微型计算机控制
  2. linux下监控用户的操作记录
  3. 纯JDBC系统的开发随想
  4. 精通Android自定义View(十九)自定义圆形炫彩加载转圈效果
  5. MIUI11新版本推送,小米10 Pro跑分轻松突破60万
  6. 为导入的项目更改cvs用户名
  7. 8/7排位赛,codeforces501
  8. [转帖] bat方式遍历目录内的文件
  9. 华为s5720默认用户名和密码_华为交换机s5720s-28p-LI-AC默认用户名和密码是什么?...
  10. 数据产品-广告投放数据打通
  11. Ubuntu 18.04安装c++版OpenCV4
  12. Java之将GB2312编码转化为汉字
  13. java 重写或者覆父类方法的使用throws 抛出异常,为什么要小于父类父类,java面试点
  14. HDU - 3966(树链剖分)
  15. ffmpeg合并mp4脚本
  16. ios系统怎么编辑html,word转html ios 可编辑
  17. Nginx之一:Nginx的编译安装
  18. 不需要解压使用对pdf文件进行压缩
  19. 阿里云盘进场,安全星球凭什么成为云盘界的一股清流
  20. USB学习入门(三)------众里寻他千百度(windows)

热门文章

  1. 信息学奥赛一本通在线评测平台的一些bug
  2. 体育教学硕士毕业论文题目
  3. 【论文笔记】使用物理原理和领域知识进行无标注的监督学习
  4. git切换到旧版本_git如何更新到指定版本,然后再更新到最新版本
  5. “海选优品,泉网打尽”胡海泉抖音直播带货首秀告捷 柏厨集成家居塔奇、I-LOFT惊艳亮相
  6. 为Linux安装虚拟PDF打印机
  7. Vue表情包输入组件
  8. matlab怎么画两个自变量的图_横道图怎么画?免费使用的项目管理软件
  9. cmos逻辑门传输延迟时间_组合逻辑电路详解、实现及其应用
  10. 软件著作权-说明书范本