FreeCAD

Форк
0
/
View3DViewerPy.cpp 
599 строк · 20.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2014 Stefan Tröger <stefantroeger@gmx.net>              *
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 <Inventor/nodes/SoCamera.h>
27
#endif
28

29
#include <Base/GeometryPyCXX.h>
30
#include <Base/Interpreter.h>
31
#include <Base/MatrixPy.h>
32

33
#include "PythonWrapper.h"
34
#include "View3DViewerPy.h"
35
#include "View3DInventorViewer.h"
36

37

38
using namespace Gui;
39

40

41
void View3DInventorViewerPy::init_type()
42
{
43
    behaviors().name("View3DInventorViewerPy");
44
    behaviors().doc("Python binding class for the 3D viewer class");
45
    // you must have overwritten the virtual functions
46
    behaviors().supportRepr();
47
    behaviors().supportGetattr();
48
    behaviors().supportSetattr();
49

50
    add_varargs_method("getSoRenderManager",&View3DInventorViewerPy::getSoRenderManager,"getSoRenderManager() -> SoRenderManager\n"
51
        "Returns the render manager which is used to handle everything related to\n"
52
        "rendering the scene graph. It can be used to get full control over the\n"
53
        "render process\n"
54
    );
55
    add_varargs_method("getSoEventManager",&View3DInventorViewerPy::getSoEventManager,"getSoEventManager() -> SoEventManager\n"
56
        "Returns the event manager which is used to handle everything event related in\n"
57
        "the viewer. It can be used to change the event processing. This must however be\n"
58
        "done very carefully to not change the user interaction in an unpredictable manner.\n"
59
    );
60
    add_varargs_method("getSceneGraph", &View3DInventorViewerPy::getSceneGraph, "getSceneGraph() -> SoNode");
61
    add_varargs_method("setSceneGraph", &View3DInventorViewerPy::setSceneGraph, "setSceneGraph(SoNode)");
62

63
    add_varargs_method("seekToPoint",&View3DInventorViewerPy::seekToPoint,"seekToPoint(tuple) -> None\n"
64
     "Initiate a seek action towards the 3D intersection of the scene and the\n"
65
     "ray from the screen coordinate's point and in the same direction as the\n"
66
     "camera is pointing. If the tuple has two entries it is interpreted as the\n"
67
     "screen coordinates xy and the intersection point with the scene is\n"
68
     "calculated. If three entries are given it is interpreted as the intersection\n"
69
     "point xyz and the seek is done towards this point"
70
    );
71
    add_varargs_method("setFocalDistance",&View3DInventorViewerPy::setFocalDistance,"setFocalDistance(float) -> None\n");
72
    add_varargs_method("getFocalDistance",&View3DInventorViewerPy::getFocalDistance,"getFocalDistance() -> float\n");
73
    add_varargs_method("getPoint", &View3DInventorViewerPy::getPointOnFocalPlane, "Same as getPointOnFocalPlane");
74
    add_varargs_method("getPointOnFocalPlane", &View3DInventorViewerPy::getPointOnFocalPlane, "getPointOnFocalPlane(x, y) -> Base::Vector(x,y,z)");
75
    add_varargs_method("getPickRadius", &View3DInventorViewerPy::getPickRadius,
76
        "getPickRadius(): returns radius of confusion in pixels for picking objects on screen (selection).");
77
    add_varargs_method("setPickRadius", &View3DInventorViewerPy::setPickRadius,
78
        "setPickRadius(new_radius): sets radius of confusion in pixels for picking objects on screen (selection).");
79
    add_varargs_method("setupEditingRoot", &View3DInventorViewerPy::setupEditingRoot,
80
        "setupEditingRoot(matrix=None): setup the editing ViewProvider's root node.\n"
81
        "All child coin nodes of the current editing ViewProvider will be transferred to\n"
82
        "an internal editing node of this viewer, with a new transformation node specified\n"
83
        "by 'matrix'. All ViewProviderLink to the editing ViewProvider will be temporary\n"
84
        "hidden. Call resetEditingRoot() to restore everything back to normal");
85
    add_varargs_method("resetEditingRoot", &View3DInventorViewerPy::resetEditingRoot,
86
        "resetEditingRoot(updateLinks=True): restore the editing ViewProvider's root node");
87
    add_varargs_method("setBackgroundColor", &View3DInventorViewerPy::setBackgroundColor,
88
        "setBackgroundColor(r,g,b): sets the background color of the current viewer.");
89
    add_varargs_method("setGradientBackground", &View3DInventorViewerPy::setGradientBackground,
90
        "setGradientBackground(str): sets the background gradient of the current viewer.");
91
    add_varargs_method("setGradientBackgroundColor", &View3DInventorViewerPy::setGradientBackgroundColor,
92
        "setGradientBackgroundColor(tuple,tuple,[tuple]): sets the gradient colors of the current viewer.");
93
    add_varargs_method("setRedirectToSceneGraph", &View3DInventorViewerPy::setRedirectToSceneGraph,
94
        "setRedirectToSceneGraph(bool): enables or disables to redirect events directly to the scene graph.");
95
    add_varargs_method("isRedirectedToSceneGraph", &View3DInventorViewerPy::isRedirectedToSceneGraph,
96
        "isRedirectedToSceneGraph() -> bool: check whether event redirection is enabled.");
97
    add_varargs_method("grabFramebuffer", &View3DInventorViewerPy::grabFramebuffer,
98
        "grabFramebuffer() -> QImage: renders and returns a 32-bit RGB image of the framebuffer.");
99
    add_varargs_method("setEnabledNaviCube", &View3DInventorViewerPy::setEnabledNaviCube,
100
        "setEnabledNaviCube(bool): enables or disables the navi cube of the viewer.");
101
    add_varargs_method("isEnabledNaviCube", &View3DInventorViewerPy::isEnabledNaviCube,
102
        "isEnabledNaviCube() -> bool: check whether the navi cube is enabled.");
103
    add_varargs_method("setNaviCubeCorner", &View3DInventorViewerPy::setNaviCubeCorner,
104
        "setNaviCubeCorner(int): sets the corner where to show the navi cube:\n"
105
        "0=top left, 1=top right, 2=bottom left, 3=bottom right");
106
}
107

