FreeCAD

Форк
0
/
View3DPy.cpp 
2503 строки · 91.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
# include <QColor>
27
# include <QDir>
28
# include <QFileInfo>
29
# include <QImage>
30

31
# include <Inventor/SoPickedPoint.h>
32
# include <Inventor/actions/SoWriteAction.h>
33
# include <Inventor/annex/HardCopy/SoVectorizePSAction.h>
34
# include <Inventor/draggers/SoDragger.h>
35
# include <Inventor/nodes/SoCamera.h>
36
# include <Inventor/nodes/SoOrthographicCamera.h>
37
# include <Inventor/nodes/SoPerspectiveCamera.h>
38
#endif
39

40
#include <App/Application.h>
41
#include <App/Document.h>
42
#include <App/DocumentObject.h>
43
#include <App/DocumentObjectPy.h>
44
#include <App/GeoFeature.h>
45
#include <Base/Console.h>
46
#include <Base/Exception.h>
47
#include <Base/GeometryPyCXX.h>
48
#include <Base/Interpreter.h>
49
#include <Base/PlacementPy.h>
50
#include <Base/PyWrapParseTupleAndKeywords.h>
51
#include <Base/RotationPy.h>
52
#include <Base/VectorPy.h>
53

54
#include "View3DPy.h"
55

56
#include "Camera.h"
57
#include "Document.h"
58
#include "NavigationStyle.h"
59
#include "PythonWrapper.h"
60
#include "SoFCDB.h"
61
#include "SoFCOffscreenRenderer.h"
62
#include "SoFCSelectionAction.h"
63
#include "SoFCVectorizeSVGAction.h"
64
#include "SoFCVectorizeU3DAction.h"
65
#include "SoMouseWheelEvent.h"
66
#include "View3DInventor.h"
67
#include "View3DInventorViewer.h"
68
#include "ViewProviderDocumentObject.h"
69
#include "ViewProviderExtern.h"
70

71

72
using namespace Gui;
73

74

75
void View3DInventorPy::init_type()
76
{
77
    behaviors().name("View3DInventorPy");
78
    behaviors().doc("Python binding class for the Inventor viewer class");
79
    // you must have overwritten the virtual functions
80
    behaviors().supportRepr();
81
    behaviors().supportGetattr();
82
    behaviors().supportSetattr();
83

84
    add_varargs_method("fitAll",&View3DInventorPy::fitAll,"fitAll()");
85
    add_keyword_method("boxZoom",&View3DInventorPy::boxZoom,"boxZoom()");
86

87
    add_noargs_method("viewBottom",&View3DInventorPy::viewBottom,"viewBottom()");
88
    add_noargs_method("viewFront",&View3DInventorPy::viewFront,"viewFront()");
89
    add_noargs_method("viewLeft",&View3DInventorPy::viewLeft,"viewLeft()");
90
    add_noargs_method("viewRear",&View3DInventorPy::viewRear,"viewRear()");
91
    add_noargs_method("viewRight",&View3DInventorPy::viewRight,"viewRight()");
92
    add_noargs_method("viewTop",&View3DInventorPy::viewTop,"viewTop()");
93
    add_noargs_method("viewAxometric",&View3DInventorPy::viewIsometric,"viewAxonometric()"); // for backward compatibility
94
    add_noargs_method("viewAxonometric",&View3DInventorPy::viewIsometric,"viewAxonometric()");
95
    add_noargs_method("viewIsometric",&View3DInventorPy::viewIsometric,"viewIsometric()");
96
    add_noargs_method("viewDimetric",&View3DInventorPy::viewDimetric,"viewDimetric()");
97
    add_noargs_method("viewTrimetric",&View3DInventorPy::viewTrimetric,"viewTrimetric()");
98
    add_varargs_method("viewDefaultOrientation",&View3DInventorPy::viewDefaultOrientation,
99
                       "viewDefaultOrientation(ori_str = '', scale = -1.0): sets camera rotation to a predefined one, \n"
100
                       "and camera position and zoom to show certain amount of model space. \n"
101
                       "ori_string can be 'Top', 'Bottom', 'Front', 'Rear', 'Left', 'Right', \n"
102
                       "'Isometric', 'Dimetric', 'Trimetric', 'Custom'. If empty, the value is \n"
103
                       "fetched from Parameters.\n"
104
                       "scale sets distance from camera to origin, and height of the screen in \n"
105
                       "model space, so that a sphere of diameter <scale> fits the height of the\n"
106
                       "viewport. If zero, scaling is not done. If negative, the value is \n"
107
                       "fetched from Parameters.");
108
    add_noargs_method("viewRotateLeft",&View3DInventorPy::viewRotateLeft,"viewRotateLeft()");
109
    add_noargs_method("viewRotateRight",&View3DInventorPy::viewRotateRight,"viewRotateRight()");
110
    add_noargs_method("zoomIn",&View3DInventorPy::zoomIn,"zoomIn()");
111
    add_noargs_method("zoomOut",&View3DInventorPy::zoomOut,"zoomOut()");
112
    add_varargs_method("viewPosition",&View3DInventorPy::viewPosition,"viewPosition()");
113
    add_varargs_method("startAnimating",&View3DInventorPy::startAnimating,"startAnimating()");
114
    add_noargs_method("stopAnimating",&View3DInventorPy::stopAnimating,"stopAnimating()");
115
    add_varargs_method("setAnimationEnabled",&View3DInventorPy::setAnimationEnabled,"setAnimationEnabled()");
116
    add_noargs_method("isAnimationEnabled",&View3DInventorPy::isAnimationEnabled,"isAnimationEnabled()");
117
    add_varargs_method("setPopupMenuEnabled",&View3DInventorPy::setPopupMenuEnabled,"setPopupMenuEnabled()");
118
    add_noargs_method("isPopupMenuEnabled",&View3DInventorPy::isPopupMenuEnabled,"isPopupMenuEnabled()");
119
    add_varargs_method("dump",&View3DInventorPy::dump,"dump(filename, [onlyVisible=False])");
120
    add_varargs_method("dumpNode",&View3DInventorPy::dumpNode,"dumpNode(node)");
121
    add_varargs_method("setStereoType",&View3DInventorPy::setStereoType,"setStereoType()");
122
    add_noargs_method("getStereoType",&View3DInventorPy::getStereoType,"getStereoType()");
123
    add_noargs_method("listStereoTypes",&View3DInventorPy::listStereoTypes,"listStereoTypes()");
124
    add_varargs_method("saveImage",&View3DInventorPy::saveImage,"saveImage()");
125
    add_varargs_method("saveVectorGraphic",&View3DInventorPy::saveVectorGraphic,"saveVectorGraphic()");
126
    add_noargs_method("getCamera",&View3DInventorPy::getCamera,"getCamera()");
127
    add_noargs_method("getCameraNode",&View3DInventorPy::getCameraNode,"getCameraNode()");
128
    add_noargs_method("getViewDirection",&View3DInventorPy::getViewDirection,"getViewDirection() --> tuple of floats\n"
129
        "returns the direction vector the view is currently pointing at as tuple with xyz values\n"
130
    );
131
    add_noargs_method("getUpDirection",&View3DInventorPy::getUpDirection,"getUpDirection() --> tuple of integers\n"
132
        "Returns the up direction vector\n"
133
    );
134
    add_varargs_method("setViewDirection",&View3DInventorPy::setViewDirection,"setViewDirection(tuple) --> None\n"
135
        "Sets the direction the view is pointing at. The direction must be given as tuple with\n"
136
        "three coordinates xyz"
137
    );
138
    add_varargs_method("setCamera",&View3DInventorPy::setCamera,"setCamera()");
139
    add_varargs_method("setCameraOrientation",&View3DInventorPy::setCameraOrientation,"setCameraOrientation()");
140
    add_noargs_method("getCameraOrientation",&View3DInventorPy::getCameraOrientation,"getCameraOrientation()");
141
    add_noargs_method("getCameraType",&View3DInventorPy::getCameraType,"getCameraType()");
142
    add_varargs_method("setCameraType",&View3DInventorPy::setCameraType,"setCameraType()");
143
    add_noargs_method("listCameraTypes",&View3DInventorPy::listCameraTypes,"listCameraTypes()");
144
    add_noargs_method("getCursorPos",&View3DInventorPy::getCursorPos,
145
        "getCursorPos() -> tuple of integers\n"
146
        "\n"
147
        "Return the current cursor position relative to the coordinate system of the\n"
148
        "viewport region.\n");
149
    add_varargs_method("getObjectInfo",&View3DInventorPy::getObjectInfo,
150
        "getObjectInfo(tuple(int,int), [pick_radius]) -> dictionary or None\n"
151
        "\n"
152
        "Return a dictionary with the name of document, object and component. The\n"
153
        "dictionary also contains the coordinates of the appropriate 3d point of\n"
154
        "the underlying geometry in the scenegraph.\n"
155
        "If no geometry was found 'None' is returned, instead.\n");
156
    add_varargs_method("getObjectsInfo",&View3DInventorPy::getObjectsInfo,
157
        "getObjectsInfo(tuple(int,int), [pick_radius]) -> dictionary or None\n"
158
        "\n"
159
        "Does the same as getObjectInfo() but returns a list of dictionaries or None.\n");
160
    add_noargs_method("getSize",&View3DInventorPy::getSize,"getSize()");
161
    add_varargs_method("getPoint",&View3DInventorPy::getPointOnFocalPlane,
162
        "Same as getPointOnFocalPlane");
163
    add_varargs_method("getPointOnFocalPlane",&View3DInventorPy::getPointOnFocalPlane,
164
        "getPointOnFocalPlane(pixel coords (as integer)) -> 3D vector\n"
165
        "\n"
166
        "Return the according 3D point on the focal plane to the given 2D point (in\n"
167
        "pixel coordinates).\n");
168
    add_varargs_method("getPointOnScreen",&View3DInventorPy::getPointOnViewport,
169
        "Same as getPointOnViewport");
170
    add_varargs_method("getPointOnViewport",&View3DInventorPy::getPointOnViewport,
171
        "getPointOnViewport(3D vector) -> pixel coords (as integer)\n"
172
        "\n"
173
        "Return the projected 3D point (in pixel coordinates).\n");
174
    add_varargs_method("projectPointToLine",&View3DInventorPy::projectPointToLine,
175
        "projectPointToLine(pixel coords (as integer)) -> line defined by two points\n"
176
        "\n"
177
        "Return the projecting 3D line to the given 2D point");
178
    add_varargs_method("addEventCallback",&View3DInventorPy::addEventCallback,"addEventCallback()");
179
    add_varargs_method("removeEventCallback",&View3DInventorPy::removeEventCallback,"removeEventCallback()");
180
    add_varargs_method("setAnnotation",&View3DInventorPy::setAnnotation,"setAnnotation()");
181
    add_varargs_method("removeAnnotation",&View3DInventorPy::removeAnnotation,"removeAnnotation()");
182
    add_noargs_method("getSceneGraph",&View3DInventorPy::getSceneGraph,"getSceneGraph()");
183
    add_noargs_method("getViewer",&View3DInventorPy::getViewer,"getViewer()");
184
    add_varargs_method("addEventCallbackPivy",&View3DInventorPy::addEventCallbackPivy,"addEventCallbackPivy()");
185
    add_varargs_method("removeEventCallbackPivy",&View3DInventorPy::removeEventCallbackPivy,"removeEventCallbackPivy()");
186
    add_varargs_method("addEventCallbackSWIG",&View3DInventorPy::addEventCallbackPivy,
187
        "Deprecated -- use addEventCallbackPivy()");
188
    add_varargs_method("removeEventCallbackSWIG",&View3DInventorPy::removeEventCallbackPivy,
189
        "Deprecated -- use removeEventCallbackPivy()");
190
    add_noargs_method("listNavigationTypes",&View3DInventorPy::listNavigationTypes,"listNavigationTypes()");
191
    add_noargs_method("getNavigationType",&View3DInventorPy::getNavigationType,"getNavigationType()");
192
    add_varargs_method("setNavigationType",&View3DInventorPy::setNavigationType,"setNavigationType()");
193
    add_varargs_method("setAxisCross",&View3DInventorPy::setAxisCross,"switch the big axis-cross on and off");
194
    add_noargs_method("hasAxisCross",&View3DInventorPy::hasAxisCross,"check if the big axis-cross is on or off()");
195
    add_varargs_method("addDraggerCallback",&View3DInventorPy::addDraggerCallback,
196
        "addDraggerCallback(SoDragger, String CallbackType, function)\n"
197
        "Add a DraggerCalback function to the coin node\n"
198
        "Possibles types :\n"
199
        "'addFinishCallback','addStartCallback','addMotionCallback','addValueChangedCallback'\n");
200
    add_varargs_method("removeDraggerCallback",&View3DInventorPy::removeDraggerCallback,
201
        "removeDraggerCallback(SoDragger, String CallbackType, function)\n"
202
        "Remove the DraggerCalback function from the coin node\n"
203
        "Possibles types :\n"
204
        "'addFinishCallback','addStartCallback','addMotionCallback','addValueChangedCallback'\n");
205
    add_varargs_method("getViewProvidersOfType", &View3DInventorPy::getViewProvidersOfType, "getViewProvidersOfType(name)\nreturns a list of view providers for the given type");
206
    add_noargs_method("redraw", &View3DInventorPy::redraw, "redraw(): renders the scene on screen (useful for animations)");
207
    add_varargs_method("setName",&View3DInventorPy::setName,"setName(str): sets a name to this viewer\nThe name sets the widget's windowTitle and appears on the viewer tab");
208
    add_keyword_method("toggleClippingPlane", &View3DInventorPy::toggleClippingPlane,
209
        "toggleClippingPlane(toggle=-1, beforeEditing=False, noManip=True, pla=App.Placement()\n"
210
        "Toggle a global clipping plane\n\n"
211
        "toggle: -1 toggle, 1 show, 0 hide\n"
212
        "beforeEditing: whether to insert the clipping node before or after editing root node\n"
213
        "noManip: whether to create a manipulator\n"
214
        "pla: clipping plane placement");
215
    add_noargs_method("hasClippingPlane",&View3DInventorPy::hasClippingPlane,
216
        "hasClippingPlane(): check whether this clipping plane is active");
217
    add_noargs_method("graphicsView",&View3DInventorPy::graphicsView,
218
        "graphicsView(): Access this view as QGraphicsView");
219
    add_varargs_method("setCornerCrossVisible",&View3DInventorPy::setCornerCrossVisible,
220
        "setCornerCrossVisible(bool): Defines corner axis cross visibility");
221
    add_noargs_method("isCornerCrossVisible",&View3DInventorPy::isCornerCrossVisible,
222
        "isCornerCrossVisible(): Returns current corner axis cross visibility");
223
    add_varargs_method("setCornerCrossSize",&View3DInventorPy::setCornerCrossSize,
224
        "setCornerCrossSize(int): Defines corner axis cross size");
225
    add_noargs_method("getCornerCrossSize",&View3DInventorPy::getCornerCrossSize,
226
        "getCornerCrossSize(): Returns current corner axis cross size");
227
    add_noargs_method("cast_to_base", &View3DInventorPy::cast_to_base, "cast_to_base() cast to MDIView class");
228
}
229

