VTK(Activiz)场景应用:将离散点构建三角网、等值线、颜色渲染、等值线值标注

本文介绍了如何使用VTK库在C#(Activiz版本)中,针对离散点数据进行三角网构建、颜色渲染和等值线生成,以及如何对等值线值进行标注,提供了两种不同的标量处理思路和详细步骤实例。
摘要由CSDN通过智能技术生成

原文链接:https://www.cnblogs.com/billygisboy/p/17415588.html

1 概括

VTK将离散点构建三角网并进行颜色渲染,生成等值线,对等值线的值进行标注

现阶段了解下,对已有离散点进行三角剖分构建三角网,并进行具有实际含义(降雨量、含水量)的属性颜色渲染、等值线构建、等值线值的标注有如下思路。特别感谢前辈“硫酸亚铜”的经验分享,前辈的博客基于VTK的C++版本进行,个人开发采用的是VTK的C#版本(Activiz),现将实现总结如下。

我的Demo实现效果C#版本(Activiz):解释均在代码注释中

(1)以结点为单位构建标量思路

(2)以Cell为单位构建标量思路

(两个思路构建的颜色过渡情况不一致是因为标量设置的值不一样,前提数据都是一样的,可见下图的网格显示)

2 数据前提

**必备数据:**离散点数据(X1,Y1,Z1)、(X2,Y2,Z2)、(X3,Y3,Z3)…
**中间数据:**离散点三角剖分拓扑关系(即哪几个点构成了哪一个三角形),常用数据组成为(三角形序号,点1序号,点2序号,点3序号)

离散点数据就是我们最最基础的源数据了,这个是不可或缺的,也就是作为已知数据。对于中间数据(三角剖分拓扑关系数据)如果不是已知数据,我们有两种方案进行生成:
(1)基于Triangle工具进行三角剖分生成 (我使用的Triangle工具)
(2)基于VTK自身的Delaunay多边形过滤器(vtkDelaunay2D/vtkDelaunay3D)对点集(VtkPoints)进行过滤生成
现阶段中间数据作为已知数据进行处理。

3 构建思路

针对于我们有离散点和离散点三角剖分拓扑关系的数据前提去构建等值线和标注,有两种构建模式:
(1)构建点集——构建Cell单元集(拓扑关系)——构建结点标量集——构建模型
(2)构建点集——构建Cell单元集(拓扑关系)——构建Cell标量集——构建模型
第一种方案是将每一个结点看作一个标量单位,适用于对点元模型的渲染,即一个区域由一堆点元控制,每个点元(结点)有一个数据属性,例如一口井的水位值、一座烟囱的排放量…
第二种则将每一个Cell单元看作一个标量单位,适用于面元模型的渲染,即一片区域被划分为了一个个的单元且每一个单元有一个数据属性,例如每个单元的降雨量、事故发生率…

4 构建过程

4.1 两种思路的公用数据构建部分

第一步:将离散点构建成点集 vtkPoints

			/*构建网格结点*/
            vtkPoints points = new vtkPoints();
            points.InsertPoint(1, 0, 0, 0);
            points.InsertPoint(2, 1, 0, 0);
            points.InsertPoint(3, 2, 0, 0);
            points.InsertPoint(4, 0, 1, 0);
            points.InsertPoint(5, 1, 1, 0);
            points.InsertPoint(6, 2, 1, 0);
            points.InsertPoint(7, 0, 2, 0);
            points.InsertPoint(8, 1, 2, 0);
            points.InsertPoint(9, 2, 2, 0);
            points.InsertPoint(10, 3, 2, 0);
            points.InsertPoint(11, 3, 1, 0);