108
View3DInventorViewerPy::View3DInventorViewerPy(View3DInventorViewer *vi)
109
  : _viewer(vi)
110
{
111
}
112

113
View3DInventorViewerPy::~View3DInventorViewerPy()
114
{
115
    Base::PyGILStateLocker lock;
116
    for (auto it : callbacks)
117
        Py_DECREF(it);
118
}
119

120

121
Py::Object View3DInventorViewerPy::repr()
122
{
123
    std::ostringstream s_out;
124
    if (!_viewer)
125
        throw Py::RuntimeError("Cannot print representation of deleted object");
126
    s_out << "View3DInventorViewer";
127
    return Py::String(s_out.str());
128
}
129

130
View3DInventorViewerPy::method_varargs_handler View3DInventorViewerPy::pycxx_handler = nullptr;
131

132
PyObject *View3DInventorViewerPy::method_varargs_ext_handler(PyObject *_self_and_name_tuple, PyObject *_args)
133
{
134
    try {
135
        return pycxx_handler(_self_and_name_tuple, _args);
136
    }
137
    catch (const Base::Exception& e) {
138
        throw Py::RuntimeError(e.what());
139
    }
140
    catch (const std::exception& e) {
141
        throw Py::RuntimeError(e.what());
142
    }
143
    catch(...) {
144
        throw Py::RuntimeError("Unknown C++ exception");
145
    }
146
}
147

148
Py::Object View3DInventorViewerPy::getattr(const char * attr)
149
{
150
    if (!_viewer) {
151
        std::string s;
152
        std::ostringstream s_out;
153
        s_out << "Cannot access attribute '" << attr << "' of deleted object";
154
        throw Py::RuntimeError(s_out.str());
155
    }
156
    else {
157
        Py::Object obj = Py::PythonExtension<View3DInventorViewerPy>::getattr(attr);
158
        if (PyCFunction_Check(obj.ptr())) {
159
            auto op = reinterpret_cast<PyCFunctionObject*>(obj.ptr());
160
            if (!pycxx_handler)
161
                pycxx_handler = op->m_ml->ml_meth;
162
            op->m_ml->ml_meth = method_varargs_ext_handler;
163
        }
164
        return obj;
165
    }
166
}
167