230
View3DInventorPy::View3DInventorPy(View3DInventor *vi)
231
  : base(vi)
232
{
233
}
234

235
View3DInventorPy::~View3DInventorPy()
236
{
237
    Base::PyGILStateLocker lock;
238
    for (auto it : callbacks)
239
        Py_DECREF(it);
240
}
241

242
View3DInventor* View3DInventorPy::getView3DIventorPtr()
243
{
244
    return qobject_cast<View3DInventor*>(base.getMDIViewPtr());
245
}
246

247
Py::Object View3DInventorPy::repr()
248
{
249
    std::string s;
250
    std::ostringstream s_out;
251
    if (!getView3DIventorPtr())
252
        throw Py::RuntimeError("Cannot print representation of deleted object");
253
    s_out << "View3DInventor";
254
    return Py::String(s_out.str());
255
}
256

257
View3DInventorPy::method_varargs_handler View3DInventorPy::pycxx_handler = nullptr;
258

259
PyObject *View3DInventorPy::method_varargs_ext_handler(PyObject *_self_and_name_tuple, PyObject *_args)
260
{
261
    try {
262
        return pycxx_handler(_self_and_name_tuple, _args);
263
    }
264
    catch (const Base::Exception& e) {
265
        throw Py::RuntimeError(e.what());
266
    }
267
    catch (const std::exception& e) {
268
        throw Py::RuntimeError(e.what());
269
    }
270
    catch (const Py::Exception&) {
271
        throw;
272
    }
273
    catch (...) {
274
        throw Py::RuntimeError("Unknown C++ exception");
275
    }
276
}
277

278
// Since with PyCXX it's not possible to make a sub-class of MDIViewPy
279
// a trick is to use MDIViewPy as class member and override getattr() to
280
// join the attributes of both classes. This way all methods of MDIViewPy
281
// appear for SheetViewPy, too.
282
Py::Object View3DInventorPy::getattribute(const char * attr)
283
{
284
    if (!getView3DIventorPtr())
285
        throw Py::RuntimeError("Cannot print representation of deleted object");
286
    std::string name( attr );
287
    if (name == "__dict__" || name == "__class__") {
288
        Py::Dict dict_self(BaseType::getattr("__dict__"));
289
        Py::Dict dict_base(base.getattr("__dict__"));
290
        for (const auto& it : dict_base) {
291
            dict_self.setItem(it.first, it.second);
292
        }
293
        return dict_self;
294
    }
295

296
    try {
297
        return BaseType::getattr(attr);
298
    }
299
    catch (Py::AttributeError& e) {
300
        e.clear();
301
        return base.getattr(attr);
302
    }
303
}
304

305
Py::Object View3DInventorPy::getattr(const char * attr)
306
{
307
    if (!getView3DIventorPtr()) {
308
        std::ostringstream s_out;
309
        s_out << "Cannot access attribute '" << attr << "' of deleted object";
310
        throw Py::RuntimeError(s_out.str());
311
    }
312
    else {
313
        // see if an active object has the same name
314
        App::DocumentObject *docObj = getView3DIventorPtr()->getActiveObject<App::DocumentObject*>(attr);
315
        if (docObj) {
316
            return Py::Object(docObj->getPyObject(),true);
317
        }
318
        else {
319
            // else looking for a method with the name and call it
320
            Py::Object obj = getattribute(attr);
321
            if (PyCFunction_Check(obj.ptr())) {
322
                auto op = reinterpret_cast<PyCFunctionObject*>(obj.ptr());
323
                if (op->m_ml->ml_flags == METH_VARARGS) {
324
                    if (!pycxx_handler)
325
                        pycxx_handler = op->m_ml->ml_meth;
326
                    op->m_ml->ml_meth = method_varargs_ext_handler;
327
                }
328
            }
329
            return obj;
330
        }
331
    }
332
}
333

334
int View3DInventorPy::setattr(const char * attr, const Py::Object & value)
335
{
336
    if (!getView3DIventorPtr()) {
337
        std::string s;
338
        std::ostringstream s_out;
339
        s_out << "Cannot access attribute '" << attr << "' of deleted object";
340
        throw Py::RuntimeError(s_out.str());
341
    }
342
    else {
343
        return BaseType::setattr(attr, value);
344
    }
345
}
346

347
Py::Object View3DInventorPy::fitAll(const Py::Tuple& args)
348
{
349
    double factor = 1.0;
350
    if (!PyArg_ParseTuple(args.ptr(), "|d", &factor))
351
        throw Py::Exception();
352

353
    try {
354
        getView3DIventorPtr()->getViewer()->viewAll((float)factor);
355
    }
356
    catch (const Base::Exception& e) {
357
        throw Py::RuntimeError(e.what());
358
    }
359
    catch (const std::exception& e) {
360
        throw Py::RuntimeError(e.what());
361
    }
362
    catch (...) {
363
        throw Py::RuntimeError("Unknown C++ exception");
364
    }
365
    return Py::None();
366
}
367

368
Py::Object View3DInventorPy::boxZoom(const Py::Tuple& args, const Py::Dict& kwds)
369
{
370
    static const std::array<const char *, 5> kwds_box{"XMin", "YMin", "XMax", "YMax", nullptr};
371
    short xmin, ymin, xmax, ymax;
372
    if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "hhhh", kwds_box,
373
                                            &xmin, &ymin, &xmax, &ymax)) {
374
        throw Py::Exception();
375
    }
376

377
    SbBox2s box(xmin, ymin, xmax, ymax);
378
    getView3DIventorPtr()->getViewer()->boxZoom(box);
379
    return Py::None();
380
}
381

382
Py::Object View3DInventorPy::viewBottom()
383
{
384
    try {
385
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Bottom));
386
    }
387
    catch (const Base::Exception& e) {
388
        throw Py::RuntimeError(e.what());
389
    }
390
    catch (const std::exception& e) {
391
        throw Py::RuntimeError(e.what());
392
    }
393
    catch (...) {
394
        throw Py::RuntimeError("Unknown C++ exception");
395
    }
396

397
    return Py::None();
398
}
399

400
Py::Object View3DInventorPy::viewFront()
401
{
402
    try {
403
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Front));
404
    }
405
    catch (const Base::Exception& e) {
406
        throw Py::RuntimeError(e.what());
407
    }
408
    catch (const std::exception& e) {
409
        throw Py::RuntimeError(e.what());
410
    }
411
    catch (...) {
412
        throw Py::RuntimeError("Unknown C++ exception");
413
    }
414

415
    return Py::None();
416
}
417

418
Py::Object View3DInventorPy::viewLeft()
419
{
420
    try {
421
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Left));
422
    }
423
    catch (const Base::Exception& e) {
424
        throw Py::RuntimeError(e.what());
425
    }
426
    catch (const std::exception& e) {
427
        throw Py::RuntimeError(e.what());
428
    }
429
    catch (...) {
430
        throw Py::RuntimeError("Unknown C++ exception");
431
    }
432

433
    return Py::None();
434
}
435

436
Py::Object View3DInventorPy::viewRear()
437
{
438
    try {
439
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Rear));
440
    }
441
    catch (const Base::Exception& e) {
442
        throw Py::RuntimeError(e.what());
443
    }
444
    catch (const std::exception& e) {
445
        throw Py::RuntimeError(e.what());
446
    }
447
    catch (...) {
448
        throw Py::RuntimeError("Unknown C++ exception");
449
    }
450

451
    return Py::None();
452
}
453

454
Py::Object View3DInventorPy::viewRight()
455
{
456
    try {
457
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Right));
458
    }
459
    catch (const Base::Exception& e) {
460
        throw Py::RuntimeError(e.what());
461
    }
462
    catch (const std::exception& e) {
463
        throw Py::RuntimeError(e.what());
464
    }
465
    catch (...) {
466
        throw Py::RuntimeError("Unknown C++ exception");
467
    }
468

469
    return Py::None();
470
}
471

472
Py::Object View3DInventorPy::viewTop()
473
{
474
    try {
475
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Top));
476
    }
477
    catch (const Base::Exception& e) {
478
        throw Py::RuntimeError(e.what());
479
    }
480
    catch (const std::exception& e) {
481
        throw Py::RuntimeError(e.what());
482
    }
483
    catch (...) {
484
        throw Py::RuntimeError("Unknown C++ exception");
485
    }
486

487
    return Py::None();
488
}
489

490
Py::Object View3DInventorPy::viewIsometric()
491
{
492
    try {
493
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Isometric));
494
    }
495
    catch (const Base::Exception& e) {
496
        throw Py::RuntimeError(e.what());
497
    }
498
    catch (const std::exception& e) {
499
        throw Py::RuntimeError(e.what());
500
    }
501
    catch (...) {
502
        throw Py::RuntimeError("Unknown C++ exception");
503
    }
504

505
    return Py::None();
506
}
507

508
Py::Object View3DInventorPy::viewDimetric()
509
{
510
    try {
511
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Dimetric));
512
    }
513
    catch (const Base::Exception& e) {
514
        throw Py::RuntimeError(e.what());
515
    }
516
    catch (const std::exception& e) {
517
        throw Py::RuntimeError(e.what());
518
    }
519
    catch (...) {
520
        throw Py::RuntimeError("Unknown C++ exception");
521
    }
522

523
    return Py::None();
524
}
525

526
Py::Object View3DInventorPy::viewTrimetric()
527
{
528
    try {
529
        getView3DIventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Trimetric));
530
    }
531
    catch (const Base::Exception& e) {
532
        throw Py::RuntimeError(e.what());
533
    }
534
    catch (const std::exception& e) {
535
        throw Py::RuntimeError(e.what());
536
    }
537
    catch (...) {
538
        throw Py::RuntimeError("Unknown C++ exception");
539
    }
540

541
    return Py::None();
542
}
543