第二步:构建网格单元(即拓扑关系) vtkCellArray

            /*构建网格单元*/
            vtkIdList idList1 = new vtkIdList();
            idList1.InsertNextId(1);
            idList1.InsertNextId(2);
            idList1.InsertNextId(4);
            vtkIdList idList2 = new vtkIdList();
            idList2.InsertNextId(4);
            idList2.InsertNextId(5);
            idList2.InsertNextId(7);
            vtkIdList idList3 = new vtkIdList();
            idList3.InsertNextId(2);
            idList3.InsertNextId(5);
            idList3.InsertNextId(4);
            vtkIdList idList4 = new vtkIdList();
            idList4.InsertNextId(3);
            idList4.InsertNextId(6);
            idList4.InsertNextId(5);
            vtkIdList idList5 = new vtkIdList();
            idList5.InsertNextId(2);
            idList5.InsertNextId(3);
            idList5.InsertNextId(5);
            vtkIdList idList6 = new vtkIdList();
            idList6.InsertNextId(6);
            idList6.InsertNextId(9);
            idList6.InsertNextId(8);
            vtkIdList idList7 = new vtkIdList();
            idList7.InsertNextId(5);
            idList7.InsertNextId(6);
            idList7.InsertNextId(8);
            vtkIdList idList8 = new vtkIdList();
            idList8.InsertNextId(5);
            idList8.InsertNextId(8);
            idList8.InsertNextId(7);
            vtkIdList idList9 = new vtkIdList();
            idList9.InsertNextId(9);
            idList9.InsertNextId(6);
            idList9.InsertNextId(11);
            vtkIdList idList10 = new vtkIdList();
            idList10.InsertNextId(9);
            idList10.InsertNextId(11);
            idList10.InsertNextId(10);

            vtkCellArray cellArray = new vtkCellArray();
            cellArray.InsertNextCell(idList1);
            cellArray.InsertNextCell(idList2);
            cellArray.InsertNextCell(idList3);
            cellArray.InsertNextCell(idList4);
            cellArray.InsertNextCell(idList5);
            cellArray.InsertNextCell(idList6);
            cellArray.InsertNextCell(idList7);
            cellArray.InsertNextCell(idList8);
            cellArray.InsertNextCell(idList9);
            cellArray.InsertNextCell(idList10);

4.2 两种思路的不同构建部分

4.2.1 结点标量构建思路

第三步:设置结点标量 vtkDataArray(根据标量数据类型选择其子类,此处选的Float)

            /*设置结点标量*/
            vtkFloatArray pointScalar = new vtkFloatArray();
            //这个插入方式必须和单元集(vtkCellArray)的插入方式一致,单元集插入Cell单元采用InsertNextCell自动递增插入
            pointScalar.InsertNextValue(1); //1
            pointScalar.InsertNextValue(2); //2
            pointScalar.InsertNextValue(3); //3
            pointScalar.InsertNextValue(2); //4
            pointScalar.InsertNextValue(3); //5
            pointScalar.InsertNextValue(4); //6
            pointScalar.InsertNextValue(3); //7
            pointScalar.InsertNextValue(4); //8
            pointScalar.InsertNextValue(5); //9
            pointScalar.InsertNextValue(4); //10
            pointScalar.InsertNextValue(5); //11

            double rangeMin = pointScalar.GetRange()[0];
            double rangeMax = pointScalar.GetRange()[1];

第四步:构建表面几何模型

            /*构建表面几何模型*/
            //PolyData
            vtkPolyData surfacePolydata = vtkPolyData.New();
            surfacePolydata.SetPoints(points);
            surfacePolydata.SetPolys(cellArray); //设置数据类型为多边形,并设置多边形单元数据
            surfacePolydata.GetPointData().SetScalars(pointScalar); //设置点集标量
            //Actor:表面1 构建无规则网格单元的表面模型,效果是网格单元中的一个个面片,有颜色过渡
            vtkDataSetMapper surfaceMapper = new vtkDataSetMapper();
            surfaceMapper.SetInput(surfacePolydata);
            surfaceMapper.ScalarVisibilityOn(); //开启标量颜色渲染
            surfaceMapper.SetScalarRange(rangeMin, rangeMax);
            //surfaceMapper.SetLookupTable(vtkLookupTable lookupTable); //此处可以根据标量范围设置自己需要的颜色映射表,其它的制图器Mapper也一样
            vtkActor surfaceActor = new vtkActor();
            surfaceActor.SetMapper(surfaceMapper);