168
int View3DInventorViewerPy::setattr(const char * attr, const Py::Object & value)
169
{
170
    if (!_viewer) {
171
        std::string s;
172
        std::ostringstream s_out;
173
        s_out << "Cannot access attribute '" << attr << "' of deleted object";
174
        throw Py::RuntimeError(s_out.str());
175
    }
176
    else {
177
        return Py::PythonExtension<View3DInventorViewerPy>::setattr(attr, value);
178
    }
179
}
180

181
Py::Object View3DInventorViewerPy::getSoRenderManager(const Py::Tuple& args)
182
{
183
    if (!PyArg_ParseTuple(args.ptr(), ""))
184
        throw Py::Exception();
185

186
    try {
187
        SoRenderManager* manager = _viewer->getSoRenderManager();
188
        PyObject* proxy = nullptr;
189
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoRenderManager *", static_cast<void*>(manager), 0);
190
        return Py::Object(proxy, true);
191
    }
192
    catch (const Base::Exception& e) {
193
        throw Py::RuntimeError(e.what());
194
    }
195
}
196

197
Py::Object View3DInventorViewerPy::getSceneGraph(const Py::Tuple& args)
198
{
199
    if (!PyArg_ParseTuple(args.ptr(), ""))
200
        throw Py::Exception();
201

202
    try {
203
        SoNode* scene = _viewer->getSceneGraph();
204
        PyObject* proxy = nullptr;
205
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoSeparator *", static_cast<void*>(scene), 1);
206
        scene->ref();
207
        return Py::Object(proxy, true);
208
    }
209
    catch (const Base::Exception& e) {
210
        throw Py::RuntimeError(e.what());
211
    }
212
}
213

214
Py::Object View3DInventorViewerPy::setSceneGraph(const Py::Tuple& args)
215
{
216
    PyObject* proxy;
217
    if (!PyArg_ParseTuple(args.ptr(), "O", &proxy))
218
        throw Py::Exception();
219

220
    void* ptr = nullptr;
221
    try {
222
        Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", proxy, &ptr, 0);
223
        auto node = static_cast<SoNode*>(ptr);
224
        _viewer->setSceneGraph(node);
225
        return Py::None();
226
    }
227
    catch (const Base::Exception& e) {
228
        throw Py::RuntimeError(e.what());
229
    }
230
}
231

232
Py::Object View3DInventorViewerPy::getSoEventManager(const Py::Tuple& args)
233
{
234
    if (!PyArg_ParseTuple(args.ptr(), ""))
235
        throw Py::Exception();
236

237
    try {
238
        SoEventManager* manager = _viewer->getSoEventManager();
239
        PyObject* proxy = nullptr;
240
        proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoEventManager *", static_cast<void*>(manager), 0);
241
        return Py::Object(proxy, true);
242
    }
243
    catch (const Base::Exception& e) {
244
        throw Py::RuntimeError(e.what());
245
    }
246
}
247

248
Py::Object View3DInventorViewerPy::seekToPoint(const Py::Tuple& args)
249
{
250
    PyObject* object;
251
    if (!PyArg_ParseTuple(args.ptr(), "O", &object))
252
        throw Py::Exception();
253

254
   try {
255
        const Py::Tuple tuple(object);
256

257
        // If the 3d point is given
258
        if (tuple.size() == 3) {
259
            Py::Float x = tuple[0];
260
            Py::Float y = tuple[1];
261
            Py::Float z = tuple[2];
262

263
            SbVec3f hitpoint((float)x,(float)y,(float)z);
264
            _viewer->seekToPoint(hitpoint);
265
        }
266
        else {
267
            Py::Int x(tuple[0]);
268
            Py::Int y(tuple[1]);
269

270
            SbVec2s hitpoint ((long)x,(long)y);
271
            _viewer->seekToPoint(hitpoint);
272
        }
273

274
        return Py::None();
275
    }
276
    catch (const Py::Exception&) {
277
        throw;
278
    }
279
}
280