544
Py::Object View3DInventorPy::viewDefaultOrientation(const Py::Tuple& args)
545
{
546
    char* view = nullptr;
547
    double scale = -1.0;
548
    if (!PyArg_ParseTuple(args.ptr(), "|sd", &view, &scale))
549
        throw Py::Exception();
550

551
    try {
552
        std::string newDocView;
553
        SbRotation rot(0,0,0,1);
554
        if (view) {
555
            newDocView = view;
556
        }
557
        else {
558
            ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
559
            newDocView = hGrp->GetASCII("NewDocumentCameraOrientation", "Trimetric");
560
        }
561

562
        if (newDocView == "Top") {
563
            rot = Camera::rotation(Camera::Top);
564
        }
565
        else if (newDocView == "Bottom") {
566
            rot = Camera::rotation(Camera::Bottom);
567
        }
568
        else if (newDocView == "Front") {
569
            rot = Camera::rotation(Camera::Front);
570
        }
571
        else if (newDocView == "Rear") {
572
            rot = Camera::rotation(Camera::Rear);
573
        }
574
        else if (newDocView == "Left") {
575
            rot = Camera::rotation(Camera::Left);
576
        }
577
        else if (newDocView == "Right") {
578
            rot = Camera::rotation(Camera::Right);
579
        }
580
        else if (newDocView == "Isometric") {
581
            rot = Camera::rotation(Camera::Isometric);
582
        }
583
        else if (newDocView == "Dimetric") {
584
            rot = Camera::rotation(Camera::Dimetric);
585
        }
586
        else if (newDocView == "Trimetric") {
587
            rot = Camera::rotation(Camera::Trimetric);
588
        }
589
        else if (newDocView == "Custom") {
590
            ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View/Custom");
591
            auto q0 = static_cast<float>(hGrp->GetFloat("Q0", 0));
592
            auto q1 = static_cast<float>(hGrp->GetFloat("Q1", 0));
593
            auto q2 = static_cast<float>(hGrp->GetFloat("Q2", 0));
594
            auto q3 = static_cast<float>(hGrp->GetFloat("Q3", 1));
595
            rot.setValue(q0, q1, q2, q3);
596
        }
597

598
        SoCamera* cam = getView3DIventorPtr()->getViewer()->getCamera();
599
        cam->orientation = rot;
600

601
        if (scale < 0.0){
602
            ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
603
            scale = hGrp->GetFloat("NewDocumentCameraScale",100.0);
604
        }
605

606
        setDefaultCameraHeight(scale);
607
    }
608
    catch (const Base::Exception& e) {
609
        throw Py::RuntimeError(e.what());
610
    }
611
    catch (const std::exception& e) {
612
        throw Py::RuntimeError(e.what());
613
    }
614
    catch (...) {
615
        throw Py::RuntimeError("Unknown C++ exception");
616
    }
617

618
    return Py::None();
619
}
620

621
void View3DInventorPy::setDefaultCameraHeight(float scale)
622
{
623
    if (scale > 1e-7) {
624
        SoCamera* cam = getView3DIventorPtr()->getViewer()->getCamera();
625
        SbRotation rot = cam->orientation.getValue();
626

627
        double f = 0.0; //focal dist
628
        if (cam->isOfType(SoOrthographicCamera::getClassTypeId())){
629
            static_cast<SoOrthographicCamera*>(cam)->height = scale;
630
            f = scale;
631
        }
632
        else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())){
633
            //nothing to do
634
            double ang = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue();
635
            f = 0.5 * scale / sin(ang * 0.5);
636
        }
637

638
        SbVec3f lookDir;
639
        rot.multVec(SbVec3f(0,0,-1), lookDir);
640
        SbVec3f pos = lookDir * -f;
641
        cam->focalDistance = f;
642
        cam->position = pos;
643
    }
644
}
645

646
Py::Object View3DInventorPy::viewRotateLeft()
647
{
648
    try {
649
      SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
650
      SbRotation rot = cam->orientation.getValue();
651
      SbVec3f vdir(0, 0, -1);
652
      rot.multVec(vdir, vdir);
653
      SbRotation nrot(vdir, (float)M_PI/2);
654
      cam->orientation.setValue(rot*nrot);
655
    }
656
    catch (const Base::Exception& e) {
657
        throw Py::RuntimeError(e.what());
658
    }
659
    catch (const std::exception& e) {
660
        throw Py::RuntimeError(e.what());
661
    }
662
    catch (...) {
663
        throw Py::RuntimeError("Unknown C++ exception");
664
    }
665

666
    return Py::None();
667
}
668

669
Py::Object View3DInventorPy::viewRotateRight()
670
{
671
    try {
672
      SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
673
      SbRotation rot = cam->orientation.getValue();
674
      SbVec3f vdir(0, 0, -1);
675
      rot.multVec(vdir, vdir);
676
      SbRotation nrot(vdir, (float)-M_PI/2);
677
      cam->orientation.setValue(rot*nrot);
678
    }
679
    catch (const Base::Exception& e) {
680
        throw Py::RuntimeError(e.what());
681
    }
682
    catch (const std::exception& e) {
683
        throw Py::RuntimeError(e.what());
684
    }
685
    catch (...) {
686
        throw Py::RuntimeError("Unknown C++ exception");
687
    }
688

689
    return Py::None();
690
}
691

692
Py::Object View3DInventorPy::zoomIn()
693
{
694
    try {
695
        getView3DIventorPtr()->getViewer()->navigationStyle()->zoomIn();
696
    }
697
    catch (const Base::Exception& e) {
698
        throw Py::RuntimeError(e.what());
699
    }
700
    catch (const std::exception& e) {
701
        throw Py::RuntimeError(e.what());
702
    }
703
    catch (...) {
704
        throw Py::RuntimeError("Unknown C++ exception");
705
    }
706

707
    return Py::None();
708
}
709

710
Py::Object View3DInventorPy::zoomOut()
711
{
712
    try {
713
        getView3DIventorPtr()->getViewer()->navigationStyle()->zoomOut();
714
    }
715
    catch (const Base::Exception& e) {
716
        throw Py::RuntimeError(e.what());
717
    }
718
    catch (const std::exception& e) {
719
        throw Py::RuntimeError(e.what());
720
    }
721
    catch (...) {
722
        throw Py::RuntimeError("Unknown C++ exception");
723
    }
724

725
    return Py::None();
726
}
727

728
Py::Object View3DInventorPy::setCameraOrientation(const Py::Tuple& args)
729
{
730
    PyObject* o;
731
    PyObject* m=Py_False;
732
    if (!PyArg_ParseTuple(args.ptr(), "O|O!", &o, &PyBool_Type, &m))
733
        throw Py::Exception();
734

735
    try {
736
        if (PyTuple_Check(o)) {
737
            Py::Tuple tuple(o);
738
            float q0 = (float)Py::Float(tuple[0]);
739
            float q1 = (float)Py::Float(tuple[1]);
740
            float q2 = (float)Py::Float(tuple[2]);
741
            float q3 = (float)Py::Float(tuple[3]);
742
            getView3DIventorPtr()->getViewer()->setCameraOrientation(SbRotation(q0, q1, q2, q3), Base::asBoolean(m));
743
        }
744
        else if (PyObject_TypeCheck(o, &Base::RotationPy::Type)) {
745
            Base::Rotation r = static_cast<Base::Rotation>(Py::Rotation(o,false));
746
            double q0, q1, q2, q3;
747
            r.getValue(q0, q1, q2, q3);
748
            getView3DIventorPtr()->getViewer()->setCameraOrientation(SbRotation((float)q0, (float)q1, (float)q2, (float)q3), Base::asBoolean(m));
749
        }
750
        else {
751
            throw Py::ValueError("Neither tuple nor rotation object");
752
        }
753
    }
754
    catch (const Py::Exception&) {
755
        throw; // re-throw
756
    }
757
    catch (const Base::Exception& e) {
758
        throw Py::RuntimeError(e.what());
759
    }
760
    catch (const std::exception& e) {
761
        throw Py::RuntimeError(e.what());
762
    }
763
    catch(...) {
764
        throw Py::RuntimeError("Unknown C++ exception");
765
    }
766

767
    return Py::None();
768
}
769

770
Py::Object View3DInventorPy::getCameraOrientation()
771
{
772
    SbRotation rot = getView3DIventorPtr()->getViewer()->getCameraOrientation();
773
    float q0,q1,q2,q3;
774
    rot.getValue(q0,q1,q2,q3);
775
    return Py::Rotation(Base::Rotation(q0,q1,q2,q3));
776
}
777

778
Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args)
779
{
780
    PyObject* p = nullptr;
781
    int steps; // Unused but kept as parameter to not break the Python interface
782
    int duration = -1; // Duration in ms, will be replaced with User parameter:BaseApp/Preferences/View/AnimationDuration when not explicitly provided
783
    if (!PyArg_ParseTuple(args.ptr(), "|O!ii", &Base::PlacementPy::Type, &p, &steps, &duration))
784
        throw Py::Exception();
785

786
    if (p) {
787
        Base::Placement* plm = static_cast<Base::PlacementPy*>(p)->getPlacementPtr();
788
        Base::Rotation rot = plm->getRotation();
789
        Base::Vector3d pos = plm->getPosition();
790
        double q0,q1,q2,q3;
791
        rot.getValue(q0,q1,q2,q3);
792
        getView3DIventorPtr()->getViewer()->moveCameraTo(
793
            SbRotation((float)q0, (float)q1, (float)q2, (float)q3),
794
            SbVec3f((float)pos.x, (float)pos.y, (float)pos.z), duration);
795
    }
796

797
    SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
798
    if (!cam)
799
        return Py::None();
800

801
    SbRotation rot = cam->orientation.getValue();
802
    SbVec3f pos = cam->position.getValue();
803
    float q0,q1,q2,q3;
804
    rot.getValue(q0,q1,q2,q3);
805
    Base::Placement plm(
806
        Base::Vector3d(pos[0], pos[1], pos[2]),
807
        Base::Rotation(q0, q1, q2, q3));
808
    return Py::Placement(plm);
809
}
810

811
Py::Object View3DInventorPy::startAnimating(const Py::Tuple& args)
812
{
813
    float x, y, z;
814
    float velocity;
815
    if (!PyArg_ParseTuple(args.ptr(), "ffff", &x, &y, &z, &velocity))
816
        throw Py::Exception();
817
    getView3DIventorPtr()->getViewer()->startSpinningAnimation(SbVec3f(x, y, z), velocity);
818
    return Py::None();
819
}
820

821
Py::Object View3DInventorPy::stopAnimating()
822
{
823
    getView3DIventorPtr()->getViewer()->stopAnimating();
824
    return Py::None();
825
}
826

827
Py::Object View3DInventorPy::setAnimationEnabled(const Py::Tuple& args)
828
{
829
    int ok;
830
    if (!PyArg_ParseTuple(args.ptr(), "i", &ok))
831
        throw Py::Exception();
832
    getView3DIventorPtr()->getViewer()->setAnimationEnabled(ok!=0);
833
    return Py::None();
834
}
835

836
Py::Object View3DInventorPy::isAnimationEnabled()
837
{
838
    SbBool ok = getView3DIventorPtr()->getViewer()->isAnimationEnabled();
839
    return Py::Boolean(ok ? true : false);
840
}
841

842
Py::Object View3DInventorPy::setPopupMenuEnabled(const Py::Tuple& args)
843
{
844
    int ok;
845
    if (!PyArg_ParseTuple(args.ptr(), "i", &ok))
846
        throw Py::Exception();
847
    getView3DIventorPtr()->getViewer()->setPopupMenuEnabled(ok!=0);
848
    return Py::None();
849
}
850

851
Py::Object View3DInventorPy::isPopupMenuEnabled()
852
{
853
    SbBool ok = getView3DIventorPtr()->getViewer()->isPopupMenuEnabled();
854
    return Py::Boolean(ok ? true : false);
855
}
856

857
Py::Object View3DInventorPy::saveImage(const Py::Tuple& args)
858
{
859
    char *cFileName = nullptr;
860
    const char *cColor="Current";
861
    const char *cComment="$MIBA";
862
    int w=-1,h=-1;
863
    int s=View3DInventorViewer::getNumSamples();
864

865
    if (!PyArg_ParseTuple(args.ptr(), "et|iissi","utf-8",&cFileName,&w,&h,&cColor,&cComment,&s))
866
        throw Py::Exception();
867

868
    std::string encodedName = std::string(cFileName);
869
    PyMem_Free(cFileName);
870
    QFileInfo fi(QString::fromUtf8(encodedName.c_str()));
871

872
    if (!fi.absoluteDir().exists())
873
        throw Py::RuntimeError("Directory where to save image doesn't exist");
874

875
    QColor bg;
876
    QString colname = QString::fromLatin1(cColor);
877
    if (colname.compare(QLatin1String("Current"), Qt::CaseInsensitive) == 0)
878
        bg = QColor(); // assign an invalid color here
879
    else
880
        bg = QColor(colname);
881

882
    QImage img;
883
    getView3DIventorPtr()->getViewer()->savePicture(w, h, s, bg, img);
884

885
    SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance();
886
    SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
887
    renderer.writeToImageFile(encodedName.c_str(), cComment, cam->getViewVolume().getMatrix(), img);
888

889
    return Py::None();
890
}
891

