diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp index b20d6f504644b67f49836b8a5c35b78265510b32..76f82431e1b61e588cca8a341ea3736102975d54 100644 --- a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp +++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp @@ -105,8 +105,12 @@ namespace armarx::viz selection = new SoSelection; selection->addSelectionCallback(&selectionCallback, this); selection->addDeselectionCallback(&deselectionCallback, this); + selection->setUserData(this); selection->addChild(root); + + // Preallocate some space for layers + layers.data.reserve(32); } CoinVisualizer::~CoinVisualizer() @@ -144,24 +148,6 @@ namespace armarx::viz state = CoinVisualizerState::STOPPED; } - static void removeElementsIfNotUpdated(CoinLayer* layer) - { - for (auto iter = layer->elements.begin(); iter != layer->elements.end();) - { - coin::ElementVisualization& elementVisu = *iter->visu; - if (elementVisu.wasUpdated) - { - elementVisu.wasUpdated = false; - ++iter; - } - else - { - layer->node->removeChild(elementVisu.separator); - iter = layer->elements.erase(iter); - } - } - } - CoinVisualizer_ApplyTiming CoinVisualizer::apply(data::LayerUpdate const& update) { IceUtil::Time time_start = IceUtil::Time::now(); @@ -205,6 +191,7 @@ namespace armarx::viz root->addChild(coinNode); layerIt = layers.data.insert(layerIt, CoinLayer(layerID, coinNode)); + layerIt->elements.reserve(64); } return *layerIt; @@ -256,6 +243,37 @@ namespace armarx::viz if (updated) { + // Has an interaction been added? + viz::data::InteractionDescription& oldInteraction = oldElement->data->interaction; + viz::data::InteractionDescription& newInteraction = updatedElementPtr->interaction; + if (newInteraction.enableFlags != oldInteraction.enableFlags + || oldInteraction.contextMenuOptions != newInteraction.contextMenuOptions) + { + // Lookup the interaction entry + ElementInteractionData* foundInteraction = nullptr; + for (auto& interaction : elementInteractions) + { + if (interaction->layer == layer->id + && interaction->element == updatedElement.id) + { + foundInteraction = interaction.get(); + } + } + if (foundInteraction == nullptr) + { + // Need to add a new entry + foundInteraction = elementInteractions.emplace_back( + new ElementInteractionData).get(); + } + foundInteraction->layer = layer->id; + foundInteraction->element = updatedElement.id; + foundInteraction->interaction = newInteraction; + + // Add user data to Coin node + oldElement->visu->separator->setUserData(foundInteraction); + oldElement->visu->separator->setName("InteractiveNode"); + } + oldElement->data = updatedElementPtr; continue; } @@ -269,6 +287,35 @@ namespace armarx::viz auto elementVisu = visualizer->create(updatedElement); if (elementVisu->separator) { + // Has the new element interactions? + viz::data::InteractionDescription& newInteraction = updatedElementPtr->interaction; + if (newInteraction.enableFlags != 0) + { + // Lookup the interaction entry + ElementInteractionData* foundInteraction = nullptr; + for (auto& interaction : elementInteractions) + { + if (interaction->layer == layer->id + && interaction->element == updatedElement.id) + { + foundInteraction = interaction.get(); + } + } + if (foundInteraction == nullptr) + { + // Need to add a new entry + foundInteraction = elementInteractions.emplace_back( + new ElementInteractionData).get(); + } + foundInteraction->layer = layer->id; + foundInteraction->element = updatedElement.id; + foundInteraction->interaction = newInteraction; + + // Add user data to Coin node + elementVisu->separator->setUserData(foundInteraction); + elementVisu->separator->setName("InteractiveNode"); + } + layer->node->addChild(elementVisu->separator); if (oldElement) { @@ -291,6 +338,35 @@ namespace armarx::viz } } + void CoinVisualizer::removeElementsIfNotUpdated(CoinLayer* layer) + { + for (auto iter = layer->elements.begin(); iter != layer->elements.end();) + { + coin::ElementVisualization& elementVisu = *iter->visu; + if (elementVisu.wasUpdated) + { + elementVisu.wasUpdated = false; + ++iter; + } + else + { + void* userData = elementVisu.separator->getUserData(); + if (userData) + { + // Remove interaction entry if element has been removed + auto removedInteraction = std::find_if(elementInteractions.begin(), elementInteractions.end(), + [userData](std::unique_ptr<ElementInteractionData> const& entry) + { + return entry.get() == userData; + }); + elementInteractions.erase(removedInteraction); + } + layer->node->removeChild(elementVisu.separator); + iter = layer->elements.erase(iter); + } + } + } + void CoinVisualizer::update() { { @@ -473,11 +549,24 @@ namespace armarx::viz void CoinVisualizer::onSelection(SoPath* path) { - SoNode* tailNode = path->getTail(); + // Search for user data in the path + // We stored ElementInteractionData into the user data of the parent SoSeparator + void* userData = nullptr; + int pathLength = path->getLength(); + for (int i = 0; i < pathLength; ++i) + { + SoNode* node = path->getNode(i); + const char* name = node->getName().getString(); + if (strcmp(name, "InteractiveNode") == 0) + { + userData = node->getUserData(); + if (userData != nullptr) + { + break; + } + } + } - // TODO: Store CoinElementID into user data if interaction is enabled! - // Search for user data - void* userData = tailNode->getUserData(); if (userData == nullptr) { // In this case, we want to deselect all objects in the scene, @@ -485,10 +574,10 @@ namespace armarx::viz selection->deselectAll(); // TODO: Remove logging, this is not an error, but expected - ARMARX_INFO << "Selected: " << tailNode->getClassTypeId().getName().getString() - << "\nBut no user data attached!"; + ARMARX_INFO << "Selected something. But no user data attached!"; + return; } - CoinElementID* id = static_cast<CoinElementID*>(userData); + ElementInteractionData* id = static_cast<ElementInteractionData*>(userData); CoinLayer* layer = layers.findLayer(id->layer); if (layer == nullptr) diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.h b/source/RobotAPI/components/ArViz/Coin/Visualizer.h index 6ae911753b17d72059a7e809fd770339dc9c1360..cbb5dca4eba853422fe20bf9a3c5b7bd3d92036e 100644 --- a/source/RobotAPI/components/ArViz/Coin/Visualizer.h +++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.h @@ -186,10 +186,11 @@ namespace armarx::viz struct CoinVisualizerWrapper; - struct CoinElementID + struct ElementInteractionData { CoinLayerID layer; std::string element; + viz::data::InteractionDescription interaction; }; class CoinVisualizer @@ -229,6 +230,7 @@ namespace armarx::viz CoinLayer& findOrAddLayer(CoinLayerID const& layerID); void addOrUpdateElements(CoinLayer* layer, data::LayerUpdate const& update); + void removeElementsIfNotUpdated(CoinLayer* layer); std::vector<CoinLayerID> getLayerIDs(); void emitLayersChanged(std::vector<CoinLayerID> const& layerIDs); @@ -239,7 +241,7 @@ namespace armarx::viz // These are selectable element IDs and need to be persistent in memory. // We store a raw pointer to these into the SoSeperator objects of Coin. // Later, we can retrieve the element ID from this pointer, if it has been selected. - std::vector<std::unique_ptr<CoinElementID>> selectableElementIDs; + std::vector<std::unique_ptr<ElementInteractionData>> elementInteractions; void onUpdateSuccess(data::LayerUpdates const& updates); void onUpdateFailure(Ice::Exception const& ex);