281
Py::Object View3DInventorViewerPy::setFocalDistance(const Py::Tuple& args)
282
{
283
    float distance;
284
    if (!PyArg_ParseTuple(args.ptr(), "f", &distance))
285
        throw Py::Exception();
286

287
    try {
288
        SoCamera* cam = _viewer->getSoRenderManager()->getCamera();
289
        if (cam)
290
            cam->focalDistance.setValue(distance);
291
    }
292
    catch (const Py::Exception&) {
293
        throw; // re-throw
294
    }
295
    catch (const Base::Exception& e) {
296
        throw Py::RuntimeError(e.what());
297
    }
298
    catch (const std::exception& e) {
299
        throw Py::RuntimeError(e.what());
300
    }
301
    catch(...) {
302
        throw Py::RuntimeError("Unknown C++ exception");
303
    }
304

305
    return Py::None();
306
}
307

308
Py::Object View3DInventorViewerPy::getFocalDistance(const Py::Tuple& args)
309
{
310
    if (!PyArg_ParseTuple(args.ptr(), ""))
311
        throw Py::Exception();
312

313
    try {
314
        double d = _viewer->getSoRenderManager()->getCamera()->focalDistance.getValue();
315
        return Py::Float(d);
316
    }
317
    catch (const Base::Exception& e) {
318
        throw Py::RuntimeError(e.what());
319
    }
320
    catch (const std::exception& e) {
321
        throw Py::RuntimeError(e.what());
322
    }
323
    catch(...) {
324
        throw Py::RuntimeError("Unknown C++ exception");
325
    }
326
}
327

328
Py::Object View3DInventorViewerPy::getPointOnFocalPlane(const Py::Tuple& args)
329
{
330
    short x,y;
331
    if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
332
        PyErr_Clear();
333
        Py::Tuple t(args[0]);
334
        x = (int)Py::Int(t[0]);
335
        y = (int)Py::Int(t[1]);
336
    }
337
    try {
338
        SbVec3f pt = _viewer->getPointOnFocalPlane(SbVec2s(x,y));
339
        return Py::Vector(Base::Vector3f(pt[0], pt[1], pt[2]));
340
    }
341
    catch (const Base::Exception& e) {
342
        throw Py::RuntimeError(e.what());
343
    }
344
    catch (const Py::Exception&) {
345
        throw;
346
    }
347
}
348

349
Py::Object View3DInventorViewerPy::getPickRadius(const Py::Tuple& args)
350
{
351
    if (!PyArg_ParseTuple(args.ptr(), ""))
352
        throw Py::Exception();
353

354
    double d = _viewer->getPickRadius();
355
    return Py::Float(d);
356
}
357

358
Py::Object View3DInventorViewerPy::setPickRadius(const Py::Tuple& args)
359
{
360
    float r = 0.0;
361
    if (!PyArg_ParseTuple(args.ptr(), "f", &r)) {
362
        throw Py::Exception();
363
    }
364

365
    if (r < 0.001){
366
        throw Py::ValueError(std::string("Pick radius is zero or negative; positive number is required."));
367
    }
368
    try {
369
        _viewer->setPickRadius(r);
370
        return Py::None();
371
    }
372
    catch (const Base::Exception& e) {
373
        throw Py::RuntimeError(e.what());
374
    }
375
    catch (const std::exception& e) {
376
        throw Py::RuntimeError(e.what());
377
    }
378
    catch(...) {
379
        throw Py::RuntimeError("Unknown C++ exception");
380
    }
381
}
382