892
Py::Object View3DInventorPy::saveVectorGraphic(const Py::Tuple& args)
893
{
894
    char* filename;
895
    int ps=4;
896
    const char* name="white";
897

898
    if (!PyArg_ParseTuple(args.ptr(), "s|is",&filename,&ps,&name))
899
        throw Py::Exception();
900

901
    std::unique_ptr<SoVectorizeAction> vo;
902
    Base::FileInfo fi(filename);
903
    if (fi.hasExtension({"ps", "eps"})) {
904
        vo = std::unique_ptr<SoVectorizeAction>(new SoVectorizePSAction());
905
        //vo->setGouraudThreshold(0.0f);
906
    }
907
    else if (fi.hasExtension("svg")) {
908
        vo = std::unique_ptr<SoVectorizeAction>(new SoFCVectorizeSVGAction());
909
    }
910
    else if (fi.hasExtension("idtf")) {
911
        vo = std::unique_ptr<SoVectorizeAction>(new SoFCVectorizeU3DAction());
912
    }
913
    else {
914
        throw Py::RuntimeError("Not supported vector graphic");
915
    }
916

917
    SoVectorOutput * out = vo->getOutput();
918
    if (!out || !out->openFile(filename)) {
919
        std::ostringstream a_out;
920
        a_out << "Cannot open file '" << filename << "'";
921
        throw Py::RuntimeError(a_out.str());
922
    }
923

924
    QColor bg;
925
    QString colname = QString::fromLatin1(name);
926
    if (colname.compare(QLatin1String("Current"), Qt::CaseInsensitive) == 0)
927
        bg = getView3DIventorPtr()->getViewer()->backgroundColor();
928
    else
929
        bg = QColor(colname);
930

931
    getView3DIventorPtr()->getViewer()->saveGraphic(ps,bg,vo.get());
932
    out->closeFile();
933
    return Py::None();
934
}
935

936
Py::Object View3DInventorPy::getCameraNode()
937
{
938
    try {
939
        SoNode* camera = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
940
        PyObject* proxy = nullptr;
941
        std::string type;
942
        type = "So"; // seems that So prefix is missing in camera node
943
        type += camera->getTypeId().getName().getString();
944
        type += " *";
945
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", type.c_str(), static_cast<void*>(camera), 1);
946
        camera->ref();
947
        return Py::Object(proxy, true);
948
    }
949
    catch (const Base::Exception& e) {
950
        throw Py::RuntimeError(e.what());
951
    }
952
}
953

954
Py::Object View3DInventorPy::getCamera()
955
{
956
    SoOutput out;
957
    char buffer[512];
958
    out.setBuffer(buffer, 512, nullptr);
959

960
    try {
961
        SoWriteAction wa(&out);
962
        SoCamera * cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
963
        if (cam) wa.apply(cam);
964
        else buffer[0] = '\0';
965
        return Py::String(buffer);
966
    }
967
    catch (const Base::Exception& e) {
968
        throw Py::RuntimeError(e.what());
969
    }
970
    catch (const std::exception& e) {
971
        throw Py::RuntimeError(e.what());
972
    }
973
    catch (...) {
974
        throw Py::RuntimeError("Unknown C++ exception");
975
    }
976
}
977

978
Py::Object View3DInventorPy::getViewDirection()
979
{
980
    try {
981
        SbVec3f dvec = getView3DIventorPtr()->getViewer()->getViewDirection();
982
        return Py::Vector(Base::Vector3f(dvec[0], dvec[1], dvec[2]));
983
    }
984
    catch (const Base::Exception& e) {
985
        throw Py::RuntimeError(e.what());
986
    }
987
    catch (const std::exception& e) {
988
        throw Py::RuntimeError(e.what());
989
    }
990
    catch (...) {
991
        throw Py::RuntimeError("Unknown C++ exception");
992
    }
993
}
994

995

996
Py::Object View3DInventorPy::getUpDirection()
997
{
998
    try {
999
        SbVec3f dvec = getView3DIventorPtr()->getViewer()->getUpDirection();
1000
        return Py::Vector(Base::Vector3f(dvec[0], dvec[1], dvec[2]));
1001
    }
1002
    catch (const Base::Exception& e) {
1003
        throw Py::RuntimeError(e.what());
1004
    }
1005
    catch (const std::exception& e) {
1006
        throw Py::RuntimeError(e.what());
1007
    }
1008
    catch (...) {
1009
        throw Py::RuntimeError("Unknown C++ exception");
1010
    }
1011
}
1012

1013
Py::Object View3DInventorPy::setViewDirection(const Py::Tuple& args)
1014
{
1015
    PyObject* object;
1016
    if (!PyArg_ParseTuple(args.ptr(), "O", &object))
1017
        throw Py::Exception();
1018

1019
    try {
1020
        if (PyTuple_Check(object)) {
1021
            Py::Tuple tuple(object);
1022
            Py::Float x(tuple.getItem(0));
1023
            Py::Float y(tuple.getItem(1));
1024
            Py::Float z(tuple.getItem(2));
1025
            SbVec3f dir;
1026
            dir.setValue((float)x, (float)y, (float)z);
1027
            if (dir.length() < 0.001f)
1028
                throw Py::ValueError("Null vector cannot be used to set direction");
1029
            getView3DIventorPtr()->getViewer()->setViewDirection(dir);
1030
            return Py::None();
1031
        }
1032
    }
1033
    catch (const Py::Exception&) {
1034
        throw; // re-throw
1035
    }
1036
    catch (const Base::Exception& e) {
1037
        throw Py::RuntimeError(e.what());
1038
    }
1039
    catch (const std::exception& e) {
1040
        throw Py::RuntimeError(e.what());
1041
    }
1042
    catch (...) {
1043
        throw Py::RuntimeError("Unknown C++ exception");
1044
    }
1045

1046
    return Py::None();
1047

1048
}
1049

1050

1051
Py::Object View3DInventorPy::setCamera(const Py::Tuple& args)
1052
{
1053
    char* buffer;
1054
    if (!PyArg_ParseTuple(args.ptr(), "s", &buffer))
1055
        throw Py::Exception();
1056

1057
    try {
1058
        getView3DIventorPtr()->setCamera(buffer);
1059
        return Py::None();
1060
    }
1061
    catch (const Base::Exception& e) {
1062
        throw Py::RuntimeError(e.what());
1063
    }
1064
    catch (const std::exception& e) {
1065
        throw Py::RuntimeError(e.what());
1066
    }
1067
    catch(...) {
1068
        throw Py::RuntimeError("Unknown C++ exception");
1069
    }
1070
}
1071

1072
//FIXME: Once View3DInventor inherits from PropertyContainer we can use PropertyEnumeration.
1073
const char* CameraTypeEnums[]= {"Orthographic","Perspective",nullptr};
1074

1075
Py::Object View3DInventorPy::getCameraType()
1076
{
1077
    SoCamera* cam = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getCamera();
1078
    if (!cam) {
1079
        throw Py::RuntimeError("No camera set!");
1080
    }
1081
    else if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
1082
        return Py::String(CameraTypeEnums[0]);
1083
    }
1084
    else if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
1085
        return Py::String(CameraTypeEnums[1]);
1086
    }
1087
    else {
1088
        throw Py::TypeError("Unknown camera type");
1089
    }
1090
}
1091

1092
Py::Object View3DInventorPy::setCameraType(const Py::Tuple& args)
1093
{
1094
    int cameratype=-1;
1095
    if (!PyArg_ParseTuple(args.ptr(), "i", &cameratype)) {
1096
        char* modename;
1097
        PyErr_Clear();
1098
        if (!PyArg_ParseTuple(args.ptr(), "s", &modename))
1099
            throw Py::Exception();
1100
        for (int i=0; i<2; i++ ) {
1101
            if (strncmp(CameraTypeEnums[i],modename,20) == 0 ) {
1102
                cameratype = i;
1103
                break;
1104
            }
1105
        }
1106

1107
        if (cameratype < 0) {
1108
            std::string s;
1109
            std::ostringstream s_out;
1110
            s_out << "Unknown camera type '" << modename << "'";
1111
            throw Py::NameError(s_out.str());
1112
        }
1113
    }
1114

1115
    if (cameratype < 0 || cameratype > 1)
1116
        throw Py::IndexError("Out of range");
1117
    if (cameratype==0)
1118
        getView3DIventorPtr()->getViewer()->setCameraType(SoOrthographicCamera::getClassTypeId());
1119
    else
1120
        getView3DIventorPtr()->getViewer()->setCameraType(SoPerspectiveCamera::getClassTypeId());
1121
    return Py::None();
1122
}
1123

1124
Py::Object View3DInventorPy::listCameraTypes()
1125
{
1126
    try {
1127
        Py::List list(2);
1128
        for (int i=0; i<2; i++) {
1129
            list[i] = Py::String(CameraTypeEnums[i]);
1130
        }
1131
        return list;
1132
    }
1133
    catch (const Base::Exception& e) {
1134
        throw Py::RuntimeError(e.what());
1135
    }
1136
    catch (const std::exception& e) {
1137
        throw Py::RuntimeError(e.what());
1138
    }
1139
    catch(...) {
1140
        throw Py::RuntimeError("Unknown C++ exception");
1141
    }
1142
}
1143

1144
Py::Object View3DInventorPy::dump(const Py::Tuple& args)
1145
{
1146
    char* filename;
1147
    PyObject *onlyVisible = Py_False;
1148
    if (!PyArg_ParseTuple(args.ptr(), "s|O!", &filename, &PyBool_Type, &onlyVisible))
1149
        throw Py::Exception();
1150

1151
    try {
1152
        getView3DIventorPtr()->dump(filename, Base::asBoolean(onlyVisible));
1153
        return Py::None();
1154
    }
1155
    catch (const Base::Exception& e) {
1156
        throw Py::RuntimeError(e.what());
1157
    }
1158
    catch (const std::exception& e) {
1159
        throw Py::RuntimeError(e.what());
1160
    }
1161
    catch(...) {
1162
        throw Py::RuntimeError("Unknown C++ exception");
1163
    }
1164
}
1165

1166
Py::Object View3DInventorPy::dumpNode(const Py::Tuple& args)
1167
{
1168
    PyObject* object;
1169
    if (!PyArg_ParseTuple(args.ptr(), "O", &object))
1170
        throw Py::Exception();
1171

1172
    void* ptr = nullptr;
1173
    try {
1174
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", object, &ptr, 0);
1175
    }
1176
    catch (const Base::Exception& e) {
1177
        throw Py::RuntimeError(e.what());
1178
    }
1179
    auto node = static_cast<SoNode*>(ptr);
1180
    return Py::String(SoFCDB::writeNodesToString(node));
1181
}
1182

1183
//FIXME: Once View3DInventor inherits from PropertyContainer we can use PropertyEnumeration.
1184
const char* StereoTypeEnums[]= {"Mono","Anaglyph","QuadBuffer","InterleavedRows","InterleavedColumns",nullptr};
1185

1186
Py::Object View3DInventorPy::setStereoType(const Py::Tuple& args)
1187
{
1188
    int stereomode=-1;
1189
    if (!PyArg_ParseTuple(args.ptr(), "i", &stereomode)) {
1190
        char* modename;
1191
        PyErr_Clear();
1192
        if (!PyArg_ParseTuple(args.ptr(), "s", &modename))
1193
            throw Py::Exception();
1194
        for (int i=0; i<5; i++) {
1195
            if (strncmp(StereoTypeEnums[i],modename,20) == 0) {
1196
                stereomode = i;
1197
                break;
1198
            }
1199
        }
1200

1201
        if (stereomode < 0) {
1202
            std::string s;
1203
            std::ostringstream s_out;
1204
            s_out << "Unknown stereo type '" << modename << "'";
1205
            throw Py::NameError(s_out.str());
1206
        }
1207
    }
1208

1209
    try {
1210
        if (stereomode < 0 || stereomode > 4)
1211
            throw Py::IndexError("Out of range");
1212
        Quarter::SoQTQuarterAdaptor::StereoMode mode = Quarter::SoQTQuarterAdaptor::StereoMode(stereomode);
1213
        getView3DIventorPtr()->getViewer()->setStereoMode(mode);
1214
        return Py::None();
1215
    }
1216
    catch (const Base::Exception& e) {
1217
        throw Py::RuntimeError(e.what());
1218
    }
1219
    catch (const std::exception& e) {
1220
        throw Py::RuntimeError(e.what());
1221
    }
1222
    catch(...) {
1223
        throw Py::RuntimeError("Unknown C++ exception");
1224
    }
1225
}
1226

1227
Py::Object View3DInventorPy::getStereoType()
1228
{
1229
    try {
1230
        int mode = int(getView3DIventorPtr()->getViewer()->stereoMode());
1231
        if (mode < 0 || mode > 4)
1232
            throw Py::ValueError("Invalid stereo mode");
1233
        return Py::String(StereoTypeEnums[mode]);
1234
    }
1235
    catch (const Base::Exception& e) {
1236
        throw Py::RuntimeError(e.what());
1237
    }
1238
    catch (const std::exception& e) {
1239
        throw Py::RuntimeError(e.what());
1240
    }
1241
    catch(...) {
1242
        throw Py::RuntimeError("Unknown C++ exception");
1243
    }
1244
}
1245

1246
Py::Object View3DInventorPy::listStereoTypes()
1247
{
1248
    try {
1249
        Py::List list(5);
1250
        for (int i=0; i<5; i++) {
1251
            list[i] = Py::String(StereoTypeEnums[i]);
1252
        }
1253

1254
        return list;
1255
    }
1256
    catch (const Base::Exception& e) {
1257
        throw Py::RuntimeError(e.what());
1258
    }
1259
    catch (const std::exception& e) {
1260
        throw Py::RuntimeError(e.what());
1261
    }
1262
    catch(...) {
1263
        throw Py::RuntimeError("Unknown C++ exception");
1264
    }
1265
}
1266

