为了方便访问特定的单元类型,itk::Mesh中内置了一个机制。该机制基于Visitor Pattern。
- 该模式旨在促进遍历共享公共基类的异构对象列表的过程。
//使用CellVisitor机制的第一个要求是包含CellInterfaceVisitor头文件
#include "itkCellInterfaceVisitor.h"
typedef float PixelType;
typedef itk::Mesh< PixelType, 3 > MeshType;
typedef MeshType::CellType CellType;
typedef itk::VertexCell< CellType > VertexType;
typedef itk::LineCell< CellType > LineType;
typedef itk::TriangleCell< CellType > TriangleType;
typedef itk::TetrahedronCell< CellType > TetrahedronType;
/*
然后,应该声明一个定制的CellVisitor类。
在这个特定的示例中,visitor类仅用于处理三角类型单元格。实际上,该类可以为各种单元格类型提供visit()方法,这得益于C++函数的重载
声明visitor类的唯一要求是它必须提供一个名为Visit()的方法。
*/
//下面的代码演示了一个最小单元访问器类CustomTriangleVisitor。
class CustomTriangleVisitor
{
public: typedef itk::TriangleCell<CellType> TriangleType;
public: void Visit(unsigned long cellId, TriangleType * t )
{
std::cout << "Cell # " << cellId << " is a TriangleType ";
std::cout << t->GetNumberOfPoints() << std::endl;
}
};
/*
这个新定义的类现在将用于实例化单元格访问器。
在这个特定的示例中,我们创建了一个类CustomTriangleVisitor
当网格遍历单元格时,每当发现一个三角形单元格时,就会调用这个类。
*/
typedef itk::CellInterfaceVisitorImplementation
<
/*
请注意,实际的CellInterfaceVisitorImplementation模板化
在PixelType、CellTraits、要访问的CellType以及用所定义的Visitor类上完成。
*/
PixelType,
MeshType::CellTraits,
TriangleType,
CustomTriangleVisitor
> TriangleVisitorInterfaceType;
//现在可以使用对其New()方法的常规调用创建访问者实现类,并将结果赋值给itk::SmartPointer。
TriangleVisitorInterfaceType::Pointer triangleVisitor =
TriangleVisitorInterfaceType::New();
//可以通过这种方式配置许多不同的访问者。
//所有访问者的集合可以在为网格提供的MultiVisitor类中注册。
//MultiVisitor类的一个实例将遍历单元格,并在遇到适当的单元格类型时将操作委托给每个注册的访问者
typedef CellType::MultiVisitor CellMultiVisitorType;
CellMultiVisitorType::Pointer multiVisitor = CellMultiVisitorType::New();
//使用AddVisitor()方法在网格中注册Visitor。
multiVisitor->AddVisitor( triangleVisitor );
//最后,通过调用itk::Mesh上的Accept()方法来触发单元格的迭代。
mesh->Accept( multiVisitor );
/*
Accept()方法将遍历所有单元格,对于每个单元格,它将邀请MultiVisitor尝试对单元格进行操作。
如果没有访问者对当前单元格类型感兴趣,则忽略并跳过该单元格。
*/
下面的部分演示了在itk::Mesh上使用单元访问器的一个实际示例。
- 这里定义了一组不同的访问者,每个访问者都与特定类型的单元格关联。所有的访问者都在传递给网格的多访问者类中注册
#include "itkCellInterfaceVisitor.h"
typedef float PixelType;
typedef itk::Mesh< PixelType, 3 > MeshType;
typedef MeshType::CellType CellType;
typedef itk::VertexCell< CellType > VertexType;
typedef itk::LineCell< CellType > LineType;
typedef itk::TriangleCell< CellType > TriangleType;
typedef itk::TetrahedronCell< CellType > TetrahedronType;
下面的顶点访问器只打印出与单元格关联的点的标识符。
- 注意,单元格使用无参的GetPointId()方法。此方法仅在VertexCell上定义。
class CustomVertexVisitor
{
public:
void Visit(unsigned long cellId, VertexType * t )
{
std::cout << "cell " << cellId << " is a Vertex " << std::endl;
std::cout << " associated with point id = ";
std::cout << t->GetPointId() << std::endl;
}
};
下面的行Visitor计算行长度。
- 注意,这个访问者稍微复杂一些,因为它需要访问实际的网格,以便从行单元格返回的点标识符中获取点坐标。
- 这是通过持有一个指针到网格和查询网格的每个时间点坐标来完成的。在本例中,网格指针是用SetMesh()方法设置的。
class CustomLineVisitor
{
public: CustomLineVisitor():m_Mesh( 0 ) {}
void SetMesh( MeshType * mesh )
{ m_Mesh = mesh; }
void Visit(unsigned long cellId, LineType * t )
{
std::cout << "cell " << cellId << " is a Line " << std::endl;
LineType::PointIdIterator pit = t->PointIdsBegin();
MeshType::PointType p0;
MeshType::PointType p1;
m_Mesh->GetPoint( *pit++, &p0 );
m_Mesh->GetPoint( *pit++, &p1 );
const double length = p0.EuclideanDistanceTo( p1 );
std::cout << " length = " << length << std::endl; }
private:
MeshType::Pointer m_Mesh;
};
下面的Triangle visitor 打印出其点的标识符。
class CustomTriangleVisitor
{
public:
void Visit(unsigned long cellId, TriangleType * t )
{
std::cout << "cell " << cellId << " is a Triangle " << std::endl;
LineType::PointIdIterator pit = t->PointIdsBegin();
LineType::PointIdIterator end = t->PointIdsEnd();
while( pit != end )
{
std::cout << " point id = " << *pit << std::endl;
++pit;
}
}
};
下面的四面体访问者只返回这个图形上的面数。注意,GetNumberOfFaces()是一个3D单元格独有的方法。
class CustomTetrahedronVisitor
{
public: void Visit(unsigned long cellId, TetrahedronType * t )
{
std::cout << "cell " << cellId << " is a Tetrahedron " << std::endl;
std::cout << " number of faces = ";
std::cout << t->GetNumberOfFaces() <<
std::endl;
}
};
我们现在实例化CellVisitor。
- 上面定义的访问器类用作单元访问器实现的模板参数
typedef itk::CellInterfaceVisitorImplementation< PixelType, MeshType::CellTraits, VertexType, CustomVertexVisitor > VertexVisitorInterfaceType;
typedef itk::CellInterfaceVisitorImplementation< PixelType, MeshType::CellTraits, LineType, CustomLineVisitor > LineVisitorInterfaceType;
typedef itk::CellInterfaceVisitorImplementation< PixelType, MeshType::CellTraits, TriangleType, CustomTriangleVisitor > TriangleVisitorInterfaceType;
typedef itk::CellInterfaceVisitorImplementation< PixelType, MeshType::CellTraits, TetrahedronType, CustomTetrahedronVisitor
> TetrahedronVisitorInterfaceType;
VertexVisitorInterfaceType::Pointer vertexVisitor =
VertexVisitorInterfaceType::New();
LineVisitorInterfaceType::Pointer lineVisitor =
LineVisitorInterfaceType::New();
TriangleVisitorInterfaceType::Pointer triangleVisitor =
TriangleVisitorInterfaceType::New();
TetrahedronVisitorInterfaceType::Pointer tetrahedronVisitor =
TetrahedronVisitorInterfaceType::New();
LineVisitor需要指针指向网格对象,因为它需要访问实际的点坐标。这是通过调用上面定义的SetMesh()方法来实现的。
lineVisitor->SetMesh( mesh );
//仔细观察你会发现SetMesh()方法是在CustomLineVisitor中声明的
//但是我们是在LineVisitorInterfaceType上调用它的。
//VisitorInterfaceImplementation类来自用户提供的作为第四个模板参数的访问者类型。//LineVisitorInterfaceTypes是CustomLineVisitor的派生类
每个访问者实现都使用MultiVisitor 类的AddVisitor()方法在网格中注册。
typedef CellType::MultiVisitor CellMultiVisitorType;
CellMultiVisitorType::Pointer multiVisitor =
CellMultiVisitorType::New();
multiVisitor->AddVisitor( vertexVisitor );
multiVisitor->AddVisitor( lineVisitor );
multiVisitor->AddVisitor( triangleVisitor );
multiVisitor->AddVisitor( tetrahedronVisitor );
最后,通过调用Mesh类上的Accept()方法来触发单元格的迭代。
mesh->Accept( multiVisitor );
Accept()方法将遍历所有单元格,对于每个单元格,它将邀请MultiVisitor尝试对单元格进行操作。如果没有访问者对当前单元格类型感兴趣,则忽略并跳过该单元格。