383
Py::Object View3DInventorViewerPy::setupEditingRoot(const Py::Tuple& args)
384
{
385
    PyObject *pynode = Py_None;
386
    PyObject *pymat = Py_None;
387
    if (!PyArg_ParseTuple(args.ptr(), "|OO!", &pynode,&Base::MatrixPy::Type,&pymat)) {
388
        throw Py::Exception();
389
    }
390

391
    Base::Matrix4D *mat = nullptr;
392
    if(pymat != Py_None)
393
        mat = static_cast<Base::MatrixPy*>(pymat)->getMatrixPtr();
394

395
    try {
396
        SoNode *node = nullptr;
397
        if(pynode!=Py_None) {
398
            void* ptr = nullptr;
399
            Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", pynode, &ptr, 0);
400
            node = static_cast<SoNode*>(ptr);
401
        }
402
        _viewer->setupEditingRoot(node,mat);
403
        return Py::None();
404
    }
405
    catch (const Base::Exception& e) {
406
        e.setPyException();
407
        throw Py::Exception();
408
    }
409
    catch (const std::exception& e) {
410
        throw Py::RuntimeError(e.what());
411
    }
412
    catch(...) {
413
        throw Py::RuntimeError("Unknown C++ exception");
414
    }
415
}
416

417
Py::Object View3DInventorViewerPy::resetEditingRoot(const Py::Tuple& args)
418
{
419
    PyObject *updateLinks = Py_True;
420
    if (!PyArg_ParseTuple(args.ptr(), "|O!", &PyBool_Type, &updateLinks)) {
421
        throw Py::Exception();
422
    }
423
    try {
424
        _viewer->resetEditingRoot(Base::asBoolean(updateLinks));
425
        return Py::None();
426
    }
427
    catch (const Base::Exception& e) {
428
        e.setPyException();
429
        throw Py::Exception();
430
    }
431
    catch (const std::exception& e) {
432
        throw Py::RuntimeError(e.what());
433
    }
434
    catch(...) {
435
        throw Py::RuntimeError("Unknown C++ exception");
436
    }
437
}
438

439
Py::Object View3DInventorViewerPy::setGradientBackground(const Py::Tuple& args)
440
{
441
    const char* background;
442
    if (!PyArg_ParseTuple(args.ptr(), "s", &background)) {
443
        throw Py::Exception();
444
    }
445
    try {
446
        View3DInventorViewer::Background gradient = View3DInventorViewer::Background::NoGradient;
447
        if (strcmp(background, "LINEAR") == 0) {
448
            gradient = View3DInventorViewer::Background::LinearGradient;
449
        }
450
        else if (strcmp(background, "RADIAL") == 0) {
451
            gradient = View3DInventorViewer::Background::RadialGradient;
452
        }
453

454
        _viewer->setGradientBackground(gradient);
455
        _viewer->redraw();
456
        return Py::None();
457
    }
458
    catch (const Base::Exception& e) {
459
        throw Py::RuntimeError(e.what());
460
    }
461
    catch (const std::exception& e) {
462
        throw Py::RuntimeError(e.what());
463
    }
464
    catch(...) {
465
        throw Py::RuntimeError("Unknown C++ exception");
466
    }
467
}
468

469
Py::Object View3DInventorViewerPy::setGradientBackgroundColor(const Py::Tuple& args)
470
{
471
    PyObject* col1;
472
    PyObject* col2;
473
    PyObject* col3 = nullptr;
474
    if (!PyArg_ParseTuple(args.ptr(), "O!O!|O!",
475
                          &PyTuple_Type, &col1,
476
                          &PyTuple_Type, &col2,
477
                          &PyTuple_Type, &col3)) {
478
        throw Py::Exception();
479
    }
480

481
    auto tupleToColor = [](PyObject* col) {
482
        SbColor color;
483
        Py::Tuple tuple(col);
484
        for (int i=0; i<3; i++) {
485
            color[i] = static_cast<float>(Py::Float(tuple[i]));
486
        }
487

488
        return color;
489
    };
490

491
    try {
492
        SbColor midColor(-1, -1, -1);
493
        SbColor fromColor = tupleToColor(col1);
494
        SbColor toColor = tupleToColor(col2);
495
        if (col3) {
496
            midColor = tupleToColor(col3);
497
        }
498

499
        _viewer->setGradientBackgroundColor(fromColor, toColor, midColor);
500
        _viewer->redraw();
501
        return Py::None();
502
    }
503
    catch (const Base::Exception& e) {
504
        throw Py::RuntimeError(e.what());
505
    }
506
    catch (const std::exception& e) {
507
        throw Py::RuntimeError(e.what());
508
    }
509
    catch(...) {
510
        throw Py::RuntimeError("Unknown C++ exception");
511
    }
512
}
513

