网格的一般概念集成了许多不同的元素。原则上可以为每个这样的元素使用独立的类型。泛型编程中用于指定概念中涉及的许多不同类型的机制称为traits。它们基本上是与当前类交互的所有类型的列表。
网格通过三个参数模板化。到目前为止,我们只讨论了两个,即像素类型和维度。第三个参数是一个提供网格所需特征集的类。当省略第三个参数时,使用默认的类。这个默认类是itk::DefaultStaticMeshTraits。如果您想定制网格使用的类型,接下来的方法是修改默认特征,并将它们作为网格类实例化的第三个参数提供。有两种方法可以实现:
- 第一个是使用现有的DefaultStaticMeshTraits类。该类本身模板化了6个参数。定制这些参数可以提供足够的灵活性来定义一种非常特定的网格。
- 第二种方法是从头编写一个traits类,在这种情况下,最简单的方法是将DefaultStaticMeshTraits复制到另一个文件中并编辑它的内容。这里只演示了第一种方法。除非熟悉泛型编程,否则不建议使用这种方法
定制网格的第一步是包含网格的头文件及其静态特性:
#include "itkMesh.h"
#include "itkDefaultStaticMeshTraits.h"
然后通过选择六个模板参数中的每个参数的类型来实例化MeshTraits类。它们是有序的:
- PixelType。与点相关联的类型。
- PointDimension。嵌入网格的空间的维数。
- MaxTopologicalDimension。网格单元的最高维数。
- CoordRepType。用于表示空间坐标的类型。
- InterpolationWeightType。用于表示插值权重的类型。
- CellPixelType。与单元格关联的类型。
下面为每个元素定义类型和值。例如,下面的代码将使用3D空间中的点作为网格的节点。
- 单元格的最大维数将是2,即表面(表层)。
- 与点关联的数据类型被定义为一个四维向量。该类型可以表示四类分割方法的成员值。
- 为单元选择的值是4×3矩阵,例如,成员值可以对空间坐标求导。
- 最后选用double类型来表示网格点上的空间坐标和用于插值值的权重。
const unsigned int PointDimension = 3; //三维点
const unsigned int MaxTopologicalDimension = 2;//单元格的最大维数将是2,即表面(表层)。
typedef itk::Vector<double,4> PixelType;//与点关联的数据类型被定义为一个四维向量
typedef itk::Matrix<double,4,3> CellDataType;//单元选择的值是4×3矩阵
typedef double CoordinateType;
typedef double InterpolationWeightType;
//设置特征类参数
typedef itk::DefaultStaticMeshTraits< PixelType, PointDimension, MaxTopologicalDimension, CoordinateType, InterpolationWeightType, CellDataType > MeshTraits;
//设置网格参数
typedef itk::Mesh< PixelType, PointDimension, MeshTraits > MeshType;
使用从网格中获取的特征来实例化itk::LineCell :
typedef MeshType::CellType CellType;
typedef itk::LineCell< CellType > LineType;
//创建一个网格并在上面插入一些点。注意点的尺寸与网格的尺寸匹配。
//在这里,我们插入一个点序列,它看起来像log()函数的图形。
MeshType::Pointer mesh = MeshType::New();
typedef MeshType::PointType PointType;
PointType point;
const unsigned int numberOfPoints = 10;
for(unsigned int id=0;
id<numberOfPoints; id++)
{
point[0] = 1.565; // Initialize points here
point[1] = 3.647; // with arbitrary values
point[2] = 4.129;
mesh->SetPoint( id, point );
}
//通过使用点标识符,将创建一组行单元格并与现有的点关联。
//在这个简单的例子中,可以从单元格标识符推导出点标识符,因为行单元格的排序方式相同。
//注意,在上面的代码中,分配给点组件的值是任意的。在更实际的示例中,这些值将从另一个源计算。
CellType::CellAutoPointer line;
const unsigned int numberOfCells = numberOfPoints-1;
for(unsigned int cellId=0; cellId<numberOfCells; cellId++)
{
///CellAutoPointer通过使用TakeOwnership()方法获取接收的指针的所有权。
line.TakeOwnership( new LineType );
//尽管这看起来很冗长,但它是必要的,以便从代码中明确表明自动发送器承担内存释放的责任。
line->SetPointId( 0, cellId ); // first point
line->SetPointId( 1, cellId+1 ); // second point
mesh->SetCell( cellId, line ); // insert the cell
}
//使用SetCellData()方法将与单元格关联的数据插入到网格中。它要求用户提供一个标识符和要插入的值。标识符应该匹配插入的一个单元格。
//在这个简单的示例中,单元格标识符的方形被用作单元格数据。注意在赋值中使用了对PixelType的静态转换。
for(unsigned int cellId=0; cellId<numberOfCells; cellId++)
{
CellDataType value;
mesh->SetCellData( cellId, value );
}
可以使用GetCellData()方法从网格中读取单元格数据。它要求用户提供要检索数据的单元格的标识符。用户还应该提供一个有效的指针,指向可以复制数据的位置。
for(unsigned int cellId=0; cellId<numberOfCells; cellId++)
{
CellDataType value;
mesh->GetCellData( cellId, &value );
std::cout << "Cell " << cellId << " = " << value << std::endl;
}
SetCellData()或GetCellData()都不是访问单元格数据的有效方法。
//通过使用CellDataContainer内建的迭代器,可以实现对单元格数据的有效访问
typedef MeshType::CellDataContainer::ConstIterator CellDataIterator;
CellDataIterator cellDataIterator = mesh->GetCellData()->Begin();
CellDataIterator end = mesh->GetCellData()->End();
while( cellDataIterator != end )
{
CellDataType cellValue = cellDataIterator.Value();
std::cout << cellValue << std::endl;
++cellDataIterator;
}