2818 lines
97 KiB
C++
2818 lines
97 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include <QColor>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QImage>
|
|
|
|
#include <Inventor/SoPickedPoint.h>
|
|
#include <Inventor/actions/SoWriteAction.h>
|
|
#include <Inventor/annex/HardCopy/SoVectorizePSAction.h>
|
|
#include <Inventor/draggers/SoDragger.h>
|
|
#include <Inventor/nodes/SoCamera.h>
|
|
#include <Inventor/nodes/SoOrthographicCamera.h>
|
|
#include <Inventor/nodes/SoPerspectiveCamera.h>
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Document.h>
|
|
#include <App/DocumentObject.h>
|
|
#include <App/DocumentObjectPy.h>
|
|
#include <App/GeoFeature.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/GeometryPyCXX.h>
|
|
#include <Base/Interpreter.h>
|
|
#include <Base/PlacementPy.h>
|
|
#include <Base/PyWrapParseTupleAndKeywords.h>
|
|
#include <Base/RotationPy.h>
|
|
#include <Base/VectorPy.h>
|
|
|
|
#include "View3DPy.h"
|
|
|
|
#include "Camera.h"
|
|
#include "Document.h"
|
|
#include "Inventor/SoMouseWheelEvent.h"
|
|
#include "Navigation/NavigationStyle.h"
|
|
#include "PythonWrapper.h"
|
|
#include "SoFCDB.h"
|
|
#include "SoFCOffscreenRenderer.h"
|
|
#include "SoFCSelectionAction.h"
|
|
#include "SoFCVectorizeSVGAction.h"
|
|
#include "SoFCVectorizeU3DAction.h"
|
|
#include "View3DInventor.h"
|
|
#include "View3DInventorViewer.h"
|
|
#include "ViewProviderDocumentObject.h"
|
|
#include "ViewProviderExtern.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
|
|
void View3DInventorPy::init_type()
|
|
{
|
|
behaviors().name("View3DInventorPy");
|
|
behaviors().doc("Python binding class for the Inventor viewer class");
|
|
// you must have overwritten the virtual functions
|
|
behaviors().supportRepr();
|
|
behaviors().supportGetattr();
|
|
behaviors().supportSetattr();
|
|
|
|
add_varargs_method("fitAll", &View3DInventorPy::fitAll, "fitAll()");
|
|
add_keyword_method("boxZoom", &View3DInventorPy::boxZoom, "boxZoom()");
|
|
|
|
add_noargs_method("viewBottom", &View3DInventorPy::viewBottom, "viewBottom()");
|
|
add_noargs_method("viewFront", &View3DInventorPy::viewFront, "viewFront()");
|
|
add_noargs_method("viewLeft", &View3DInventorPy::viewLeft, "viewLeft()");
|
|
add_noargs_method("viewRear", &View3DInventorPy::viewRear, "viewRear()");
|
|
add_noargs_method("viewRight", &View3DInventorPy::viewRight, "viewRight()");
|
|
add_noargs_method("viewTop", &View3DInventorPy::viewTop, "viewTop()");
|
|
add_noargs_method(
|
|
"viewAxometric",
|
|
&View3DInventorPy::viewIsometric,
|
|
"viewAxonometric()"
|
|
); // for backward compatibility
|
|
add_noargs_method("viewAxonometric", &View3DInventorPy::viewIsometric, "viewAxonometric()");
|
|
add_noargs_method("viewIsometric", &View3DInventorPy::viewIsometric, "viewIsometric()");
|
|
add_noargs_method("viewDimetric", &View3DInventorPy::viewDimetric, "viewDimetric()");
|
|
add_noargs_method("viewTrimetric", &View3DInventorPy::viewTrimetric, "viewTrimetric()");
|
|
add_varargs_method(
|
|
"viewDefaultOrientation",
|
|
&View3DInventorPy::viewDefaultOrientation,
|
|
"viewDefaultOrientation(ori_str = '', scale = -1.0): sets camera rotation to a predefined "
|
|
"one, \n"
|
|
"and camera position and zoom to show certain amount of model space. \n"
|
|
"ori_string can be 'Top', 'Bottom', 'Front', 'Rear', 'Left', 'Right', \n"
|
|
"'Isometric', 'Dimetric', 'Trimetric', 'Custom'. If empty, the value is \n"
|
|
"fetched from Parameters.\n"
|
|
"scale sets distance from camera to origin, and height of the screen in \n"
|
|
"model space, so that a sphere of diameter <scale> fits the height of the\n"
|
|
"viewport. If zero, scaling is not done. If negative, the value is \n"
|
|
"fetched from Parameters."
|
|
);
|
|
add_noargs_method("viewRotateLeft", &View3DInventorPy::viewRotateLeft, "viewRotateLeft()");
|
|
add_noargs_method("viewRotateRight", &View3DInventorPy::viewRotateRight, "viewRotateRight()");
|
|
add_noargs_method("zoomIn", &View3DInventorPy::zoomIn, "zoomIn()");
|
|
add_noargs_method("zoomOut", &View3DInventorPy::zoomOut, "zoomOut()");
|
|
add_varargs_method("viewPosition", &View3DInventorPy::viewPosition, "viewPosition()");
|
|
add_varargs_method("startAnimating", &View3DInventorPy::startAnimating, "startAnimating()");
|
|
add_noargs_method("stopAnimating", &View3DInventorPy::stopAnimating, "stopAnimating()");
|
|
add_varargs_method(
|
|
"setAnimationEnabled",
|
|
&View3DInventorPy::setAnimationEnabled,
|
|
"setAnimationEnabled()"
|
|
);
|
|
add_noargs_method("isAnimationEnabled", &View3DInventorPy::isAnimationEnabled, "isAnimationEnabled()");
|
|
add_varargs_method(
|
|
"setPopupMenuEnabled",
|
|
&View3DInventorPy::setPopupMenuEnabled,
|
|
"setPopupMenuEnabled()"
|
|
);
|
|
add_noargs_method("isPopupMenuEnabled", &View3DInventorPy::isPopupMenuEnabled, "isPopupMenuEnabled()");
|
|
add_varargs_method("dump", &View3DInventorPy::dump, "dump(filename, [onlyVisible=False])");
|
|
add_varargs_method("dumpNode", &View3DInventorPy::dumpNode, "dumpNode(node)");
|
|
add_varargs_method("setStereoType", &View3DInventorPy::setStereoType, "setStereoType()");
|
|
add_noargs_method("getStereoType", &View3DInventorPy::getStereoType, "getStereoType()");
|
|
add_noargs_method("listStereoTypes", &View3DInventorPy::listStereoTypes, "listStereoTypes()");
|
|
add_varargs_method("saveImage", &View3DInventorPy::saveImage, "saveImage()");
|
|
add_varargs_method("saveVectorGraphic", &View3DInventorPy::saveVectorGraphic, "saveVectorGraphic()");
|
|
add_noargs_method("getCamera", &View3DInventorPy::getCamera, "getCamera()");
|
|
add_noargs_method("getCameraNode", &View3DInventorPy::getCameraNode, "getCameraNode()");
|
|
add_noargs_method(
|
|
"getViewDirection",
|
|
&View3DInventorPy::getViewDirection,
|
|
"getViewDirection() --> tuple of floats\n"
|
|
"returns the direction vector the view is currently pointing at as tuple with xyz values\n"
|
|
);
|
|
add_noargs_method(
|
|
"getUpDirection",
|
|
&View3DInventorPy::getUpDirection,
|
|
"getUpDirection() --> tuple of integers\n"
|
|
"Returns the up direction vector\n"
|
|
);
|
|
add_varargs_method(
|
|
"setViewDirection",
|
|
&View3DInventorPy::setViewDirection,
|
|
"setViewDirection(tuple) --> None\n"
|
|
"Sets the direction the view is pointing at. The direction must be given as tuple with\n"
|
|
"three coordinates xyz"
|
|
);
|
|
add_varargs_method("setCamera", &View3DInventorPy::setCamera, "setCamera()");
|
|
add_varargs_method(
|
|
"setCameraOrientation",
|
|
&View3DInventorPy::setCameraOrientation,
|
|
"setCameraOrientation()"
|
|
);
|
|
add_noargs_method(
|
|
"getCameraOrientation",
|
|
&View3DInventorPy::getCameraOrientation,
|
|
"getCameraOrientation()"
|
|
);
|
|
add_noargs_method("getCameraType", &View3DInventorPy::getCameraType, "getCameraType()");
|
|
add_varargs_method("setCameraType", &View3DInventorPy::setCameraType, "setCameraType()");
|
|
add_noargs_method("listCameraTypes", &View3DInventorPy::listCameraTypes, "listCameraTypes()");
|
|
add_noargs_method(
|
|
"getCursorPos",
|
|
&View3DInventorPy::getCursorPos,
|
|
"getCursorPos() -> tuple of integers\n"
|
|
"\n"
|
|
"Return the current cursor position relative to the coordinate system of the\n"
|
|
"viewport region.\n"
|
|
);
|
|
add_varargs_method(
|
|
"getObjectInfo",
|
|
&View3DInventorPy::getObjectInfo,
|
|
"getObjectInfo(tuple(int,int), [pick_radius]) -> dictionary or None\n"
|
|
"\n"
|
|
"Return a dictionary with the name of document, object and component. The\n"
|
|
"dictionary also contains the coordinates of the appropriate 3d point of\n"
|
|
"the underlying geometry in the scenegraph.\n"
|
|
"If no geometry was found 'None' is returned, instead.\n"
|
|
);
|
|
add_varargs_method(
|
|
"getObjectsInfo",
|
|
&View3DInventorPy::getObjectsInfo,
|
|
"getObjectsInfo(tuple(int,int), [pick_radius]) -> dictionary or None\n"
|
|
"\n"
|
|
"Does the same as getObjectInfo() but returns a list of dictionaries or None.\n"
|
|
);
|
|
add_noargs_method("getSize", &View3DInventorPy::getSize, "getSize()");
|
|
add_varargs_method(
|
|
"getObjectInfoRay",
|
|
&View3DInventorPy::getObjectInfoRay,
|
|
"getObjectInfoRay(tuple(3D vector,3D vector) or tuple of 6 floats) -> dictionary or None\n"
|
|
"\n"
|
|
"Vectors represent start point and direction of intersection ray\n"
|
|
"Return a dictionary with the name of document, object and component. The\n"
|
|
"dictionary also contains the coordinates of the appropriate 3d point of\n"
|
|
"the underlying geometry in the scenegraph.\n"
|
|
"If no geometry was found 'None' is returned, instead.\n"
|
|
);
|
|
add_varargs_method(
|
|
"getPoint",
|
|
&View3DInventorPy::getPointOnFocalPlane,
|
|
"Same as getPointOnFocalPlane"
|
|
);
|
|
add_varargs_method(
|
|
"getPointOnFocalPlane",
|
|
&View3DInventorPy::getPointOnFocalPlane,
|
|
"getPointOnFocalPlane(pixel coords (as integer)) -> 3D vector\n"
|
|
"\n"
|
|
"Return the according 3D point on the focal plane to the given 2D point (in\n"
|
|
"pixel coordinates).\n"
|
|
);
|
|
add_varargs_method(
|
|
"getPointOnScreen",
|
|
&View3DInventorPy::getPointOnViewport,
|
|
"Same as getPointOnViewport"
|
|
);
|
|
add_varargs_method(
|
|
"getPointOnViewport",
|
|
&View3DInventorPy::getPointOnViewport,
|
|
"getPointOnViewport(3D vector) -> pixel coords (as integer)\n"
|
|
"\n"
|
|
"Return the projected 3D point (in pixel coordinates).\n"
|
|
);
|
|
add_varargs_method(
|
|
"projectPointToLine",
|
|
&View3DInventorPy::projectPointToLine,
|
|
"projectPointToLine(pixel coords (as integer)) -> line defined by two points\n"
|
|
"\n"
|
|
"Return the projecting 3D line to the given 2D point"
|
|
);
|
|
add_varargs_method("addEventCallback", &View3DInventorPy::addEventCallback, "addEventCallback()");
|
|
add_varargs_method(
|
|
"removeEventCallback",
|
|
&View3DInventorPy::removeEventCallback,
|
|
"removeEventCallback()"
|
|
);
|
|
add_varargs_method("setAnnotation", &View3DInventorPy::setAnnotation, "setAnnotation()");
|
|
add_varargs_method("removeAnnotation", &View3DInventorPy::removeAnnotation, "removeAnnotation()");
|
|
add_noargs_method("getSceneGraph", &View3DInventorPy::getSceneGraph, "getSceneGraph()");
|
|
add_noargs_method("getViewer", &View3DInventorPy::getViewer, "getViewer()");
|
|
add_varargs_method(
|
|
"addEventCallbackPivy",
|
|
&View3DInventorPy::addEventCallbackPivy,
|
|
"addEventCallbackPivy()"
|
|
);
|
|
add_varargs_method(
|
|
"removeEventCallbackPivy",
|
|
&View3DInventorPy::removeEventCallbackPivy,
|
|
"removeEventCallbackPivy()"
|
|
);
|
|
add_varargs_method(
|
|
"addEventCallbackSWIG",
|
|
&View3DInventorPy::addEventCallbackPivy,
|
|
"Deprecated -- use addEventCallbackPivy()"
|
|
);
|
|
add_varargs_method(
|
|
"removeEventCallbackSWIG",
|
|
&View3DInventorPy::removeEventCallbackPivy,
|
|
"Deprecated -- use removeEventCallbackPivy()"
|
|
);
|
|
add_noargs_method(
|
|
"listNavigationTypes",
|
|
&View3DInventorPy::listNavigationTypes,
|
|
"listNavigationTypes()"
|
|
);
|
|
add_noargs_method("getNavigationType", &View3DInventorPy::getNavigationType, "getNavigationType()");
|
|
add_varargs_method("setNavigationType", &View3DInventorPy::setNavigationType, "setNavigationType()");
|
|
add_varargs_method(
|
|
"setAxisCross",
|
|
&View3DInventorPy::setAxisCross,
|
|
"switch the big axis-cross on and off"
|
|
);
|
|
add_noargs_method(
|
|
"hasAxisCross",
|
|
&View3DInventorPy::hasAxisCross,
|
|
"check if the big axis-cross is on or off()"
|
|
);
|
|
add_varargs_method(
|
|
"addDraggerCallback",
|
|
&View3DInventorPy::addDraggerCallback,
|
|
"addDraggerCallback(SoDragger, String CallbackType, function)\n"
|
|
"Add a DraggerCalback function to the coin node\n"
|
|
"Possibles types :\n"
|
|
"'addFinishCallback','addStartCallback','addMotionCallback','addValueChangedCallback'\n"
|
|
);
|
|
add_varargs_method(
|
|
"removeDraggerCallback",
|
|
&View3DInventorPy::removeDraggerCallback,
|
|
"removeDraggerCallback(SoDragger, String CallbackType, function)\n"
|
|
"Remove the DraggerCalback function from the coin node\n"
|
|
"Possibles types :\n"
|
|
"'addFinishCallback','addStartCallback','addMotionCallback','addValueChangedCallback'\n"
|
|
);
|
|
add_varargs_method(
|
|
"getViewProvidersOfType",
|
|
&View3DInventorPy::getViewProvidersOfType,
|
|
"getViewProvidersOfType(name)\nreturns a list of view providers for the given type"
|
|
);
|
|
add_noargs_method(
|
|
"redraw",
|
|
&View3DInventorPy::redraw,
|
|
"redraw(): renders the scene on screen (useful for animations)"
|
|
);
|
|
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"
|
|
);
|
|
add_keyword_method(
|
|
"toggleClippingPlane",
|
|
&View3DInventorPy::toggleClippingPlane,
|
|
"toggleClippingPlane(toggle=-1, beforeEditing=False, noManip=True, pla=App.Placement()\n"
|
|
"Toggle a global clipping plane\n\n"
|
|
"toggle: -1 toggle, 1 show, 0 hide\n"
|
|
"beforeEditing: whether to insert the clipping node before or after editing root node\n"
|
|
"noManip: whether to create a manipulator\n"
|
|
"pla: clipping plane placement"
|
|
);
|
|
add_noargs_method(
|
|
"hasClippingPlane",
|
|
&View3DInventorPy::hasClippingPlane,
|
|
"hasClippingPlane(): check whether this clipping plane is active"
|
|
);
|
|
add_noargs_method(
|
|
"graphicsView",
|
|
&View3DInventorPy::graphicsView,
|
|
"graphicsView(): Access this view as QGraphicsView"
|
|
);
|
|
add_varargs_method(
|
|
"setCornerCrossVisible",
|
|
&View3DInventorPy::setCornerCrossVisible,
|
|
"setCornerCrossVisible(bool): Defines corner axis cross visibility"
|
|
);
|
|
add_noargs_method(
|
|
"isCornerCrossVisible",
|
|
&View3DInventorPy::isCornerCrossVisible,
|
|
"isCornerCrossVisible(): Returns current corner axis cross visibility"
|
|
);
|
|
add_varargs_method(
|
|
"setCornerCrossSize",
|
|
&View3DInventorPy::setCornerCrossSize,
|
|
"setCornerCrossSize(int): Defines corner axis cross size"
|
|
);
|
|
add_noargs_method(
|
|
"getCornerCrossSize",
|
|
&View3DInventorPy::getCornerCrossSize,
|
|
"getCornerCrossSize(): Returns current corner axis cross size"
|
|
);
|
|
add_noargs_method(
|
|
"cast_to_base",
|
|
&View3DInventorPy::cast_to_base,
|
|
"cast_to_base() cast to MDIView class"
|
|
);
|
|
}
|
|
|
|
View3DInventorPy::View3DInventorPy(View3DInventor* vi)
|
|
: base(vi)
|
|
{}
|
|
|
|
View3DInventorPy::~View3DInventorPy()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
for (auto it : callbacks) {
|
|
Py_DECREF(it);
|
|
}
|
|
}
|
|
|
|
View3DInventor* View3DInventorPy::getView3DInventorPtr()
|
|
{
|
|
return qobject_cast<View3DInventor*>(base.getMDIViewPtr());
|
|
}
|
|
|
|
Py::Object View3DInventorPy::repr()
|
|
{
|
|
if (!getView3DInventorPtr()) {
|
|
throw Py::RuntimeError("Cannot print representation of deleted object");
|
|
}
|
|
|
|
return Py::String("View3DInventor");
|
|
}
|
|
|
|
View3DInventorPy::method_varargs_handler View3DInventorPy::pycxx_handler = nullptr;
|
|
|
|
PyObject* View3DInventorPy::method_varargs_ext_handler(PyObject* _self_and_name_tuple, PyObject* _args)
|
|
{
|
|
try {
|
|
return pycxx_handler(_self_and_name_tuple, _args);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
// Since with PyCXX it's not possible to make a sub-class of MDIViewPy
|
|
// a trick is to use MDIViewPy as class member and override getattr() to
|
|
// join the attributes of both classes. This way all methods of MDIViewPy
|
|
// appear for SheetViewPy, too.
|
|
Py::Object View3DInventorPy::getattribute(const char* attr)
|
|
{
|
|
if (!getView3DInventorPtr()) {
|
|
throw Py::RuntimeError("Cannot print representation of deleted object");
|
|
}
|
|
std::string name(attr);
|
|
if (name == "__dict__" || name == "__class__") {
|
|
Py::Dict dict_self(BaseType::getattr("__dict__"));
|
|
Py::Dict dict_base(base.getattr("__dict__"));
|
|
for (const auto& it : dict_base) {
|
|
dict_self.setItem(it.first, it.second);
|
|
}
|
|
return dict_self;
|
|
}
|
|
|
|
try {
|
|
return BaseType::getattr(attr);
|
|
}
|
|
catch (Py::AttributeError& e) {
|
|
e.clear();
|
|
return base.getattr(attr);
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getattr(const char* attr)
|
|
{
|
|
if (!getView3DInventorPtr()) {
|
|
std::ostringstream s_out;
|
|
s_out << "Cannot access attribute '" << attr << "' of deleted object";
|
|
throw Py::RuntimeError(s_out.str());
|
|
}
|
|
else {
|
|
// see if an active object has the same name
|
|
App::DocumentObject* docObj = getView3DInventorPtr()->getActiveObject<App::DocumentObject*>(
|
|
attr
|
|
);
|
|
if (docObj) {
|
|
return Py::Object(docObj->getPyObject(), true);
|
|
}
|
|
else {
|
|
// else looking for a method with the name and call it
|
|
Py::Object obj = getattribute(attr);
|
|
if (PyCFunction_Check(obj.ptr())) {
|
|
auto op = reinterpret_cast<PyCFunctionObject*>(obj.ptr());
|
|
if (op->m_ml->ml_flags == METH_VARARGS) {
|
|
if (!pycxx_handler) {
|
|
pycxx_handler = op->m_ml->ml_meth;
|
|
}
|
|
op->m_ml->ml_meth = method_varargs_ext_handler;
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
int View3DInventorPy::setattr(const char* attr, const Py::Object& value)
|
|
{
|
|
if (!getView3DInventorPtr()) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << "Cannot access attribute '" << attr << "' of deleted object";
|
|
throw Py::RuntimeError(s_out.str());
|
|
}
|
|
else {
|
|
return BaseType::setattr(attr, value);
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::fitAll(const Py::Tuple& args)
|
|
{
|
|
double factor = 1.0;
|
|
if (!PyArg_ParseTuple(args.ptr(), "|d", &factor)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->viewAll((float)factor);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::boxZoom(const Py::Tuple& args, const Py::Dict& kwds)
|
|
{
|
|
static const std::array<const char*, 5> kwds_box {"XMin", "YMin", "XMax", "YMax", nullptr};
|
|
short xmin, ymin, xmax, ymax;
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(
|
|
args.ptr(),
|
|
kwds.ptr(),
|
|
"hhhh",
|
|
kwds_box,
|
|
&xmin,
|
|
&ymin,
|
|
&xmax,
|
|
&ymax
|
|
)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
SbBox2s box(xmin, ymin, xmax, ymax);
|
|
getView3DInventorPtr()->getViewer()->boxZoom(box);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewBottom()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Bottom));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewFront()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Front));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewLeft()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Left));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewRear()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Rear));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewRight()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Right));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewTop()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Top));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewIsometric()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Isometric));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewDimetric()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Dimetric));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewTrimetric()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(Camera::rotation(Camera::Trimetric));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewDefaultOrientation(const Py::Tuple& args)
|
|
{
|
|
char* view = nullptr;
|
|
double scale = -1.0;
|
|
if (!PyArg_ParseTuple(args.ptr(), "|zd", &view, &scale)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
std::string newDocView;
|
|
SbRotation rot(0, 0, 0, 1);
|
|
if (view) {
|
|
newDocView = view;
|
|
}
|
|
else {
|
|
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
|
"User parameter:BaseApp/Preferences/View"
|
|
);
|
|
newDocView = hGrp->GetASCII("NewDocumentCameraOrientation", "Trimetric");
|
|
}
|
|
|
|
if (newDocView == "Top") {
|
|
rot = Camera::rotation(Camera::Top);
|
|
}
|
|
else if (newDocView == "Bottom") {
|
|
rot = Camera::rotation(Camera::Bottom);
|
|
}
|
|
else if (newDocView == "Front") {
|
|
rot = Camera::rotation(Camera::Front);
|
|
}
|
|
else if (newDocView == "Rear") {
|
|
rot = Camera::rotation(Camera::Rear);
|
|
}
|
|
else if (newDocView == "Left") {
|
|
rot = Camera::rotation(Camera::Left);
|
|
}
|
|
else if (newDocView == "Right") {
|
|
rot = Camera::rotation(Camera::Right);
|
|
}
|
|
else if (newDocView == "Isometric") {
|
|
rot = Camera::rotation(Camera::Isometric);
|
|
}
|
|
else if (newDocView == "Dimetric") {
|
|
rot = Camera::rotation(Camera::Dimetric);
|
|
}
|
|
else if (newDocView == "Trimetric") {
|
|
rot = Camera::rotation(Camera::Trimetric);
|
|
}
|
|
else if (newDocView == "Custom") {
|
|
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
|
"User parameter:BaseApp/Preferences/View/Custom"
|
|
);
|
|
auto q0 = static_cast<float>(hGrp->GetFloat("Q0", 0));
|
|
auto q1 = static_cast<float>(hGrp->GetFloat("Q1", 0));
|
|
auto q2 = static_cast<float>(hGrp->GetFloat("Q2", 0));
|
|
auto q3 = static_cast<float>(hGrp->GetFloat("Q3", 1));
|
|
rot.setValue(q0, q1, q2, q3);
|
|
}
|
|
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getCamera();
|
|
cam->orientation = rot;
|
|
|
|
if (scale < 0.0) {
|
|
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
|
"User parameter:BaseApp/Preferences/View"
|
|
);
|
|
scale = hGrp->GetFloat("NewDocumentCameraScale", 100.0);
|
|
}
|
|
|
|
setDefaultCameraHeight(scale);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
void View3DInventorPy::setDefaultCameraHeight(float scale)
|
|
{
|
|
if (scale > 1e-7) {
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getCamera();
|
|
SbRotation rot = cam->orientation.getValue();
|
|
|
|
double f = 0.0; // focal dist
|
|
if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
|
|
static_cast<SoOrthographicCamera*>(cam)->height = scale;
|
|
f = scale;
|
|
}
|
|
else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
|
|
// nothing to do
|
|
double ang = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue();
|
|
f = 0.5 * scale / sin(ang * 0.5);
|
|
}
|
|
|
|
SbVec3f lookDir;
|
|
rot.multVec(SbVec3f(0, 0, -1), lookDir);
|
|
SbVec3f pos = lookDir * -f;
|
|
cam->focalDistance = f;
|
|
cam->position = pos;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewRotateLeft()
|
|
{
|
|
try {
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
SbRotation rot = cam->orientation.getValue();
|
|
SbVec3f vdir(0, 0, -1);
|
|
rot.multVec(vdir, vdir);
|
|
SbRotation nrot(vdir, (float)std::numbers::pi / 2);
|
|
cam->orientation.setValue(rot * nrot);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewRotateRight()
|
|
{
|
|
try {
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
SbRotation rot = cam->orientation.getValue();
|
|
SbVec3f vdir(0, 0, -1);
|
|
rot.multVec(vdir, vdir);
|
|
SbRotation nrot(vdir, (float)-std::numbers::pi / 2);
|
|
cam->orientation.setValue(rot * nrot);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::zoomIn()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->navigationStyle()->zoomIn();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::zoomOut()
|
|
{
|
|
try {
|
|
getView3DInventorPtr()->getViewer()->navigationStyle()->zoomOut();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setCameraOrientation(const Py::Tuple& args)
|
|
{
|
|
PyObject* o;
|
|
PyObject* m = Py_False;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O|O!", &o, &PyBool_Type, &m)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
if (PyTuple_Check(o)) {
|
|
Py::Tuple tuple(o);
|
|
float q0 = (float)Py::Float(tuple[0]);
|
|
float q1 = (float)Py::Float(tuple[1]);
|
|
float q2 = (float)Py::Float(tuple[2]);
|
|
float q3 = (float)Py::Float(tuple[3]);
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(
|
|
SbRotation(q0, q1, q2, q3),
|
|
Base::asBoolean(m)
|
|
);
|
|
}
|
|
else if (PyObject_TypeCheck(o, &Base::RotationPy::Type)) {
|
|
Base::Rotation r = static_cast<Base::Rotation>(Py::Rotation(o, false));
|
|
double q0, q1, q2, q3;
|
|
r.getValue(q0, q1, q2, q3);
|
|
getView3DInventorPtr()->getViewer()->setCameraOrientation(
|
|
SbRotation((float)q0, (float)q1, (float)q2, (float)q3),
|
|
Base::asBoolean(m)
|
|
);
|
|
}
|
|
else {
|
|
throw Py::ValueError("Neither tuple nor rotation object");
|
|
}
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw; // re-throw
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getCameraOrientation()
|
|
{
|
|
SbRotation rot = getView3DInventorPtr()->getViewer()->getCameraOrientation();
|
|
float q0, q1, q2, q3;
|
|
rot.getValue(q0, q1, q2, q3);
|
|
return Py::Rotation(Base::Rotation(q0, q1, q2, q3));
|
|
}
|
|
|
|
Py::Object View3DInventorPy::viewPosition(const Py::Tuple& args)
|
|
{
|
|
PyObject* p = nullptr;
|
|
int steps; // Unused but kept as parameter to not break the Python interface
|
|
int duration = -1; // Duration in ms, will be replaced with User
|
|
// parameter:BaseApp/Preferences/View/AnimationDuration when not explicitly
|
|
// provided
|
|
if (!PyArg_ParseTuple(args.ptr(), "|O!ii", &Base::PlacementPy::Type, &p, &steps, &duration)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
if (p) {
|
|
Base::Placement* plm = static_cast<Base::PlacementPy*>(p)->getPlacementPtr();
|
|
Base::Rotation rot = plm->getRotation();
|
|
Base::Vector3d pos = plm->getPosition();
|
|
double q0, q1, q2, q3;
|
|
rot.getValue(q0, q1, q2, q3);
|
|
getView3DInventorPtr()->getViewer()->moveCameraTo(
|
|
SbRotation((float)q0, (float)q1, (float)q2, (float)q3),
|
|
SbVec3f((float)pos.x, (float)pos.y, (float)pos.z),
|
|
duration
|
|
);
|
|
}
|
|
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
if (!cam) {
|
|
return Py::None();
|
|
}
|
|
|
|
SbRotation rot = cam->orientation.getValue();
|
|
SbVec3f pos = cam->position.getValue();
|
|
float q0, q1, q2, q3;
|
|
rot.getValue(q0, q1, q2, q3);
|
|
Base::Placement plm(Base::Vector3d(pos[0], pos[1], pos[2]), Base::Rotation(q0, q1, q2, q3));
|
|
return Py::Placement(plm);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::startAnimating(const Py::Tuple& args)
|
|
{
|
|
float x, y, z;
|
|
float velocity;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ffff", &x, &y, &z, &velocity)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->startSpinningAnimation(SbVec3f(x, y, z), velocity);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::stopAnimating()
|
|
{
|
|
getView3DInventorPtr()->getViewer()->stopAnimating();
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setAnimationEnabled(const Py::Tuple& args)
|
|
{
|
|
int ok;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setAnimationEnabled(ok != 0);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::isAnimationEnabled()
|
|
{
|
|
SbBool ok = getView3DInventorPtr()->getViewer()->isAnimationEnabled();
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setPopupMenuEnabled(const Py::Tuple& args)
|
|
{
|
|
int ok;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setPopupMenuEnabled(ok != 0);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::isPopupMenuEnabled()
|
|
{
|
|
SbBool ok = getView3DInventorPtr()->getViewer()->isPopupMenuEnabled();
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::saveImage(const Py::Tuple& args)
|
|
{
|
|
char* cFileName = nullptr;
|
|
const char* cColor = "Current";
|
|
const char* cComment = "$MIBA";
|
|
int w = -1, h = -1;
|
|
int s = View3DInventorViewer::getNumSamples();
|
|
|
|
if (!PyArg_ParseTuple(args.ptr(), "et|iissi", "utf-8", &cFileName, &w, &h, &cColor, &cComment, &s)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
std::string encodedName = std::string(cFileName);
|
|
PyMem_Free(cFileName);
|
|
QFileInfo fi(QString::fromUtf8(encodedName.c_str()));
|
|
|
|
if (!fi.absoluteDir().exists()) {
|
|
throw Py::RuntimeError("Directory where to save image doesn't exist");
|
|
}
|
|
|
|
QColor bg;
|
|
QString colname = QString::fromLatin1(cColor);
|
|
if (colname.compare(QLatin1String("Current"), Qt::CaseInsensitive) == 0) {
|
|
bg = QColor(); // assign an invalid color here
|
|
}
|
|
else {
|
|
bg = QColor(colname);
|
|
}
|
|
|
|
QImage img;
|
|
getView3DInventorPtr()->getViewer()->savePicture(w, h, s, bg, img);
|
|
|
|
SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance();
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
renderer.writeToImageFile(encodedName.c_str(), cComment, cam->getViewVolume().getMatrix(), img);
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::saveVectorGraphic(const Py::Tuple& args)
|
|
{
|
|
char* filename;
|
|
int ps = 4;
|
|
const char* name = "white";
|
|
|
|
if (!PyArg_ParseTuple(args.ptr(), "s|is", &filename, &ps, &name)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
std::unique_ptr<SoVectorizeAction> vo;
|
|
Base::FileInfo fi(filename);
|
|
if (fi.hasExtension({"ps", "eps"})) {
|
|
vo = std::unique_ptr<SoVectorizeAction>(new SoVectorizePSAction());
|
|
// vo->setGouraudThreshold(0.0f);
|
|
}
|
|
else if (fi.hasExtension("svg")) {
|
|
vo = std::unique_ptr<SoVectorizeAction>(new SoFCVectorizeSVGAction());
|
|
}
|
|
else if (fi.hasExtension("idtf")) {
|
|
vo = std::unique_ptr<SoVectorizeAction>(new SoFCVectorizeU3DAction());
|
|
}
|
|
else {
|
|
throw Py::RuntimeError("Not supported vector graphic");
|
|
}
|
|
|
|
SoVectorOutput* out = vo->getOutput();
|
|
if (!out || !out->openFile(filename)) {
|
|
std::ostringstream a_out;
|
|
a_out << "Cannot open file '" << filename << "'";
|
|
throw Py::RuntimeError(a_out.str());
|
|
}
|
|
|
|
QColor bg;
|
|
QString colname = QString::fromLatin1(name);
|
|
if (colname.compare(QLatin1String("Current"), Qt::CaseInsensitive) == 0) {
|
|
bg = getView3DInventorPtr()->getViewer()->backgroundColor();
|
|
}
|
|
else {
|
|
bg = QColor(colname);
|
|
}
|
|
|
|
getView3DInventorPtr()->getViewer()->saveGraphic(ps, bg, vo.get());
|
|
out->closeFile();
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getCameraNode()
|
|
{
|
|
try {
|
|
SoNode* camera = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
PyObject* proxy = nullptr;
|
|
std::string type;
|
|
type = "So"; // seems that So prefix is missing in camera node
|
|
type += camera->getTypeId().getName().getString();
|
|
type += " *";
|
|
proxy = Base::Interpreter()
|
|
.createSWIGPointerObj("pivy.coin", type.c_str(), static_cast<void*>(camera), 1);
|
|
camera->ref();
|
|
return Py::Object(proxy, true);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getCamera()
|
|
{
|
|
SoOutput out;
|
|
char buffer[512];
|
|
out.setBuffer(buffer, 512, nullptr);
|
|
|
|
try {
|
|
SoWriteAction wa(&out);
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
if (cam) {
|
|
wa.apply(cam);
|
|
}
|
|
else {
|
|
buffer[0] = '\0';
|
|
}
|
|
return Py::String(buffer);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getViewDirection()
|
|
{
|
|
try {
|
|
SbVec3f dvec = getView3DInventorPtr()->getViewer()->getViewDirection();
|
|
return Py::Vector(Base::Vector3f(dvec[0], dvec[1], dvec[2]));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
|
|
Py::Object View3DInventorPy::getUpDirection()
|
|
{
|
|
try {
|
|
SbVec3f dvec = getView3DInventorPtr()->getViewer()->getUpDirection();
|
|
return Py::Vector(Base::Vector3f(dvec[0], dvec[1], dvec[2]));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setViewDirection(const Py::Tuple& args)
|
|
{
|
|
PyObject* object;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &object)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
if (PyTuple_Check(object)) {
|
|
Py::Tuple tuple(object);
|
|
Py::Float x(tuple.getItem(0));
|
|
Py::Float y(tuple.getItem(1));
|
|
Py::Float z(tuple.getItem(2));
|
|
SbVec3f dir;
|
|
dir.setValue((float)x, (float)y, (float)z);
|
|
if (dir.length() < 0.001f) {
|
|
throw Py::ValueError("Null vector cannot be used to set direction");
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setViewDirection(dir);
|
|
return Py::None();
|
|
}
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw; // re-throw
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
|
|
Py::Object View3DInventorPy::setCamera(const Py::Tuple& args)
|
|
{
|
|
char* buffer;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &buffer)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
getView3DInventorPtr()->setCamera(buffer);
|
|
return Py::None();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
// FIXME: Once View3DInventor inherits from PropertyContainer we can use PropertyEnumeration.
|
|
const char* CameraTypeEnums[] = {"Orthographic", "Perspective", nullptr};
|
|
|
|
Py::Object View3DInventorPy::getCameraType()
|
|
{
|
|
SoCamera* cam = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getCamera();
|
|
if (!cam) {
|
|
throw Py::RuntimeError("No camera set!");
|
|
}
|
|
else if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
|
|
return Py::String(CameraTypeEnums[0]);
|
|
}
|
|
else if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
|
|
return Py::String(CameraTypeEnums[1]);
|
|
}
|
|
else {
|
|
throw Py::TypeError("Unknown camera type");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setCameraType(const Py::Tuple& args)
|
|
{
|
|
int cameratype = -1;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &cameratype)) {
|
|
char* modename;
|
|
PyErr_Clear();
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &modename)) {
|
|
throw Py::Exception();
|
|
}
|
|
for (int i = 0; i < 2; i++) {
|
|
if (strncmp(CameraTypeEnums[i], modename, 20) == 0) {
|
|
cameratype = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cameratype < 0) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << "Unknown camera type '" << modename << "'";
|
|
throw Py::NameError(s_out.str());
|
|
}
|
|
}
|
|
|
|
if (cameratype < 0 || cameratype > 1) {
|
|
throw Py::IndexError("Out of range");
|
|
}
|
|
if (cameratype == 0) {
|
|
getView3DInventorPtr()->getViewer()->setCameraType(SoOrthographicCamera::getClassTypeId());
|
|
}
|
|
else {
|
|
getView3DInventorPtr()->getViewer()->setCameraType(SoPerspectiveCamera::getClassTypeId());
|
|
}
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::listCameraTypes()
|
|
{
|
|
try {
|
|
Py::List list(2);
|
|
for (int i = 0; i < 2; i++) {
|
|
list[i] = Py::String(CameraTypeEnums[i]);
|
|
}
|
|
return list;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::dump(const Py::Tuple& args)
|
|
{
|
|
char* filename;
|
|
PyObject* onlyVisible = Py_False;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s|O!", &filename, &PyBool_Type, &onlyVisible)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
getView3DInventorPtr()->dump(filename, Base::asBoolean(onlyVisible));
|
|
return Py::None();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::dumpNode(const Py::Tuple& args)
|
|
{
|
|
PyObject* object;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &object)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
void* ptr = nullptr;
|
|
try {
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", object, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of SoNode failed");
|
|
}
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
auto node = static_cast<SoNode*>(ptr);
|
|
return Py::String(SoFCDB::writeNodesToString(node));
|
|
}
|
|
|
|
// FIXME: Once View3DInventor inherits from PropertyContainer we can use PropertyEnumeration.
|
|
const char* StereoTypeEnums[]
|
|
= {"Mono", "Anaglyph", "QuadBuffer", "InterleavedRows", "InterleavedColumns", nullptr};
|
|
|
|
Py::Object View3DInventorPy::setStereoType(const Py::Tuple& args)
|
|
{
|
|
int stereomode = -1;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &stereomode)) {
|
|
char* modename;
|
|
PyErr_Clear();
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &modename)) {
|
|
throw Py::Exception();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
if (strncmp(StereoTypeEnums[i], modename, 20) == 0) {
|
|
stereomode = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (stereomode < 0) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << "Unknown stereo type '" << modename << "'";
|
|
throw Py::NameError(s_out.str());
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (stereomode < 0 || stereomode > 4) {
|
|
throw Py::IndexError("Out of range");
|
|
}
|
|
Quarter::SoQTQuarterAdaptor::StereoMode mode = Quarter::SoQTQuarterAdaptor::StereoMode(
|
|
stereomode
|
|
);
|
|
getView3DInventorPtr()->getViewer()->setStereoMode(mode);
|
|
return Py::None();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getStereoType()
|
|
{
|
|
try {
|
|
int mode = int(getView3DInventorPtr()->getViewer()->stereoMode());
|
|
if (mode < 0 || mode > 4) {
|
|
throw Py::ValueError("Invalid stereo mode");
|
|
}
|
|
return Py::String(StereoTypeEnums[mode]);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::listStereoTypes()
|
|
{
|
|
try {
|
|
Py::List list(5);
|
|
for (int i = 0; i < 5; i++) {
|
|
list[i] = Py::String(StereoTypeEnums[i]);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getCursorPos()
|
|
{
|
|
try {
|
|
QPoint pos = getView3DInventorPtr()->mapFromGlobal(QCursor::pos());
|
|
auto viewer = getView3DInventorPtr()->getViewer();
|
|
SbVec2s vec = viewer->fromQPoint(pos);
|
|
Py::Tuple tuple(2);
|
|
tuple.setItem(0, Py::Long(vec[0]));
|
|
tuple.setItem(1, Py::Long(vec[1]));
|
|
return tuple;
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args)
|
|
{
|
|
PyObject* object;
|
|
float r = getView3DInventorPtr()->getViewer()->getPickRadius();
|
|
if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
// Note: For gcc (4.2) we need the 'const' keyword to avoid the compiler error:
|
|
// conversion from 'Py::seqref<Py::Object>' to non-scalar type 'Py::Long' requested
|
|
// We should report this problem to the PyCXX project as in the documentation an
|
|
// example without the 'const' keyword is used.
|
|
// Or we can also write Py::Long x(tuple[0]);
|
|
const Py::Tuple tuple(object);
|
|
Py::Long x(tuple[0]);
|
|
Py::Long y(tuple[1]);
|
|
|
|
// As this method could be called during a SoHandleEventAction scene
|
|
// graph traversal we must not use a second SoHandleEventAction as
|
|
// we will get Coin warnings because of multiple scene graph traversals
|
|
// which is regarded as error-prone.
|
|
SoRayPickAction action(
|
|
getView3DInventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion()
|
|
);
|
|
action.setPoint(SbVec2s((long)x, (long)y));
|
|
action.setRadius(r);
|
|
action.apply(getView3DInventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph());
|
|
SoPickedPoint* Point = action.getPickedPoint();
|
|
|
|
Py::Object ret = Py::None();
|
|
if (Point) {
|
|
Py::Dict dict;
|
|
SbVec3f pt = Point->getPoint();
|
|
dict.setItem("x", Py::Float(pt[0]));
|
|
dict.setItem("y", Py::Float(pt[1]));
|
|
dict.setItem("z", Py::Float(pt[2]));
|
|
|
|
ViewProvider* vp = getView3DInventorPtr()->getViewer()->getViewProviderByPath(
|
|
Point->getPath()
|
|
);
|
|
if (vp && vp->isDerivedFrom<ViewProviderDocumentObject>()) {
|
|
if (!vp->isSelectable()) {
|
|
return ret;
|
|
}
|
|
auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
|
|
if (vp->useNewSelectionModel()) {
|
|
std::string subname;
|
|
if (!vp->getElementPicked(Point, subname)) {
|
|
return ret;
|
|
}
|
|
auto obj = vpd->getObject();
|
|
if (!obj) {
|
|
return ret;
|
|
}
|
|
if (!subname.empty()) {
|
|
App::ElementNamePair elementName;
|
|
auto sobj = App::GeoFeature::resolveElement(obj, subname.c_str(), elementName);
|
|
if (!sobj) {
|
|
return ret;
|
|
}
|
|
if (sobj != obj) {
|
|
dict.setItem("ParentObject", Py::Object(obj->getPyObject(), true));
|
|
dict.setItem("SubName", Py::String(subname));
|
|
obj = sobj;
|
|
}
|
|
subname = !elementName.oldName.empty() ? elementName.oldName
|
|
: elementName.newName;
|
|
}
|
|
dict.setItem("Document", Py::String(obj->getDocument()->getName()));
|
|
dict.setItem("Object", Py::String(obj->getNameInDocument()));
|
|
dict.setItem("Component", Py::String(subname));
|
|
}
|
|
else {
|
|
dict.setItem("Document", Py::String(vpd->getObject()->getDocument()->getName()));
|
|
dict.setItem("Object", Py::String(vpd->getObject()->getNameInDocument()));
|
|
// search for a SoFCSelection node
|
|
SoFCDocumentObjectAction objaction;
|
|
objaction.apply(Point->getPath());
|
|
if (objaction.isHandled()) {
|
|
dict.setItem("Component", Py::String(objaction.componentName.getString()));
|
|
}
|
|
}
|
|
|
|
// ok, found the node of interest
|
|
ret = dict;
|
|
}
|
|
else {
|
|
// custom nodes not in a VP: search for a SoFCSelection node
|
|
SoFCDocumentObjectAction objaction;
|
|
objaction.apply(Point->getPath());
|
|
if (objaction.isHandled()) {
|
|
dict.setItem("Document", Py::String(objaction.documentName.getString()));
|
|
dict.setItem("Object", Py::String(objaction.objectName.getString()));
|
|
dict.setItem("Component", Py::String(objaction.componentName.getString()));
|
|
// ok, found the node of interest
|
|
ret = dict;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args)
|
|
{
|
|
PyObject* object;
|
|
float r = getView3DInventorPtr()->getViewer()->getPickRadius();
|
|
if (!PyArg_ParseTuple(args.ptr(), "O|f", &object, &r)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
// Note: For gcc (4.2) we need the 'const' keyword to avoid the compiler error:
|
|
// conversion from 'Py::seqref<Py::Object>' to non-scalar type 'Py::Long' requested
|
|
// We should report this problem to the PyCXX project as in the documentation an
|
|
// example without the 'const' keyword is used.
|
|
// Or we can also write Py::Long x(tuple[0]);
|
|
const Py::Tuple tuple(object);
|
|
Py::Long x(tuple[0]);
|
|
Py::Long y(tuple[1]);
|
|
|
|
// As this method could be called during a SoHandleEventAction scene
|
|
// graph traversal we must not use a second SoHandleEventAction as
|
|
// we will get Coin warnings because of multiple scene graph traversals
|
|
// which is regarded as error-prone.
|
|
SoRayPickAction action(
|
|
getView3DInventorPtr()->getViewer()->getSoRenderManager()->getViewportRegion()
|
|
);
|
|
action.setPickAll(true);
|
|
action.setRadius(r);
|
|
action.setPoint(SbVec2s((long)x, (long)y));
|
|
action.apply(getView3DInventorPtr()->getViewer()->getSoRenderManager()->getSceneGraph());
|
|
const SoPickedPointList& pp = action.getPickedPointList();
|
|
|
|
Py::Object ret = Py::None();
|
|
if (pp.getLength() > 0) {
|
|
Py::List list;
|
|
for (int i = 0; i < pp.getLength(); i++) {
|
|
Py::Dict dict;
|
|
auto point = static_cast<SoPickedPoint*>(pp.get(i));
|
|
SbVec3f pt = point->getPoint();
|
|
dict.setItem("x", Py::Float(pt[0]));
|
|
dict.setItem("y", Py::Float(pt[1]));
|
|
dict.setItem("z", Py::Float(pt[2]));
|
|
|
|
ViewProvider* vp = getView3DInventorPtr()->getViewer()->getViewProviderByPath(
|
|
point->getPath()
|
|
);
|
|
if (vp && vp->isDerivedFrom<ViewProviderDocumentObject>()) {
|
|
if (!vp->isSelectable()) {
|
|
continue;
|
|
}
|
|
auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
|
|
if (vp->useNewSelectionModel()) {
|
|
std::string subname;
|
|
if (!vp->getElementPicked(point, subname)) {
|
|
continue;
|
|
}
|
|
auto obj = vpd->getObject();
|
|
if (!obj) {
|
|
continue;
|
|
}
|
|
if (!subname.empty()) {
|
|
App::ElementNamePair elementName;
|
|
auto sobj
|
|
= App::GeoFeature::resolveElement(obj, subname.c_str(), elementName);
|
|
if (!sobj) {
|
|
continue;
|
|
}
|
|
if (sobj != obj) {
|
|
dict.setItem("ParentObject", Py::Object(obj->getPyObject(), true));
|
|
dict.setItem("SubName", Py::String(subname));
|
|
obj = sobj;
|
|
}
|
|
subname = !elementName.oldName.empty() ? elementName.oldName
|
|
: elementName.newName;
|
|
}
|
|
dict.setItem("Document", Py::String(obj->getDocument()->getName()));
|
|
dict.setItem("Object", Py::String(obj->getNameInDocument()));
|
|
dict.setItem("Component", Py::String(subname));
|
|
}
|
|
else {
|
|
dict.setItem("Document", Py::String(vpd->getObject()->getDocument()->getName()));
|
|
dict.setItem("Object", Py::String(vpd->getObject()->getNameInDocument()));
|
|
// search for a SoFCSelection node
|
|
SoFCDocumentObjectAction objaction;
|
|
objaction.apply(point->getPath());
|
|
if (objaction.isHandled()) {
|
|
dict.setItem("Component", Py::String(objaction.componentName.getString()));
|
|
}
|
|
}
|
|
// ok, found the node of interest
|
|
list.append(dict);
|
|
}
|
|
else {
|
|
// custom nodes not in a VP: search for a SoFCSelection node
|
|
SoFCDocumentObjectAction objaction;
|
|
objaction.apply(point->getPath());
|
|
if (objaction.isHandled()) {
|
|
dict.setItem("Document", Py::String(objaction.documentName.getString()));
|
|
dict.setItem("Object", Py::String(objaction.objectName.getString()));
|
|
dict.setItem("Component", Py::String(objaction.componentName.getString()));
|
|
// ok, found the node of interest
|
|
ret = dict;
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = list;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getObjectInfoRay(const Py::Tuple& args)
|
|
{
|
|
PyObject* vs;
|
|
PyObject* vd;
|
|
double vsx, vsy, vsz;
|
|
double vdx, vdy, vdz;
|
|
Py::Object ret = Py::None();
|
|
if (PyArg_ParseTuple(args.ptr(), "O!O!", &Base::VectorPy::Type, &vs, &Base::VectorPy::Type, &vd)) {
|
|
Base::Vector3d* startvec = static_cast<Base::VectorPy*>(vs)->getVectorPtr();
|
|
Base::Vector3d* dirvec = static_cast<Base::VectorPy*>(vd)->getVectorPtr();
|
|
try {
|
|
RayPickInfo pinfo = getView3DInventorPtr()->getObjInfoRay(startvec, dirvec);
|
|
if (!pinfo.isValid) {
|
|
return ret;
|
|
}
|
|
Py::Dict dict;
|
|
dict.setItem("PickedPoint", Py::asObject(new Base::VectorPy(pinfo.point)));
|
|
dict.setItem("Document", Py::String(pinfo.document));
|
|
dict.setItem("Object", Py::String(pinfo.object));
|
|
if (pinfo.parentObject) {
|
|
dict.setItem("ParentObject", Py::String(pinfo.parentObject.value()));
|
|
}
|
|
if (pinfo.component) {
|
|
dict.setItem("Component", Py::String(pinfo.component.value()));
|
|
}
|
|
if (pinfo.subName) {
|
|
dict.setItem("SubName", Py::String(pinfo.subName.value()));
|
|
}
|
|
ret = dict;
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
else {
|
|
PyErr_Clear();
|
|
if (!PyArg_ParseTuple(args.ptr(), "dddddd", &vsx, &vsy, &vsz, &vdx, &vdy, &vdz)) {
|
|
throw Py::TypeError("Wrong arguments, two Vectors or six floats expected");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getSize()
|
|
{
|
|
try {
|
|
SbVec2s size = getView3DInventorPtr()->getViewer()->getSoRenderManager()->getSize();
|
|
Py::Tuple tuple(2);
|
|
tuple.setItem(0, Py::Long(size[0]));
|
|
tuple.setItem(1, Py::Long(size[1]));
|
|
return tuple;
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getPointOnFocalPlane(const Py::Tuple& args)
|
|
{
|
|
short x, y;
|
|
if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
|
|
PyErr_Clear();
|
|
Py::Tuple t(args[0]);
|
|
x = (int)Py::Long(t[0]);
|
|
y = (int)Py::Long(t[1]);
|
|
}
|
|
try {
|
|
SbVec3f pt = getView3DInventorPtr()->getViewer()->getPointOnFocalPlane(SbVec2s(x, y));
|
|
return Py::Vector(Base::Vector3f(pt[0], pt[1], pt[2]));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getPointOnViewport(const Py::Tuple& args)
|
|
{
|
|
PyObject* v;
|
|
double vx, vy, vz;
|
|
if (PyArg_ParseTuple(args.ptr(), "O!", &Base::VectorPy::Type, &v)) {
|
|
Base::Vector3d* vec = static_cast<Base::VectorPy*>(v)->getVectorPtr();
|
|
vx = vec->x;
|
|
vy = vec->y;
|
|
vz = vec->z;
|
|
}
|
|
else {
|
|
PyErr_Clear();
|
|
if (!PyArg_ParseTuple(args.ptr(), "ddd", &vx, &vy, &vz)) {
|
|
throw Py::TypeError("Wrong argument, Vector or three floats expected expected");
|
|
}
|
|
}
|
|
|
|
try {
|
|
SbVec2s pt = getView3DInventorPtr()->getViewer()->getPointOnViewport(SbVec3f(vx, vy, vz));
|
|
Py::Tuple tuple(2);
|
|
tuple.setItem(0, Py::Long(pt[0]));
|
|
tuple.setItem(1, Py::Long(pt[1]));
|
|
|
|
return tuple;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::projectPointToLine(const Py::Tuple& args)
|
|
{
|
|
short x, y;
|
|
if (!PyArg_ParseTuple(args.ptr(), "hh", &x, &y)) {
|
|
PyErr_Clear();
|
|
Py::Tuple t(args[0]);
|
|
x = (int)Py::Long(t[0]);
|
|
y = (int)Py::Long(t[1]);
|
|
}
|
|
try {
|
|
SbVec3f pt1, pt2;
|
|
getView3DInventorPtr()->getViewer()->projectPointToLine(SbVec2s(x, y), pt1, pt2);
|
|
Py::Tuple tuple(2);
|
|
tuple.setItem(0, Py::Vector(Base::Vector3f(pt1[0], pt1[1], pt1[2])));
|
|
tuple.setItem(1, Py::Vector(Base::Vector3f(pt2[0], pt2[1], pt2[2])));
|
|
return tuple;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::listNavigationTypes()
|
|
{
|
|
std::vector<Base::Type> types;
|
|
Py::List styles;
|
|
Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types);
|
|
for (auto it = types.begin() + 1; it != types.end(); ++it) {
|
|
styles.append(Py::String(it->getName()));
|
|
}
|
|
return styles;
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getNavigationType()
|
|
{
|
|
std::string name = getView3DInventorPtr()->getViewer()->navigationStyle()->getTypeId().getName();
|
|
return Py::String(name);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setNavigationType(const Py::Tuple& args)
|
|
{
|
|
char* style;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &style)) {
|
|
throw Py::Exception();
|
|
}
|
|
Base::Type type = Base::Type::fromName(style);
|
|
getView3DInventorPtr()->getViewer()->setNavigationType(type);
|
|
return Py::None();
|
|
}
|
|
|
|
void View3DInventorPy::eventCallback(void* ud, SoEventCallback* n)
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
Py::Dict dict;
|
|
const SoEvent* e = n->getEvent();
|
|
if (!e) { // invalid event
|
|
return;
|
|
}
|
|
// Type
|
|
dict.setItem("Type", Py::String(std::string(e->getTypeId().getName().getString())));
|
|
// Time
|
|
dict.setItem(
|
|
"Time",
|
|
Py::String(std::string(e->getTime().formatDate("%Y-%m-%d %H:%M:%S").getString()))
|
|
);
|
|
SbVec2s p = n->getEvent()->getPosition();
|
|
Py::Tuple pos(2);
|
|
pos.setItem(0, Py::Long(p[0]));
|
|
pos.setItem(1, Py::Long(p[1]));
|
|
// Position
|
|
dict.setItem("Position", pos);
|
|
// Shift, Ctrl, Alt down
|
|
dict.setItem("ShiftDown", Py::Object((e->wasShiftDown() ? Py_True : Py_False)));
|
|
dict.setItem("CtrlDown", Py::Object((e->wasCtrlDown() ? Py_True : Py_False)));
|
|
dict.setItem("AltDown", Py::Object((e->wasAltDown() ? Py_True : Py_False)));
|
|
if (e->isOfType(SoButtonEvent::getClassTypeId())) {
|
|
std::string state;
|
|
const auto be = static_cast<const SoButtonEvent*>(e);
|
|
switch (be->getState()) {
|
|
case SoButtonEvent::UP:
|
|
state = "UP";
|
|
break;
|
|
case SoButtonEvent::DOWN:
|
|
state = "DOWN";
|
|
break;
|
|
default:
|
|
state = "UNKNOWN";
|
|
break;
|
|
}
|
|
|
|
dict.setItem("State", Py::String(state));
|
|
}
|
|
if (e->isOfType(SoKeyboardEvent::getClassTypeId())) {
|
|
const auto ke = static_cast<const SoKeyboardEvent*>(e);
|
|
switch (ke->getKey()) {
|
|
case SoKeyboardEvent::ANY:
|
|
dict.setItem("Key", Py::String("ANY"));
|
|
break;
|
|
case SoKeyboardEvent::UNDEFINED:
|
|
dict.setItem("Key", Py::String("UNDEFINED"));
|
|
break;
|
|
case SoKeyboardEvent::LEFT_SHIFT:
|
|
case SoKeyboardEvent::RIGHT_SHIFT:
|
|
dict.setItem("Key", Py::String("SHIFT"));
|
|
break;
|
|
case SoKeyboardEvent::LEFT_CONTROL:
|
|
case SoKeyboardEvent::RIGHT_CONTROL:
|
|
dict.setItem("Key", Py::String("CONTROL"));
|
|
break;
|
|
case SoKeyboardEvent::LEFT_ALT:
|
|
case SoKeyboardEvent::RIGHT_ALT:
|
|
dict.setItem("Key", Py::String("ALT"));
|
|
break;
|
|
case SoKeyboardEvent::HOME:
|
|
dict.setItem("Key", Py::String("HOME"));
|
|
break;
|
|
case SoKeyboardEvent::LEFT_ARROW:
|
|
dict.setItem("Key", Py::String("LEFT_ARROW"));
|
|
break;
|
|
case SoKeyboardEvent::UP_ARROW:
|
|
dict.setItem("Key", Py::String("UP_ARROW"));
|
|
break;
|
|
case SoKeyboardEvent::RIGHT_ARROW:
|
|
dict.setItem("Key", Py::String("RIGHT_ARROW"));
|
|
break;
|
|
case SoKeyboardEvent::DOWN_ARROW:
|
|
dict.setItem("Key", Py::String("DOWN_ARROW"));
|
|
break;
|
|
case SoKeyboardEvent::PAGE_UP:
|
|
dict.setItem("Key", Py::String("PAGE_UP"));
|
|
break;
|
|
case SoKeyboardEvent::PAGE_DOWN:
|
|
dict.setItem("Key", Py::String("PAGE_DOWN"));
|
|
break;
|
|
case SoKeyboardEvent::END:
|
|
dict.setItem("Key", Py::String("END"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_ENTER:
|
|
dict.setItem("Key", Py::String("PAD_ENTER"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_F1:
|
|
dict.setItem("Key", Py::String("PAD_F1"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_F2:
|
|
dict.setItem("Key", Py::String("PAD_F2"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_F3:
|
|
dict.setItem("Key", Py::String("PAD_F3"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_F4:
|
|
dict.setItem("Key", Py::String("PAD_F4"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_0:
|
|
dict.setItem("Key", Py::String("PAD_0"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_1:
|
|
dict.setItem("Key", Py::String("PAD_1"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_2:
|
|
dict.setItem("Key", Py::String("PAD_2"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_3:
|
|
dict.setItem("Key", Py::String("PAD_3"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_4:
|
|
dict.setItem("Key", Py::String("PAD_4"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_5:
|
|
dict.setItem("Key", Py::String("PAD_5"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_6:
|
|
dict.setItem("Key", Py::String("PAD_6"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_7:
|
|
dict.setItem("Key", Py::String("PAD_7"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_8:
|
|
dict.setItem("Key", Py::String("PAD_8"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_9:
|
|
dict.setItem("Key", Py::String("PAD_9"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_ADD:
|
|
dict.setItem("Key", Py::String("PAD_ADD"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_SUBTRACT:
|
|
dict.setItem("Key", Py::String("PAD_SUBTRACT"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_MULTIPLY:
|
|
dict.setItem("Key", Py::String("PAD_MULTIPLY"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_DIVIDE:
|
|
dict.setItem("Key", Py::String("PAD_DIVIDE"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_TAB:
|
|
dict.setItem("Key", Py::String("PAD_TAB"));
|
|
break;
|
|
case SoKeyboardEvent::PAD_DELETE:
|
|
dict.setItem("Key", Py::String("PAD_DELETE"));
|
|
break;
|
|
case SoKeyboardEvent::F1:
|
|
dict.setItem("Key", Py::String("F1"));
|
|
break;
|
|
case SoKeyboardEvent::F2:
|
|
dict.setItem("Key", Py::String("F2"));
|
|
break;
|
|
case SoKeyboardEvent::F3:
|
|
dict.setItem("Key", Py::String("F3"));
|
|
break;
|
|
case SoKeyboardEvent::F4:
|
|
dict.setItem("Key", Py::String("F4"));
|
|
break;
|
|
case SoKeyboardEvent::F5:
|
|
dict.setItem("Key", Py::String("F5"));
|
|
break;
|
|
case SoKeyboardEvent::F6:
|
|
dict.setItem("Key", Py::String("F6"));
|
|
break;
|
|
case SoKeyboardEvent::F7:
|
|
dict.setItem("Key", Py::String("F7"));
|
|
break;
|
|
case SoKeyboardEvent::F8:
|
|
dict.setItem("Key", Py::String("F8"));
|
|
break;
|
|
case SoKeyboardEvent::F9:
|
|
dict.setItem("Key", Py::String("F9"));
|
|
break;
|
|
case SoKeyboardEvent::F10:
|
|
dict.setItem("Key", Py::String("F10"));
|
|
break;
|
|
case SoKeyboardEvent::F11:
|
|
dict.setItem("Key", Py::String("F11"));
|
|
break;
|
|
case SoKeyboardEvent::F12:
|
|
dict.setItem("Key", Py::String("F12"));
|
|
break;
|
|
case SoKeyboardEvent::BACKSPACE:
|
|
dict.setItem("Key", Py::String("BACKSPACE"));
|
|
break;
|
|
case SoKeyboardEvent::TAB:
|
|
dict.setItem("Key", Py::String("TAB"));
|
|
break;
|
|
case SoKeyboardEvent::RETURN:
|
|
dict.setItem("Key", Py::String("RETURN"));
|
|
break;
|
|
case SoKeyboardEvent::PAUSE:
|
|
dict.setItem("Key", Py::String("PAUSE"));
|
|
break;
|
|
case SoKeyboardEvent::SCROLL_LOCK:
|
|
dict.setItem("Key", Py::String("SCROLL_LOCK"));
|
|
break;
|
|
case SoKeyboardEvent::ESCAPE:
|
|
dict.setItem("Key", Py::String("ESCAPE"));
|
|
break;
|
|
case SoKeyboardEvent::KEY_DELETE:
|
|
dict.setItem("Key", Py::String("DELETE"));
|
|
break;
|
|
case SoKeyboardEvent::PRINT:
|
|
dict.setItem("Key", Py::String("PRINT"));
|
|
break;
|
|
case SoKeyboardEvent::INSERT:
|
|
dict.setItem("Key", Py::String("INSERT"));
|
|
break;
|
|
case SoKeyboardEvent::NUM_LOCK:
|
|
dict.setItem("Key", Py::String("NUM_LOCK"));
|
|
break;
|
|
case SoKeyboardEvent::CAPS_LOCK:
|
|
dict.setItem("Key", Py::String("CAPS_LOCK"));
|
|
break;
|
|
case SoKeyboardEvent::SHIFT_LOCK:
|
|
dict.setItem("Key", Py::String("SHIFT_LOCK"));
|
|
break;
|
|
case SoKeyboardEvent::SPACE:
|
|
dict.setItem("Key", Py::String("SPACE"));
|
|
break;
|
|
case SoKeyboardEvent::APOSTROPHE:
|
|
dict.setItem("Key", Py::String("APOSTROPHE"));
|
|
break;
|
|
case SoKeyboardEvent::COMMA:
|
|
dict.setItem("Key", Py::String("COMMA"));
|
|
break;
|
|
case SoKeyboardEvent::MINUS:
|
|
dict.setItem("Key", Py::String("MINUS"));
|
|
break;
|
|
case SoKeyboardEvent::PERIOD:
|
|
dict.setItem("Key", Py::String("PERIOD"));
|
|
break;
|
|
case SoKeyboardEvent::SLASH:
|
|
dict.setItem("Key", Py::String("SLASH"));
|
|
break;
|
|
case SoKeyboardEvent::SEMICOLON:
|
|
dict.setItem("Key", Py::String("SEMICOLON"));
|
|
break;
|
|
case SoKeyboardEvent::EQUAL:
|
|
dict.setItem("Key", Py::String("EQUAL"));
|
|
break;
|
|
case SoKeyboardEvent::BRACKETLEFT:
|
|
dict.setItem("Key", Py::String("BRACKETLEFT"));
|
|
break;
|
|
case SoKeyboardEvent::BACKSLASH:
|
|
dict.setItem("Key", Py::String("BACKSLASH"));
|
|
break;
|
|
case SoKeyboardEvent::BRACKETRIGHT:
|
|
dict.setItem("Key", Py::String("BRACKETRIGHT"));
|
|
break;
|
|
case SoKeyboardEvent::GRAVE:
|
|
dict.setItem("Key", Py::String("GRAVE"));
|
|
break;
|
|
default:
|
|
dict.setItem("Key", Py::Char(ke->getPrintableCharacter()));
|
|
break;
|
|
}
|
|
}
|
|
if (e->isOfType(SoMouseButtonEvent::getClassTypeId())) {
|
|
const auto mbe = static_cast<const SoMouseButtonEvent*>(e);
|
|
std::string button;
|
|
switch (mbe->getButton()) {
|
|
case SoMouseButtonEvent::BUTTON1:
|
|
button = "BUTTON1";
|
|
break;
|
|
case SoMouseButtonEvent::BUTTON2:
|
|
button = "BUTTON2";
|
|
break;
|
|
case SoMouseButtonEvent::BUTTON3:
|
|
button = "BUTTON3";
|
|
break;
|
|
case SoMouseButtonEvent::BUTTON4:
|
|
button = "BUTTON4";
|
|
break;
|
|
case SoMouseButtonEvent::BUTTON5:
|
|
button = "BUTTON5";
|
|
break;
|
|
default:
|
|
button = "ANY";
|
|
break;
|
|
}
|
|
|
|
dict.setItem("Button", Py::String(button));
|
|
}
|
|
if (e->isOfType(SoMouseWheelEvent::getClassTypeId())) {
|
|
const auto mwe = static_cast<const SoMouseWheelEvent*>(e);
|
|
dict.setItem("Delta", Py::Long(mwe->getDelta()));
|
|
}
|
|
if (e->isOfType(SoSpaceballButtonEvent::getClassTypeId())) {
|
|
const auto sbe = static_cast<const SoSpaceballButtonEvent*>(e);
|
|
std::string button;
|
|
switch (sbe->getButton()) {
|
|
case SoSpaceballButtonEvent::BUTTON1:
|
|
button = "BUTTON1";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON2:
|
|
button = "BUTTON2";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON3:
|
|
button = "BUTTON3";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON4:
|
|
button = "BUTTON4";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON5:
|
|
button = "BUTTON5";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON6:
|
|
button = "BUTTON6";
|
|
break;
|
|
case SoSpaceballButtonEvent::BUTTON7:
|
|
button = "BUTTON7";
|
|
break;
|
|
default:
|
|
button = "ANY";
|
|
break;
|
|
}
|
|
|
|
dict.setItem("Button", Py::String(button));
|
|
}
|
|
if (e->isOfType(SoMotion3Event::getClassTypeId())) {
|
|
const auto me = static_cast<const SoMotion3Event*>(e);
|
|
const SbVec3f& m = me->getTranslation();
|
|
const SbRotation& r = me->getRotation();
|
|
Py::Tuple mov(3);
|
|
mov.setItem(0, Py::Float(m[0]));
|
|
mov.setItem(1, Py::Float(m[1]));
|
|
mov.setItem(2, Py::Float(m[2]));
|
|
dict.setItem("Translation", mov);
|
|
Py::Tuple rot(4);
|
|
rot.setItem(0, Py::Float(r.getValue()[0]));
|
|
rot.setItem(1, Py::Float(r.getValue()[1]));
|
|
rot.setItem(2, Py::Float(r.getValue()[2]));
|
|
rot.setItem(3, Py::Float(r.getValue()[3]));
|
|
dict.setItem("Rotation", rot);
|
|
}
|
|
|
|
// now run the method
|
|
Py::Callable method(reinterpret_cast<PyObject*>(ud));
|
|
Py::Tuple args(1);
|
|
args.setItem(0, dict);
|
|
method.apply(args);
|
|
}
|
|
catch (const Py::Exception& e) {
|
|
Py::Object o = Py::type(e);
|
|
if (o.isString()) {
|
|
Py::String s(o);
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
else {
|
|
Py::String s(o.repr());
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
// Prints message to console window if we are in interactive mode
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::addEventCallback(const Py::Tuple& args)
|
|
{
|
|
char* eventtype;
|
|
PyObject* method;
|
|
if (!PyArg_ParseTuple(args.ptr(), "sO", &eventtype, &method)) {
|
|
throw Py::Exception();
|
|
}
|
|
try {
|
|
if (PyCallable_Check(method) == 0) {
|
|
throw Py::TypeError("object is not callable");
|
|
}
|
|
SoType eventId = SoType::fromName(eventtype);
|
|
if (eventId.isBad() || !eventId.isDerivedFrom(SoEvent::getClassTypeId())) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << eventtype << " is not a valid event type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
getView3DInventorPtr()->getViewer()->addEventCallback(
|
|
eventId,
|
|
View3DInventorPy::eventCallback,
|
|
method
|
|
);
|
|
callbacks.push_back(method);
|
|
Py_INCREF(method);
|
|
return Py::Callable(method, false);
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::removeEventCallback(const Py::Tuple& args)
|
|
{
|
|
char* eventtype;
|
|
PyObject* method;
|
|
if (!PyArg_ParseTuple(args.ptr(), "sO", &eventtype, &method)) {
|
|
throw Py::Exception();
|
|
}
|
|
try {
|
|
if (PyCallable_Check(method) == 0) {
|
|
throw Py::RuntimeError("object is not callable");
|
|
}
|
|
SoType eventId = SoType::fromName(eventtype);
|
|
if (eventId.isBad() || !eventId.isDerivedFrom(SoEvent::getClassTypeId())) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << eventtype << " is not a valid event type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
getView3DInventorPtr()->getViewer()->removeEventCallback(
|
|
eventId,
|
|
View3DInventorPy::eventCallback,
|
|
method
|
|
);
|
|
callbacks.remove(method);
|
|
Py_DECREF(method);
|
|
return Py::None();
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setAnnotation(const Py::Tuple& args)
|
|
{
|
|
char *psAnnoName, *psBuffer;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ss", &psAnnoName, &psBuffer)) {
|
|
throw Py::Exception();
|
|
}
|
|
ViewProviderExtern* view = nullptr;
|
|
try {
|
|
view = new ViewProviderExtern();
|
|
view->setModeByString(psAnnoName, psBuffer);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
delete view;
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
|
|
getView3DInventorPtr()->getGuiDocument()->setAnnotationViewProvider(psAnnoName, view);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::removeAnnotation(const Py::Tuple& args)
|
|
{
|
|
char* psAnnoName;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &psAnnoName)) {
|
|
throw Py::Exception();
|
|
}
|
|
ViewProvider* view = nullptr;
|
|
view = getView3DInventorPtr()->getGuiDocument()->getAnnotationViewProvider(psAnnoName);
|
|
if (view) {
|
|
getView3DInventorPtr()->getGuiDocument()->removeAnnotationViewProvider(psAnnoName);
|
|
return Py::None();
|
|
}
|
|
else {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << "No such annotation '" << psAnnoName << "'";
|
|
throw Py::KeyError(s_out.str());
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getSceneGraph()
|
|
{
|
|
try {
|
|
SoNode* scene = getView3DInventorPtr()->getViewer()->getSceneGraph();
|
|
if (scene == nullptr) {
|
|
return Py::None();
|
|
}
|
|
PyObject* proxy = nullptr;
|
|
proxy = Base::Interpreter()
|
|
.createSWIGPointerObj("pivy.coin", "SoSeparator *", static_cast<void*>(scene), 1);
|
|
scene->ref();
|
|
return Py::Object(proxy, true);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getViewer()
|
|
{
|
|
View3DInventorViewer* viewer = getView3DInventorPtr()->getViewer();
|
|
return Py::Object(viewer->getPyObject(), true);
|
|
}
|
|
|
|
void View3DInventorPy::eventCallbackPivy(void* ud, SoEventCallback* n)
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
const SoEvent* e = n->getEvent();
|
|
std::string type = e->getTypeId().getName().getString();
|
|
type += " *";
|
|
|
|
PyObject* proxy = nullptr;
|
|
try {
|
|
proxy = Base::Interpreter().createSWIGPointerObj(
|
|
"pivy.coin",
|
|
type.c_str(),
|
|
const_cast<void*>(static_cast<const void*>(e)),
|
|
0
|
|
);
|
|
// now run the method
|
|
Py::Object event(proxy, true);
|
|
Py::Callable method(static_cast<PyObject*>(ud));
|
|
Py::Tuple args(1);
|
|
args.setItem(0, event);
|
|
method.apply(args);
|
|
}
|
|
catch (const Base::Exception&) {
|
|
return;
|
|
}
|
|
catch (const Py::Exception& e) {
|
|
Py::Object o = Py::type(e);
|
|
if (o.isString()) {
|
|
Py::String s(o);
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
else {
|
|
Py::String s(o.repr());
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
// Prints message to console window if we are in interactive mode
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
|
|
void View3DInventorPy::eventCallbackPivyEx(void* ud, SoEventCallback* n)
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
std::string type = "SoEventCallback *";
|
|
|
|
PyObject* proxy = nullptr;
|
|
try {
|
|
proxy = Base::Interpreter()
|
|
.createSWIGPointerObj("pivy.coin", type.c_str(), static_cast<void*>(n), 0);
|
|
// now run the method
|
|
Py::Object event(proxy, true);
|
|
Py::Callable method(reinterpret_cast<PyObject*>(ud));
|
|
Py::Tuple args(1);
|
|
args.setItem(0, event);
|
|
method.apply(args);
|
|
}
|
|
catch (const Base::Exception&) {
|
|
return;
|
|
}
|
|
catch (const Py::Exception& e) {
|
|
Py::Object o = Py::type(e);
|
|
if (o.isString()) {
|
|
Py::String s(o);
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
else {
|
|
Py::String s(o.repr());
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
// Prints message to console window if we are in interactive mode
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::addEventCallbackPivy(const Py::Tuple& args)
|
|
{
|
|
PyObject* proxy;
|
|
PyObject* method;
|
|
int ex = 1; // if 1, use eventCallbackPivyEx
|
|
if (!PyArg_ParseTuple(args.ptr(), "OO|i", &proxy, &method, &ex)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
void* ptr = nullptr;
|
|
try {
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoType *", proxy, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of SoType failed");
|
|
}
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
|
|
auto eventId = static_cast<SoType*>(ptr);
|
|
if (eventId->isBad() || !eventId->isDerivedFrom(SoEvent::getClassTypeId())) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << eventId->getName().getString() << "is not a valid event type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
try {
|
|
if (PyCallable_Check(method) == 0) {
|
|
throw Py::TypeError("object is not callable");
|
|
}
|
|
|
|
SoEventCallbackCB* callback
|
|
= (ex == 1 ? View3DInventorPy::eventCallbackPivyEx : View3DInventorPy::eventCallbackPivy);
|
|
getView3DInventorPtr()->getViewer()->addEventCallback(*eventId, callback, method);
|
|
callbacks.push_back(method);
|
|
Py_INCREF(method);
|
|
return Py::Callable(method, false);
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::removeEventCallbackPivy(const Py::Tuple& args)
|
|
{
|
|
PyObject* proxy;
|
|
PyObject* method;
|
|
int ex = 1; // if 1, use eventCallbackPivyEx
|
|
if (!PyArg_ParseTuple(args.ptr(), "OO|i", &proxy, &method, &ex)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
void* ptr = nullptr;
|
|
try {
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoType *", proxy, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of SoType failed");
|
|
}
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
|
|
auto eventId = static_cast<SoType*>(ptr);
|
|
if (eventId->isBad() || !eventId->isDerivedFrom(SoEvent::getClassTypeId())) {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << eventId->getName().getString() << "is not a valid event type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
try {
|
|
if (PyCallable_Check(method) == 0) {
|
|
throw Py::TypeError("object is not callable");
|
|
}
|
|
|
|
SoEventCallbackCB* callback
|
|
= (ex == 1 ? View3DInventorPy::eventCallbackPivyEx : View3DInventorPy::eventCallbackPivy);
|
|
getView3DInventorPtr()->getViewer()->removeEventCallback(*eventId, callback, method);
|
|
callbacks.remove(method);
|
|
Py_DECREF(method);
|
|
return Py::Callable(method, false);
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setAxisCross(const Py::Tuple& args)
|
|
{
|
|
int ok;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setAxisCross(ok != 0);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::hasAxisCross()
|
|
{
|
|
SbBool ok = getView3DInventorPtr()->getViewer()->hasAxisCross();
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
void View3DInventorPy::draggerCallback(void* ud, SoDragger* n)
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
PyObject* proxy = nullptr;
|
|
try {
|
|
proxy = Base::Interpreter()
|
|
.createSWIGPointerObj("pivy.coin", "SoDragger *", static_cast<void*>(n), 0);
|
|
// call the method
|
|
Py::Object dragger(proxy, true);
|
|
Py::Callable method(reinterpret_cast<PyObject*>(ud));
|
|
Py::Tuple args(1);
|
|
args.setItem(0, dragger);
|
|
method.apply(args);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const Py::Exception& e) {
|
|
Py::Object o = Py::type(e);
|
|
if (o.isString()) {
|
|
Py::String s(o);
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
else {
|
|
Py::String s(o.repr());
|
|
Base::Console().warning("%s\n", s.as_std_string("utf-8").c_str());
|
|
}
|
|
// Prints message to console window if we are in interactive mode
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::addDraggerCallback(const Py::Tuple& args)
|
|
{
|
|
PyObject* dragger;
|
|
char* type;
|
|
PyObject* method;
|
|
if (!PyArg_ParseTuple(args.ptr(), "OsO", &dragger, &type, &method)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
|
|
// Check if dragger is a SoDragger object and cast
|
|
void* ptr = nullptr;
|
|
try {
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDragger *", dragger, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of SoDragger failed");
|
|
}
|
|
}
|
|
catch (const Base::Exception&) {
|
|
throw Py::TypeError("The first argument must be of type SoDragger");
|
|
}
|
|
auto drag = static_cast<SoDragger*>(ptr);
|
|
|
|
// Check if method is callable
|
|
if (PyCallable_Check(method) == 0) {
|
|
throw Py::TypeError("the method is not callable");
|
|
}
|
|
|
|
try {
|
|
if (strcmp(type, "addFinishCallback") == 0) {
|
|
drag->addFinishCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addStartCallback") == 0) {
|
|
drag->addStartCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addMotionCallback") == 0) {
|
|
drag->addMotionCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addValueChangedCallback") == 0) {
|
|
drag->addValueChangedCallback(draggerCallback, method);
|
|
}
|
|
else {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << type << " is not a valid dragger callback type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
callbacks.push_back(method);
|
|
Py_INCREF(method);
|
|
return Py::Callable(method, false);
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::removeDraggerCallback(const Py::Tuple& args)
|
|
{
|
|
PyObject* dragger;
|
|
char* type;
|
|
PyObject* method;
|
|
if (!PyArg_ParseTuple(args.ptr(), "OsO", &dragger, &type, &method)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
// Check if dragger is a SoDragger object and cast
|
|
void* ptr = nullptr;
|
|
try {
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDragger *", dragger, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of SoDragger failed");
|
|
}
|
|
}
|
|
catch (const Base::Exception&) {
|
|
throw Py::TypeError("The first argument must be of type SoDragger");
|
|
}
|
|
|
|
auto drag = static_cast<SoDragger*>(ptr);
|
|
try {
|
|
if (strcmp(type, "addFinishCallback") == 0) {
|
|
drag->removeFinishCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addStartCallback") == 0) {
|
|
drag->removeStartCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addMotionCallback") == 0) {
|
|
drag->removeMotionCallback(draggerCallback, method);
|
|
}
|
|
else if (strcmp(type, "addValueChangedCallback") == 0) {
|
|
drag->removeValueChangedCallback(draggerCallback, method);
|
|
}
|
|
else {
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << type << " is not a valid dragger callback type";
|
|
throw Py::TypeError(s_out.str());
|
|
}
|
|
|
|
callbacks.remove(method);
|
|
Py_DECREF(method);
|
|
return Py::Callable(method, false);
|
|
}
|
|
catch (const Py::Exception&) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getViewProvidersOfType(const Py::Tuple& args)
|
|
{
|
|
char* name;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &name)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
std::vector<ViewProvider*> vps = getView3DInventorPtr()->getViewer()->getViewProvidersOfType(
|
|
Base::Type::fromName(name)
|
|
);
|
|
Py::List list;
|
|
for (const auto& vp : vps) {
|
|
list.append(Py::asObject(vp->getPyObject()));
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
Py::Object View3DInventorPy::redraw()
|
|
{
|
|
getView3DInventorPtr()->getViewer()->redraw();
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setName(const Py::Tuple& args)
|
|
{
|
|
char* buffer;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s", &buffer)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
try {
|
|
getView3DInventorPtr()->setWindowTitle(QString::fromUtf8(buffer));
|
|
return Py::None();
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (const std::exception& e) {
|
|
throw Py::RuntimeError(e.what());
|
|
}
|
|
catch (...) {
|
|
throw Py::RuntimeError("Unknown C++ exception");
|
|
}
|
|
}
|
|
|
|
Py::Object View3DInventorPy::toggleClippingPlane(const Py::Tuple& args, const Py::Dict& kwds)
|
|
{
|
|
static const std::array<const char*, 5> keywords {"toggle", "beforeEditing", "noManip", "pla", nullptr};
|
|
int toggle = -1;
|
|
PyObject* beforeEditing = Py_False;
|
|
PyObject* noManip = Py_True;
|
|
PyObject* pyPla = Py_None;
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(
|
|
args.ptr(),
|
|
kwds.ptr(),
|
|
"|iO!O!O!",
|
|
keywords,
|
|
&toggle,
|
|
&PyBool_Type,
|
|
&beforeEditing,
|
|
&PyBool_Type,
|
|
&noManip,
|
|
&Base::PlacementPy::Type,
|
|
&pyPla
|
|
)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
Base::Placement pla;
|
|
if (pyPla != Py_None) {
|
|
pla = *static_cast<Base::PlacementPy*>(pyPla)->getPlacementPtr();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->toggleClippingPlane(
|
|
toggle,
|
|
Base::asBoolean(beforeEditing),
|
|
Base::asBoolean(noManip),
|
|
pla
|
|
);
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::hasClippingPlane()
|
|
{
|
|
return Py::Boolean(getView3DInventorPtr()->getViewer()->hasClippingPlane());
|
|
}
|
|
|
|
Py::Object View3DInventorPy::graphicsView()
|
|
{
|
|
PythonWrapper wrap;
|
|
wrap.loadWidgetsModule();
|
|
return wrap.fromQWidget(getView3DInventorPtr()->getViewer(), "QGraphicsView");
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setCornerCrossVisible(const Py::Tuple& args)
|
|
{
|
|
int ok;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &ok)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setFeedbackVisibility(ok != 0);
|
|
getView3DInventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when
|
|
// focus is in Python Console
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::isCornerCrossVisible()
|
|
{
|
|
bool ok = getView3DInventorPtr()->getViewer()->isFeedbackVisible();
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::setCornerCrossSize(const Py::Tuple& args)
|
|
{
|
|
int size = 0;
|
|
if (!PyArg_ParseTuple(args.ptr(), "i", &size)) {
|
|
throw Py::Exception();
|
|
}
|
|
getView3DInventorPtr()->getViewer()->setFeedbackSize(size);
|
|
getView3DInventorPtr()->getViewer()->redraw(); // added because isViewing() returns False when
|
|
// focus is in Python Console
|
|
return Py::None();
|
|
}
|
|
|
|
Py::Object View3DInventorPy::getCornerCrossSize()
|
|
{
|
|
int size = getView3DInventorPtr()->getViewer()->getFeedbackSize();
|
|
return Py::Long(size);
|
|
}
|
|
|
|
Py::Object View3DInventorPy::cast_to_base()
|
|
{
|
|
return Gui::MDIViewPy::create(getView3DInventorPtr());
|
|
}
|