第五步:构建等值线

            /*构建等值线*/
            //Fileter:等值线/面过滤器
            vtkContourFilter contourFilter = new vtkContourFilter();
            contourFilter.SetInput(surfacePolydata);
            contourFilter.GenerateValues(8, rangeMin, rangeMax);
            contourFilter.Update();
            //数据处理类:用于将离散的三角面片拼接为连续的等值面
            vtkStripper stripper = new vtkStripper();
            stripper.SetInput(contourFilter.GetOutput());
            stripper.Update();
            //Mapper
            vtkDataSetMapper contourMapper = new vtkDataSetMapper();
            contourMapper.SetInput(stripper.GetOutput());
            //Actor
            vtkActor isolineActor = new vtkActor();
            isolineActor.SetMapper(contourMapper);

第六步:构建等值线标注

            /*等值线值标注*/
            //构建等值线标注几何数据
            //long linesCount = stripper.GetOutput().GetNumberOfLines(); //等值线的数目
            vtkPoints isolinePoints = stripper.GetOutput().GetPoints(); //等值线的点集
            vtkCellArray isolineCells = stripper.GetOutput().GetLines(); //等值线的线单元数组
            vtkDataArray isolineScalars = stripper.GetOutput().GetPointData().GetScalars(); //等值线的点标量数组
            //等值线标注Label数据
            vtkPolyData labelPolyData = new vtkPolyData(); //标注点几何数据
            vtkPoints labelPoints = new vtkPoints(); //标注点集
            vtkDoubleArray labelScalars = new vtkDoubleArray(); //标注点标量数组
            labelScalars.SetNumberOfComponents(1);
            //labelScalars.SetName("Isovalues");
            //构建等值线标注Label数据,此处将每一个等值线进行遍历,获取线上的一点作为等值线的标注点
            vtkIdList isoCell = new vtkIdList();
            while (isolineCells.GetNextCell(isoCell) > 0)
            {
                long idCount = isoCell.GetNumberOfIds(); //获取这条等值线单元的点个数
                //long samplePointIndex = (long)vtkMath.Random(0, idCount); //随机取该等值线上一个点
                long labelPointId = isoCell.GetId(idCount / 2); //获取该点的id作为标记点。此方法是根据点数量顺序排序序号Index获取,获取到这个cell中的指定序号Index的点的vtkId(个人认为)

                double[] midPoint = isolinePoints.GetPoint(labelPointId); //获取该点的坐标

                labelPoints.InsertNextPoint(midPoint[0], midPoint[1], midPoint[2]); //插入到标注点集
                labelScalars.InsertNextTuple1(isolineScalars.GetTuple1(labelPointId)); //取该点的标量值插入到标注点标量数组
            }
            labelPolyData.SetPoints(labelPoints); //设置标注点集
            labelPolyData.GetPointData().SetScalars(labelScalars); //设置点数据的标量数组
            labelPolyData.Update();
            //Mapper
            vtkLabeledDataMapper labelMapper = new vtkLabeledDataMapper();
            //labelMapper.SetFieldDataName("Isovalues");
            labelMapper.SetInput(labelPolyData);
            labelMapper.SetLabelModeToLabelScalars();
            labelMapper.SetLabelFormat("%6.2f");
            labelMapper.GetLabelTextProperty().SetColor(0, 0, 1);
            //Actor
            vtkActor2D isoLabelActor = new vtkActor2D();
            isoLabelActor.SetMapper(labelMapper);

第七步:添加角色到场景

			SceneControl.AddActor(surfaceActor);
            SceneControl.AddActor(isolineActor);
            SceneControl.AddActor2D(isoLabelActor);
            SceneControl.RefreshScene(true);

这个SceneControl就是vtkSceneControl,我是基于C#版本的VTK进行开发的,为了便于开发工作,将其控件进行了封装。

4.2.2 单元标量构建思路

第三步:设置单元标量 vtkDataArray(根据标量数据类型选择其子类,此处选的Float)

            /*设置单元标量*/
            vtkFloatArray cellScalar = new vtkFloatArray();
            //这个插入方式必须和单元集(vtkCellArray)的插入方式一致,单元集插入cell单元采用InsertNextCell自动递增插入
            cellScalar.InsertNextValue(1); //1
            cellScalar.InsertNextValue(2); //2
            cellScalar.InsertNextValue(2); //3
            cellScalar.InsertNextValue(3); //4
            cellScalar.InsertNextValue(2); //5
            cellScalar.InsertNextValue(4); //6
            cellScalar.InsertNextValue(3); //7
            cellScalar.InsertNextValue(3); //8
            cellScalar.InsertNextValue(3); //9
            cellScalar.InsertNextValue(4); //10

            double rangeMin = cellScalar.GetRange()[0];
            double rangeMax = cellScalar.GetRange()[1];

