I am trying to combine Calculator Filter with Glyph Filter but I think there is an issue with how both filters are linking. I can’t find the “Result” array of calculator in Orientation or Scale array of Glyph and I get this error:
ERROR: In vtkAlgorithm.cxx, line 570
myPVGlyphFilter (000001F9644D4950): Attempt to get an input array for an index that has not been specified
This is the RequestData function of my new filter:
int vtkMyForceFilter::RequestData(
vtkInformation *request,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
int arrayCalcResult = this->ArrayCalculator->RequestData(request, inputVector, outputVector);
// Get the output of ArrayCalculator
vtkDataSet *arrayCalcOutput = vtkDataSet::SafeDownCast(outputVector->GetInformationObject(0)->Get(vtkDataObject::DATA_OBJECT()));
vtkPointData* pointData = arrayCalcOutput->GetPointData();
// Create a new input vector for GlyphFilter
vtkInformationVector* glyphInputVector = vtkInformationVector::New();
vtkInformation* glyphInputInfo = vtkInformation::New();
glyphInputInfo->Set(vtkDataObject::DATA_OBJECT(), arrayCalcOutput);
glyphInputVector->SetInformationObject(0, glyphInputInfo);
int glyphFilterResult = this->GlyphFilter->RequestData(request, &glyphInputVector, outputVector);
// Clean up
glyphInputInfo->Delete();
glyphInputVector->Delete();
return glyphFilterResult;
}
Thanks for the response, I am new to creating filters so I wasn’t sure what’s the right way. So I will tell you how I am doing this.
Because I am combining two filters (Calculator and Glyph) I am using composition instead of inheritance (becuase vtk does not allow inheriting from two classes)
But how would all other functions which are actually called from ArrayCalculator’s RequestData would be called (I mean all the code in ArrayCalculator’s RequestData)?
Do I also need to call this->ArrayCalculator->Update() as you are calling for GlyphFilter?
As for the GlyphFilter I was just calling the RequestData with input as the output of ArrayCalculator’s output (as I shared above) so I did not specify Source input because I thought if I am calling GlyphFilter->RequestData it would be taken care of there.
I believe this is the issue. So I tried debugging, in the RequestData function I found out that number of source inputs are 0
vtkInformationVector* sourceVector = inputVector[1];
int numSourceInputs = this->GetNumberOfInputConnections(1); // 1 for the source port
logFile << "Number of source inputs: " << numSourceInputs << std::endl;
I get Number of source inputs: 0
Moreover, in the Execute function OrientArray and ScaleArrays are not there:
I believe this is the issue. I added some debugging statements and found out that Number of Source Inputs are 0
vtkInformationVector* sourceVector = inputVector[1];
int numSourceInputs = this->GetNumberOfInputConnections(1); // 1 for the source port
logFile << "Number of source inputs: " << numSourceInputs << std::endl;
It prints Number of source inputs: 0
Moreover, in Execute function I OrientArray and ScaleArrays are also not found.
Checkout this GlyphFilter example: https://kitware.github.io/vtk-examples/site/Java/Filtering/Glyph3D/
This shows how to setup the source input. In the example a vtkCubeSource is used to produce the dataset to use as a glyph. You can ofcourse choose the type you want.
vtkAlgorithm::SetInputArrayToProcess is used to select arrays for scale and orientation. For example,
glyph->SetInputArrayToProcess(0 /* index for scale array*/, /*port=*/0, /*connection=*/ 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Result");
This will attempt to use the a point array named “Result” from the 0th input connnection on input port index 0.
Since you are new to VTK pipelines, I’d suggest trying to modifying the VTK Python example to setup your pipeline and get it to work that way before attempting to package it in a filter to use in ParaView. It’ll perhaps be easier to debug any issues like these in the VTK code – just a suggestion, of course.
Thank you so much again!
Sorry to keep on bugging you. I have a couple of more questions:
Let’s say I set the source using vtkCubeSource, will my filter be restricted to cubes structure only? I want my filter to be general so that it can be applied on any object (just like actual Glyph filter in Paraview)
Is there any example where another filter/s are being used in the RequestData which I can follow. I want to see an example where something of this sort is happening:
I’d really recommend playing with the VTK example to understand how the glyph filter works. The “source” input for the Glyph filter is the geometry used for the glyph. The Glyph filter takes two inputs: one is the geometry and the other is the dataset that provides the points on which to place the glyphs.
Thank you for your help and suggestions. I was able to get rid of the errors and warnings, but glyph part of my filter cannot see “Result” array and it does not show in dropdown of Orientation and Scale arrays. And the glyphs also does not show up.
But I can see “Result” array in ArrayCalculator output, also in Glyph input.
Just as a reminder ArrayCalculator is an object of vtkPVArrayCalculator and GlyphFilter is an object of vtkPVGlyphFilter
Here is my Request Data function:
int vtkMyForceFilter::RequestData(
vtkInformation *request,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
auto* input0 = vtkDataObject::GetData(inputVector[0], 0);
this->ArrayCalculator->SetInputDataObject(input0);
if (input0)
{
logFile << "Input dataset: " << std::endl;
input0->Print(logFile);
}
else
{
logFile << "Input dataset not available." << std::endl;
}
this->ArrayCalculator->Update();
vtkDataObject* arrayCalcOutput = this->ArrayCalculator->GetOutputDataObject(0);
if (!arrayCalcOutput)
{
logFile << "ArrayCalculator output not generated." << std::endl;
return 0; // ArrayCalculator failed, return 0 to indicate failure
}
else{
logFile << "ArrayCalculator output: " << std::endl;
arrayCalcOutput->Print(logFile);
}
// Glyph Parts
vtkNew<vtkArrowSource> arrowSource;
this->GlyphFilter->SetSourceConnection(arrowSource->GetOutputPort());
this->GlyphFilter->SetInputConnection(0,this->ArrayCalculator->GetOutputPort(0));
// Set the vector array
this->GlyphFilter->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Result");
this->GlyphFilter->Update();
// Get the output data object of the GlyphFilter
vtkDataObject* glyphOutput = this->GlyphFilter->GetOutputDataObject(0);
// Get the output data object of vtkMyForceFilter
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkDataObject* outputDataObject = outInfo->Get(vtkDataObject::DATA_OBJECT());
// Shallow copy the output of GlyphFilter to the output of vtkMyForceFilter
if (glyphOutput)
{
outputDataObject->ShallowCopy(glyphOutput);
glyphOutput->Print(logFile);
}
else
{
logFile << "GlyphFilter output not generated." << std::endl;
}
return 1;
Hi,
Thanks for your help again. In think I have almost made the filter. I can see the glyphs being generated.
I have two issues left now:
If I make any changes in my filter more than once in the GUI, e.g. if I change the vector equation or change the color and click “Apply” for the second time the changes does not show. So essentially I can only see the changes once (for the first time only)
I have checked that my filter’s RequestData function does not get called for the second time (if I click “Apply” for the second time)
The orientation array and the scale array of Glyph part does not get updated and does not show “Result” array of calculator part in the dropdown.
And this is my XML file. I have essentially just copied the XML files of Calculator and Glyph Filters.
<ServerManagerConfiguration>
<ProxyGroup name="filters">
<SourceProxy name="MyForceFilter" class="vtkMyForceFilter" label="MyForce">
<Documentation long_help="Combines vtkPVArrayCalculator and vtkPVGlyphFilter functionality in a single filter.">
This filter combines the functionalities of vtkPVArrayCalculator and vtkPVGlyphFilter in a single filter.
</Documentation>
<InputProperty command="SetInputConnection"
name="Input">
<ProxyGroupDomain name="groups">
<Group name="sources" />
<Group name="filters" />
</ProxyGroupDomain>
<DataTypeDomain name="input_type">
<DataType value="vtkDataSet" />
<DataType value="vtkGraph"/>
<DataType value="vtkTable"/>
<DataType value="vtkHyperTreeGrid"/>
</DataTypeDomain>
<InputArrayDomain name="input_array" optional="1"/>
<Documentation>This property specifies the input dataset (vtkDataSet, vtkTable or vtkGraph) to the
Calculator filter. The scalar and vector variables may be chosen from
this dataset's arrays.</Documentation>
</InputProperty>
<IntVectorProperty command="SetAttributeType"
default_values="0"
name="AttributeType"
number_of_elements="1">
<FieldDataDomain name="enum">
<RequiredProperties>
<Property function="Input"
name="Input" />
</RequiredProperties>
</FieldDataDomain>
<Documentation>This property determines on which types of field data the computation is to
be performed on.</Documentation>
</IntVectorProperty>
<IntVectorProperty command="SetCoordinateResults"
default_values="0"
name="CoordinateResults"
number_of_elements="1">
<BooleanDomain name="bool" />
<Hints>
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="AttributeType" value="0" inverse="0" />
</Hints>
<Documentation>The value of this property determines whether the
results of this computation should be used as point coordinates or as a
new array.</Documentation>
</IntVectorProperty>
<IntVectorProperty command="SetResultNormals"
default_values="0"
name="ResultNormals"
number_of_elements="1"
panel_visibility="advanced">
<BooleanDomain name="bool" />
<Documentation>Set whether to output results as point/cell
normals. Outputting as normals is only valid with vector
results. Point or cell normals are selected using
AttributeMode.</Documentation>
</IntVectorProperty>
<IntVectorProperty command="SetResultTCoords"
default_values="0"
name="ResultTCoords"
number_of_elements="1"
panel_visibility="advanced">
<BooleanDomain name="bool" />
<Documentation>Set whether to output results as point/cell
texture coordinates. Point or cell texture coordinates are
selected using AttributeMode. 2-component texture coordinates
cannot be generated at this time.</Documentation>
</IntVectorProperty>
<StringVectorProperty command="SetResultArrayName"
default_values="Result"
name="ResultArrayName"
number_of_elements="1">
<Documentation>This property contains the name for the output array
containing the result of this computation.</Documentation>
</StringVectorProperty>
<StringVectorProperty command="SetFunction"
name="Function"
number_of_elements="1"
panel_widget="calculator" >
<Documentation>
This property contains the equation for computing the new
array.
</Documentation>
</StringVectorProperty>
<IntVectorProperty command="SetReplaceInvalidValues"
default_values="1"
label="Replace Invalid Results"
name="ReplaceInvalidValues"
number_of_elements="1"
panel_visibility="advanced">
<BooleanDomain name="bool" />
<Documentation>This property determines whether invalid values in the
computation will be replaced with a specific value. (See the
ReplacementValue property.)</Documentation>
</IntVectorProperty>
<DoubleVectorProperty command="SetReplacementValue"
default_values="0.0"
name="ReplacementValue"
number_of_elements="1"
panel_visibility="advanced">
<DoubleRangeDomain name="range" />
<Documentation>If invalid values in the computation are to be replaced
with another value, this property contains that value.</Documentation>
</DoubleVectorProperty>
<IntVectorProperty command="SetResultArrayType"
default_values="11"
label="Result Array Type"
name="ResultArrayType"
number_of_elements="1"
panel_visibility="advanced">
<EnumerationDomain name="enum">
<Entry text="Char"
value="2" />
<Entry text="Signed Char"
value="15" />
<Entry text="Unsigned Char"
value="3" />
<Entry text="Short"
value="4" />
<Entry text="Unsigned Short"
value="5" />
<Entry text="Int"
value="6" />
<Entry text="Unsigned Int"
value="7" />
<Entry text="Long"
value="8" />
<Entry text="Unsigned Long"
value="9" />
<Entry text="Float"
value="10" />
<Entry text="Double"
value="11" />
<Entry text="Id Type"
value="12" />
</EnumerationDomain>
<Documentation>This property determines what array type to output.
The default is a vtkDoubleArray.</Documentation>
</IntVectorProperty>
<IntVectorProperty name="FunctionParserType"
command="SetFunctionParserTypeFromInt"
default_values="1"
number_of_elements="1"
panel_visibility="never">
<Documentation>Hidden property that specifies whether the old (ParaView 5.9 and before)
expression parser or new (ParaView 5.10) vtkPVLinearExtrusionFilter is used.</Documentation>
</IntVectorProperty>
<InputProperty command="SetSourceConnection"
label="Glyph Type"
name="Source">
<ProxyGroupDomain name="groups">
<Group name="sources" />
<Group name="glyph_sources" />
</ProxyGroupDomain>
<DataTypeDomain name="input_type">
<DataType value="vtkPolyData" />
</DataTypeDomain>
<ProxyListDomain name="proxy_list">
<Proxy group="sources" name="ArrowSource" />
<Proxy group="sources" name="ConeSource" />
<Proxy group="sources" name="CubeSource" />
<Proxy group="sources" name="CylinderSource" />
<Proxy group="sources" name="LineSource" />
<Proxy group="sources" name="SphereSource" />
<Proxy group="sources" name="GlyphSource2D" />
</ProxyListDomain>
<Hints>
<ProxyPropertyWidget selected_proxy_panel_visibility="advanced" />
<!-- show the selected proxy's panel, only in advanced mode. -->
</Hints>
<Documentation>
This property determines which type of glyph will be placed at the
points in the input dataset.
</Documentation>
</InputProperty>
<StringVectorProperty command="SetInputArrayToProcess"
default_values="1"
element_types="0 0 0 0 2"
name="OrientationArray"
number_of_elements="5">
<!-- default value=1 so normals go to the right place -->
<ArrayListDomain attribute_type="Vectors"
input_domain_name="vector_array"
name="array_list"
none_string="No orientation array">
<RequiredProperties>
<Property function="Input"
name="Input" />
</RequiredProperties>
</ArrayListDomain>
<Documentation>
Select the input array to use for orienting the glyphs.
</Documentation>
</StringVectorProperty>
<StringVectorProperty command="SetInputArrayToProcess"
default_values="0"
element_types="0 0 0 0 2"
name="ScaleArray"
number_of_elements="5">
<ArrayListDomain attribute_type="Scalars"
input_domain_name="scale_array"
name="array_list"
none_string="No scale array">
<RequiredProperties>
<Property function="Input"
name="Input" />
</RequiredProperties>
</ArrayListDomain>
<Documentation>
Select the input array to be used for scaling the glyphs. If the scale
array is a vector array, you can control how the glyphs are scaled with
the **Vector Scale Mode** property.
</Documentation>
</StringVectorProperty>
<IntVectorProperty command="SetVectorScaleMode"
default_values="0"
name="VectorScaleMode"
number_of_elements="1">
<EnumerationDomain name="enum">
<Entry text="Scale by Magnitude"
value="0" />
<Entry text="Scale by Components"
value="1" />
</EnumerationDomain>
<Documentation>
Select the mode when the scaling array is a vector. **Scale by Magnitude** scales the glyph by
the vector magnitude. **Scale by Components** scales glyphs by each vector component in the dimension
that component represents, e.g., the x-direction is scaled by component 0, the y-direction is
scaled by component 1, and so on.
</Documentation>
<Hints>
<PropertyWidgetDecorator type="GenericDecorator"
mode="visibility"
property="ScaleArray"
number_of_components="3"
index="4" />
</Hints>
</IntVectorProperty>
<IntVectorProperty information_only="1"
name="ComponentSelection"
default_values="4"
number_of_elements="1"
panel_visibility="never">
<Documentation>
Specifies array component to use. Fixed at 4 to ensure the
ArrayRangeDomain is set to the vector magnitude for up to 3-component
arrays.
</Documentation>
</IntVectorProperty>
<DoubleVectorProperty command="SetScaleFactor"
default_values="1.0"
name="ScaleFactor"
number_of_elements="1"
panel_widget="glyph_scale_factor">
<BoundsDomain mode="scaled_extent" name="bounds" scale_factor="0.1">
<RequiredProperties>
<Property function="Input" name="Input" />
</RequiredProperties>
</BoundsDomain>
<ArrayRangeDomain name="scalar_range">
<RequiredProperties>
<Property function="Input" name="Input" />
<Property function="ArraySelection" name="ScaleArray" />
</RequiredProperties>
</ArrayRangeDomain>
<ArrayRangeDomain name="vector_range">
<RequiredProperties>
<Property function="Input" name="Input" />
<Property function="ArraySelection" name="OrientationArray" />
</RequiredProperties>
</ArrayRangeDomain>
<Documentation>Specify the constant multiplier to use to scale the glyphs.
</Documentation>
</DoubleVectorProperty>
<ProxyProperty command="SetSourceTransform"
name="GlyphTransform"
panel_visibility="advanced">
<ProxyListDomain name="proxy_list">
<Proxy group="extended_sources"
name="Transform2" />
</ProxyListDomain>
<Documentation>
The values in this property allow you to specify the transform
(translation, rotation, and scaling) to apply to the glyph
source.</Documentation>
</ProxyProperty>
<IntVectorProperty command="SetGlyphMode"
default_values="2"
name="GlyphMode"
number_of_elements="1"
panel_visibility="default">
<EnumerationDomain name="enum">
<Entry text="All Points" value="0"/>
<Entry text="Every Nth Point" value="1"/>
<Entry text="Uniform Spatial Distribution (Bounds Based)" value="2"/>
<Entry text="Uniform Spatial Distribution (Surface Sampling)" value="3"/>
<Entry text="Uniform Spatial Distribution (Volume Sampling)" value="4"/>
</EnumerationDomain>
<Documentation>
This property indicates the mode that will be used to generate
glyphs from the dataset.
</Documentation>
</IntVectorProperty>
<IntVectorProperty command="SetMaximumNumberOfSamplePoints"
number_of_elements="1"
default_values="5000"
name="MaximumNumberOfSamplePoints">
<IntRangeDomain min="1" name="range" />
<Documentation>
This property specifies the maximum number of sample points to use
when sampling the space when Uniform Spatial Distribution is used.
</Documentation>
<Hints>
<PropertyWidgetDecorator type="CompositeDecorator">
<Expression type="or">
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="2" inverse="0" />
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="3" inverse="0" />
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="4" inverse="0" />
</Expression>
</PropertyWidgetDecorator>
<!-- show this widget when GlyphMode==2||3||4 -->
</Hints>
</IntVectorProperty>
<IntVectorProperty command="SetSeed"
number_of_elements="1"
default_values="10339"
name="Seed">
<IntRangeDomain min="1" name="range"/>
<Documentation>
This property specifies the seed that will be used for generating a
uniform distribution of glyph points when a Uniform Spatial
Distribution is used.
</Documentation>
<Hints>
<PropertyWidgetDecorator type="CompositeDecorator">
<Expression type="or">
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="2" inverse="0" />
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="3" inverse="0" />
<PropertyWidgetDecorator type="GenericDecorator" mode="visibility" property="GlyphMode" value="4" inverse="0" />
</Expression>
</PropertyWidgetDecorator>
<!-- show this widget when GlyphMode==2||3||4 -->
</Hints>
</IntVectorProperty>
<IntVectorProperty command="SetStride"
number_of_elements="1"
default_values="1"
name="Stride">
<IntRangeDomain min="1" name="range"/>
<Documentation>
This property specifies the stride that will be used when glyphing by
Every Nth Point.
</Documentation>
<Hints>
<PropertyWidgetDecorator type="GenericDecorator"
mode="visibility"
property="GlyphMode"
value="1" />
<!-- show this widget when GlyphMode==1 -->
</Hints>
</IntVectorProperty>
<PropertyGroup label="Glyph Source">
<Property name="Source" />
</PropertyGroup>
<PropertyGroup label="Orientation">
<Property name="OrientationArray" />
</PropertyGroup>
<PropertyGroup label="Scale">
<Property name="ScaleArray" />
<Property name="VectorScaleMode" />
<Property name="ScaleFactor" />
</PropertyGroup>
<PropertyGroup label="Glyph Transform">
<Property name="GlyphTransform" />
</PropertyGroup>
<PropertyGroup label="Masking">
<Property name="GlyphMode" />
<Property name="MaximumNumberOfSamplePoints" />
<Property name="Seed" />
<Property name="Stride" />
</PropertyGroup>
<Hints>
<!-- Visibility Element can be used to suggest the GUI about
visibility of this filter (or its input) on creation.
replace_input="0" implies that the input visibility is not
changed on creation of this filter (defaults to "1")
-->
<Visibility replace_input="0" />
<WarnOnCreate>
<DataTypeDomain name="input_type">
<DataType value="vtkDataSet" />
</DataTypeDomain>
<MemoryUsage relative="500" />
<Text title="Potentially running out of memory">
**Glyph** filter will create one geometry by point
if configured as such in the "Glyph Mode" property,
which you may not have enough memory to do.
Do you want to continue?
</Text>
</WarnOnCreate>
</Hints>
</SourceProxy>
</ProxyGroup>
</ServerManagerConfiguration>
BTW in the information tab of pipeline browser, I can see “Result” and “Tcoords” arrays but the orientation and scale arrays show “Normals” and “TCoords”
So, the vector equation or the function in the Calculator filter is referred to as “Result”. When I write a vector equation in the Calculator filter part of my filter and click “Apply” I can see that “Result” array is generated in the Information tab. And glyphs also change direction based on the equation I write in the Calculator.
But the orientation and scale arrays of Glyph filter part does not gets updated with “Result” array/vector.
Whereas, if I don’t combine these two filters into one and just use Paraview’s given calculator and glyph filter one by one, the glyph filter’s orientation and scale arrays do show “Result” array/vector from the calculator filter, and I am able to change both the scale and orientation of the glyphs based on the arrays/vectors I choose from their dropdown menus.