1267
Py::Object View3DInventorPy::getCursorPos()
1268
{
1269
    try {
1270
        QPoint pos = getView3DIventorPtr()->mapFromGlobal(QCursor::pos());
1271
        auto viewer = getView3DIventorPtr()->getViewer();
1272
        SbVec2s vec = viewer->fromQPoint(pos);
1273
        Py::Tuple tuple(2);
1274
        tuple.setItem(0, Py::Int(vec[0]));
1275
        tuple.setItem(1, Py::Int(vec[1]));
1276
        return tuple;
1277
    }
1278
    catch (const Py::Exception&) {
1279
        throw;
1280
    }
1281
}
1282

1283
Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args)
1284
{
1285
    PyObject* object;
1286
    float r = getView3DIventorPtr()->getViewer()->getPickRadius();
1287
    if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r))
1288
        throw Py::Exception();
1289

1290
    try {
1291
        //Note: For gcc (4.2) we need the 'const' keyword to avoid the compiler error:
1292
        //conversion from 'Py::seqref<Py::Object>' to non-scalar type 'Py::Int' requested
1293
        //We should report this problem to the PyCXX project as in the documentation an
1294
        //example without the 'const' keyword is used.
1295
        //Or we can also write Py::Int x(tuple[0]);
1296
        const Py::Tuple tuple(object);
1297
        Py::Int x(tuple[0]);
1298
        Py::Int y(tuple[1]);
1299

1300
        // As this method could be called during a SoHandleEventAction scene
1301
        // graph traversal we must not use a second SoHandleEventAction as
1302
        // we will get Coin warnings because of multiple scene graph traversals
1303
        // which is regarded as error-prone.
1304
        SoRayPickAction action(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion());
1305
        action.setPoint(SbVec2s((long)x,(long)y));
1306
        action.setRadius(r);
1307
        action.apply(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph());
1308
        SoPickedPoint *Point = action.getPickedPoint();
1309

1310
        Py::Object ret = Py::None();
1311
        if (Point) {
1312
            Py::Dict dict;
1313
            SbVec3f pt = Point->getPoint();
1314
            dict.setItem("x", Py::Float(pt[0]));
1315
            dict.setItem("y", Py::Float(pt[1]));
1316
            dict.setItem("z", Py::Float(pt[2]));
1317

1318
            ViewProvider *vp = getView3DIventorPtr()->getViewer()->getViewProviderByPath(Point->getPath());
1319
            if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
1320
                if (!vp->isSelectable())
1321
                    return ret;
1322
                auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
1323
                if (vp->useNewSelectionModel()) {
1324
                    std::string subname;
1325
                    if (!vp->getElementPicked(Point,subname))
1326
                        return ret;
1327
                    auto obj = vpd->getObject();
1328
                    if (!obj)
1329
                        return ret;
1330
                    if (!subname.empty()) {
1331
                        App::ElementNamePair elementName;
1332
                        auto sobj = App::GeoFeature::resolveElement(obj,subname.c_str(),elementName);
1333
                        if (!sobj)
1334
                            return ret;
1335
                        if (sobj != obj) {
1336
                            dict.setItem("ParentObject",Py::Object(obj->getPyObject(),true));
1337
                            dict.setItem("SubName",Py::String(subname));
1338
                            obj = sobj;
1339
                        }
1340
                        subname = !elementName.oldName.empty()?elementName.oldName:elementName.newName;
1341
                    }
1342
                    dict.setItem("Document",
1343
                        Py::String(obj->getDocument()->getName()));
1344
                    dict.setItem("Object",
1345
                        Py::String(obj->getNameInDocument()));
1346
                    dict.setItem("Component",Py::String(subname));
1347
                }
1348
                else {
1349
                    dict.setItem("Document",
1350
                        Py::String(vpd->getObject()->getDocument()->getName()));
1351
                    dict.setItem("Object",
1352
                        Py::String(vpd->getObject()->getNameInDocument()));
1353
                    // search for a SoFCSelection node
1354
                    SoFCDocumentObjectAction objaction;
1355
                    objaction.apply(Point->getPath());
1356
                    if (objaction.isHandled()) {
1357
                        dict.setItem("Component",
1358
                            Py::String(objaction.componentName.getString()));
1359
                    }
1360
                }
1361

1362
                // ok, found the node of interest
1363
                ret = dict;
1364
            }
1365
            else {
1366
                // custom nodes not in a VP: search for a SoFCSelection node
1367
                SoFCDocumentObjectAction objaction;
1368
                objaction.apply(Point->getPath());
1369
                if (objaction.isHandled()) {
1370
                    dict.setItem("Document",
1371
                        Py::String(objaction.documentName.getString()));
1372
                    dict.setItem("Object",
1373
                        Py::String(objaction.objectName.getString()));
1374
                    dict.setItem("Component",
1375
                        Py::String(objaction.componentName.getString()));
1376
                    // ok, found the node of interest
1377
                    ret = dict;
1378
                }
1379
            }
1380
        }
1381

1382
        return ret;
1383
    }
1384
    catch (const Py::Exception&) {
1385
        throw;
1386
    }
1387
}
1388

1389
Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args)
1390
{
1391
    PyObject* object;
1392
    float r = getView3DIventorPtr()->getViewer()->getPickRadius();
1393
    if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r))
1394
        throw Py::Exception();
1395

1396
    try {
1397
        //Note: For gcc (4.2) we need the 'const' keyword to avoid the compiler error:
1398
        //conversion from 'Py::seqref<Py::Object>' to non-scalar type 'Py::Int' requested
1399
        //We should report this problem to the PyCXX project as in the documentation an
1400
        //example without the 'const' keyword is used.
1401
        //Or we can also write Py::Int x(tuple[0]);
1402
        const Py::Tuple tuple(object);
1403
        Py::Int x(tuple[0]);
1404
        Py::Int y(tuple[1]);
1405

1406
        // As this method could be called during a SoHandleEventAction scene
1407
        // graph traversal we must not use a second SoHandleEventAction as
1408
        // we will get Coin warnings because of multiple scene graph traversals
1409
        // which is regarded as error-prone.
1410
        SoRayPickAction action(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion());
1411
        action.setPickAll(true);
1412
        action.setRadius(r);
1413
        action.setPoint(SbVec2s((long)x,(long)y));
1414
        action.apply(getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph());
1415
        const SoPickedPointList& pp = action.getPickedPointList();
1416

1417
        Py::Object ret = Py::None();
1418
        if (pp.getLength() > 0) {
1419
            Py::List list;
1420
            for (int i=0; i<pp.getLength(); i++) {
1421
                Py::Dict dict;
1422
                auto point = static_cast<SoPickedPoint*>(pp.get(i));
1423
                SbVec3f pt = point->getPoint();
1424
                dict.setItem("x", Py::Float(pt[0]));
1425
                dict.setItem("y", Py::Float(pt[1]));
1426
                dict.setItem("z", Py::Float(pt[2]));
1427

1428
                ViewProvider *vp = getView3DIventorPtr()->getViewer()->getViewProviderByPath(point->getPath());
1429
                if(vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
1430
                    if(!vp->isSelectable())
1431
                        continue;
1432
                    auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
1433
                    if (vp->useNewSelectionModel()) {
1434
                        std::string subname;
1435
                        if (!vp->getElementPicked(point,subname))
1436
                            continue;
1437
                        auto obj = vpd->getObject();
1438
                        if (!obj)
1439
                            continue;
1440
                        if (!subname.empty()) {
1441
                            App::ElementNamePair elementName;
1442
                            auto sobj = App::GeoFeature::resolveElement(obj,subname.c_str(),elementName);
1443
                            if (!sobj)
1444
                                continue;
1445
                            if (sobj != obj) {
1446
                                dict.setItem("ParentObject",Py::Object(obj->getPyObject(),true));
1447
                                dict.setItem("SubName",Py::String(subname));
1448
                                obj = sobj;
1449
                            }
1450
                            subname = !elementName.oldName.empty()?elementName.oldName:elementName.newName;
1451
                        }
1452
                        dict.setItem("Document",
1453
                            Py::String(obj->getDocument()->getName()));
1454
                        dict.setItem("Object",
1455
                            Py::String(obj->getNameInDocument()));
1456
                        dict.setItem("Component",Py::String(subname));
1457
                    }
1458
                    else {
1459
                        dict.setItem("Document",
1460
                            Py::String(vpd->getObject()->getDocument()->getName()));
1461
                        dict.setItem("Object",
1462
                            Py::String(vpd->getObject()->getNameInDocument()));
1463
                        // search for a SoFCSelection node
1464
                        SoFCDocumentObjectAction objaction;
1465
                        objaction.apply(point->getPath());
1466
                        if (objaction.isHandled()) {
1467
                            dict.setItem("Component",
1468
                                Py::String(objaction.componentName.getString()));
1469
                        }
1470
                    }
1471
                    // ok, found the node of interest
1472
                    list.append(dict);
1473
                }
1474
                else {
1475
                    // custom nodes not in a VP: search for a SoFCSelection node
1476
                    SoFCDocumentObjectAction objaction;
1477
                    objaction.apply(point->getPath());
1478
                    if (objaction.isHandled()) {
1479
                        dict.setItem("Document",
1480
                            Py::String(objaction.documentName.getString()));
1481
                        dict.setItem("Object",
1482
                            Py::String(objaction.objectName.getString()));
1483
                        dict.setItem("Component",
1484
                            Py::String(objaction.componentName.getString()));
1485
                        // ok, found the node of interest
1486
                        ret = dict;
1487
                    }
1488
                }
1489
            }
1490

1491
            ret = list;
1492
        }
1493

1494
        return ret;
1495
    }
1496
    catch (const Py::Exception&) {
1497
        throw;
1498
    }
1499
}
1500

1501
Py::Object View3DInventorPy::getSize()
1502
{
1503
    try {
1504
        SbVec2s size = getView3DIventorPtr()->getViewer()->getSoRenderManager()->getSize();
1505
        Py::Tuple tuple(2);
1506
        tuple.setItem(0, Py::Int(size[0]));
1507
        tuple.setItem(1, Py::Int(size[1]));
1508
        return tuple;
1509
    }
1510
    catch (const Py::Exception&) {
1511
        throw;
1512
    }
1513
}
1514

1515
Py::Object View3DInventorPy::getPointOnFocalPlane(const Py::Tuple& args)
1516
{
1517
    short x,y;
1518
    if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
1519
        PyErr_Clear();
1520
        Py::Tuple t(args[0]);
1521
        x = (int)Py::Int(t[0]);
1522
        y = (int)Py::Int(t[1]);
1523
    }
1524
    try {
1525
        SbVec3f pt = getView3DIventorPtr()->getViewer()->getPointOnFocalPlane(SbVec2s(x,y));
1526
        return Py::Vector(Base::Vector3f(pt[0], pt[1], pt[2]));
1527
    }
1528
    catch (const Base::Exception& e) {
1529
        throw Py::RuntimeError(e.what());
1530
    }
1531
    catch (const Py::Exception&) {
1532
        throw;
1533
    }
1534
}
1535

1536
Py::Object View3DInventorPy::getPointOnViewport(const Py::Tuple& args)
1537
{
1538
    PyObject* v;
1539
    double vx,vy,vz;
1540
    if (PyArg_ParseTuple(args.ptr(), "O!", &Base::VectorPy::Type, &v)) {
1541
        Base::Vector3d* vec = static_cast<Base::VectorPy*>(v)->getVectorPtr();
1542
        vx = vec->x;
1543
        vy = vec->y;
1544
        vz = vec->z;
1545
    }
1546
    else {
1547
        PyErr_Clear();
1548
        if (!PyArg_ParseTuple(args.ptr(), "ddd", &vx,&vy,&vz)) {
1549
            throw Py::TypeError("Wrong argument, Vector or three floats expected expected");
1550
        }
1551
    }
1552

1553
    try {
1554
        SbVec2s pt = getView3DIventorPtr()->getViewer()->getPointOnViewport(SbVec3f(vx,vy,vz));
1555
        Py::Tuple tuple(2);
1556
        tuple.setItem(0, Py::Int(pt[0]));
1557
        tuple.setItem(1, Py::Int(pt[1]));
1558

1559
        return tuple;
1560
    }
1561
    catch (const Base::Exception& e) {
1562
        throw Py::RuntimeError(e.what());
1563
    }
1564
    catch (const Py::Exception&) {
1565
        throw;
1566
    }
1567
}
1568

1569
Py::Object View3DInventorPy::projectPointToLine(const Py::Tuple& args)
1570
{
1571
    short x,y;
1572
    if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
1573
        PyErr_Clear();
1574
        Py::Tuple t(args[0]);
1575
        x = (int)Py::Int(t[0]);
1576
        y = (int)Py::Int(t[1]);
1577
    }