第四步:构建表面几何模型

            /*构建表面模型:效果是网格单元中的一个个面片,每个面片有这个cell标量对应的色值*/
            //Data:非结构化网格对象
            vtkUnstructuredGrid grid = new vtkUnstructuredGrid();
            grid.SetPoints(points);
            grid.SetCells(new vtkTriangle().GetCellType(), cellArray); //因为后续用到了三角单元数据处理类,处理的数据都是三角形,所以直接使用确定的cell类型
            grid.GetCellData().SetScalars(cellScalar); //设置标量
            //Mapper
            vtkDataSetMapper surfaceMapper = new vtkDataSetMapper();
            surfaceMapper.SetInput(grid);
            //surfaceMapper.ScalarVisibilityOn();
            surfaceMapper.SetScalarRange(rangeMin, rangeMax);
            //Actor
            vtkActor surfaceActor = new vtkActor();
            surfaceActor.SetMapper(surfaceMapper);


            ///vtkCellDataToPointData
            ///官方说明:
            ///(1)是一个用于转换单元格数据的过滤器
            ///(2)它将每个单元指定的数据转换为点数据(即在单元点指定的数据)
            ///(3)变换方法是基于使用特定点对所有单元的数据值求平均值,也可以选择将输入单元格数据传递到输出
            ///个人理解/问题:
            ///(1)为什么经过vtkCellDataToPointData处理后产生的模型颜色会均匀过渡?该工具类将grid的单元数据进行了处理,将标量在各个点进行了均匀的计算赋值(插值)

            /*构建表面模型:效果是网格单元中的一个个面片,但通过cell转点,实现了颜色的均匀过渡*/
            //Data:将构建的非结构化网格对象的每个单元转换为结点
            vtkCellDataToPointData cellDataToPointData = new vtkCellDataToPointData();
            cellDataToPointData.SetInput(grid);
            cellDataToPointData.PassCellDataOn();
            cellDataToPointData.Update();
            //Mapper
            vtkDataSetMapper surfaceMapper2 = new vtkDataSetMapper();
            surfaceMapper2.SetInput(cellDataToPointData.GetOutput());
            //surfaceMapper2.SetScalarModeToUsePointData();
            //surfaceMapper2.ScalarVisibilityOn();
            surfaceMapper2.SetScalarRange(rangeMin, rangeMax);
            //Actor
            vtkActor surfaceActor2 = new vtkActor();
            surfaceActor2.SetMapper(surfaceMapper2);

第五步:构建等值线

            /*构建等值线*/
            //等值线/面过滤器
            vtkContourFilter contourFilter = new vtkContourFilter();
            contourFilter.SetInput(cellDataToPointData.GetOutput());
            contourFilter.GenerateValues(8, rangeMin, rangeMax);
            contourFilter.Update();
            //用于将离散的三角面片拼接为连续的等值面
            vtkStripper stripper = new vtkStripper();
            stripper.SetInput(contourFilter.GetOutput());
            stripper.Update();
            //Actor:等值线
            vtkDataSetMapper contourMapper = new vtkDataSetMapper();
            contourMapper.SetInput(stripper.GetOutput());
            vtkActor isolineActor = new vtkActor();
            isolineActor.SetMapper(contourMapper);

