Gui: add box geometry element selection command

Implement box element selection that support linked and grouped objects.
Also modified original box selection command to support the same with
the same code.
This commit is contained in:
Zheng, Lei
2019-07-11 13:49:15 +08:00
committed by wmayer
parent 81d3cf1b89
commit f7edaabe43
3 changed files with 266 additions and 32 deletions

View File

@@ -70,6 +70,7 @@
#include "NavigationStyle.h"
#include <Base/Console.h>
#include <Base/Tools2D.h>
#include <Base/Exception.h>
#include <Base/FileInfo.h>
#include <Base/Reader.h>
@@ -80,6 +81,8 @@
#include <App/DocumentObjectGroup.h>
#include <App/MeasureDistance.h>
#include <App/DocumentObject.h>
#include <App/ComplexGeoDataPy.h>
#include <App/GeoFeatureGroupExtension.h>
#include <QDomDocument>
#include <QDomElement>
@@ -785,6 +788,7 @@ StdCmdToggleVisibility::StdCmdToggleVisibility()
eType = Alter3DView;
}
void StdCmdToggleVisibility::activated(int iMsg)
{
Q_UNUSED(iMsg);
@@ -2463,14 +2467,139 @@ StdBoxSelection::StdBoxSelection()
eType = AlterSelection;
}
typedef enum { CENTER, INTERSECT } SelectionMode;
static std::vector<std::string> getBoxSelection(
ViewProviderDocumentObject *vp, SelectionMode mode, bool selectElement,
const Base::ViewProjMethod &proj, const Base::Polygon2d &polygon,
const Base::Matrix4D &mat, bool transform=true, int depth=0)
{
std::vector<std::string> ret;
auto obj = vp->getObject();
if(!obj || !obj->getNameInDocument())
return ret;
// DO NOT check this view object Visibility, let the caller do this. Because
// we may be called by upper object hierarchy that manages our visibility.
auto bbox3 = vp->getBoundingBox(0,transform);
if(!bbox3.IsValid())
return ret;
auto bbox = bbox3.Transformed(mat).ProjectBox(&proj);
// check if both two boundary points are inside polygon, only
// valid since we know the given polygon is a box.
if(polygon.Contains(Base::Vector2d(bbox.MinX,bbox.MinY)) &&
polygon.Contains(Base::Vector2d(bbox.MaxX,bbox.MaxY)))
{
ret.emplace_back("");
return ret;
}
if(!bbox.Intersect(polygon))
return ret;
const auto &subs = obj->getSubObjects(App::DocumentObject::GS_SELECT);
if(subs.empty()) {
if(!selectElement) {
if(mode==INTERSECT || bbox.Contains(bbox.GetCenter()))
ret.emplace_back("");
return ret;
}
Base::PyGILStateLocker lock;
PyObject *pyobj = 0;
Base::Matrix4D matCopy(mat);
obj->getSubObject(0,&pyobj,&matCopy,transform,depth);
if(!pyobj)
return ret;
Py::Object pyobject(pyobj,true);
if(!PyObject_TypeCheck(pyobj,&Data::ComplexGeoDataPy::Type))
return ret;
auto data = static_cast<Data::ComplexGeoDataPy*>(pyobj)->getComplexGeoDataPtr();
for(auto type : data->getElementTypes()) {
size_t count = data->countSubElements(type);
if(!count)
continue;
for(size_t i=1;i<=count;++i) {
std::string element(type);
element += std::to_string(i);
std::unique_ptr<Data::Segment> segment(data->getSubElementByName(element.c_str()));
if(!segment)
continue;
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
data->getLinesFromSubelement(segment.get(),points,lines);
if(lines.empty()) {
if(points.empty())
continue;
auto v = proj(points[0]);
if(polygon.Contains(Base::Vector2d(v.x,v.y)))
ret.push_back(element);
continue;
}
Base::Polygon2d loop;
// TODO: can we assume the line returned above are in proper
// order if the element is a face?
auto v = proj(points[lines.front().I1]);
loop.Add(Base::Vector2d(v.x,v.y));
for(auto &line : lines) {
for(auto i=line.I1;i<line.I2;++i) {
auto v = proj(points[i+1]);
loop.Add(Base::Vector2d(v.x,v.y));
}
}
if(!polygon.Intersect(loop))
continue;
if(mode==CENTER && !polygon.Contains(loop.CalcBoundBox().GetCenter()))
continue;
ret.push_back(element);
}
break;
}
return ret;
}
size_t count = 0;
for(auto &sub : subs) {
App::DocumentObject *parent = 0;
std::string childName;
Base::Matrix4D smat(mat);
auto sobj = obj->resolve(sub.c_str(),&parent,&childName,0,0,&smat,transform,depth+1);
if(!sobj)
continue;
int vis;
if(!parent || (vis=parent->isElementVisible(childName.c_str()))<0)
vis = sobj->Visibility.getValue()?1:0;
if(!vis)
continue;
auto svp = dynamic_cast<ViewProviderDocumentObject*>(Application::Instance->getViewProvider(sobj));
if(!svp)
continue;
const auto &sels = getBoxSelection(svp,mode,selectElement,proj,polygon,smat,false,depth+1);
if(sels.size()==1 && sels[0] == "")
++count;
for(auto &sel : sels)
ret.emplace_back(sub+sel);
}
if(count==subs.size()) {
ret.resize(1);
ret[0].clear();
}
return ret;
}
static void selectionCallback(void * ud, SoEventCallback * cb)
{
bool selectElement = ud?true:false;
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(cb->getUserData());
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud);
SoNode* root = view->getSceneGraph();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(true);
typedef enum { CENTER, INTERSECT } SelectionMode;
SelectionMode selectionMode = CENTER;
std::vector<SbVec2f> picked = view->getGLPolygon();
@@ -2505,33 +2634,17 @@ static void selectionCallback(void * ud, SoEventCallback * cb)
Gui::Selection().clearSelection(doc->getName());
}
std::vector<App::DocumentObject*> geom = doc->getObjectsOfType<App::DocumentObject>();
for (std::vector<App::DocumentObject*>::iterator it = geom.begin(); it != geom.end(); ++it) {
Gui::ViewProvider* vp = Application::Instance->getViewProvider(*it);
if (!vp->isVisible())
for(auto obj : doc->getObjects()) {
if(App::GeoFeatureGroupExtension::getGroupOfObject(obj))
continue;
// 0002706: For box selection use SoGetBoundingBoxAction for
// the view provider of an object
SoGetBoundingBoxAction bboxAction(view->getViewportRegion());
bboxAction.apply(vp->getRoot());
SbBox3f bbox = bboxAction.getBoundingBox();
Base::BoundBox3d bbox3;
bbox3.Add(Base::convertTo<Base::Vector3d>(bbox.getMax()));
bbox3.Add(Base::convertTo<Base::Vector3d>(bbox.getMin()));
if (selectionMode == CENTER) {
Base::Vector3d pt2d;
pt2d = proj(bbox3.GetCenter());
if (polygon.Contains(Base::Vector2d(pt2d.x, pt2d.y))) {
Gui::Selection().addSelection(doc->getName(), (*it)->getNameInDocument());
}
}
else {
Base::BoundBox2d bbox2 = bbox3.ProjectBox(&proj);
if (bbox2.Intersect(polygon)) {
Gui::Selection().addSelection(doc->getName(), (*it)->getNameInDocument());
}
}
auto vp = dynamic_cast<ViewProviderDocumentObject*>(Application::Instance->getViewProvider(obj));
if (!vp || !vp->isVisible())
continue;
Base::Matrix4D mat;
for(auto &sub : getBoxSelection(vp,selectionMode,selectElement,proj,polygon,mat))
Gui::Selection().addSelection(doc->getName(), obj->getNameInDocument(), sub.c_str());
}
}
}
@@ -2558,6 +2671,49 @@ void StdBoxSelection::activated(int iMsg)
}
}
//===========================================================================
// Std_BoxElementSelection
//===========================================================================
DEF_3DV_CMD(StdBoxElementSelection)
StdBoxElementSelection::StdBoxElementSelection()
: Command("Std_BoxElementSelection")
{
sGroup = QT_TR_NOOP("Standard-View");
sMenuText = QT_TR_NOOP("Box element selection");
sToolTipText = QT_TR_NOOP("Box element selection");
sWhatsThis = "Std_BoxElementSelection";
sStatusTip = QT_TR_NOOP("Box element selection");
#if QT_VERSION >= 0x040200
sPixmap = "edit-element-select-box";
#endif
sAccel = "Shift+E";
eType = AlterSelection;
}
void StdBoxElementSelection::activated(int iMsg)
{
Q_UNUSED(iMsg);
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
if (view) {
View3DInventorViewer* viewer = view->getViewer();
if (!viewer->isSelecting()) {
// #0002931: Box select misbehaves with touchpad navigation style
// Notify the navigation style to cleanup internal states
int mode = viewer->navigationStyle()->getViewingMode();
if (mode != Gui::NavigationStyle::IDLE) {
SoKeyboardEvent ev;
viewer->navigationStyle()->processEvent(&ev);
}
viewer->startSelection(View3DInventorViewer::Rubberband);
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, this);
SoNode* root = viewer->getSceneGraph();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(false);
}
}
}
//===========================================================================
// Std_TreeSelection
//===========================================================================
@@ -3350,7 +3506,7 @@ void CreateViewStdCommands(void)
rcCmdMgr.addCommand(new StdViewZoomOut());
rcCmdMgr.addCommand(new StdViewBoxZoom());
rcCmdMgr.addCommand(new StdBoxSelection());
rcCmdMgr.addCommand(new StdCmdTreeSelection());
rcCmdMgr.addCommand(new StdBoxElementSelection());
rcCmdMgr.addCommand(new StdCmdTreeExpand());
rcCmdMgr.addCommand(new StdCmdTreeCollapse());
rcCmdMgr.addCommand(new StdCmdTreeSelectAllInstances());