Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,129 @@ void BaseViewer::fitObjectBBox(sofa::core::objectmodel::BaseObject * object)
redraw();
}

void BaseViewer::drawSelection(sofa::core::visual::VisualParams* vparams)
{
assert(vparams && "call of drawSelection without a valid visual param is not allowed");

auto drawTool = vparams->drawTool();

if(currentSelection.empty())
return;

drawTool->setPolygonMode(0, false);
float screenHeight = vparams->viewport()[4];

for(auto current : currentSelection)
{
using sofa::type::Vec3;
using sofa::type::RGBAColor;
using sofa::defaulttype::RigidCoord;
using sofa::defaulttype::Rigid3Types;

////////////////////// Render when the selection is a Node ///////////////////////////////
auto node = castTo<sofa::simulation::Node*>(current.get());
if(node && m_showSelectedNodeBoundingBox)
{
auto box = node->f_bbox.getValue();
drawTool->drawBoundingBox(box.minBBox(), box.maxBBox(), 2.0);

// If it is a node... it is not a BaseObject, so we can continue.
continue;
}

////////////////////// Render when the selection is a BaseObject //////////////////////////
auto object = castTo<sofa::core::objectmodel::BaseObject*>(current.get());
if(object)
{
sofa::type::BoundingBox box;
auto ownerNode = dynamic_cast<sofa::simulation::Node*>(object->getContext());
if(ownerNode)
{
box = ownerNode->f_bbox.getValue();
}

if(m_showSelectedObjectBoundingBox)
{
drawTool->drawBoundingBox(box.minBBox(), box.maxBBox(), 2.0);
}

std::vector<Vec3> positions;
auto position = object->findData("position");
if(position)
{
auto positionsData = dynamic_cast<Data<sofa::type::vector<Vec3>>*>(position);
if(positionsData)
{
positions = positionsData->getValue();
if(m_showSelectedObjectBoundingBox){
drawTool->drawPoints(positions, 2.0, RGBAColor::yellow());
}
}
else
{
auto rigidPositions = dynamic_cast<Data<sofa::type::vector<RigidCoord<3, SReal>>>*>(position);
if(rigidPositions)
{
for(auto frame : rigidPositions->getValue())
{
float targetScreenSize = 50.0;
float distance = (currentCamera->getPosition() - Rigid3Types::getCPos(frame)).norm();
SReal scale = distance * tan(currentCamera->getFieldOfView() / 2.0f) * targetScreenSize / screenHeight;
drawTool->drawFrame(Rigid3Types::getCPos(frame), Rigid3Types::getCRot(frame), {scale, scale,scale});
positions.push_back(Rigid3Types::getCPos(frame));
}
}
}
}

if(m_showSelectedObjectSurfaces && !positions.empty())
{
auto triangles = object->findData("triangles");
if(triangles)
{
auto d_triangles = dynamic_cast<Data<sofa::type::vector<core::topology::Topology::Triangle>>*>(triangles);
if(d_triangles)
{
std::vector<Vec3> tripoints;
for(auto indices : d_triangles->getValue())
{
if(indices[0] < positions.size() &&
indices[1] < positions.size() &&
indices[2] < positions.size())
{
tripoints.push_back(positions[indices[0]]);
tripoints.push_back(positions[indices[1]]);
tripoints.push_back(positions[indices[1]]);
tripoints.push_back(positions[indices[2]]);
tripoints.push_back(positions[indices[2]]);
tripoints.push_back(positions[indices[0]]);
}
}
drawTool->drawLines(tripoints, 1.5, RGBAColor::fromFloat(1.0,1.0,1.0,0.7));
}
}
}

if(!positions.empty() && m_showSelectedObjectIndices)
{
const float scale = (box.maxBBox() - box.minBBox()).norm() * m_visualScaling;
drawTool->draw3DText_Indices(positions, scale, RGBAColor::white());
}

continue;
}
msg_error("BaseViewer") << "Only node and object can be selected, if you see this line please report to sofa-developement team";
}
}

void BaseViewer::setCurrentSelection(const std::set<sofa::core::objectmodel::Base::SPtr>& selection)
{
currentSelection = selection;
}

const std::set<core::objectmodel::Base::SPtr> &BaseViewer::getCurrentSelection() const
{
return currentSelection;
}

} // namespace sofa::gui::common
19 changes: 19 additions & 0 deletions Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,23 @@ class SOFA_GUI_COMMON_API BaseViewer
/// the rendering pass is done here (have to be called in a loop)
virtual void drawScene(void) = 0;

void drawSelection(sofa::core::visual::VisualParams* vparams);

void setCurrentSelection(const std::set<core::objectmodel::Base::SPtr> &selection);
const std::set<sofa::core::objectmodel::Base::SPtr>& getCurrentSelection() const;

public:
bool m_showSelectedNodeBoundingBox {true};
bool m_showSelectedObjectBoundingBox {true};
bool m_showSelectedObjectPositions {true};
bool m_showSelectedObjectSurfaces {true};
bool m_showSelectedObjectVolumes {true};
bool m_showSelectedObjectIndices {true};
float m_visualScaling {0.2};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be some kind of merge between this and the VisualStyle flags ?

Copy link
Contributor Author

@damienmarchal damienmarchal Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank for the question,

I think that VisualStyle is to control how objects are rendered not to control the viewer itself.
When I tried to do what you suggested, l discovered that there exist a sofa object with that purpose, it is called ViewerSettings so I made the changed there (see #5639)

More generally this questionning (and design choices) should be part of a general refactoring of the whole overlay/gizmos rendering... covering the situation of: LineAxis, Grid, OglFrame, how imGUI and Sofa.Qt's are actually implementing the overlays and how to configure that ViewerSettings, VisualStyle.

protected:
void drawIndices(const sofa::type::BoundingBox& bbox, const std::vector<sofa::type::Vec3>& positions);

/// internally called while the actual viewer needs a redraw (ie the camera changed)
virtual void redraw() = 0;

Expand All @@ -135,6 +151,7 @@ class SOFA_GUI_COMMON_API BaseViewer
bool _video;
bool m_isVideoButtonPressed;
bool m_bShowAxis;

bool _fullScreen;
int _background;
bool initTexturesDone;
Expand All @@ -153,6 +170,8 @@ class SOFA_GUI_COMMON_API BaseViewer
int _mouseInteractorSavedPosY;

std::string _screenshotDirectory;

std::set<sofa::core::objectmodel::Base::SPtr> currentSelection;
};

} // namespace sofa::gui::common