1578
    try {
1579
        SbVec3f pt1, pt2;
1580
        getView3DIventorPtr()->getViewer()->projectPointToLine(SbVec2s(x,y), pt1, pt2);
1581
        Py::Tuple tuple(2);
1582
        tuple.setItem(0, Py::Vector(Base::Vector3f(pt1[0], pt1[1], pt1[2])));
1583
        tuple.setItem(1, Py::Vector(Base::Vector3f(pt2[0], pt2[1], pt2[2])));
1584
        return tuple;
1585
    }
1586
    catch (const Base::Exception& e) {
1587
        throw Py::RuntimeError(e.what());
1588
    }
1589
    catch (const Py::Exception&) {
1590
        throw;
1591
    }
1592
}
1593

1594
Py::Object View3DInventorPy::listNavigationTypes()
1595
{
1596
    std::vector<Base::Type> types;
1597
    Py::List styles;
1598
    Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types);
1599
    for (auto it = types.begin() + 1; it != types.end(); ++it) {
1600
        styles.append(Py::String(it->getName()));
1601
    }
1602
    return styles;
1603
}
1604

1605
Py::Object View3DInventorPy::getNavigationType()
1606
{
1607
    std::string name = getView3DIventorPtr()->getViewer()->navigationStyle()->getTypeId().getName();
1608
    return Py::String(name);
1609
}
1610

1611
Py::Object View3DInventorPy::setNavigationType(const Py::Tuple& args)
1612
{
1613
    char* style;
1614
    if (!PyArg_ParseTuple(args.ptr(), "s", &style))
1615
        throw Py::Exception();
1616
    Base::Type type = Base::Type::fromName(style);
1617
    getView3DIventorPtr()->getViewer()->setNavigationType(type);
1618
    return Py::None();
1619
}
1620

1621
void View3DInventorPy::eventCallback(void * ud, SoEventCallback * n)
1622
{
1623
    Base::PyGILStateLocker lock;
1624
    try {
1625
        Py::Dict dict;
1626
        const SoEvent* e = n->getEvent();
1627
        if (!e) // invalid event
1628
            return;
1629
        // Type
1630
        dict.setItem("Type", Py::String(std::string(e->getTypeId().getName().getString())));
1631
        // Time
1632
        dict.setItem("Time", Py::String(std::string(e->getTime().formatDate("%Y-%m-%d %H:%M:%S").getString())));
1633
        SbVec2s p = n->getEvent()->getPosition();
1634
        Py::Tuple pos(2);
1635
        pos.setItem(0, Py::Int(p[0]));
1636
        pos.setItem(1, Py::Int(p[1]));
1637
        // Position
1638
        dict.setItem("Position", pos);
1639
        // Shift, Ctrl, Alt down
1640
        dict.setItem("ShiftDown", Py::Object((e->wasShiftDown() ? Py_True : Py_False)));
1641
        dict.setItem("CtrlDown",  Py::Object((e->wasCtrlDown()  ? Py_True : Py_False)));
1642
        dict.setItem("AltDown",   Py::Object((e->wasAltDown()   ? Py_True : Py_False)));
1643
        if (e->isOfType(SoButtonEvent::getClassTypeId())) {
1644
            std::string state;
1645
            const auto be = static_cast<const SoButtonEvent*>(e);
1646
            switch (be->getState()) {
1647
                case SoButtonEvent::UP:
1648
                    state = "UP";
1649
                    break;
1650
                case SoButtonEvent::DOWN:
1651
                    state = "DOWN";
1652
                    break;
1653
                default:
1654
                    state = "UNKNOWN";
1655
                    break;
1656
            }
1657

1658
            dict.setItem("State", Py::String(state));
1659
        }
1660
        if (e->isOfType(SoKeyboardEvent::getClassTypeId())) {
1661
            const auto ke = static_cast<const SoKeyboardEvent*>(e);
1662
            switch (ke->getKey()) {
1663
                case SoKeyboardEvent::ANY:
1664
                    dict.setItem("Key", Py::String("ANY"));
1665
                    break;
1666
                case SoKeyboardEvent::UNDEFINED:
1667
                    dict.setItem("Key", Py::String("UNDEFINED"));
1668
                    break;
1669
                case SoKeyboardEvent::LEFT_SHIFT:
1670
                case SoKeyboardEvent::RIGHT_SHIFT:
1671
                    dict.setItem("Key", Py::String("SHIFT"));
1672
                    break;
1673
                case SoKeyboardEvent::LEFT_CONTROL:
1674
                case SoKeyboardEvent::RIGHT_CONTROL:
1675
                    dict.setItem("Key", Py::String("CONTROL"));
1676
                    break;
1677
                case SoKeyboardEvent::LEFT_ALT:
1678
                case SoKeyboardEvent::RIGHT_ALT:
1679
                    dict.setItem("Key", Py::String("ALT"));
1680
                    break;
1681
                case SoKeyboardEvent::HOME:
1682
                    dict.setItem("Key", Py::String("HOME"));
1683
                    break;
1684
                case SoKeyboardEvent::LEFT_ARROW:
1685
                    dict.setItem("Key", Py::String("LEFT_ARROW"));
1686
                    break;
1687
                case SoKeyboardEvent::UP_ARROW:
1688
                    dict.setItem("Key", Py::String("UP_ARROW"));
1689
                    break;
1690
                case SoKeyboardEvent::RIGHT_ARROW:
1691
                    dict.setItem("Key", Py::String("RIGHT_ARROW"));
1692
                    break;
1693
                case SoKeyboardEvent::DOWN_ARROW:
1694
                    dict.setItem("Key", Py::String("DOWN_ARROW"));
1695
                    break;
1696
                case SoKeyboardEvent::PAGE_UP:
1697
                    dict.setItem("Key", Py::String("PAGE_UP"));
1698
                    break;
1699
                case SoKeyboardEvent::PAGE_DOWN:
1700
                    dict.setItem("Key", Py::String("PAGE_DOWN"));
1701
                    break;
1702
                case SoKeyboardEvent::END:
1703
                    dict.setItem("Key", Py::String("END"));
1704
                    break;
1705
                case SoKeyboardEvent::PAD_ENTER:
1706
                    dict.setItem("Key", Py::String("PAD_ENTER"));
1707
                    break;
1708
                case SoKeyboardEvent::PAD_F1:
1709
                    dict.setItem("Key", Py::String("PAD_F1"));
1710
                    break;
1711
                case SoKeyboardEvent::PAD_F2:
1712
                    dict.setItem("Key", Py::String("PAD_F2"));
1713
                    break;
1714
                case SoKeyboardEvent::PAD_F3:
1715
                    dict.setItem("Key", Py::String("PAD_F3"));
1716
                    break;
1717
                case SoKeyboardEvent::PAD_F4:
1718
                    dict.setItem("Key", Py::String("PAD_F4"));
1719
                    break;
1720
                case SoKeyboardEvent::PAD_0:
1721
                    dict.setItem("Key", Py::String("PAD_0"));
1722
                    break;
1723
                case SoKeyboardEvent::PAD_1:
1724
                    dict.setItem("Key", Py::String("PAD_1"));
1725
                    break;
1726
                case SoKeyboardEvent::PAD_2:
1727
                    dict.setItem("Key", Py::String("PAD_2"));
1728
                    break;
1729
                case SoKeyboardEvent::PAD_3:
1730
                    dict.setItem("Key", Py::String("PAD_3"));
1731
                    break;
1732
                case SoKeyboardEvent::PAD_4:
1733
                    dict.setItem("Key", Py::String("PAD_4"));
1734
                    break;
1735
                case SoKeyboardEvent::PAD_5:
1736
                    dict.setItem("Key", Py::String("PAD_5"));
1737
                    break;
1738
                case SoKeyboardEvent::PAD_6:
1739
                    dict.setItem("Key", Py::String("PAD_6"));
1740
                    break;
1741
                case SoKeyboardEvent::PAD_7:
1742
                    dict.setItem("Key", Py::String("PAD_7"));
1743
                    break;
1744
                case SoKeyboardEvent::PAD_8:
1745
                    dict.setItem("Key", Py::String("PAD_8"));
1746
                    break;
1747
                case SoKeyboardEvent::PAD_9:
1748
                    dict.setItem("Key", Py::String("PAD_9"));
1749
                    break;
1750
                case SoKeyboardEvent::PAD_ADD:
1751
                    dict.setItem("Key", Py::String("PAD_ADD"));
1752
                    break;
1753
                case SoKeyboardEvent::PAD_SUBTRACT:
1754
                    dict.setItem("Key", Py::String("PAD_SUBTRACT"));
1755
                    break;
1756
                case SoKeyboardEvent::PAD_MULTIPLY:
1757
                    dict.setItem("Key", Py::String("PAD_MULTIPLY"));
1758
                    break;
1759
                case SoKeyboardEvent::PAD_DIVIDE:
1760
                    dict.setItem("Key", Py::String("PAD_DIVIDE"));
1761
                    break;
1762
                case SoKeyboardEvent::PAD_TAB:
1763
                    dict.setItem("Key", Py::String("PAD_TAB"));
1764
                    break;
1765
                case SoKeyboardEvent::PAD_DELETE:
1766
                    dict.setItem("Key", Py::String("PAD_DELETE"));
1767
                    break;
1768
                case SoKeyboardEvent::F1:
1769
                    dict.setItem("Key", Py::String("F1"));
1770
                    break;
1771
                case SoKeyboardEvent::F2:
1772
                    dict.setItem("Key", Py::String("F2"));
1773
                    break;
1774
                case SoKeyboardEvent::F3:
1775
                    dict.setItem("Key", Py::String("F3"));
1776
                    break;
1777
                case SoKeyboardEvent::F4:
1778
                    dict.setItem("Key", Py::String("F4"));
1779
                    break;
1780
                case SoKeyboardEvent::F5:
1781
                    dict.setItem("Key", Py::String("F5"));
1782
                    break;
1783
                case SoKeyboardEvent::F6:
1784
                    dict.setItem("Key", Py::String("F6"));
1785
                    break;
1786
                case SoKeyboardEvent::F7:
1787
                    dict.setItem("Key", Py::String("F7"));
1788
                    break;
1789
                case SoKeyboardEvent::F8:
1790
                    dict.setItem("Key", Py::String("F8"));
1791
                    break;
1792
                case SoKeyboardEvent::F9:
1793
                    dict.setItem("Key", Py::String("F9"));
1794
                    break;
1795
                case SoKeyboardEvent::F10:
1796
                    dict.setItem("Key", Py::String("F10"));
1797
                    break;
1798
                case SoKeyboardEvent::F11:
1799
                    dict.setItem("Key", Py::String("F11"));
1800
                    break;
1801
                case SoKeyboardEvent::F12:
1802
                    dict.setItem("Key", Py::String("F12"));
1803
                    break;
1804
                case SoKeyboardEvent::BACKSPACE:
1805
                    dict.setItem("Key", Py::String("BACKSPACE"));
1806
                    break;
1807
                case SoKeyboardEvent::TAB:
1808
                    dict.setItem("Key", Py::String("TAB"));
1809
                    break;
1810
                case SoKeyboardEvent::RETURN:
1811
                    dict.setItem("Key", Py::String("RETURN"));
1812
                    break;
1813
                case SoKeyboardEvent::PAUSE:
1814
                    dict.setItem("Key", Py::String("PAUSE"));
1815
                    break;
1816
                case SoKeyboardEvent::SCROLL_LOCK:
1817
                    dict.setItem("Key", Py::String("SCROLL_LOCK"));
1818
                    break;
1819
                case SoKeyboardEvent::ESCAPE:
1820
                    dict.setItem("Key", Py::String("ESCAPE"));
1821
                    break;
1822
                case SoKeyboardEvent::KEY_DELETE:
1823
                    dict.setItem("Key", Py::String("DELETE"));
1824
                    break;
1825
                case SoKeyboardEvent::PRINT:
1826
                    dict.setItem("Key", Py::String("PRINT"));
1827
                    break;
1828
                case SoKeyboardEvent::INSERT:
1829
                    dict.setItem("Key", Py::String("INSERT"));
1830
                    break;
1831
                case SoKeyboardEvent::NUM_LOCK:
1832
                    dict.setItem("Key", Py::String("NUM_LOCK"));
1833
                    break;
1834
                case SoKeyboardEvent::CAPS_LOCK:
1835
                    dict.setItem("Key", Py::String("CAPS_LOCK"));
1836
                    break;
1837
                case SoKeyboardEvent::SHIFT_LOCK:
1838
                    dict.setItem("Key", Py::String("SHIFT_LOCK"));
1839
                    break;
1840
                case SoKeyboardEvent::SPACE:
1841
                    dict.setItem("Key", Py::String("SPACE"));
1842
                    break;
1843
                case SoKeyboardEvent::APOSTROPHE:
1844
                    dict.setItem("Key", Py::String("APOSTROPHE"));
1845
                    break;
1846
                case SoKeyboardEvent::COMMA:
1847
                    dict.setItem("Key", Py::String("COMMA"));
1848
                    break;
1849
                case SoKeyboardEvent::MINUS:
1850
                    dict.setItem("Key", Py::String("MINUS"));
1851
                    break;
1852
                case SoKeyboardEvent::PERIOD:
1853
                    dict.setItem("Key", Py::String("PERIOD"));
1854
                    break;
1855
                case SoKeyboardEvent::SLASH:
1856
                    dict.setItem("Key", Py::String("SLASH"));
1857
                    break;
1858
                case SoKeyboardEvent::SEMICOLON:
1859
                    dict.setItem("Key", Py::String("SEMICOLON"));
1860
                    break;
1861
                case SoKeyboardEvent::EQUAL:
1862
                    dict.setItem("Key", Py::String("EQUAL"));
1863
                    break;
1864
                case SoKeyboardEvent::BRACKETLEFT:
1865
                    dict.setItem("Key", Py::String("BRACKETLEFT"));
1866
                    break;
1867
                case SoKeyboardEvent::BACKSLASH:
1868
                    dict.setItem("Key", Py::String("BACKSLASH"));
1869
                    break;
1870
                case SoKeyboardEvent::BRACKETRIGHT:
1871
                    dict.setItem("Key", Py::String("BRACKETRIGHT"));
1872
                    break;
1873
                case SoKeyboardEvent::GRAVE:
1874
                    dict.setItem("Key", Py::String("GRAVE"));
1875
                    break;
1876
                default:
1877
                    dict.setItem("Key", Py::Char(ke->getPrintableCharacter()));
1878
                    break;
1879
            }
1880
        }
1881
        if (e->isOfType(SoMouseButtonEvent::getClassTypeId())) {
1882
            const auto mbe = static_cast<const SoMouseButtonEvent*>(e);
1883
            std::string button;
1884
            switch (mbe->getButton()) {
1885
                case SoMouseButtonEvent::BUTTON1:
1886
                    button = "BUTTON1";
1887
                    break;
1888
                case SoMouseButtonEvent::BUTTON2:
1889
                    button = "BUTTON2";
1890
                    break;
1891
                case SoMouseButtonEvent::BUTTON3:
1892
                    button = "BUTTON3";
1893
                    break;
1894
                case SoMouseButtonEvent::BUTTON4:
1895
                    button = "BUTTON4";
1896
                    break;
1897
                case SoMouseButtonEvent::BUTTON5:
1898
                    button = "BUTTON5";
1899
                    break;
1900
                default:
1901
                    button = "ANY";
1902
                    break;
1903
            }
1904

1905
            dict.setItem("Button", Py::String(button));
1906
        }
1907
        if (e->isOfType(SoMouseWheelEvent::getClassTypeId())){
1908
            const auto mwe = static_cast<const SoMouseWheelEvent*>(e);
1909
            dict.setItem("Delta", Py::Long(mwe->getDelta()));
1910
        }
1911
        if (e->isOfType(SoSpaceballButtonEvent::getClassTypeId())) {
1912
            const auto sbe = static_cast<const SoSpaceballButtonEvent*>(e);
1913
            std::string button;
1914
            switch (sbe->getButton()) {
1915
                case SoSpaceballButtonEvent::BUTTON1:
1916
                    button = "BUTTON1";
1917
                    break;
1918
                case SoSpaceballButtonEvent::BUTTON2:
1919
                    button = "BUTTON2";
1920
                    break;
1921
                case SoSpaceballButtonEvent::BUTTON3:
1922
                    button = "BUTTON3";
1923
                    break;
1924
                case SoSpaceballButtonEvent::BUTTON4:
1925
                    button = "BUTTON4";
1926
                    break;
1927
                case SoSpaceballButtonEvent::BUTTON5:
1928
                    button = "BUTTON5";
1929
                    break;
1930
                case SoSpaceballButtonEvent::BUTTON6:
1931
                    button = "BUTTON6";
1932
                    break;
1933
                case SoSpaceballButtonEvent::BUTTON7:
1934
                    button = "BUTTON7";
1935
                    break;
1936
                default:
1937
                    button = "ANY";
1938
                    break;
1939
            }
1940

1941
            dict.setItem("Button", Py::String(button));
1942
        }
1943
        if (e->isOfType(SoMotion3Event::getClassTypeId())) {
1944
            const auto me = static_cast<const SoMotion3Event*>(e);
1945
            const SbVec3f& m = me->getTranslation();
1946
            const SbRotation& r = me->getRotation();
1947
            Py::Tuple mov(3);
1948
            mov.setItem(0, Py::Float(m[0]));
1949
            mov.setItem(1, Py::Float(m[1]));
1950
            mov.setItem(2, Py::Float(m[2]));
1951
            dict.setItem("Translation", mov);
1952
            Py::Tuple rot(4);
1953
            rot.setItem(0, Py::Float(r.getValue()[0]));
1954
            rot.setItem(1, Py::Float(r.getValue()[1]));
1955
            rot.setItem(2, Py::Float(r.getValue()[2]));
1956
            rot.setItem(3, Py::Float(r.getValue()[3]));
1957
            dict.setItem("Rotation", rot);
1958
        }
1959

1960
        // now run the method
1961
        Py::Callable method(reinterpret_cast<PyObject*>(ud));
1962
        Py::Tuple args(1);
1963
        args.setItem(0, dict);
1964
        method.apply(args);
1965
    }
1966
    catch (const Py::Exception& e) {
1967
        Py::Object o = Py::type(e);
1968
        if (o.isString()) {
1969
            Py::String s(o);
1970
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
1971
        }
1972
        else {
1973
            Py::String s(o.repr());
1974
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
1975
        }
1976
        // Prints message to console window if we are in interactive mode
1977
        PyErr_Print();
1978
    }
1979
}
1980

