Я пишу приложение, которое визуализирует большой набор данных, используя библиотеку Coin3d (которая основана на той же кодовой базе, что и OpenInventor). Я боролся с этой проблемой некоторое время, и я никогда не находил удовлетворительного решения.
Данные поступают в переменное количество «полос», и я создал SoEngine
который собирает данные для визуализации, отправляет их на несколько выходов, которые затем подключаются к SoQuadMesh
для каждой полосы для рендеринга.
Причина, по которой я использую движок, заключается в том, что данные извлекаются из источника данных, а визуализация обновляется по мере того, как пользователь перемещается по нему. То есть, когда пользователь увеличивает и уменьшает масштаб изображения, его разрешение изменяется (согласно картам Google). Данные извлекаются в фоновом потоке (это занимает секунду или две), а затем используются для обновления выходных данных двигателя.
Проблема в том, что не существует способа создать произвольное число SoEngineOutput
s — все они должны быть объявлены в определении класса перед добавлением в движок с SO_ENGINE_ADD_OUTPUT
макро.
Анализируя исходный код Coin, я попытался обойти это путем реализации кода, стоящего за SO_ENGINE_ADD_OUTPUT
макрос в слегка измененной форме, но в конечном итоге я потерпел неудачу (или потерял самообладание), потому что SoEngine::outputdata
статическое поле, которое должно быть создано только один раз; Я не хотел рисковать последствиями его повторной инициализации, не зная деталей всей внутренней реализации.
Решение, которое я сейчас работаю, состоит в том, чтобы объявить все выходные данные до возможного максимального значения, как в заголовке:
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
Затем в конструкторе Engine добавьте каждый вывод в списки вывода engine:
#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
Это работает, но производительность падает, когда класс Engine создается примерно 20 секунд, когда MAX_NUM_SAMPLE_SETS
установлен на 100 — что означает объявление 600 SoEngineOutputs
, MAX_NUM_SAMPLE_SETS = 100
является наибольшим из возможных — для большинства визуализаций требуется намного меньше (менее 10), поэтому я хочу иметь возможность определять количество выходных данных во время выполнения.
Итак, мои вопросы:
SoEngineOutput
в Coin3d во время выполнения?Если бы у меня была 50 репутация, которая позволила бы мне комментировать, я бы спросил, почему вы хотите использовать SoEngine
за это. Цель SoEngine
s состоит в том, чтобы включить вычисления и построить зависимости между различными элементами в графе сцены, которые должны быть активными во время обхода, то есть динамически, и которые могут быть записаны в .iv
файл.
У меня складывается впечатление, что то, что вы делаете, нужно сделать один раз, когда вы загружаете свои данные до презентации. В этом случае вы можете построить свой граф сцены и заполнить свои узлы непосредственно на основе набора данных, не направляя его через SoEngine
,
Обратите внимание, что даже если у вас есть поток данных во время выполнения, для которого визуализация должна обновляться динамически, вы все равно можете изменять график сцены, пока он используется, если вы позаботитесь о том, чтобы не удалять или добавлять узлы во время его работы. пройден. Есть разные способы сделать это, но это, вероятно, другой вопрос.
Изменить: Другой вопрос: почему, если вы получите данные в полосах, вы бы преобразовать их в SoIndexedFaceSet
и не SoTriangleStripSet
на первом месте?
Других решений пока нет …