第六步:构建等值线标注

            /*等值线值标注——构建等值线标注几何数据*/
            //获取等值线数据
            //long linesCount = stripper.GetOutput().GetNumberOfLines(); //等值线的数目
            vtkPoints isolinePoints = stripper.GetOutput().GetPoints(); //等值线的点集
            vtkCellArray isolineCells = stripper.GetOutput().GetLines(); //等值线的线单元数组
            vtkDataArray isolineScalars = stripper.GetOutput().GetPointData().GetScalars(); //等值线的点标量数组
            //Data:等值线标注Label数据
            vtkPolyData labelPolyData = new vtkPolyData(); //标注点几何数据
            vtkPoints labelPoints = new vtkPoints(); //标注点集
            vtkDoubleArray labelScalars = new vtkDoubleArray(); //标注点标量数组
            //labelScalars.SetNumberOfComponents(1);
            //labelScalars.SetName("Isovalues");
            //构建等值线标注Label数据,此处将每一个等值线进行遍历,获取线上的一点作为等值线的标注点
            vtkIdList isoCell = new vtkIdList();
            while (isolineCells.GetNextCell(isoCell) > 0)
            {
                long idCount = isoCell.GetNumberOfIds(); //获取这条等值线单元的点个数
                //long samplePointIndex = (long)vtkMath.Random(0, idCount); //随机取该等值线上一个点
                long labelPointId = isoCell.GetId(idCount / 2); //获取该点的id作为标记点。此方法是根据点数量顺序排序序号Index获取,获取到这个cell中的指定序号Index的点的vtkId(个人认为)

                double[] midPoint = isolinePoints.GetPoint(labelPointId); //获取该点的坐标

                labelPoints.InsertNextPoint(midPoint[0], midPoint[1], midPoint[2]); //插入到标注点集
                labelScalars.InsertNextValue(isolineScalars.GetTuple1(labelPointId)); //取该点的标量值插入到标注点标量数组
            }
            labelPolyData.SetPoints(labelPoints); //设置标注点集
            labelPolyData.GetPointData().SetScalars(labelScalars); //设置点数据的标量数组
            //Mapper
            vtkLabeledDataMapper labelMapper = new vtkLabeledDataMapper();
            //labelMapper.SetFieldDataName("Isovalues");
            labelMapper.SetInput(labelPolyData);
            labelMapper.SetLabelModeToLabelScalars();
            labelMapper.SetLabelFormat("%6.2f");
            labelMapper.GetLabelTextProperty().SetColor(0, 0, 1);
            //Actor:等值线标注,采用二维角色
            vtkActor2D isoLabelActor = new vtkActor2D();
            isoLabelActor.SetMapper(labelMapper);

第七步:添加角色到场景

			//SceneControl.AddActor(surfaceActor);
            SceneControl.AddActor(surfaceActor2);
            SceneControl.AddActor(isolineActor);
            SceneControl.AddActor2D(isoLabelActor);
            SceneControl.RefreshScene(true);

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VTK中提取等面的等值线,可以使用vtkContourFilter类。vtkContourFilter是一种数据过滤器,可以从输入数据集中提取等值线,并生成等面。以下是使用vtkContourFilter提取等面的等值线C++代码实现: ```c++ #include <vtkSmartPointer.h> #include <vtkContourFilter.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkXMLImageDataReader.h> int main(int argc, char* argv[]) { // 读取图像数据 vtkSmartPointer<vtkXMLImageDataReader> reader = vtkSmartPointer<vtkXMLImageDataReader>::New(); reader->SetFileName("volume.vti"); reader->Update(); // 提取等面的等值线 vtkSmartPointer<vtkContourFilter> contourFilter = vtkSmartPointer<vtkContourFilter>::New(); contourFilter->SetInputConnection(reader->GetOutputPort()); contourFilter->SetValue(0, 200); // 等参数为200 // 显示等值线 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(contourFilter->GetOutputPort()); mapper->ScalarVisibilityOff(); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); // 创建渲染器和窗口 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); // 创建交互器并启动渲染 vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); interactor->Initialize(); renderWindow->Render(); interactor->Start(); return 0; } ``` 在上面的代码中,我们首先使用vtkXMLImageDataReader读取了一个VTI格式的图像数据集。然后,我们使用vtkContourFilter提取了等面的等值线,并将其输出连接到vtkPolyDataMapper的输入端。最后,我们创建了一个vtkActor对象,并将vtkPolyDataMapper设置为其Mapper属性。我们使用vtkRenderWindow和vtkRenderer显示了等值线,并使用vtkRenderWindowInteractor启动了渲染

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值