1981
Py::Object View3DInventorPy::addEventCallback(const Py::Tuple& args)
1982
{
1983
    char* eventtype;
1984
    PyObject* method;
1985
    if (!PyArg_ParseTuple(args.ptr(), "sO", &eventtype, &method))
1986
        throw Py::Exception();
1987
    try {
1988
        if (PyCallable_Check(method) == 0) {
1989
            throw Py::TypeError("object is not callable");
1990
        }
1991
        SoType eventId = SoType::fromName(eventtype);
1992
        if (eventId.isBad() || !eventId.isDerivedFrom(SoEvent::getClassTypeId())) {
1993
            std::string s;
1994
            std::ostringstream s_out;
1995
            s_out << eventtype << " is not a valid event type";
1996
            throw Py::TypeError(s_out.str());
1997
        }
1998

1999
        getView3DIventorPtr()->getViewer()->addEventCallback(eventId, View3DInventorPy::eventCallback, method);
2000
        callbacks.push_back(method);
2001
        Py_INCREF(method);
2002
        return Py::Callable(method, false);
2003
    }
2004
    catch (const Py::Exception&) {
2005
        throw;
2006
    }
2007
}
2008

2009
Py::Object View3DInventorPy::removeEventCallback(const Py::Tuple& args)
2010
{
2011
    char* eventtype;
2012
    PyObject* method;
2013
    if (!PyArg_ParseTuple(args.ptr(), "sO", &eventtype, &method))
2014
        throw Py::Exception();
2015
    try {
2016
        if (PyCallable_Check(method) == 0) {
2017
            throw Py::RuntimeError("object is not callable");
2018
        }
2019
        SoType eventId = SoType::fromName(eventtype);
2020
        if (eventId.isBad() || !eventId.isDerivedFrom(SoEvent::getClassTypeId())) {
2021
            std::string s;
2022
            std::ostringstream s_out;
2023
            s_out << eventtype << " is not a valid event type";
2024
            throw Py::TypeError(s_out.str());
2025
        }
2026

2027
        getView3DIventorPtr()->getViewer()->removeEventCallback(eventId, View3DInventorPy::eventCallback, method);
2028
        callbacks.remove(method);
2029
        Py_DECREF(method);
2030
        return Py::None();
2031
    }
2032
    catch (const Py::Exception&) {
2033
        throw;
2034
    }
2035
}
2036

2037
Py::Object View3DInventorPy::setAnnotation(const Py::Tuple& args)
2038
{
2039
    char *psAnnoName,*psBuffer;
2040
    if (!PyArg_ParseTuple(args.ptr(), "ss", &psAnnoName, &psBuffer))
2041
        throw Py::Exception();
2042
    ViewProviderExtern* view = nullptr;
2043
    try {
2044
        view = new ViewProviderExtern();
2045
        view->setModeByString(psAnnoName, psBuffer);
2046
    }
2047
    catch (const Base::Exception& e) {
2048
        delete view;
2049
        throw Py::RuntimeError(e.what());
2050
    }
2051

2052
    getView3DIventorPtr()->getGuiDocument()->setAnnotationViewProvider(psAnnoName, view);
2053
    return Py::None();
2054
}
2055

2056
Py::Object View3DInventorPy::removeAnnotation(const Py::Tuple& args)
2057
{
2058
    char *psAnnoName;
2059
    if (!PyArg_ParseTuple(args.ptr(), "s", &psAnnoName))
2060
        throw Py::Exception();
2061
    ViewProvider* view = nullptr;
2062
    view = getView3DIventorPtr()->getGuiDocument()->getAnnotationViewProvider(psAnnoName);
2063
    if (view) {
2064
        getView3DIventorPtr()->getGuiDocument()->removeAnnotationViewProvider(psAnnoName);
2065
        return Py::None();
2066
    }
2067
    else {
2068
        std::string s;
2069
        std::ostringstream s_out;
2070
        s_out << "No such annotation '" << psAnnoName << "'";
2071
        throw Py::KeyError(s_out.str());
2072
    }
2073
}
2074

2075
Py::Object View3DInventorPy::getSceneGraph()
2076
{
2077
    try {
2078
        SoNode* scene = getView3DIventorPtr()->getViewer()->getSceneGraph();
2079
        PyObject* proxy = nullptr;
2080
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoSeparator *", static_cast<void*>(scene), 1);
2081
        scene->ref();
2082
        return Py::Object(proxy, true);
2083
    }
2084
    catch (const Base::Exception& e) {
2085
        throw Py::RuntimeError(e.what());
2086
    }
2087
}
2088

2089
Py::Object View3DInventorPy::getViewer()
2090
{
2091
    View3DInventorViewer* viewer = getView3DIventorPtr()->getViewer();
2092
    return Py::Object(viewer->getPyObject(), true);
2093
}
2094

2095
void View3DInventorPy::eventCallbackPivy(void * ud, SoEventCallback * n)
2096
{
2097
    Base::PyGILStateLocker lock;
2098
    const SoEvent* e = n->getEvent();
2099
    std::string type = e->getTypeId().getName().getString();
2100
    type += " *";
2101

2102
    PyObject* proxy = nullptr;
2103
    try {
2104
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", type.c_str(), const_cast<void*>(static_cast<const void*>(e)), 0);
2105
        // now run the method
2106
        Py::Object event(proxy,true);
2107
        Py::Callable method(static_cast<PyObject*>(ud));
2108
        Py::Tuple args(1);
2109
        args.setItem(0, event);
2110
        method.apply(args);
2111
    }
2112
    catch (const Base::Exception&) {
2113
        return;
2114
    }
2115
    catch (const Py::Exception& e) {
2116
        Py::Object o = Py::type(e);
2117
        if (o.isString()) {
2118
            Py::String s(o);
2119
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2120
        }
2121
        else {
2122
            Py::String s(o.repr());
2123
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2124
        }
2125
        // Prints message to console window if we are in interactive mode
2126
        PyErr_Print();
2127
    }
2128
}
2129

2130
void View3DInventorPy::eventCallbackPivyEx(void * ud, SoEventCallback * n)
2131
{
2132
    Base::PyGILStateLocker lock;
2133
    std::string type = "SoEventCallback *";
2134

2135
    PyObject* proxy = nullptr;
2136
    try {
2137
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", type.c_str(), static_cast<void*>(n), 0);
2138
        // now run the method
2139
        Py::Object event(proxy,true);
2140
        Py::Callable method(reinterpret_cast<PyObject*>(ud));
2141
        Py::Tuple args(1);
2142
        args.setItem(0, event);
2143
        method.apply(args);
2144
    }
2145
    catch (const Base::Exception&) {
2146
        return;
2147
    }
2148
    catch (const Py::Exception& e) {
2149
        Py::Object o = Py::type(e);
2150
        if (o.isString()) {
2151
            Py::String s(o);
2152
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2153
        }
2154
        else {
2155
            Py::String s(o.repr());
2156
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2157
        }
2158
        // Prints message to console window if we are in interactive mode
2159
        PyErr_Print();
2160
    }
2161
}
2162

