Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
Dealing with Multiple-Value Fields

This second engine has a slightly more complex evaluate() method. Before creating the output, it determines the longest input field, and replicates the last value in short fields that need to be filled out to match the number of values in the longest field. The SO_ENGINE_OUTPUT() macro is used to set the number of values in the fields connected from the output, as well as to set the values.

Creating an Engine with Multiple Inputs

Examples 6-3 and 6-4 show the header and source files for SoComposeVec2f. This engine has two inputs, x and y, of type SoMFFloat, and one output, an SoEngineOutput of type SoMFVec2f.

This engine illustrates a general policy for handling multiple-value inputs that is followed by all arithmetic engines in Inventor. This policy is useful for engines that process multiple-value inputs as “parallel” independent data sets, but it is not required. Because the

x and y inputs of the SoComposeVec2f engine are multiple-value fields, they can each contain any number of values. Replicating Values in Fields with Fewer Values illustrates a case where the last value of y is replicated to fill out the field with values to match up with the number of values provided in x.

Replicating Values in Fields with Fewer Values

Note that the constructor sets the default value for both input fields to 0.0.

Example : SoComposeVec2f.h

#include <Inventor/engines/SoSubEngine.h>
#include <Inventor/fields/SoMFFloat.h>
#include <Inventor/fields/SoMFVec2f.h>
class SoComposeVec2f : public SoEngine
{
SO_ENGINE_HEADER( SoComposeVec2f );
public:
// Inputs:
SoMFFloat x;
SoMFFloat y;
// Output:
SoEngineOutput vector; // (SoMFVec2f)
// Initialization
static void initClass();
static void exitClass();
// Constructor
SoComposeVec2f();
private:
// Destructor
virtual ~SoComposeVec2f();
// Evaluation method
virtual void evaluate();
};

Example : SoComposeVec2f.c++

#include "SoComposeVec2f.h"
SO_ENGINE_SOURCE( SoComposeVec2f );
// Initializes the SoComposeVec2f class.
void
SoComposeVec2f::initClass()
{
SO_ENGINE_INIT_CLASS( SoComposeVec2f, SoEngine, "Engine" );
}
void
SoComposeVec2f::exitClass()
{
SO_ENGINE_EXIT_CLASS( SoComposeVec2f );
}
// Constructor
SoComposeVec2f::SoComposeVec2f()
{
// Do standard constructor tasks
SO_ENGINE_CONSTRUCTOR( SoComposeVec2f );
// Define input fields and their default values
SO_ENGINE_ADD_INPUT( x, ( 0.0 ) );
SO_ENGINE_ADD_INPUT( y, ( 0.0 ) );
// Define the output, specifying its type
SO_ENGINE_ADD_OUTPUT( vector, SoMFVec2f );
}
// Destructor. Does nothing.
SoComposeVec2f::~SoComposeVec2f() {}
// This is the evaluation routine.
void
SoComposeVec2f::evaluate()
{
// Figure out how many input values we have
int numX = x.getNum();
int numY = y.getNum();
// We will output as many values as there are in the input
// with the greater number of values
int numToOutput = ( numX > numY ? numX : numY );
// Make sure that all of the fields connected from the output
// have enough room for the results. The SoMField::setNum()
// method does this.
SO_ENGINE_OUTPUT( vector, SoMFVec2f, setNum( numToOutput ) );
// Now output the vectors composed from the input values
float xValue, yValue;
int i;
for ( i = 0; i < numToOutput; i++ )
{
// If there are different numbers of values in the input
// fields, repeat the last value as necessary.
xValue = ( i < numX ? x[i] : x[numX - 1] );
yValue = ( i < numY ? y[i] : y[numY - 1] );
// Set the vector value in the indexed slot in all
// connected fields
SO_ENGINE_OUTPUT( vector, SoMFVec2f, set1Value( i, xValue, yValue ) );
}
}

Creating an Engine with Multiple Outputs

This engine class shows creating an engine with more than one output. Examples 6-5 and 6-6 illustrate an engine that decomposes a vector into its individual float values. The evaluate() method uses the getNum() method to determine how many input values there are. Then it uses the SoMField::setNum() method to ensure that the fields connected from this engine have enough room for the results, as in the previous example.

Example : SoDecomposeVec2f.h

#include <Inventor/engines/SoSubEngine.h>
#include <Inventor/fields/SoMFFloat.h>
#include <Inventor/fields/SoMFVec2f.h>
class SoDecomposeVec2f : public SoEngine
{
SO_ENGINE_HEADER( SoDecomposeVec2f );
public:
// Input:
SoMFVec2f vector;
// Outputs:
SoEngineOutput x; // (SoMFFloat)
SoEngineOutput y; // (SoMFFloat)
// Initialization
static void initClass();
// Constructor
SoDecomposeVec2f();
private:
// Destructor
virtual ~SoDecomposeVec2f();
// Evaluation method
virtual void evaluate();
};

Example : SoDecomposeVec2f.c++

#include "SoDecomposeVec2f.h"
SO_ENGINE_SOURCE( SoDecomposeVec2f );
// Initializes the SoDecomposeVec2f class.
void
SoDecomposeVec2f::initClass()
{
SO_ENGINE_INIT_CLASS( SoDecomposeVec2f, SoEngine, "Engine" );
}
// Constructor
SoDecomposeVec2f::SoDecomposeVec2f()
{
// Do standard constructor tasks
SO_ENGINE_CONSTRUCTOR( SoDecomposeVec2f );
// Define input field and its default value
SO_ENGINE_ADD_INPUT( vector, ( 0.0, 0.0 ) );
// Define the outputs, specifying their types
SO_ENGINE_ADD_OUTPUT( x, SoMFFloat );
SO_ENGINE_ADD_OUTPUT( y, SoMFFloat );
}
// Destructor. Does nothing.
SoDecomposeVec2f::~SoDecomposeVec2f() {}
// This is the evaluation routine.
void
SoDecomposeVec2f::evaluate()
{
// Figure out how many input values we have
int numToOutput = vector.getNum();
// Make sure that all of the fields connected from the
// outputs have enough room for the results. The
// SoMField::setNum() method does this.
SO_ENGINE_OUTPUT( x, SoMFFloat, setNum( numToOutput ) );
SO_ENGINE_OUTPUT( y, SoMFFloat, setNum( numToOutput ) );
// Now output the values extracted from the input vectors
for ( int i = 0; i < numToOutput; i++ )
{
SO_ENGINE_OUTPUT( x, SoMFFloat, set1Value( i, vector[i][0] ) );
SO_ENGINE_OUTPUT( y, SoMFFloat, set1Value( i, vector[i][1] ) );
}
}