VTK是一个可视化工具包,将数据展现为二维或三维图像,依赖于可视化管线,用于获取或创建数据,处理数据,以及把数据写入文件或者把数据传递给渲染引擎进行显示,如图一所示。数据对象(Data Object)、处理对象(Process Object)和数据流方向(Direction of Data Flow)是可视化管线的三个基本要素。每个VTK程序都会有可视化管线存在。
可视化管线是由四个关键的类构成的,这四个类分别是:vtkInformation,vtkDataObject,vtkAlgorithm和vtkExecutive。
vtkInformation
vtkInformation存储vtkAlgorithm输入/输出信息,用于存储和传递管线执行过程中的信息、请求和数据,实现执行管线的连接和控制。
vtkInformation表示vtkAlgorithm的一个输入或一个输出的信息和/或数据。它从键映射到几种数据类型的值,即是key-value的映射形式。vtkInformation类的实例收集在vtkInformationVector实例中,并传递给vtkAlgorithm::ProcessRequest调用。vtkInformation实例在特定输入或输出上引用的信息和数据定义了对vtkAlgorithm实例的请求。
为扩展增加了灵活性。大部分的方法和头信息的存储都会用到vtkInformation。vtkInformation是一个基于Map的数据结构,它支持与编译时类型检查异构的键值操作。这也是一个用于存储information数据体的向量类vtkInformationVector。当向管道的上方或下方传递信息时(或从执行到算法),这个类将会被用到。
vtkInformation使用 vtkInformationInternals中的Map保存vtkInformation记录的Key-Value信息;
vtkInformationKey是vtkInformation中Key的基类,派生了各种Key信息类,可以参考vtkInformationKey Class Reference查看vtkInformation继承类图;
// vtkInformationInternals.h
typedef vtkInformationKey* KeyType;
typedef vtkObjectBase* DataType;
struct HashFun
{
size_t operator()(KeyType key) const { return static_cast<size_t>(key - KeyType(nullptr)); }
};
typedef std::unordered_map<KeyType, DataType, HashFun> MapType;
MapType Map;
使用Has、Remove和Append对Map内的不同种类的Key-Value进行管理;
CopyEntry
CopyEntry提供了将vtkInformation信息复制给key对应的value,如果deep是1的话,将进行深拷贝,默认为0;
void Copy(vtkInformation* from, int deep = 0);
void Append(vtkInformation* from, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationDataObjectKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationDoubleVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationVariantKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationVariantVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationInformationKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationInformationVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationIntegerKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationIntegerVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationObjectBaseVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationRequestKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationStringKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationStringVectorKey* key, int deep = 0);
void CopyEntry(vtkInformation* from, vtkInformationUnsignedLongKey* key, int deep = 0);
void CopyEntries(vtkInformation* from, vtkInformationKeyVectorKey* key, int deep = 0);
Get接口
Get函数可以根据输入不同类型的Key返回对应的Value值,然后向下转换后获取具体类型,得到相关信息,一般配合vtkDataObject类使用;
int Get(vtkInformationIntegerKey* key);
double Get(vtkInformationDoubleKey* key);
vtkIdType Get(vtkInformationIdTypeKey* key);
int* Get(vtkInformationIntegerVectorKey* key);
int Get(vtkInformationIntegerVectorKey* key, int idx);
void Get(vtkInformationIntegerVectorKey* key, int* value);
int* Get(vtkInformationIntegerPointerKey* key);
void Get(vtkInformationIntegerPointerKey* key, int* value);
double* Get(vtkInformationDoubleVectorKey* key);
double Get(vtkInformationDoubleVectorKey* key, int idx);
void Get(vtkInformationDoubleVectorKey* key, double* value);
void Get(vtkInformationVariantVectorKey* key, vtkVariant* value);
void Get(vtkInformationKeyVectorKey* key, vtkInformationKey** value);
const vtkVariant& Get(vtkInformationVariantKey* key);
unsigned long Get(vtkInformationUnsignedLongKey* key);
const char* Get(vtkInformationStringVectorKey* key, int idx = 0);
const vtkVariant* Get(vtkInformationVariantVectorKey* key);
const vtkVariant& Get(vtkInformationVariantVectorKey* key, int idx);
vtkInformationKey** Get(vtkInformationKeyVectorKey* key);
vtkInformationKey* Get(vtkInformationKeyVectorKey* key, int idx);
const char* Get(vtkInformationStringKey* key);
vtkInformation* Get(vtkInformationInformationKey* key);
vtkInformationVector* Get(vtkInformationInformationVectorKey* key);
vtkObjectBase* Get(vtkInformationObjectBaseKey* key);
vtkObjectBase* Get(vtkInformationObjectBaseVectorKey* key, int idx = 0);
vtkDataObject VTK_WRAP_EXTERN* Get(vtkInformationDataObjectKey* key);
每个vtkInformationKey子类对应信息
通过使用vtkDataObject类提供的方法获取想要获取值的Key,然后通过调用vtkInformation的Get函数获取对应的数据信息;
static vtkInformationStringKey * DATA_TYPE_NAME ()
static vtkInformationDataObjectKey * DATA_OBJECT ()
static vtkInformationIntegerKey * DATA_EXTENT_TYPE ()
static vtkInformationIntegerPointerKey * DATA_EXTENT ()
static vtkInformationIntegerVectorKey * ALL_PIECES_EXTENT ()
static vtkInformationIntegerKey * DATA_PIECE_NUMBER ()
static vtkInformationIntegerKey * DATA_NUMBER_OF_PIECES ()
static vtkInformationIntegerKey * DATA_NUMBER_OF_GHOST_LEVELS ()
static vtkInformationDoubleKey * DATA_TIME_STEP ()
static vtkInformationInformationVectorKey * POINT_DATA_VECTOR ()
static vtkInformationInformationVectorKey * CELL_DATA_VECTOR ()
static vtkInformationInformationVectorKey * VERTEX_DATA_VECTOR ()
static vtkInformationInformationVectorKey * EDGE_DATA_VECTOR ()
static vtkInformationIntegerKey * FIELD_ARRAY_TYPE ()
static vtkInformationIntegerKey * FIELD_ASSOCIATION ()
static vtkInformationIntegerKey * FIELD_ATTRIBUTE_TYPE ()
static vtkInformationIntegerKey * FIELD_ACTIVE_ATTRIBUTE ()
static vtkInformationIntegerKey * FIELD_NUMBER_OF_COMPONENTS ()
static vtkInformationIntegerKey * FIELD_NUMBER_OF_TUPLES ()
static vtkInformationIntegerKey * FIELD_OPERATION ()
static vtkInformationDoubleVectorKey * FIELD_RANGE ()
static vtkInformationIntegerVectorKey * PIECE_EXTENT ()
static vtkInformationStringKey * FIELD_NAME ()
static vtkInformationDoubleVectorKey * ORIGIN ()
static vtkInformationDoubleVectorKey * SPACING ()
static vtkInformationDoubleVectorKey * DIRECTION ()
static vtkInformationDoubleVectorKey * BOUNDING_BOX ()
static vtkInformationDataObjectKey * SIL ()
从输入和输出的vtkInformation中获取数据集vtkPolyData;
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
vtkPolyData *input = vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
for(vtkIdType i = 0; i < input->GetNumberOfPoints(); i++){
this->UpdateProgress(static_cast<double>(i)/input->GetNumberOfPoints());
}
output->ShallowCopy(input);
vtkDataObject
在过去,这个类既存储数据又处理一些管道逻辑。在新的管道中,这个类只应该存储数据。实际上,类中有一些用于向后兼容的管道方法,这样就不会破坏所有的VTK,但目标是vtkDataObject应该只用于存储数据。vtkDataObject有一个vtkInformation实例,可用于存储键值对。例如,存储了数据对象的当前范围,但没有存储整个范围,因为这是一个包含特定管道拓扑信息的管道属性。
vtkAlgorithm
vtkAlgorithm是VTK中所有sources, filters, and sinks的基类。它定义了一个用于执行数据处理算法的通用接口。管道连接与输入和输出端口相关联,这些端口独立于通过连接的数据类型。
vtkAlgorithm实例可以独立使用,也可以在管道内使用,管道中可以使用各种架构和更新机制。管道由vtkExecutive实例控制。当在管道中使用时,每个vtkAlgorithm实例都有一个关联的vtkExecutive。执行人员负责数据流。
和vtkDataObject一样,vtkAlgorithm不应该知道关于pipeline的任何环节,而仅仅只是一个algorithm/function/filter。输入正确的参数调用它,它便会产生结果。它也有一个vtkInformation的实例,用来描述算法的特征和属性,而且拥有描述算法输入和输出端口属性的信息。
SetInput和GetOutput,用于串联起来数据源、Filter和渲染管线;
void RemoveAllInputs();
vtkDataObject* GetOutputDataObject(int port);
vtkDataObject* GetInputDataObject(int port, int connection);
virtual void SetInputConnection(int port, vtkAlgorithmOutput* input);
virtual void SetInputConnection(vtkAlgorithmOutput* input);
virtual void AddInputConnection(int port, vtkAlgorithmOutput* input);
virtual void AddInputConnection(vtkAlgorithmOutput* input);
virtual void RemoveInputConnection(int port, vtkAlgorithmOutput* input);
virtual void RemoveInputConnection(int port, int idx);
virtual void RemoveAllInputConnections(int port);
virtual void SetInputDataObject(int port, vtkDataObject* data);
virtual void SetInputDataObject(vtkDataObject* data) { this->SetInputDataObject(0, data); }
virtual void AddInputDataObject(int port, vtkDataObject* data);
virtual void AddInputDataObject(vtkDataObject* data) { this->AddInputDataObject(0, data); }
vtkAlgorithmOutput* GetOutputPort(int index);
vtkAlgorithmOutput* GetOutputPort() { return this->GetOutputPort(0); }
int GetNumberOfInputConnections(int port);
int GetTotalNumberOfInputConnections();
vtkAlgorithmOutput* GetInputConnection(int port, int index);
vtkExecutive
vtkExecutive是VTK中所有管道执行类的基类。vtkExecutive负责控制vtkAlgorithm的一个实例。管道由一个或多个控制数据流的vtkExecutive组成。管道中的每个reader, source, writer或数据处理算法都在vtkAlgorithm的一个实例中实现。
vtkAlgorithmOutput
vtkAlgorithmOutput用于连接输入/输出端口的代理对象。
vtkAlgorithmOutput是vtkAlgorithm的GetOutputPort方法返回的代理对象。它可以传递给另一个vtkAlgorithm的SetInputConnection、AddInputConnection或RemoveInputConnection方法,以在输出和输入端口之间建立连接。连接不存储在代理对象中:它只是方便创建或删除连接。
总结
VTK框架里,大多数的类都是从vtkObject派生,vtkObject实现了观察者/命令(Observer/Command)设计模式,内部维护一个修改时间,用于控制可视化管线的执行。可视化管线是VTK里的重要概念,管线的连接应该使用SetInputConnection()/GetOutputPort()接口进行连接。VTK采用“惰性赋值”(Lazy Evaluation)的方案来控制管线的执行,只有当发出“请求数据”时,管线才会被执行。
参考文献
1.VTK修炼之道82:VTK管线机制_信息对象类VTKInformation
2.VTK/Tutorials/New Pipeline文档翻译
3.04-VTK可视化管线(2)