1
/***************************************************************************
2
* Copyright (c) 2014 Stefan Tröger <stefantroeger@gmx.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
26
# include <Inventor/nodes/SoCamera.h>
29
#include <Base/GeometryPyCXX.h>
30
#include <Base/Interpreter.h>
31
#include <Base/MatrixPy.h>
33
#include "PythonWrapper.h"
34
#include "View3DViewerPy.h"
35
#include "View3DInventorViewer.h"
41
void View3DInventorViewerPy::init_type()
43
behaviors().name("View3DInventorViewerPy");
44
behaviors().doc("Python binding class for the 3D viewer class");
45
// you must have overwritten the virtual functions
46
behaviors().supportRepr();
47
behaviors().supportGetattr();
48
behaviors().supportSetattr();
50
add_varargs_method("getSoRenderManager",&View3DInventorViewerPy::getSoRenderManager,"getSoRenderManager() -> SoRenderManager\n"
51
"Returns the render manager which is used to handle everything related to\n"
52
"rendering the scene graph. It can be used to get full control over the\n"
55
add_varargs_method("getSoEventManager",&View3DInventorViewerPy::getSoEventManager,"getSoEventManager() -> SoEventManager\n"
56
"Returns the event manager which is used to handle everything event related in\n"
57
"the viewer. It can be used to change the event processing. This must however be\n"
58
"done very carefully to not change the user interaction in an unpredictable manner.\n"
60
add_varargs_method("getSceneGraph", &View3DInventorViewerPy::getSceneGraph, "getSceneGraph() -> SoNode");
61
add_varargs_method("setSceneGraph", &View3DInventorViewerPy::setSceneGraph, "setSceneGraph(SoNode)");
63
add_varargs_method("seekToPoint",&View3DInventorViewerPy::seekToPoint,"seekToPoint(tuple) -> None\n"
64
"Initiate a seek action towards the 3D intersection of the scene and the\n"
65
"ray from the screen coordinate's point and in the same direction as the\n"
66
"camera is pointing. If the tuple has two entries it is interpreted as the\n"
67
"screen coordinates xy and the intersection point with the scene is\n"
68
"calculated. If three entries are given it is interpreted as the intersection\n"
69
"point xyz and the seek is done towards this point"
71
add_varargs_method("setFocalDistance",&View3DInventorViewerPy::setFocalDistance,"setFocalDistance(float) -> None\n");
72
add_varargs_method("getFocalDistance",&View3DInventorViewerPy::getFocalDistance,"getFocalDistance() -> float\n");
73
add_varargs_method("getPoint", &View3DInventorViewerPy::getPointOnFocalPlane, "Same as getPointOnFocalPlane");
74
add_varargs_method("getPointOnFocalPlane", &View3DInventorViewerPy::getPointOnFocalPlane, "getPointOnFocalPlane(x, y) -> Base::Vector(x,y,z)");
75
add_varargs_method("getPickRadius", &View3DInventorViewerPy::getPickRadius,
76
"getPickRadius(): returns radius of confusion in pixels for picking objects on screen (selection).");
77
add_varargs_method("setPickRadius", &View3DInventorViewerPy::setPickRadius,
78
"setPickRadius(new_radius): sets radius of confusion in pixels for picking objects on screen (selection).");
79
add_varargs_method("setupEditingRoot", &View3DInventorViewerPy::setupEditingRoot,
80
"setupEditingRoot(matrix=None): setup the editing ViewProvider's root node.\n"
81
"All child coin nodes of the current editing ViewProvider will be transferred to\n"
82
"an internal editing node of this viewer, with a new transformation node specified\n"
83
"by 'matrix'. All ViewProviderLink to the editing ViewProvider will be temporary\n"
84
"hidden. Call resetEditingRoot() to restore everything back to normal");
85
add_varargs_method("resetEditingRoot", &View3DInventorViewerPy::resetEditingRoot,
86
"resetEditingRoot(updateLinks=True): restore the editing ViewProvider's root node");
87
add_varargs_method("setBackgroundColor", &View3DInventorViewerPy::setBackgroundColor,
88
"setBackgroundColor(r,g,b): sets the background color of the current viewer.");
89
add_varargs_method("setGradientBackground", &View3DInventorViewerPy::setGradientBackground,
90
"setGradientBackground(str): sets the background gradient of the current viewer.");
91
add_varargs_method("setGradientBackgroundColor", &View3DInventorViewerPy::setGradientBackgroundColor,
92
"setGradientBackgroundColor(tuple,tuple,[tuple]): sets the gradient colors of the current viewer.");
93
add_varargs_method("setRedirectToSceneGraph", &View3DInventorViewerPy::setRedirectToSceneGraph,
94
"setRedirectToSceneGraph(bool): enables or disables to redirect events directly to the scene graph.");
95
add_varargs_method("isRedirectedToSceneGraph", &View3DInventorViewerPy::isRedirectedToSceneGraph,
96
"isRedirectedToSceneGraph() -> bool: check whether event redirection is enabled.");
97
add_varargs_method("grabFramebuffer", &View3DInventorViewerPy::grabFramebuffer,
98
"grabFramebuffer() -> QImage: renders and returns a 32-bit RGB image of the framebuffer.");
99
add_varargs_method("setEnabledNaviCube", &View3DInventorViewerPy::setEnabledNaviCube,
100
"setEnabledNaviCube(bool): enables or disables the navi cube of the viewer.");
101
add_varargs_method("isEnabledNaviCube", &View3DInventorViewerPy::isEnabledNaviCube,
102
"isEnabledNaviCube() -> bool: check whether the navi cube is enabled.");
103
add_varargs_method("setNaviCubeCorner", &View3DInventorViewerPy::setNaviCubeCorner,
104
"setNaviCubeCorner(int): sets the corner where to show the navi cube:\n"
105
"0=top left, 1=top right, 2=bottom left, 3=bottom right");
108
View3DInventorViewerPy::View3DInventorViewerPy(View3DInventorViewer *vi)
113
View3DInventorViewerPy::~View3DInventorViewerPy()
115
Base::PyGILStateLocker lock;
116
for (auto it : callbacks)
121
Py::Object View3DInventorViewerPy::repr()
123
std::ostringstream s_out;
125
throw Py::RuntimeError("Cannot print representation of deleted object");
126
s_out << "View3DInventorViewer";
127
return Py::String(s_out.str());
130
View3DInventorViewerPy::method_varargs_handler View3DInventorViewerPy::pycxx_handler = nullptr;
132
PyObject *View3DInventorViewerPy::method_varargs_ext_handler(PyObject *_self_and_name_tuple, PyObject *_args)
135
return pycxx_handler(_self_and_name_tuple, _args);
137
catch (const Base::Exception& e) {
138
throw Py::RuntimeError(e.what());
140
catch (const std::exception& e) {
141
throw Py::RuntimeError(e.what());
144
throw Py::RuntimeError("Unknown C++ exception");
148
Py::Object View3DInventorViewerPy::getattr(const char * attr)
152
std::ostringstream s_out;
153
s_out << "Cannot access attribute '" << attr << "' of deleted object";
154
throw Py::RuntimeError(s_out.str());
157
Py::Object obj = Py::PythonExtension<View3DInventorViewerPy>::getattr(attr);
158
if (PyCFunction_Check(obj.ptr())) {
159
auto op = reinterpret_cast<PyCFunctionObject*>(obj.ptr());
161
pycxx_handler = op->m_ml->ml_meth;
162
op->m_ml->ml_meth = method_varargs_ext_handler;
168
int View3DInventorViewerPy::setattr(const char * attr, const Py::Object & value)
172
std::ostringstream s_out;
173
s_out << "Cannot access attribute '" << attr << "' of deleted object";
174
throw Py::RuntimeError(s_out.str());
177
return Py::PythonExtension<View3DInventorViewerPy>::setattr(attr, value);
181
Py::Object View3DInventorViewerPy::getSoRenderManager(const Py::Tuple& args)
183
if (!PyArg_ParseTuple(args.ptr(), ""))
184
throw Py::Exception();
187
SoRenderManager* manager = _viewer->getSoRenderManager();
188
PyObject* proxy = nullptr;
189
proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoRenderManager *", static_cast<void*>(manager), 0);
190
return Py::Object(proxy, true);
192
catch (const Base::Exception& e) {
193
throw Py::RuntimeError(e.what());
197
Py::Object View3DInventorViewerPy::getSceneGraph(const Py::Tuple& args)
199
if (!PyArg_ParseTuple(args.ptr(), ""))
200
throw Py::Exception();
203
SoNode* scene = _viewer->getSceneGraph();
204
PyObject* proxy = nullptr;
205
proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoSeparator *", static_cast<void*>(scene), 1);
207
return Py::Object(proxy, true);
209
catch (const Base::Exception& e) {
210
throw Py::RuntimeError(e.what());
214
Py::Object View3DInventorViewerPy::setSceneGraph(const Py::Tuple& args)
217
if (!PyArg_ParseTuple(args.ptr(), "O", &proxy))
218
throw Py::Exception();
222
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", proxy, &ptr, 0);
223
auto node = static_cast<SoNode*>(ptr);
224
_viewer->setSceneGraph(node);
227
catch (const Base::Exception& e) {
228
throw Py::RuntimeError(e.what());
232
Py::Object View3DInventorViewerPy::getSoEventManager(const Py::Tuple& args)
234
if (!PyArg_ParseTuple(args.ptr(), ""))
235
throw Py::Exception();
238
SoEventManager* manager = _viewer->getSoEventManager();
239
PyObject* proxy = nullptr;
240
proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoEventManager *", static_cast<void*>(manager), 0);
241
return Py::Object(proxy, true);
243
catch (const Base::Exception& e) {
244
throw Py::RuntimeError(e.what());
248
Py::Object View3DInventorViewerPy::seekToPoint(const Py::Tuple& args)
251
if (!PyArg_ParseTuple(args.ptr(), "O", &object))
252
throw Py::Exception();
255
const Py::Tuple tuple(object);
257
// If the 3d point is given
258
if (tuple.size() == 3) {
259
Py::Float x = tuple[0];
260
Py::Float y = tuple[1];
261
Py::Float z = tuple[2];
263
SbVec3f hitpoint((float)x,(float)y,(float)z);
264
_viewer->seekToPoint(hitpoint);
270
SbVec2s hitpoint ((long)x,(long)y);
271
_viewer->seekToPoint(hitpoint);
276
catch (const Py::Exception&) {
281
Py::Object View3DInventorViewerPy::setFocalDistance(const Py::Tuple& args)
284
if (!PyArg_ParseTuple(args.ptr(), "f", &distance))
285
throw Py::Exception();
288
SoCamera* cam = _viewer->getSoRenderManager()->getCamera();
290
cam->focalDistance.setValue(distance);
292
catch (const Py::Exception&) {
295
catch (const Base::Exception& e) {
296
throw Py::RuntimeError(e.what());
298
catch (const std::exception& e) {
299
throw Py::RuntimeError(e.what());
302
throw Py::RuntimeError("Unknown C++ exception");
308
Py::Object View3DInventorViewerPy::getFocalDistance(const Py::Tuple& args)
310
if (!PyArg_ParseTuple(args.ptr(), ""))
311
throw Py::Exception();
314
double d = _viewer->getSoRenderManager()->getCamera()->focalDistance.getValue();
317
catch (const Base::Exception& e) {
318
throw Py::RuntimeError(e.what());
320
catch (const std::exception& e) {
321
throw Py::RuntimeError(e.what());
324
throw Py::RuntimeError("Unknown C++ exception");
328
Py::Object View3DInventorViewerPy::getPointOnFocalPlane(const Py::Tuple& args)
331
if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
333
Py::Tuple t(args[0]);
334
x = (int)Py::Int(t[0]);
335
y = (int)Py::Int(t[1]);
338
SbVec3f pt = _viewer->getPointOnFocalPlane(SbVec2s(x,y));
339
return Py::Vector(Base::Vector3f(pt[0], pt[1], pt[2]));
341
catch (const Base::Exception& e) {
342
throw Py::RuntimeError(e.what());
344
catch (const Py::Exception&) {
349
Py::Object View3DInventorViewerPy::getPickRadius(const Py::Tuple& args)
351
if (!PyArg_ParseTuple(args.ptr(), ""))
352
throw Py::Exception();
354
double d = _viewer->getPickRadius();
358
Py::Object View3DInventorViewerPy::setPickRadius(const Py::Tuple& args)
361
if (!PyArg_ParseTuple(args.ptr(), "f", &r)) {
362
throw Py::Exception();
366
throw Py::ValueError(std::string("Pick radius is zero or negative; positive number is required."));
369
_viewer->setPickRadius(r);
372
catch (const Base::Exception& e) {
373
throw Py::RuntimeError(e.what());
375
catch (const std::exception& e) {
376
throw Py::RuntimeError(e.what());
379
throw Py::RuntimeError("Unknown C++ exception");
383
Py::Object View3DInventorViewerPy::setupEditingRoot(const Py::Tuple& args)
385
PyObject *pynode = Py_None;
386
PyObject *pymat = Py_None;
387
if (!PyArg_ParseTuple(args.ptr(), "|OO!", &pynode,&Base::MatrixPy::Type,&pymat)) {
388
throw Py::Exception();
391
Base::Matrix4D *mat = nullptr;
393
mat = static_cast<Base::MatrixPy*>(pymat)->getMatrixPtr();
396
SoNode *node = nullptr;
397
if(pynode!=Py_None) {
399
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", pynode, &ptr, 0);
400
node = static_cast<SoNode*>(ptr);
402
_viewer->setupEditingRoot(node,mat);
405
catch (const Base::Exception& e) {
407
throw Py::Exception();
409
catch (const std::exception& e) {
410
throw Py::RuntimeError(e.what());
413
throw Py::RuntimeError("Unknown C++ exception");
417
Py::Object View3DInventorViewerPy::resetEditingRoot(const Py::Tuple& args)
419
PyObject *updateLinks = Py_True;
420
if (!PyArg_ParseTuple(args.ptr(), "|O!", &PyBool_Type, &updateLinks)) {
421
throw Py::Exception();
424
_viewer->resetEditingRoot(Base::asBoolean(updateLinks));
427
catch (const Base::Exception& e) {
429
throw Py::Exception();
431
catch (const std::exception& e) {
432
throw Py::RuntimeError(e.what());
435
throw Py::RuntimeError("Unknown C++ exception");
439
Py::Object View3DInventorViewerPy::setGradientBackground(const Py::Tuple& args)
441
const char* background;
442
if (!PyArg_ParseTuple(args.ptr(), "s", &background)) {
443
throw Py::Exception();
446
View3DInventorViewer::Background gradient = View3DInventorViewer::Background::NoGradient;
447
if (strcmp(background, "LINEAR") == 0) {
448
gradient = View3DInventorViewer::Background::LinearGradient;
450
else if (strcmp(background, "RADIAL") == 0) {
451
gradient = View3DInventorViewer::Background::RadialGradient;
454
_viewer->setGradientBackground(gradient);
458
catch (const Base::Exception& e) {
459
throw Py::RuntimeError(e.what());
461
catch (const std::exception& e) {
462
throw Py::RuntimeError(e.what());
465
throw Py::RuntimeError("Unknown C++ exception");
469
Py::Object View3DInventorViewerPy::setGradientBackgroundColor(const Py::Tuple& args)
473
PyObject* col3 = nullptr;
474
if (!PyArg_ParseTuple(args.ptr(), "O!O!|O!",
475
&PyTuple_Type, &col1,
476
&PyTuple_Type, &col2,
477
&PyTuple_Type, &col3)) {
478
throw Py::Exception();
481
auto tupleToColor = [](PyObject* col) {
483
Py::Tuple tuple(col);
484
for (int i=0; i<3; i++) {
485
color[i] = static_cast<float>(Py::Float(tuple[i]));
492
SbColor midColor(-1, -1, -1);
493
SbColor fromColor = tupleToColor(col1);
494
SbColor toColor = tupleToColor(col2);
496
midColor = tupleToColor(col3);
499
_viewer->setGradientBackgroundColor(fromColor, toColor, midColor);
503
catch (const Base::Exception& e) {
504
throw Py::RuntimeError(e.what());
506
catch (const std::exception& e) {
507
throw Py::RuntimeError(e.what());
510
throw Py::RuntimeError("Unknown C++ exception");
514
Py::Object View3DInventorViewerPy::setBackgroundColor(const Py::Tuple& args)
516
float red, green, blue = 0.0;
517
if (!PyArg_ParseTuple(args.ptr(), "fff", &red, &green, &blue)) {
518
throw Py::Exception();
521
SbColor col(red, green, blue);
522
_viewer->setGradientBackgroundColor(col, col);
525
qtcolor.setRedF(red);
526
qtcolor.setGreenF(green);
527
qtcolor.setBlueF(blue);
528
if (qtcolor.isValid()) {
529
_viewer->setBackgroundColor(qtcolor);
534
catch (const Base::Exception& e) {
535
throw Py::RuntimeError(e.what());
537
catch (const std::exception& e) {
538
throw Py::RuntimeError(e.what());
541
throw Py::RuntimeError("Unknown C++ exception");
545
Py::Object View3DInventorViewerPy::setRedirectToSceneGraph(const Py::Tuple& args)
547
PyObject* m=Py_False;
548
if (!PyArg_ParseTuple(args.ptr(), "O!", &PyBool_Type, &m))
549
throw Py::Exception();
550
_viewer->setRedirectToSceneGraph(Base::asBoolean(m));
554
Py::Object View3DInventorViewerPy::isRedirectedToSceneGraph(const Py::Tuple& args)
556
if (!PyArg_ParseTuple(args.ptr(), ""))
557
throw Py::Exception();
558
bool ok = _viewer->isRedirectedToSceneGraph();
559
return Py::Boolean(ok);
562
Py::Object View3DInventorViewerPy::grabFramebuffer(const Py::Tuple& args)
564
if (!PyArg_ParseTuple(args.ptr(), ""))
565
throw Py::Exception();
566
QImage img = _viewer->grabFramebuffer();
569
wrap.loadGuiModule();
570
return wrap.fromQImage(img.mirrored());
573
Py::Object View3DInventorViewerPy::setEnabledNaviCube(const Py::Tuple& args)
575
PyObject* m=Py_False;
576
if (!PyArg_ParseTuple(args.ptr(), "O!", &PyBool_Type, &m))
577
throw Py::Exception();
578
_viewer->setEnabledNaviCube(Base::asBoolean(m));
582
Py::Object View3DInventorViewerPy::isEnabledNaviCube(const Py::Tuple& args)
584
if (!PyArg_ParseTuple(args.ptr(), ""))
585
throw Py::Exception();
586
bool ok = _viewer->isEnabledNaviCube();
587
return Py::Boolean(ok);
590
Py::Object View3DInventorViewerPy::setNaviCubeCorner(const Py::Tuple& args)
593
if (!PyArg_ParseTuple(args.ptr(), "i", &pos))
594
throw Py::Exception();
595
if (pos < 0 || pos > 3)
596
throw Py::IndexError("Value out of range");
597
_viewer->setNaviCubeCorner(pos);