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:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user