Gui: add method to select objects with a 3D ray (#16789)
* Implementation of ray picking method for 3d picking * Ray picking logic moved to C++ (cherry picked from commit ed23214c0bce7b70fd1003a7c4612e2d0d7da4cb) * formatting, do not return unecessary dict keys, near plane clipping
This commit is contained in:
@@ -47,9 +47,11 @@
|
||||
# include <Inventor/nodes/SoOrthographicCamera.h>
|
||||
# include <Inventor/nodes/SoPerspectiveCamera.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <Inventor/SoPickedPoint.h>
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <Base/Builder3D.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
@@ -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<Base::Vector3d>(Point->getPoint());
|
||||
ViewProvider* vp = getViewer()->getViewProviderByPath(Point->getPath());
|
||||
if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
|
||||
if (!vp->isSelectable()) {
|
||||
return ret;
|
||||
}
|
||||
auto vpd = static_cast<ViewProviderDocumentObject*>(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
|
||||
|
||||
@@ -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<std::string> parentObject;
|
||||
std::optional<std::string> component;
|
||||
std::optional<std::string> subName;
|
||||
};
|
||||
class GuiExport GLOverlayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -98,6 +109,8 @@ public:
|
||||
* 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;
|
||||
|
||||
@@ -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<Base::VectorPy*>(vs)->getVectorPtr();
|
||||
Base::Vector3d* dirvec = static_cast<Base::VectorPy*>(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 {
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
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&);
|
||||
|
||||
Reference in New Issue
Block a user