It has two important arguments, inputVector, which
contains all the filter’s inputs, and outputVector,
which is an output argument into which the filter’s
output is supposed to be stored. The argument
request in some cases contains some additional in-
formation for the filter’s operation and in such cases
has to be considered an input argument as well, al-
though in many cases it is unused. The method’s re-
turn value only indicates whether the operation has
finished successfully. There is one more hidden in-
put argument which is the filter itself (meaning the
instance of the filter class on which the RequestData
method is called) since the filter’s configuration also
has impact on its output.
To create a caching version of an existing fil-
ter new class must be created inheriting from the
CachingFilter class. Creation of such class can be
similar to this example:
class CachingDecimator :
public CachingFilter<CachingDecimator,
vtkDecimatePro>
{ ... };
In this case, we have created a new filter which will
be a caching version of the vtkDecimatePro
8
filter
whose task is to perform a triangle mesh simplifica-
tion. We note that this task is crucial for an interac-
tive visualization of big data sets, multi-resolution hi-
erarchies for efficient geometry processing, and many
other computer graphics applications.
The CachingFilter class internally creates a
caching object which simulates calls of the original
filter’s RequestData method, in our case the origi-
nal filter is vtkDecimatePro, therefore it simulates
calls of vtkDecimatePro::RequestData. It also in-
herits from the original filter (vtkDecimatePro in
our case), therefore it is a valid VTK filter, and
it overrides the RequestData method to use the
caching object to perform the original filter’s op-
eration instead of performing it directly. Inherit-
ing from such class gives us the caching version of
the original filter (vtkDecimatePro), in our case the
CachingDecimator.
For all this to work, the data manipulation func-
tions must be defined, which can be done through
several methods declared in CachingFilter that the
user can override in the inheriting class. For example,
in the case of the CachingDecimator, the compar-
ison function for the input parameter inputVector
can be overridden to look like this:
bool inputEqualsFunction(
vtkInformationVector** a,
vtkInformationVector** b)
8
http://www.vtk.org/doc/nightly/html/
classvtkDecimatePro.html#details
{
vtkPolyData* inputPoly1 =
vtkPolyData::GetData(a[0]);
vtkPolyData* inputPoly2 =
vtkPolyData::GetData(b[0]);
return CacheUtils::CacheEquals(
inputPoly1, inputPoly2);
}
The static function CacheEquals is a predefined
data manipulation function that compares two in-
stances of the class vtkPolyData. The data manipu-
lation functions for the most used data types in VTK
are predefined in the CacheUtils class so that the de-
velopers do not have to create them on their own.
Actually, for the two most important argu-
ments of the RequestData method, inputVector
and outputVector, the data manipulation func-
tions are already defined in a usable way in the
CachingFilter class so that in most cases the user
does not have to override and redefine them at all. The
data manipulation functions, however, should always
be overridden and redefined for the filter object, in our
case the CachingDecimator, since the filter’s output
usually depends on its configuration and it is virtually
impossible to create generic data manipulation func-
tions for filters. This is due to the fact that C++ lacks
any advanced reflection features (such as in, e.g., C#)
and, therefore, it is impossible to identify all the filter
parameters in runtime.
Nevertheless, even if the runtime parameter iden-
tification was possible, it would still be impossi-
ble to detect mutual interdependencies between the
parameters. For example, the vtkDecimatePro
class has a parameter named Splitting, which is
an ON/OFF switch, and also a parameter named
SplitAngle that is completely ignored by the filter,
when Splitting parameter is set to OFF. The VTK,
by default, does not take such dependencies into ac-
count and, therefore, without our library, just chang-
ing the SplitAngle (and nothing else including the
input data) would lead to a new execution of the fil-
ter’s operation even when the Splitting parameter is
set to OFF creating exactly the same output as when
executed the last time (see also Section 2.1). Us-
ing our caching library such unnecessary executions
can be prevented by defining the filter’s data manip-
ulation functions correctly, especially the comparison
function which in our case could be overridden and
defined for example like this:
bool filterEqualsFunction(
CachingDecimator* filter1,
CachingDecimator* filter2)
{
if ((filter1->GetSplitting() !=
filter2->GetSplitting()) ||
(filter1->GetSplitting() &&
GRAPP 2018 - International Conference on Computer Graphics Theory and Applications
160