I am writing an application that visualises a large data set using the Coin3d library (which is based on the same code base as OpenInventor). I have been wrestling with this problem for a while and I have never found a satisfactory solution.
The data comes in a variable number of 'strips' and I have created a SoEngine
that collects data to be visualised, sends it to a number of outputs, which is then connected to an SoQuadMesh
for each strip for rendering.
The reason why I am using an engine here is that the data is fetched from the data source and the visualisation updated as the user navigates around it. That is, as the user zooms in and out, the resolution of the image is changed (as per google maps). The data is retrieved in a background thread (it takes a second or two) and then used to update the engine outputs.
The problem is that there does not seem to be a way to create an arbitrary number of SoEngineOutput
s - they all have to be declared in the class definition before adding to the engine with the SO_ENGINE_ADD_OUTPUT
macro.
By analysing the Coin source code, I have tried to workaround this by implementing the code behind the SO_ENGINE_ADD_OUTPUT
macro in a slightly modified form, but ultimately I failed (or lost my nerve) because the SoEngine::outputdata
is a static field which should be created only once; I did not want to risk the consequences of re-initialising it, without knowing the details of the whole implementation under-the-hood.
The solution I have working now is to declare all the outputs up to a possible maximum value, as in the header:
class Engine : public SoEngine
{
SO_ENGINE_HEADER(Engine);
public:
// The output: vector of points, edges, colours and indices
// A set of these is needed for each strip in the visualisation
SoEngineOutputList dataPoints;
SoEngineOutputList edgePoints;
SoEngineOutputList dataColours;
SoEngineOutputList edgeColours;
SoEngineOutputList numSamples;
SoEngineOutputList numDepths;
// Macro to simplify and shorten the code for adding multiple engine outputs
#define ENGINE_DECLARE_OUTPUTS(N) \
SoEngineOutput dataPoints_##N; /*SoMFVec3f*/ \
SoEngineOutput edgePoints_##N; /*SoMFVec3f*/ \
SoEngineOutput dataColours_##N; /*SoMFColor*/ \
SoEngineOutput edgeColours_##N; /*SoMFColor*/ \
SoEngineOutput numSamples_##N; /*SoSFInt32 */ \
SoEngineOutput numDepths_##N; /*SoSFInt32 */
// Declare all the outputs from the engine. Note that they have to be added
// individually because it uses the macro above.
ENGINE_DECLARE_OUTPUTS(0);
ENGINE_DECLARE_OUTPUTS(1);
ENGINE_DECLARE_OUTPUTS(2);
ENGINE_DECLARE_OUTPUTS(3);
// etc. all the way to a constant MAX_NUM_SAMPLE_SETS
Then in the Engine constructor, add each output to the engines output lists:
#define ENGINE_ADD_OUTPUTS(N) \
SO_ENGINE_ADD_OUTPUT(dataPoints_##N, SoMFVec3f); \
SO_ENGINE_ADD_OUTPUT(edgePoints_##N, SoMFVec3f); \
SO_ENGINE_ADD_OUTPUT(dataColours_##N, SoMFColor); \
SO_ENGINE_ADD_OUTPUT(edgeColours_##N, SoMFColor); \
SO_ENGINE_ADD_OUTPUT(numSamples_##N, SoSFInt32); \
SO_ENGINE_ADD_OUTPUT(numDepths_##N, SoSFInt32); \
dataPoints.append(&dataPoints_##N); \
edgePoints.append(&edgePoints_##N); \
dataColours.append(&dataColours_##N); \
edgeColours.append(&edgeColours_##N); \
numSamples.append(&numSamples_##N); \
numDepths.append(&numDepths_##N);
// Add all the outputs from the engine. Note that they have to be added
// individually because it uses the macro above. The number added should match
// the number defined in MAX_NUM_SAMPLE_SETS
ENGINE_ADD_OUTPUTS(0);
ENGINE_ADD_OUTPUTS(1);
ENGINE_ADD_OUTPUTS(2);
ENGINE_ADD_OUTPUTS(3);
// etc. all the way to a constant MAX_NUM_SAMPLE_SETS
This works, but there is a performance hit when the Engine class in instantiated of about 20 seconds when MAX_NUM_SAMPLE_SETS
is set to 100 - which means a declaration of 600 SoEngineOutputs
. MAX_NUM_SAMPLE_SETS = 100
is the largest possible - most visualisations require a lot less than this (less than 10), so I want to be able to determine the number of outputs at run-time.
So my questions are:
- Is there a way to add an arbitrary number of
SoEngineOutput
s in Coin3d at runtime? - Why is there such a performance hit with this number of declarations of `SoEngineOutput? (This is possibly a general C++ question for which I will create a separate question, or it is an issue with Coin3d)
- Is there a better way to implement a solution for this?