2163
Py::Object View3DInventorPy::addEventCallbackPivy(const Py::Tuple& args)
2164
{
2165
    PyObject* proxy;
2166
    PyObject* method;
2167
    int ex=1; // if 1, use eventCallbackPivyEx
2168
    if (!PyArg_ParseTuple(args.ptr(), "OO|i", &proxy, &method,&ex))
2169
        throw Py::Exception();
2170

2171
    void* ptr = nullptr;
2172
    try {
2173
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoType *", proxy, &ptr, 0);
2174
    }
2175
    catch (const Base::Exception& e) {
2176
        throw Py::RuntimeError(e.what());
2177
    }
2178

2179
    auto eventId = static_cast<SoType*>(ptr);
2180
    if (eventId->isBad() || !eventId->isDerivedFrom(SoEvent::getClassTypeId())) {
2181
        std::string s;
2182
        std::ostringstream s_out;
2183
        s_out << eventId->getName().getString() << "is not a valid event type";
2184
        throw Py::TypeError(s_out.str());
2185
    }
2186

2187
    try {
2188
        if (PyCallable_Check(method) == 0) {
2189
            throw Py::TypeError("object is not callable");
2190
        }
2191

2192
        SoEventCallbackCB* callback = (ex == 1 ?
2193
            View3DInventorPy::eventCallbackPivyEx :
2194
            View3DInventorPy::eventCallbackPivy);
2195
        getView3DIventorPtr()->getViewer()->addEventCallback(*eventId, callback, method);
2196
        callbacks.push_back(method);
2197
        Py_INCREF(method);
2198
        return Py::Callable(method, false);
2199
    }
2200
    catch (const Py::Exception&) {
2201
        throw;
2202
    }
2203
}
2204

2205
Py::Object View3DInventorPy::removeEventCallbackPivy(const Py::Tuple& args)
2206
{
2207
    PyObject* proxy;
2208
    PyObject* method;
2209
    int ex=1; // if 1, use eventCallbackPivyEx
2210
    if (!PyArg_ParseTuple(args.ptr(), "OO|i", &proxy, &method,&ex))
2211
        throw Py::Exception();
2212

2213
    void* ptr = nullptr;
2214
    try {
2215
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoType *", proxy, &ptr, 0);
2216
    }
2217
    catch (const Base::Exception& e) {
2218
        throw Py::RuntimeError(e.what());
2219
    }
2220

2221
    auto eventId = static_cast<SoType*>(ptr);
2222
    if (eventId->isBad() || !eventId->isDerivedFrom(SoEvent::getClassTypeId())) {
2223
        std::string s;
2224
        std::ostringstream s_out;
2225
        s_out << eventId->getName().getString() << "is not a valid event type";
2226
        throw Py::TypeError(s_out.str());
2227
    }
2228

2229
    try {
2230
        if (PyCallable_Check(method) == 0) {
2231
            throw Py::TypeError("object is not callable");
2232
        }
2233

2234
        SoEventCallbackCB* callback = (ex == 1 ?
2235
            View3DInventorPy::eventCallbackPivyEx :
2236
            View3DInventorPy::eventCallbackPivy);
2237
        getView3DIventorPtr()->getViewer()->removeEventCallback(*eventId, callback, method);
2238
        callbacks.remove(method);
2239
        Py_DECREF(method);
2240
        return Py::Callable(method, false);
2241
    }
2242
    catch (const Py::Exception&) {
2243
        throw;
2244
    }
2245
}
2246

2247
Py::Object View3DInventorPy::setAxisCross(const Py::Tuple& args)
2248
{
2249
    int ok;
2250
    if (!PyArg_ParseTuple(args.ptr(), "i", &ok))
2251
        throw Py::Exception();
2252
    getView3DIventorPtr()->getViewer()->setAxisCross(ok!=0);
2253
    return Py::None();
2254
}
2255

2256
Py::Object View3DInventorPy::hasAxisCross()
2257
{
2258
    SbBool ok = getView3DIventorPtr()->getViewer()->hasAxisCross();
2259
    return Py::Boolean(ok ? true : false);
2260
}
2261

2262
void View3DInventorPy::draggerCallback(void * ud, SoDragger* n)
2263
{
2264
    Base::PyGILStateLocker lock;
2265
    PyObject* proxy = nullptr;
2266
    try {
2267
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoDragger *", static_cast<void*>(n), 0);
2268
        //call the method
2269
        Py::Object dragger(proxy,true);
2270
        Py::Callable method(reinterpret_cast<PyObject*>(ud));
2271
        Py::Tuple args(1);
2272
        args.setItem(0, dragger);
2273
        method.apply(args);
2274
    }
2275
    catch (const Base::Exception& e) {
2276
        throw Py::RuntimeError(e.what());
2277
    }
2278
    catch (const Py::Exception& e) {
2279
        Py::Object o = Py::type(e);
2280
        if (o.isString()) {
2281
            Py::String s(o);
2282
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2283
        }
2284
        else {
2285
            Py::String s(o.repr());
2286
            Base::Console().Warning("%s\n", s.as_std_string("utf-8").c_str());
2287
        }
2288
        // Prints message to console window if we are in interactive mode
2289
        PyErr_Print();
2290
    }
2291
}
2292

2293
Py::Object View3DInventorPy::addDraggerCallback(const Py::Tuple& args)
2294
{
2295
    PyObject* dragger;
2296
    char* type;
2297
    PyObject* method;
2298
    if (!PyArg_ParseTuple(args.ptr(), "OsO", &dragger,&type, &method))
2299
        throw Py::Exception();
2300

2301

2302
    //Check if dragger is a SoDragger object and cast
2303
    void* ptr = nullptr;
2304
    try {
2305
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDragger *", dragger, &ptr, 0);
2306
    }
2307
    catch (const Base::Exception&) {
2308
        throw Py::TypeError("The first argument must be of type SoDragger");
2309
    }
2310
    auto drag = static_cast<SoDragger*>(ptr);
2311

2312
    //Check if method is callable
2313
    if (PyCallable_Check(method) == 0) {
2314
        throw Py::TypeError("the method is not callable");
2315
    }
2316

2317
    try {
2318
        if (strcmp(type,"addFinishCallback")==0) {
2319
            drag->addFinishCallback(draggerCallback,method);
2320
        }
2321
        else if (strcmp(type,"addStartCallback")==0) {
2322
            drag->addStartCallback(draggerCallback,method);
2323
        }
2324
        else if (strcmp(type,"addMotionCallback")==0) {
2325
            drag->addMotionCallback(draggerCallback,method);
2326
        }
2327
        else if (strcmp(type,"addValueChangedCallback")==0) {
2328
            drag->addValueChangedCallback(draggerCallback,method);
2329
        }
2330
        else {
2331
            std::string s;
2332
            std::ostringstream s_out;
2333
            s_out << type << " is not a valid dragger callback type";
2334
            throw Py::TypeError(s_out.str());
2335
        }
2336

2337
        callbacks.push_back(method);
2338
        Py_INCREF(method);
2339
        return Py::Callable(method, false);
2340
    }
2341
    catch (const Py::Exception&) {
2342
        throw;
2343
    }
2344
}
2345

2346
Py::Object View3DInventorPy::removeDraggerCallback(const Py::Tuple& args)
2347
{
2348
    PyObject* dragger;
2349
    char* type;
2350
    PyObject* method;
2351
    if (!PyArg_ParseTuple(args.ptr(), "OsO", &dragger, &type, &method))
2352
        throw Py::Exception();
2353

2354
    //Check if dragger is a SoDragger object and cast
2355
    void* ptr = nullptr;
2356
    try {
2357
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDragger *", dragger, &ptr, 0);
2358
    }
2359
    catch (const Base::Exception&) {
2360
        throw Py::TypeError("The first argument must be of type SoDragger");
2361
    }
2362

2363
    auto drag = static_cast<SoDragger*>(ptr);
2364
    try {
2365
        if (strcmp(type, "addFinishCallback") == 0) {
2366
            drag->removeFinishCallback(draggerCallback, method);
2367
        }
2368
        else if (strcmp(type, "addStartCallback") == 0) {
2369
            drag->removeStartCallback(draggerCallback, method);
2370
        }
2371
        else if (strcmp(type, "addMotionCallback") == 0) {
2372
            drag->removeMotionCallback(draggerCallback, method);
2373
        }
2374
        else if (strcmp(type, "addValueChangedCallback") == 0) {
2375
            drag->removeValueChangedCallback(draggerCallback, method);
2376
        }
2377
        else {
2378
            std::string s;
2379
            std::ostringstream s_out;
2380
            s_out << type << " is not a valid dragger callback type";
2381
            throw Py::TypeError(s_out.str());
2382
        }
2383

2384
        callbacks.remove(method);
2385
        Py_DECREF(method);
2386
        return Py::Callable(method, false);
2387
    }
2388
    catch (const Py::Exception&) {
2389
        throw;
2390
    }
2391
}
2392

2393
Py::Object View3DInventorPy::getViewProvidersOfType(const Py::Tuple& args)
2394
{
2395
    char* name;
2396
    if (!PyArg_ParseTuple(args.ptr(), "s", &name))
2397
        throw Py::Exception();
2398

2399
    std::vector<ViewProvider*> vps = getView3DIventorPtr()->getViewer()->getViewProvidersOfType(Base::Type::fromName(name));
2400
    Py::List list;
2401
    for (const auto & vp : vps) {
2402
        list.append(Py::asObject(vp->getPyObject()));
2403
    }
2404

2405
    return list;
2406
}
2407

2408
Py::Object View3DInventorPy::redraw()
2409
{
2410
    getView3DIventorPtr()->getViewer()->redraw();
2411
    return Py::None();
2412
}
2413

2414
Py::Object View3DInventorPy::setName(const Py::Tuple& args)
2415
{
2416
    char* buffer;
2417
    if (!PyArg_ParseTuple(args.ptr(), "s", &buffer))
2418
        throw Py::Exception();
2419

2420
    try {
2421
        getView3DIventorPtr()->setWindowTitle(QString::fromUtf8(buffer));
2422
        return Py::None();
2423
    }
2424
    catch (const Base::Exception& e) {
2425
        throw Py::RuntimeError(e.what());
2426
    }
2427
    catch (const std::exception& e) {
2428
        throw Py::RuntimeError(e.what());
2429
    }
2430
    catch(...) {
2431
        throw Py::RuntimeError("Unknown C++ exception");
2432
    }
2433
}
2434

2435
Py::Object View3DInventorPy::toggleClippingPlane(const Py::Tuple& args, const Py::Dict& kwds)
2436
{
2437
    static const std::array<const char *, 5> keywords {"toggle", "beforeEditing", "noManip", "pla", nullptr};
2438
    int toggle = -1;
2439
    PyObject *beforeEditing = Py_False;
2440
    PyObject *noManip = Py_True;
2441
    PyObject *pyPla = Py_None;
2442
    if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "|iO!O!O!", keywords,
2443
                    &toggle, &PyBool_Type, &beforeEditing, &PyBool_Type, &noManip,
2444
                    &Base::PlacementPy::Type, &pyPla)) {
2445
        throw Py::Exception();
2446
    }
2447

2448
    Base::Placement pla;
2449
    if(pyPla!=Py_None)
2450
        pla = *static_cast<Base::PlacementPy*>(pyPla)->getPlacementPtr();
2451
    getView3DIventorPtr()->getViewer()->toggleClippingPlane(toggle, Base::asBoolean(beforeEditing),
2452
            Base::asBoolean(noManip), pla);
2453
    return Py::None();
2454
}
2455

2456
Py::Object View3DInventorPy::hasClippingPlane()
2457
{
2458
    return Py::Boolean(getView3DIventorPtr()->getViewer()->hasClippingPlane());
2459
}
2460

2461
Py::Object View3DInventorPy::graphicsView()
2462
{
2463
    PythonWrapper wrap;
2464
    wrap.loadWidgetsModule();
2465
    return wrap.fromQWidget(getView3DIventorPtr()->getViewer(), "QGraphicsView");
2466
}
2467

2468
Py::Object View3DInventorPy::setCornerCrossVisible(const Py::Tuple& args)
2469
{
2470
    int ok;
2471
    if (!PyArg_ParseTuple(args.ptr(), "i", &ok))
2472
        throw Py::Exception();
2473
    getView3DIventorPtr()->getViewer()->setFeedbackVisibility(ok!=0);
2474
    getView3DIventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when focus is in Python Console
2475
    return Py::None();
2476
}
2477

2478
Py::Object View3DInventorPy::isCornerCrossVisible()
2479
{
2480
    bool ok = getView3DIventorPtr()->getViewer()->isFeedbackVisible();
2481
    return Py::Boolean(ok ? true : false);
2482
}
2483

2484
Py::Object View3DInventorPy::setCornerCrossSize(const Py::Tuple& args)
2485
{
2486
    int size=0;
2487
    if (!PyArg_ParseTuple(args.ptr(), "i", &size))
2488
        throw Py::Exception();
2489
    getView3DIventorPtr()->getViewer()->setFeedbackSize(size);
2490
    getView3DIventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when focus is in Python Console
2491
    return Py::None();
2492
}
2493

2494
Py::Object View3DInventorPy::getCornerCrossSize()
2495
{
2496
    int size = getView3DIventorPtr()->getViewer()->getFeedbackSize();
2497
    return Py::Int(size);
2498
}
2499

2500
Py::Object View3DInventorPy::cast_to_base()
2501
{
2502
    return Gui::MDIViewPy::create(getView3DIventorPtr());
2503
}
2504

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.