前言
VTK框架里,大多数的类都是从vtkObject派生,vtkObject实现了观察者/命令(Observer/Command)设计模式,内部维护一个修改时间,用于控制可视化管线的执行。可视化管线是VTK里的重要概念,管线的连接应该使用SetInputConnection()/GetOutputPort()接口进行连接。VTK采用“惰性赋值”(Lazy Evaluation)的方案来控制管线的执行,只有当发出“请求数据”时,管线才会被执行。
具体讲,惰性赋值是指根据每个对象的内部修改时间来决定什么时候执行管线,只有当你或者程序发出“请求数据”时,管线才会被执行(前面提到vtkObject里有一个重要的vtkTimeStamp类型的成员变量MTime,管线里的每个从vtkObject派生的类的对象都会跟踪自己的内部修改时间(Modified()),当遇到“请求数据”时,该对象会比较这个修改时间,如果发现修改时间发生了改变,对象就会执行。)。换言之,VTK是采用命令驱动(Demand Driven)的方法来控制管线的执行,这种方法的好处是,当对数据对象作了更改时,不必立即作计算,只有当发出请求时才开始处理,这样能最小化计算所需的时间,以便更流畅地与数据进行交互。
通常,我们不用显性地去调用Update()函数,因为在渲染引擎的最后,当我们调用Render()函数的时候,Actor就会收到渲染请求,接着Actor会请求Mapper给它发送数据,而Mapper又会请求上一层的Filter的数据,Filter最后去请求Source给它数据,于是,整条管线就被执行。除非像上面的代码段里列出的,读入数据以后,中间想要输出某些信息,在得到这些信息之前,你就应该显性地调用Update()函数。
vtkTimeStamp
vtkTimeStamp类就是前文中“惰性赋值”实现的重要环节,是VTK的时间戳类;
vtkTimeStamp类记录了对象的执行(execution)和修改(modification)时间;
vtkTimeStamp类记录方法Modified()执行时的唯一时间。这个时间保证是单调递增的。vtkObject类以及其派生类使用此对象来记录修改、执行时间。vtkTimeStamp类支持两个vtkTimeStamp对象之间的二进制<和>比较运算符。
在vtkType.h文件中定义了vtkMTimeType类型:
typedef vtkTypeUInt64 vtkMTimeType;
#define VTK_MTIME_TYPE_IMPL VTK_TYPE_UINT64
#define VTK_MTIME_MIN VTK_TYPE_UINT64_MIN
#define VTK_MTIME_MAX VTK_TYPE_UINT64_MAX
详细代码内容如下:
class vtkTimeStamp
{
public:
vtkTimeStamp() { this->ModifiedTime = 0; }
static vtkTimeStamp* New() { return new vtkTimeStamp; }
void Delete() { delete this; }
// 修改对象的修改时间
void Modified(){
#if defined(VTK_USE_64BIT_TIMESTAMPS) || VTK_SIZEOF_VOID_P == 8
static std::atomic<uint64_t> GlobalTimeStamp(0U);
#else
static std::atomic<uint32_t> GlobalTimeStamp(0U);
#endif
this->ModifiedTime = (vtkMTimeType)++GlobalTimeStamp;
}
// 获取对象的修改时间
// 当前时间只是一个单调递增的无符号长整数
// 这个数字有可能回绕回零,整数溢出,从最大值溢出成0
// 这应该只发生在已经运行了很长时间的进程中,同时在程序中不断地改变对象
// 当这种情况发生时,典型的后果应该是某些过滤器会在真正不需要时进行自我更新
vtkMTimeType GetMTime() const { return this->ModifiedTime; }
// 比较两个vtkTimeStamp对象的时间早和晚
bool operator>(vtkTimeStamp& ts) { return (this->ModifiedTime > ts.ModifiedTime); }
bool operator<(vtkTimeStamp& ts) { return (this->ModifiedTime < ts.ModifiedTime); }
// 允许vtkTimeStamp类型转换为vtkMTimeType类型时返回unsigned long
operator vtkMTimeType() const { return this->ModifiedTime; }
private:
vtkMTimeType ModifiedTime;
};