514
Py::Object View3DInventorViewerPy::setBackgroundColor(const Py::Tuple& args)
515
{
516
    float red, green, blue = 0.0;
517
    if (!PyArg_ParseTuple(args.ptr(), "fff", &red, &green, &blue)) {
518
        throw Py::Exception();
519
    }
520
    try {
521
        SbColor col(red, green, blue);
522
        _viewer->setGradientBackgroundColor(col, col);
523

524
        QColor qtcolor;
525
        qtcolor.setRedF(red);
526
        qtcolor.setGreenF(green);
527
        qtcolor.setBlueF(blue);
528
        if (qtcolor.isValid()) {
529
            _viewer->setBackgroundColor(qtcolor);
530
        }
531
        _viewer->redraw();
532
        return Py::None();
533
    }
534
    catch (const Base::Exception& e) {
535
        throw Py::RuntimeError(e.what());
536
    }
537
    catch (const std::exception& e) {
538
        throw Py::RuntimeError(e.what());
539
    }
540
    catch(...) {
541
        throw Py::RuntimeError("Unknown C++ exception");
542
    }
543
}
544

545
Py::Object View3DInventorViewerPy::setRedirectToSceneGraph(const Py::Tuple& args)
546
{
547
    PyObject* m=Py_False;
548
    if (!PyArg_ParseTuple(args.ptr(), "O!", &PyBool_Type, &m))
549
        throw Py::Exception();
550
    _viewer->setRedirectToSceneGraph(Base::asBoolean(m));
551
    return Py::None();
552
}
553

554
Py::Object View3DInventorViewerPy::isRedirectedToSceneGraph(const Py::Tuple& args)
555
{
556
    if (!PyArg_ParseTuple(args.ptr(), ""))
557
        throw Py::Exception();
558
    bool ok = _viewer->isRedirectedToSceneGraph();
559
    return Py::Boolean(ok);
560
}
561

562
Py::Object View3DInventorViewerPy::grabFramebuffer(const Py::Tuple& args)
563
{
564
    if (!PyArg_ParseTuple(args.ptr(), ""))
565
        throw Py::Exception();
566
    QImage img = _viewer->grabFramebuffer();
567

568
    PythonWrapper wrap;
569
    wrap.loadGuiModule();
570
    return wrap.fromQImage(img.mirrored());
571
}
572

573
Py::Object View3DInventorViewerPy::setEnabledNaviCube(const Py::Tuple& args)
574
{
575
    PyObject* m=Py_False;
576
    if (!PyArg_ParseTuple(args.ptr(), "O!", &PyBool_Type, &m))
577
        throw Py::Exception();
578
    _viewer->setEnabledNaviCube(Base::asBoolean(m));
579
    return Py::None();
580
}
581

582
Py::Object View3DInventorViewerPy::isEnabledNaviCube(const Py::Tuple& args)
583
{
584
    if (!PyArg_ParseTuple(args.ptr(), ""))
585
        throw Py::Exception();
586
    bool ok = _viewer->isEnabledNaviCube();
587
    return Py::Boolean(ok);
588
}
589

590
Py::Object View3DInventorViewerPy::setNaviCubeCorner(const Py::Tuple& args)
591
{
592
    int pos;
593
    if (!PyArg_ParseTuple(args.ptr(), "i", &pos))
594
        throw Py::Exception();
595
    if (pos < 0 || pos > 3)
596
        throw Py::IndexError("Value out of range");
597
    _viewer->setNaviCubeCorner(pos);
598
    return Py::None();
599
}
600

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

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

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

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