diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 0b134306347c..1c542629c590 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -47,9 +47,11 @@ # include # include # include +# include #endif #include +#include #include #include #include @@ -70,8 +72,10 @@ #include "View3DInventorViewer.h" #include "View3DPy.h" #include "ViewProvider.h" +#include "ViewProviderDocumentObject.h" #include "WaitCursor.h" +#include "Utilities.h" using namespace Gui; @@ -773,6 +777,97 @@ void View3DInventor::setCurrentViewMode(ViewMode newmode) } } +RayPickInfo View3DInventor::getObjInfoRay(Base::Vector3d* startvec, Base::Vector3d* dirvec) +{ + double vsx, vsy, vsz; + double vdx, vdy, vdz; + vsx = startvec->x; + vsy = startvec->y; + vsz = startvec->z; + vdx = dirvec->x; + vdy = dirvec->y; + vdz = dirvec->z; + // near plane clipping is required to avoid false intersections + float near = 0.1; + + RayPickInfo ret = {.isValid = false, + .point = Base::Vector3d(), + .document = "", + .object = "", + .parentObject = std::nullopt, + .component = std::nullopt, + .subName = std::nullopt}; + SoRayPickAction action(getViewer()->getSoRenderManager()->getViewportRegion()); + action.setRay(SbVec3f(vsx, vsy, vsz), SbVec3f(vdx, vdy, vdz), near); + action.apply(getViewer()->getSoRenderManager()->getSceneGraph()); + SoPickedPoint* Point = action.getPickedPoint(); + + if (!Point) { + return ret; + } + + ret.point = Base::convertTo(Point->getPoint()); + ViewProvider* vp = getViewer()->getViewProviderByPath(Point->getPath()); + if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { + if (!vp->isSelectable()) { + return ret; + } + auto vpd = static_cast(vp); + if (vp->useNewSelectionModel()) { + std::string subname; + if (!vp->getElementPicked(Point, subname)) { + return ret; + } + auto obj = vpd->getObject(); + if (!obj) { + return ret; + } + if (!subname.empty()) { + App::ElementNamePair elementName; + auto sobj = App::GeoFeature::resolveElement(obj, subname.c_str(), elementName); + if (!sobj) { + return ret; + } + if (sobj != obj) { + ret.parentObject = obj->getExportName(); + ret.subName = subname; + obj = sobj; + } + subname = !elementName.oldName.empty() ? elementName.oldName : elementName.newName; + } + ret.document = obj->getDocument()->getName(); + ret.object = obj->getNameInDocument(); + ret.component = subname; + ret.isValid = true; + } + else { + ret.document = vpd->getObject()->getDocument()->getName(); + ret.object = vpd->getObject()->getNameInDocument(); + // search for a SoFCSelection node + SoFCDocumentObjectAction objaction; + objaction.apply(Point->getPath()); + if (objaction.isHandled()) { + ret.component = objaction.componentName.getString(); + } + } + // ok, found the node of interest + ret.isValid = true; + } + else { + // custom nodes not in a VP: search for a SoFCSelection node + SoFCDocumentObjectAction objaction; + objaction.apply(Point->getPath()); + if (objaction.isHandled()) { + ret.document = objaction.documentName.getString(); + ret.object = objaction.objectName.getString(); + ret.component = objaction.componentName.getString(); + // ok, found the node of interest + ret.isValid = true; + } + } + return ret; +} + bool View3DInventor::eventFilter(QObject* watched, QEvent* e) { // As long as this widget is a top-level window (either in 'TopLevel' or 'FullScreen' mode) we diff --git a/src/Gui/View3DInventor.h b/src/Gui/View3DInventor.h index 3bfe2b237ad9..882265183acb 100644 --- a/src/Gui/View3DInventor.h +++ b/src/Gui/View3DInventor.h @@ -31,6 +31,7 @@ #include "MDIView.h" +#include "Base/Vector3D.h" class QPrinter; class QStackedWidget; @@ -43,6 +44,16 @@ class View3DPy; class View3DSettings; class NaviCubeSettings; +struct RayPickInfo +{ + bool isValid; + Base::Vector3d point; + std::string document; + std::string object; + std::optional parentObject; + std::optional component; + std::optional subName; +}; class GuiExport GLOverlayWidget : public QWidget { Q_OBJECT @@ -98,6 +109,8 @@ class GuiExport View3DInventor : public MDIView * GL widget to get all key events in \a TopLevel or \a Fullscreen mode. */ void setCurrentViewMode(ViewMode b) override; + RayPickInfo getObjInfoRay(Base::Vector3d* startvec, + Base::Vector3d* dirvec); bool setCamera(const char* pCamera); void toggleClippingPlane(); bool hasClippingPlane() const; diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index e2e73772a5c6..41eae0c32e79 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -158,6 +158,14 @@ void View3DInventorPy::init_type() "\n" "Does the same as getObjectInfo() but returns a list of dictionaries or None.\n"); add_noargs_method("getSize",&View3DInventorPy::getSize,"getSize()"); + add_varargs_method("getObjectInfoRay",&View3DInventorPy::getObjectInfoRay, + "getObjectInfoRay(tuple(3D vector,3D vector) or tuple of 6 floats) -> dictionary or None\n" + "\n" + "Vectors represent start point and direction of intersection ray\n" + "Return a dictionary with the name of document, object and component. The\n" + "dictionary also contains the coordinates of the appropriate 3d point of\n" + "the underlying geometry in the scenegraph.\n" + "If no geometry was found 'None' is returned, instead.\n"); add_varargs_method("getPoint",&View3DInventorPy::getPointOnFocalPlane, "Same as getPointOnFocalPlane"); add_varargs_method("getPointOnFocalPlane",&View3DInventorPy::getPointOnFocalPlane, @@ -1501,6 +1509,54 @@ Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args) } } +Py::Object View3DInventorPy::getObjectInfoRay(const Py::Tuple& args) +{ + PyObject* vs; + PyObject* vd; + double vsx, vsy, vsz; + double vdx, vdy, vdz; + Py::Object ret = Py::None(); + if (PyArg_ParseTuple(args.ptr(), + "O!O!", + &Base::VectorPy::Type, + &vs, + &Base::VectorPy::Type, + &vd)) { + Base::Vector3d* startvec = static_cast(vs)->getVectorPtr(); + Base::Vector3d* dirvec = static_cast(vd)->getVectorPtr(); + try { + RayPickInfo pinfo = getView3DIventorPtr()->getObjInfoRay(startvec, dirvec); + if (!pinfo.isValid) { + return ret; + } + Py::Dict dict; + dict.setItem("PickedPoint", Py::asObject(new Base::VectorPy(pinfo.point))); + dict.setItem("Document", Py::String(pinfo.document)); + dict.setItem("Object", Py::String(pinfo.object)); + if (pinfo.parentObject) { + dict.setItem("ParentObject", Py::String(pinfo.parentObject.value())); + } + if (pinfo.component) { + dict.setItem("Component", Py::String(pinfo.component.value())); + } + if (pinfo.subName) { + dict.setItem("SubName", Py::String(pinfo.subName.value())); + } + ret = dict; + } + catch (const Py::Exception&) { + throw; + } + } + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args.ptr(), "dddddd", &vsx, &vsy, &vsz, &vdx, &vdy, &vdz)) { + throw Py::TypeError("Wrong arguments, two Vectors or six floats expected"); + } + } + return ret; +} + Py::Object View3DInventorPy::getSize() { try { diff --git a/src/Gui/View3DPy.h b/src/Gui/View3DPy.h index 2a63dc7d045c..08ad8aa07e93 100644 --- a/src/Gui/View3DPy.h +++ b/src/Gui/View3DPy.h @@ -95,6 +95,7 @@ class View3DInventorPy : public Py::PythonExtension Py::Object getObjectInfo(const Py::Tuple&); Py::Object getObjectsInfo(const Py::Tuple&); Py::Object getSize(); + Py::Object getObjectInfoRay(const Py::Tuple&); Py::Object getPointOnFocalPlane(const Py::Tuple&); Py::Object projectPointToLine(const Py::Tuple&); Py::Object getPointOnViewport(const Py::Tuple&);