Most of the new nodes will derive from either the Node abstract class or the BufferedNode abstract class. You should use public inheritance when deriving your new class. In all cases, you will need to define a constructor for your new node class. The parameters for this constructors are: (string nodeName, const ParameterSet ¶ms), which are used to initialize the base class, e.g.
#include "BufferedNode.h" class MyNode : public BufferedNode { public: MyNode(nodeName, params) : BufferedNode(nodeName, params) ... };
Also, if you derive from BufferedNode, you need to define the virtual void calculate(int output_id, int count, Buffer &out) method. The arguments are the ID of the input requested (output_id), the iteration ID (count) and the output buffer for the requested output (out). The calculate method is expected to assign an object to out[count].
If you derive directly from the Node class, you will need to override the ObjectRef getOutput(int output_id, int count) method. The meaning of output_id and count is the same as for the BufferedNode equivalent, and the result should be returned as an ObjectRef.
Here are some other methods you might want to define too:
In some rare cases, you will want to define the following method:
At last for a new node to be visible in flowdesigner, a special header must be present. An example of this is:
class MyNode; DECLARE_NODE( MyNode) /*Node * * @name MyNode * @category MyCategory:MySubCategory * @description Some description of what MyNode does * * @input_name SOME_INPUT_NAME * @input_type this_input_type * @input_description Description of this input * * @input_name SOME_OTHER_INPUT * @input_type that_input_type * @input_description Description of that output * * @output_name SOME_OUTPUT * @output_type this_output_type * @output_description Description of the output * * @parameter_name SOME_PARAMETER * @parameter_type this_parameter_type * @parameter_description The description of the parameter * * END*/
Although this header is only a C++ comment, it is parsed by a PERL script to produce an XML description of each toolbox. The DECLARE_NODE(MyNode) macro is used to register the node in a dictionary when the toolbox is dynamically loaded.
Most nodes must include BufferedNode.h. Also, since this node deals with vectors, we need Vector.h
#include "BufferedNode.h" #include "Vector.h" //forward declaration of class VAdd for use with the DECLARE_NODE macro class VAdd; //Declaration of the node. This definition is transformed into XML data for the GUI, as well as documentation for the node DECLARE_NODE(VAdd) /*Node * * @name VAdd * @category DSP:Base * @description Adds two vectors of same length * * * @input_name INPUT1 * @input_type Vector<float> * * @input_description First vector * * @input_name INPUT2 * @input_type Vector<float> * @input_description Second vector * * @output_name OUTPUT * @output_type Vector<float> * @output_description Result vector * END*/ //Class definition/implementation. Note that because we won't need to derive from this class, we don't need a header file (.h) and we can put everything in the .cc. Our node, like most other nodes, derives from BufferedNode. class VAdd : public BufferedNode { int input1ID; int input2ID; int outputID; public: VAdd(string nodeName, ParameterSet params) : BufferedNode(nodeName, params) { //In the constructor, we create both the inputs and outputs. input1ID = addInput("INPUT1"); input2ID = addInput("INPUT2"); outputID = addOutput("OUTPUT"); } //This is the main method for the node, it is called from the BufferedNode class each time a result needs to be calculated. void calculate(int output_id, int count, Buffer &out) { //Get input data from previous node(s). ObjectRef input1Value = getInput(input1ID, count); ObjectRef input2Value = getInput(input2ID, count); //We cast the generic objects (received through ObjectRefs) into a reference to a Vector<float>. //If the cast fails, an exception will automatically be thrown. const Vector<float> &in1 = object_cast<float> > (input1Value); const Vector<float> &in2 = object_cast<float> > (input2Value); //Check that the size of the two vectors match. Otherwise, throw an exception. //Here __FILE__ and __LINE__ are pre-processor macros that will print the file and line where this exception was thrown. if (in1.size() != in2.size()) throw new NodeException(this, "Input vectors must be of same length", __FILE__, __LINE__); int inputLength = in1.size(); //Allocate a new Vector<float> from the pool of free vectors (that's why we don't use new). Vector<float> = &output = *Vector<float>::alloc(inputLength); //Put the new Vector<float> in the return buffer. out[count] = &output; //Compute the result of the sum. for (int i=0;i
It is possible to define new types in FlowDesigner. In order to be used in new nodes, new types must derive from the Object base class. That the only absolute requirement. However, if you want the new type to integrate more closely with FlowDesigner, there are several things you can do:
It is possible to define binary operators that can act on different kinds of input. One example is the "add" operator, which can be used to add two ints, two floats, two vectors, or an int and a float, ... See data-flow/include/operators.h