From bc26820837ab1672bc8b8e900e8e7b417a3fa992 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Fri, 12 Jul 2019 08:32:28 +0800 Subject: [PATCH] Gui: Placement/DatumCS view provider changes * Add always zoom invariant and always on top rendering to ViewProviderDatumCS * Add a new utility class AxisOrigin for more efficient axis rendering. Also exposed to python. * Change ViewProviderPlacement to use AxisOrigin for rendering. A single instance of AxisOrigin is shared by all ViewProviderPlacement. Selection context is used to distinguish among different instances. --- src/App/Application.cpp | 1 + src/App/Placement.cpp | 8 + src/App/Placement.h | 2 + src/Gui/Application.cpp | 5 + src/Gui/AxisOrigin.cpp | 211 ++++++++++++++++++ src/Gui/AxisOrigin.h | 109 +++++++++ src/Gui/AxisOriginPy.xml | 85 +++++++ src/Gui/AxisOriginPyImp.cpp | 170 ++++++++++++++ src/Gui/CMakeLists.txt | 5 + src/Gui/Inventor/SoAutoZoomTranslation.cpp | 6 +- src/Gui/Inventor/SoAutoZoomTranslation.h | 2 + src/Gui/ViewProviderPlacement.cpp | 161 +++++-------- src/Gui/ViewProviderPlacement.h | 15 +- .../PartDesign/Gui/ViewProviderDatumCS.cpp | 153 +++++++++++-- src/Mod/PartDesign/Gui/ViewProviderDatumCS.h | 18 ++ 15 files changed, 811 insertions(+), 140 deletions(-) create mode 100644 src/Gui/AxisOrigin.cpp create mode 100644 src/Gui/AxisOrigin.h create mode 100644 src/Gui/AxisOriginPy.xml create mode 100644 src/Gui/AxisOriginPyImp.cpp diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 4dcad653a9..b020e98b5e 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1862,6 +1862,7 @@ void Application::initTypes(void) App ::MaterialObjectPython ::init(); App ::TextDocument ::init(); App ::Placement ::init(); + App ::PlacementPython ::init(); App ::OriginFeature ::init(); App ::Plane ::init(); App ::Line ::init(); diff --git a/src/App/Placement.cpp b/src/App/Placement.cpp index 6b9df04442..1860855b55 100644 --- a/src/App/Placement.cpp +++ b/src/App/Placement.cpp @@ -51,6 +51,14 @@ Placement::~Placement(void) +// Python feature --------------------------------------------------------- +namespace App { +PROPERTY_SOURCE_TEMPLATE(App::PlacementPython, App::Placement) +template<> const char* App::PlacementPython::getViewProviderName(void) const { + return "Gui::ViewProviderPlacementPython"; +} +template class AppExport FeaturePythonT; +} diff --git a/src/App/Placement.h b/src/App/Placement.h index d3665efe20..2b4d845d15 100644 --- a/src/App/Placement.h +++ b/src/App/Placement.h @@ -28,6 +28,7 @@ #include +#include "FeaturePython.h" #include "GeoFeature.h" #include "PropertyGeo.h" @@ -66,6 +67,7 @@ public: }; +typedef App::FeaturePythonT PlacementPython; diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 9543e793c7..982215d144 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -121,6 +121,7 @@ #include "ViewProviderGroupExtension.h" #include "ViewProviderLink.h" #include "LinkViewPy.h" +#include "AxisOriginPy.h" #include "Language/Translator.h" #include "TaskView/TaskView.h" @@ -403,7 +404,9 @@ Application::Application(bool GUIenabled) Gui::TaskView::ControlPy::init_type(); Py::Module(module).setAttr(std::string("Control"), Py::Object(Gui::TaskView::ControlPy::getInstance(), true)); + Base::Interpreter().addType(&LinkViewPy::Type,module,"LinkView"); + Base::Interpreter().addType(&AxisOriginPy::Type,module,"AxisOrigin"); } Base::PyGILStateLocker lock; @@ -1674,6 +1677,7 @@ void Application::initTypes(void) Gui::ViewProviderPythonFeature ::init(); Gui::ViewProviderPythonGeometry ::init(); Gui::ViewProviderPlacement ::init(); + Gui::ViewProviderPlacementPython ::init(); Gui::ViewProviderOriginFeature ::init(); Gui::ViewProviderPlane ::init(); Gui::ViewProviderLine ::init(); @@ -1689,6 +1693,7 @@ void Application::initTypes(void) Gui::LinkView ::init(); Gui::ViewProviderLink ::init(); Gui::ViewProviderLinkPython ::init(); + Gui::AxisOrigin ::init(); // Workbench Gui::Workbench ::init(); diff --git a/src/Gui/AxisOrigin.cpp b/src/Gui/AxisOrigin.cpp new file mode 100644 index 0000000000..06c1c698b6 --- /dev/null +++ b/src/Gui/AxisOrigin.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** + * Copyright (c) 2019 Zheng, Lei (realthunder) * + * * + * 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 "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "Inventor/SoAutoZoomTranslation.h" +#include "SoFCSelection.h" +#include "SoFCUnifiedSelection.h" +#include "AxisOrigin.h" + +using namespace Gui; + +TYPESYSTEM_SOURCE(Gui::AxisOrigin,Base::BaseClass); + +AxisOrigin::AxisOrigin() + :size(6),pSize(4),dist(2),scale(1),lineSize(2),pointSize(4) +{ +} + +SoGroup *AxisOrigin::getNode() { + if(node) + return node; + + node.reset(new SoGroup); + auto pMat = new SoMaterial(); + + const SbVec3f verts[13] = + { + SbVec3f(0,0,0), SbVec3f(size,0,0), + SbVec3f(0,size,0), SbVec3f(0,0,size), + SbVec3f(dist,dist,0), SbVec3f(dist,pSize,0), SbVec3f(pSize,dist,0), // XY Plane + SbVec3f(dist,0,dist), SbVec3f(dist,0,pSize), SbVec3f(pSize,0,dist), // XY Plane + SbVec3f(0,dist,dist), SbVec3f(0,pSize,dist), SbVec3f(0,dist,pSize) // XY Plane + }; + + // indexes used to create the edges + const int32_t lines[21] = + { + 0,1,-1, + 0,2,-1, + 0,3,-1, + 5,4,6,-1, + 8,7,9,-1, + 11,10,12,-1 + }; + + pMat->diffuseColor.setNum(3); + pMat->diffuseColor.set1Value(0, SbColor(1.0f, 0.2f, 0.2f)); + pMat->diffuseColor.set1Value(1, SbColor(0.2f, 0.6f, 0.2f)); + pMat->diffuseColor.set1Value(2, SbColor(0.2f, 0.2f, 1.0f)); + pMat->diffuseColor.set1Value(4, SbColor(0.8f, 0.8f, 0.8f)); + + auto pCoords = new SoCoordinate3(); + pCoords->point.setNum(3); + pCoords->point.setValues(0, 13, verts); + + SoAutoZoomTranslation *zoom = new SoAutoZoomTranslation; + zoom->scaleFactor = scale; + + SoDrawStyle* style = new SoDrawStyle(); + style->lineWidth = lineSize; + style->pointSize = pointSize; + + SoMaterialBinding* matBinding = new SoMaterialBinding; + matBinding->value = SoMaterialBinding::PER_FACE_INDEXED; + + node->addChild(zoom); + node->addChild(style); + node->addChild(matBinding); + node->addChild(pMat); + node->addChild(pCoords); + +#define CREATE_AXIS(_type,_key,_count,_offset,_mat) do{\ + const char *label=_key;\ + if(labels.size()){\ + auto iter = labels.find(_key);\ + if(iter == labels.end())\ + break;\ + else if(iter->second.size())\ + label = iter->second.c_str();\ + }\ + auto pAxis = new SoFCSelection;\ + pAxis->applySettings();\ + pAxis->style = SoFCSelection::EMISSIVE_DIFFUSE;\ + pAxis->subElementName = label;\ + nodeMap[label].reset(pAxis);\ + node->addChild(pAxis);\ + auto _type = new SoIndexed##_type##Set;\ + pAxis->addChild(_type);\ + _type->coordIndex.setNum(_count);\ + _type->coordIndex.setValues(0,_count,lines+_offset);\ + _type->materialIndex.setValue(_mat);\ + }while(0) + + CREATE_AXIS(Point,"O",1,0,4); + CREATE_AXIS(Line,"X",3,0,0); + CREATE_AXIS(Line,"Y",3,3,1); + CREATE_AXIS(Line,"Z",3,6,2); + CREATE_AXIS(Line,"XY",4,9,2); + CREATE_AXIS(Line,"XZ",4,13,1); + CREATE_AXIS(Line,"YZ",4,17,0); + return node; +} + +bool AxisOrigin::getElementPicked(const SoPickedPoint *pp, std::string &subname) const { + SoPath *path = pp->getPath(); + int length = path->getLength(); + for(int i=0;igetNodeFromTail(i); + if(node->isOfType(SoFCSelection::getClassTypeId())) { + subname = static_cast(node)->subElementName.getValue().getString(); + return true; + } else if(node->isOfType(SoFCSelectionRoot::getClassTypeId())) + break; + } + return false; +} + +bool AxisOrigin::getDetailPath(const char *subname, SoFullPath *pPath, SoDetail *&) const { + if(!node) + return false; + if(!subname || !subname[0]) + return true; + + auto it = nodeMap.find(subname); + if(it == nodeMap.end()) + return false; + pPath->append(node); + pPath->append(it->second); + return true; +} + +void AxisOrigin::setLineWidth(float size) { + if(size!=lineSize) { + node.reset(); + nodeMap.clear(); + lineSize = size; + } +} + +void AxisOrigin::setPointSize(float size) { + if(pointSize!=size) { + pointSize = size; + node.reset(); + nodeMap.clear(); + } +} + +void AxisOrigin::setAxisLength(float size) { + if(this->size!=size) { + this->size = size; + node.reset(); + nodeMap.clear(); + } +} + +void AxisOrigin::setPlane(float size, float dist) { + if(pSize!=size || this->dist!=dist) { + pSize = size; + this->dist = dist; + node.reset(); + nodeMap.clear(); + } +} + +void AxisOrigin::setScale(float scale) { + if(this->scale!=scale) { + this->scale = scale; + node.reset(); + nodeMap.clear(); + } +} + +void AxisOrigin::setLabels(const std::map &labels) { + this->labels = labels; + node.reset(); + nodeMap.clear(); +} diff --git a/src/Gui/AxisOrigin.h b/src/Gui/AxisOrigin.h new file mode 100644 index 0000000000..b91754476c --- /dev/null +++ b/src/Gui/AxisOrigin.h @@ -0,0 +1,109 @@ +/**************************************************************************** + * Copyright (c) 2019 Zheng, Lei (realthunder) * + * * + * 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 * + * * + ****************************************************************************/ + +#ifndef GUI_AxisOrigin_H +#define GUI_AxisOrigin_H + +#include "ViewProvider.h" + +namespace Gui { + +/// A class to create a Coin3D node representation of an coordinate system +class GuiExport AxisOrigin : public Base::BaseClass { + TYPESYSTEM_HEADER(); + +public: + AxisOrigin(); + + /// Set axis line width + void setLineWidth(float size); + + /// Get axis line width + float getLineWidth() const { return lineSize; } + + /// Set origin point size + void setPointSize(float size); + + /// Get origin point size + float getPointSize() const { return pointSize; } + + /// Set the axis line length + void setAxisLength(float size); + + /// Get axis base line length + float getAxisLength() const { return size; } + + /// Set the origin plane size and distance from the axis + void setPlane(float size, float dist); + + /// Get the origin plane size and distance from the axis + std::pair getPlane() const {return std::make_pair(pSize,dist);} + + /// Set the auto scale factor, 0 to disable it + void setScale(float scale); + + /// Get the auto scale factor + float getScale() const { return scale; } + + /** Set customized names for axis components + * + * @param labels: the input names. Avaiable keys are, O: origin, + * X: x axis, Y: y axis, Z: z axis, XY: XY plane, + * XZ: XY plane, YZ: YZ plane + * + * There are default labels for all components. You can also use + * this function to choose which components are hidden, by not + * include the key in the input labels. + */ + void setLabels(const std::map &labels); + + /// Obtain the axis component names + const std::map &getLabels() const { return labels; } + + /// Obtain the constructed Coin3D representation + SoGroup *getNode(); + + /** Return the name of picked element + * @sa ViewProvider::getElementPicked() + */ + bool getElementPicked(const SoPickedPoint *pp, std::string &subname) const; + + /** Return the coin path of a named element + * @sa ViewProvider::getDetailPath() + */ + bool getDetailPath(const char *subname, SoFullPath *pPath, SoDetail *&det) const; + +private: + float size; + float pSize; + float dist; + float scale; + float lineSize; + float pointSize; + std::map labels; + CoinPtr node; + std::map > nodeMap; +}; + +} // namepsace Gui + +#endif //GUI_AxisOrigin_H diff --git a/src/Gui/AxisOriginPy.xml b/src/Gui/AxisOriginPy.xml new file mode 100644 index 0000000000..9f3d8d7c5a --- /dev/null +++ b/src/Gui/AxisOriginPy.xml @@ -0,0 +1,85 @@ + + + + + + Class for creating a Coin3D representation of a coordinate system + + + + getElementPicked(pickPoint): return the picked subelement + + + + + +getDetailPath(subname,path): return Coin detail and path of an subelement + +subelement: dot separated string reference to the sub element +pPath: output coin path leading to the returned element detail + + + + + + Get/set the axis length + + + + + + Get/set the axis line width for rendering + + + + + + Get/set the origin point size for rendering + + + + + + Get/set auto scaling factor, 0 to disable + + + + + + Get/set axis plane size and distance to axis line + + + + + + +Get/set axis component names as a dictionary. Avaiable keys are, +'O': origin +'X': x axis +'Y': y axis +'Z': z axis +'XY': xy plane +'XZ': xz plane +'YZ': yz plane + + + + + + + Get the Coin3D node + + + + + diff --git a/src/Gui/AxisOriginPyImp.cpp b/src/Gui/AxisOriginPyImp.cpp new file mode 100644 index 0000000000..068e5bb189 --- /dev/null +++ b/src/Gui/AxisOriginPyImp.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** + * Copyright (c) 2019 Zheng, Lei (realthunder) * + * * + * 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 "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +#endif + +#include "AxisOriginPy.h" +#include "AxisOriginPy.cpp" + +using namespace Gui; + +PyObject *AxisOriginPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +{ + return new AxisOriginPy(new AxisOrigin); +} + +int AxisOriginPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + + +// returns a string which represent the object e.g. when printed in python +std::string AxisOriginPy::representation(void) const +{ + return ""; +} + +PyObject* AxisOriginPy::getElementPicked(PyObject* args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O",&obj)) + return NULL; + void *ptr = 0; + Base::Interpreter().convertSWIGPointerObj("pivy.coin", "_p_SoPickedPoint", obj, &ptr, 0); + SoPickedPoint *pp = reinterpret_cast(ptr); + if(!pp) + throw Base::TypeError("type must be of coin.SoPickedPoint"); + std::string name; + if(!getAxisOriginPtr()->getElementPicked(pp,name)) + Py_Return; + return Py::new_reference_to(Py::String(name)); +} + +PyObject* AxisOriginPy::getDetailPath(PyObject* args) +{ + const char *sub; + PyObject *path; + if (!PyArg_ParseTuple(args, "sO",&sub,&path)) + return NULL; + void *ptr = 0; + Base::Interpreter().convertSWIGPointerObj("pivy.coin", "_p_SoPath", path, &ptr, 0); + SoPath *pPath = reinterpret_cast(ptr); + if(!pPath) + throw Base::TypeError("type must be of coin.SoPath"); + SoDetail *det = 0; + if(!getAxisOriginPtr()->getDetailPath( + sub,static_cast(pPath),det)) + { + if(det) delete det; + Py_Return; + } + if(!det) + return Py::new_reference_to(Py::True()); + return Base::Interpreter().createSWIGPointerObj("pivy.coin", "_p_SoDetail", (void*)det, 0); +} + +Py::Float AxisOriginPy::getAxisLength() const { + return Py::Float(getAxisOriginPtr()->getAxisLength()); +} + +void AxisOriginPy::setAxisLength(Py::Float size) { + getAxisOriginPtr()->setAxisLength(size); +} + +Py::Float AxisOriginPy::getLineWidth() const { + return Py::Float(getAxisOriginPtr()->getLineWidth()); +} + +void AxisOriginPy::setLineWidth(Py::Float size) { + getAxisOriginPtr()->setLineWidth(size); +} + +Py::Float AxisOriginPy::getPointSize() const { + return Py::Float(getAxisOriginPtr()->getPointSize()); +} + +void AxisOriginPy::setPointSize(Py::Float size) { + getAxisOriginPtr()->setPointSize(size); +} + +Py::Float AxisOriginPy::getScale() const { + return Py::Float(getAxisOriginPtr()->getScale()); +} + +void AxisOriginPy::setScale(Py::Float size) { + getAxisOriginPtr()->setScale(size); +} + +Py::Tuple AxisOriginPy::getPlane() const { + auto info = getAxisOriginPtr()->getPlane(); + Py::Tuple ret(2); + ret.setItem(0,Py::Float(info.first)); + ret.setItem(1,Py::Float(info.second)); + return ret; +} + +void AxisOriginPy::setPlane(Py::Tuple tuple) { + float s,d; + if (!PyArg_ParseTuple(*tuple, "dd",&s,&d)) + throw Py::Exception(); + getAxisOriginPtr()->setPlane(s,d); +} + +Py::Dict AxisOriginPy::getLabels() const { + Py::Dict dict; + for(auto &v : getAxisOriginPtr()->getLabels()) + dict.setItem(Py::String(v.first),Py::String(v.second)); + return dict; +} + +void AxisOriginPy::setLabels(Py::Dict dict) { + std::map labels; + for(auto it=dict.begin();it!=dict.end();++it) { + const auto &value = *it; + labels[value.first.as_string()] = Py::Object(value.second).as_string(); + } + getAxisOriginPtr()->setLabels(labels); +} + +Py::Object AxisOriginPy::getNode(void) const +{ + SoGroup* node = getAxisOriginPtr()->getNode(); + PyObject* Ptr = Base::Interpreter().createSWIGPointerObj("pivy.coin","SoGroup *", node, 1); + node->ref(); + return Py::Object(Ptr, true); +} + +PyObject *AxisOriginPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int AxisOriginPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 7e29453ad5..4377289b78 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -212,6 +212,7 @@ generate_from_xml(WorkbenchPy) generate_from_xml(SelectionObjectPy) generate_from_xml(LinkViewPy) generate_from_xml(ViewProviderLinkPy) +generate_from_xml(AxisOriginPy) generate_from_py(FreeCADGuiInit GuiInitScript.h) @@ -225,6 +226,7 @@ SET(FreeCADGui_XML_SRCS DocumentPy.xml LinkViewPy.xml ViewProviderLinkPy.xml + AxisOriginPy.xml ) SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS}) @@ -1001,6 +1003,8 @@ SET(Viewprovider_CPP_SRCS ViewProviderLink.cpp LinkViewPyImp.cpp ViewProviderLinkPyImp.cpp + AxisOriginPyImp.cpp + AxisOrigin.cpp ) SET(Viewprovider_SRCS ${Viewprovider_CPP_SRCS} @@ -1032,6 +1036,7 @@ SET(Viewprovider_SRCS ViewProviderMaterialObject.h ViewProviderTextDocument.h ViewProviderLink.h + AxisOrigin.h ) SOURCE_GROUP("View3D\\Viewprovider" FILES ${Viewprovider_SRCS}) diff --git a/src/Gui/Inventor/SoAutoZoomTranslation.cpp b/src/Gui/Inventor/SoAutoZoomTranslation.cpp index 34f7d58164..22b8ce8502 100644 --- a/src/Gui/Inventor/SoAutoZoomTranslation.cpp +++ b/src/Gui/Inventor/SoAutoZoomTranslation.cpp @@ -73,16 +73,20 @@ void SoAutoZoomTranslation::initClass() float SoAutoZoomTranslation::getScaleFactor(SoAction* action) const { + float scale = scaleFactor.getValue(); + if(!scale) + return 1.0; // Dividing by 5 seems to work well SbViewVolume vv = SoViewVolumeElement::get(action->getState()); float aspectRatio = SoViewportRegionElement::get(action->getState()).getViewportAspectRatio(); - float scale = vv.getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / (5*aspectRatio); + scale *= vv.getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / (5*aspectRatio); return scale; } SoAutoZoomTranslation::SoAutoZoomTranslation() { SO_NODE_CONSTRUCTOR(SoAutoZoomTranslation); + SO_NODE_ADD_FIELD(scaleFactor, (1.0f)); //SO_NODE_ADD_FIELD(abPos, (SbVec3f(0.f,0.f,0.f))); } diff --git a/src/Gui/Inventor/SoAutoZoomTranslation.h b/src/Gui/Inventor/SoAutoZoomTranslation.h index 954a75eb08..d763a6bd86 100644 --- a/src/Gui/Inventor/SoAutoZoomTranslation.h +++ b/src/Gui/Inventor/SoAutoZoomTranslation.h @@ -39,6 +39,8 @@ public: SoAutoZoomTranslation(); //SoSFVec3f abPos; + SoSFFloat scaleFactor; + protected: virtual ~SoAutoZoomTranslation() {}; virtual void doAction(SoAction * action); diff --git a/src/Gui/ViewProviderPlacement.cpp b/src/Gui/ViewProviderPlacement.cpp index c272bd56bc..3bd7cd7ad5 100644 --- a/src/Gui/ViewProviderPlacement.cpp +++ b/src/Gui/ViewProviderPlacement.cpp @@ -36,6 +36,7 @@ # include # include # include +# include # include # include #endif @@ -45,6 +46,7 @@ #include #include "ViewProviderPlacement.h" #include "SoFCSelection.h" +#include "SoFCUnifiedSelection.h" #include "Application.h" #include "Document.h" #include "View3DInventorViewer.h" @@ -61,63 +63,23 @@ using namespace Gui; PROPERTY_SOURCE(Gui::ViewProviderPlacement, Gui::ViewProviderGeometryObject) - ViewProviderPlacement::ViewProviderPlacement() { + // Change root node to SoFCSelectionRoot because we share the same + // AxisOrigin node for all instances of Placement + auto newRoot = new SoFCSelectionRoot(true); + for(int i=0;igetNumChildren();++i) + newRoot->addChild(pcRoot->getChild(i)); + pcRoot->unref(); + pcRoot = newRoot; + pcRoot->ref(); + sPixmap = "CoordinateSystem"; - pMat = new SoMaterial(); - pMat->ref(); - - const float dist = 2; - const float size = 6; - const float pSize = 4; - - static const SbVec3f verts[13] = - { - SbVec3f(0,0,0), SbVec3f(size,0,0), - SbVec3f(0,size,0), SbVec3f(0,0,size), - SbVec3f(dist,dist,0), SbVec3f(dist,pSize,0), SbVec3f(pSize,dist,0), // XY Plane - SbVec3f(dist,0,dist), SbVec3f(dist,0,pSize), SbVec3f(pSize,0,dist), // XY Plane - SbVec3f(0,dist,dist), SbVec3f(0,pSize,dist), SbVec3f(0,dist,pSize) // XY Plane - }; - - // indexes used to create the edges - static const int32_t lines[21] = - { - 0,1,-1, - 0,2,-1, - 0,3,-1, - 5,4,6,-1, - 8,7,9,-1, - 11,10,12,-1 - }; - - pMat->diffuseColor.setNum(6); - pMat->diffuseColor.set1Value(0, SbColor(1.0f, 0.2f, 0.2f)); - pMat->diffuseColor.set1Value(1, SbColor(0.2f, 1.0f, 0.2f)); - pMat->diffuseColor.set1Value(2, SbColor(0.2f, 0.2f, 1.0f)); - - pMat->diffuseColor.set1Value(3, SbColor(1.0f, 1.0f, 0.8f)); - pMat->diffuseColor.set1Value(4, SbColor(1.0f, 0.8f, 1.0f)); - pMat->diffuseColor.set1Value(5, SbColor(0.8f, 1.0f, 1.0f)); - - pCoords = new SoCoordinate3(); - pCoords->ref(); - pCoords->point.setNum(13); - pCoords->point.setValues(0, 13, verts); - - pLines = new SoIndexedLineSet(); - pLines->ref(); - pLines->coordIndex.setNum(21); - pLines->coordIndex.setValues(0, 21, lines); - sPixmap = "view-measurement"; + OnTopWhenSelected.setValue(1); } ViewProviderPlacement::~ViewProviderPlacement() { - pCoords->unref(); - pLines->unref(); - pMat->unref(); } void ViewProviderPlacement::onChanged(const App::Property* prop) @@ -140,29 +102,24 @@ void ViewProviderPlacement::setDisplayMode(const char* ModeName) ViewProviderGeometryObject::setDisplayMode(ModeName); } +static std::unique_ptr Axis; + void ViewProviderPlacement::attach(App::DocumentObject* pcObject) { ViewProviderGeometryObject::attach(pcObject); - - SoAnnotation *lineSep = new SoAnnotation(); - - - SoAutoZoomTranslation *zoom = new SoAutoZoomTranslation; - - SoDrawStyle* style = new SoDrawStyle(); - style->lineWidth = 2.0f; - - SoMaterialBinding* matBinding = new SoMaterialBinding; - matBinding->value = SoMaterialBinding::PER_FACE; - - lineSep->addChild(zoom); - lineSep->addChild(style); - lineSep->addChild(matBinding); - lineSep->addChild(pMat); - lineSep->addChild(pCoords); - lineSep->addChild(pLines); - - addDisplayMaskMode(lineSep, "Base"); + if(!Axis) { + Axis.reset(new AxisOrigin); + std::map labels; + labels["O"] = "Origin"; + labels["X"] = "X-Axis"; + labels["Y"] = "Y-Axis"; + labels["Z"] = "Z-Axis"; + labels["XY"] = "XY-Plane"; + labels["XZ"] = "XZ-Plane"; + labels["YZ"] = "YZ-Plane"; + Axis->setLabels(labels); + } + addDisplayMaskMode(Axis->getNode(), "Base"); } void ViewProviderPlacement::updateData(const App::Property* prop) @@ -170,47 +127,27 @@ void ViewProviderPlacement::updateData(const App::Property* prop) ViewProviderGeometryObject::updateData(prop); } -std::string ViewProviderPlacement::getElement(const SoDetail* detail) const -{ - if (detail) { - if (detail->getTypeId() == SoLineDetail::getClassTypeId()) { - const SoLineDetail* line_detail = static_cast(detail); - int edge = line_detail->getLineIndex(); - switch (edge) - { - case 0: return std::string("X-Axis"); - case 1: return std::string("Y-Axis"); - case 2: return std::string("Z-Axis"); - case 3: return std::string("XY-Plane"); - case 4: return std::string("XZ-Plane"); - case 5: return std::string("YZ-Plane"); - } - } - } - - return std::string(""); +bool ViewProviderPlacement::getElementPicked(const SoPickedPoint *pp, std::string &subname) const { + if(!Axis) + return false; + return Axis->getElementPicked(pp,subname); } -SoDetail* ViewProviderPlacement::getDetail(const char* subelement) const +bool ViewProviderPlacement::getDetailPath( + const char *subname, SoFullPath *pPath, bool append, SoDetail *&det) const { - SoLineDetail* detail = 0; - std::string subelem(subelement); - int edge = -1; - - if(subelem == "X-Axis") edge = 0; - else if(subelem == "Y-Axis") edge = 1; - else if(subelem == "Z-Axis") edge = 2; - else if(subelem == "XY-Plane") edge = 3; - else if(subelem == "XZ-Plane") edge = 4; - else if(subelem == "YZ-Plane") edge = 5; - - if(edge >= 0) { - detail = new SoLineDetail(); - detail->setPartIndex(edge); + if(!Axis) + return false; + int length = pPath->getLength(); + if(append) { + pPath->append(pcRoot); + pPath->append(pcModeSwitch); } - - - return detail; + if(!Axis->getDetailPath(subname,pPath,det)) { + pPath->truncate(length); + return false; + } + return true; } bool ViewProviderPlacement::isSelectable(void) const @@ -219,4 +156,14 @@ bool ViewProviderPlacement::isSelectable(void) const } // ---------------------------------------------------------------------------- +// Python feature ----------------------------------------------------------------------- + +namespace Gui { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderPlacementPython, Gui::ViewProviderPlacement) +/// @endcond + +// explicit template instantiation +template class GuiExport ViewProviderPythonFeatureT; +} diff --git a/src/Gui/ViewProviderPlacement.h b/src/Gui/ViewProviderPlacement.h index a14ee67763..dfdf6fa034 100644 --- a/src/Gui/ViewProviderPlacement.h +++ b/src/Gui/ViewProviderPlacement.h @@ -24,7 +24,9 @@ #ifndef GUI_ViewProviderPlacement_H #define GUI_ViewProviderPlacement_H +#include "AxisOrigin.h" #include "ViewProviderGeometryObject.h" +#include "ViewProviderPythonFeature.h" #include class SoFontStyle; @@ -39,7 +41,6 @@ class SoMaterial; namespace Gui { - class GuiExport ViewProviderPlacement : public ViewProviderGeometryObject { PROPERTY_HEADER(Gui::ViewProviderPlacement); @@ -58,19 +59,17 @@ public: virtual bool useNewSelectionModel(void) const {return true;} /// indicates if the ViewProvider can be selected virtual bool isSelectable(void) const ; - /// return a hit element to the selection path or 0 - virtual std::string getElement(const SoDetail *) const; - virtual SoDetail* getDetail(const char*) const; + + virtual bool getElementPicked(const SoPickedPoint *pp, std::string &subname) const override; + virtual bool getDetailPath(const char *, SoFullPath *, bool, SoDetail *&) const override; protected: void onChanged(const App::Property* prop); -private: - SoCoordinate3 * pCoords; - SoMaterial * pMat; - SoIndexedLineSet * pLines; }; +typedef ViewProviderPythonFeatureT ViewProviderPlacementPython; + } //namespace Gui diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumCS.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumCS.cpp index d7bbadfe16..c334d491c5 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumCS.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumCS.cpp @@ -24,7 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include +# include # include # include # include @@ -32,8 +32,12 @@ # include # include # include +# include +# include #endif +#include +#include #include "TaskDatumParameters.h" #include @@ -43,13 +47,33 @@ using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumCoordinateSystem,PartDesignGui::ViewProviderDatum) +const App::PropertyFloatConstraint::Constraints ZoomConstraint = {0.0,DBL_MAX,0.2}; +const App::PropertyIntegerConstraint::Constraints FontConstraint = {1,INT_MAX,1}; + ViewProviderDatumCoordinateSystem::ViewProviderDatumCoordinateSystem() { + Zoom.setConstraints(&ZoomConstraint); + FontSize.setConstraints(&FontConstraint); + + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/PartDesign"); + auto fontSize = hGrp->GetInt("CoordinateSystemFontSize",10); + auto zoom = hGrp->GetFloat("CoordinateSystemZoom",1.0); + auto showLabel = hGrp->GetBool("CoordinateSystemShowLabel",false); + + ADD_PROPERTY_TYPE(FontSize, (fontSize), "Datum", App::Prop_None, ""); + ADD_PROPERTY_TYPE(Zoom, (zoom), "Datum", App::Prop_None, ""); + ADD_PROPERTY_TYPE(ShowLabel, (showLabel), "Datum", App::Prop_None, ""); + + if(hGrp->GetBool("CoordinateSystemSelectOnTop",true)) + OnTopWhenSelected.setValue(1); + sPixmap = "PartDesign_CoordinateSystem.svg"; coord = new SoCoordinate3(); coord->ref(); font = new SoFont(); + font->size = FontSize.getValue(); font->ref(); axisLabelXTrans = new SoTranslation(); axisLabelXTrans->ref(); @@ -57,6 +81,11 @@ ViewProviderDatumCoordinateSystem::ViewProviderDatumCoordinateSystem() axisLabelXToYTrans->ref(); axisLabelYToZTrans = new SoTranslation(); axisLabelYToZTrans->ref(); + + autoZoom = new Gui::SoAutoZoomTranslation; + autoZoom->ref(); + + labelSwitch = 0; } ViewProviderDatumCoordinateSystem::~ViewProviderDatumCoordinateSystem() @@ -66,6 +95,9 @@ ViewProviderDatumCoordinateSystem::~ViewProviderDatumCoordinateSystem() axisLabelXTrans->unref(); axisLabelXToYTrans->unref(); axisLabelYToZTrans->unref(); + if(labelSwitch) + labelSwitch->unref(); + autoZoom->unref(); } void ViewProviderDatumCoordinateSystem::attach ( App::DocumentObject *obj ) { @@ -75,11 +107,13 @@ void ViewProviderDatumCoordinateSystem::attach ( App::DocumentObject *obj ) { material->diffuseColor.setNum(4); material->diffuseColor.set1Value(0, SbColor(0.f, 0.f, 0.f)); material->diffuseColor.set1Value(1, SbColor(1.f, 0.f, 0.f)); - material->diffuseColor.set1Value(2, SbColor(0.f, 1.f, 0.f)); + material->diffuseColor.set1Value(2, SbColor(0.f, 0.6f, 0.f)); material->diffuseColor.set1Value(3, SbColor(0.f, 0.f, 1.f)); SoMaterialBinding* binding = new SoMaterialBinding(); binding->value = SoMaterialBinding::PER_FACE_INDEXED; + autoZoom->scaleFactor.setValue(Zoom.getValue()); + getShapeRoot ()->addChild(autoZoom); getShapeRoot ()->addChild(binding); getShapeRoot ()->addChild(material); @@ -114,55 +148,126 @@ void ViewProviderDatumCoordinateSystem::attach ( App::DocumentObject *obj ) { lineSet->materialIndex.set1Value(2,3); getShapeRoot ()->addChild(lineSet); - getShapeRoot ()->addChild(font); + setupLabels(); +} + +void ViewProviderDatumCoordinateSystem::setupLabels() { + + if(!ShowLabel.getValue()) { + if(labelSwitch) + labelSwitch->whichChild = -1; + return; + }else if(labelSwitch) { + labelSwitch->whichChild = 0; + return; + } + + labelSwitch = new SoSwitch; + labelSwitch->ref(); + + getShapeRoot ()->addChild(labelSwitch); + + SoGroup *labelGroup = new SoGroup; + labelSwitch->addChild(labelGroup); + labelSwitch->whichChild = 0; + + labelGroup->addChild(font); // Transformation for axis labels are relative so no need in separators - getShapeRoot ()->addChild(axisLabelXTrans); - SoAsciiText* t = new SoAsciiText(); + labelGroup->addChild(axisLabelXTrans); + auto* t = new SoText2(); t->string = "X"; - getShapeRoot ()->addChild(t); + labelGroup->addChild(t); - getShapeRoot ()->addChild(axisLabelXToYTrans); - t = new SoAsciiText(); + labelGroup->addChild(axisLabelXToYTrans); + t = new SoText2(); t->string = "Y"; - getShapeRoot ()->addChild(t); + labelGroup->addChild(t); - getShapeRoot ()->addChild(axisLabelYToZTrans); - SoRotation *rot = new SoRotation(); - rot->rotation = SbRotation(SbVec3f(1,1,1), static_cast(2*M_PI/3)); - getShapeRoot ()->addChild(rot); - t = new SoAsciiText(); + labelGroup->addChild(axisLabelYToZTrans); + t = new SoText2(); t->string = "Z"; - getShapeRoot ()->addChild(t); + labelGroup->addChild(t); } void ViewProviderDatumCoordinateSystem::updateData(const App::Property* prop) { - if (strcmp(prop->getName(),"Placement") == 0) { + if (strcmp(prop->getName(),"Placement") == 0) updateExtents (); - } ViewProviderDatum::updateData(prop); } +void ViewProviderDatumCoordinateSystem::onChanged(const App::Property *prop) { + if(getObject()) { + if(prop == &ShowLabel) + setupLabels(); + else if(prop == &Zoom) { + autoZoom->scaleFactor.setValue(Zoom.getValue()); + updateExtents (); + } else if(prop == &FontSize) + font->size = FontSize.getValue(); + } + ViewProviderDatum::onChanged(prop); +} + void ViewProviderDatumCoordinateSystem::setExtents (Base::BoundBox3d bbox) { // Axis length of the CS is 1/3 of maximum bbox dimension, any smarter sizing will make it only worse - double axisLength = std::max ( { bbox.LengthX (), bbox.LengthY(), bbox.LengthZ() } ); - axisLength *= (1 + marginFactor ()) / 3; + double axisLength; + + if(Zoom.getValue()) { + axisLength = 6 * Zoom.getValue(); + }else{ + axisLength = std::max ( { bbox.LengthX (), bbox.LengthY(), bbox.LengthZ() } ); + axisLength *= (1 + marginFactor ()) / 3; + } coord->point.set1Value ( 0, 0, 0, 0 ); coord->point.set1Value ( 1, axisLength, 0, 0 ); coord->point.set1Value ( 2, 0, axisLength, 0 ); coord->point.set1Value ( 3, 0, 0, axisLength ); - double fontSz = axisLength / 10.; - font->size = fontSz; - - double labelPos = 9./10.*axisLength; - double labelOffset = fontSz/8.; + double labelPos = axisLength; + double labelOffset = 0; // offset 1 pixel axisLabelXTrans->translation.setValue ( SbVec3f( labelPos, labelOffset, 0) ); axisLabelXToYTrans->translation.setValue ( SbVec3f( -labelPos + labelOffset, labelPos - labelOffset, 0) ); axisLabelYToZTrans->translation.setValue ( SbVec3f( -labelOffset, -labelPos + labelOffset, labelPos) ); } + +std::string ViewProviderDatumCoordinateSystem::getElement(const SoDetail* detail) const +{ + if (detail && detail->getTypeId() == SoLineDetail::getClassTypeId()) { + const SoLineDetail* line_detail = static_cast(detail); + switch(line_detail->getLineIndex()) { + case 0: + return "X"; + case 1: + return "Y"; + case 2: + return "Z"; + } + } + + return std::string(); +} + +SoDetail* ViewProviderDatumCoordinateSystem::getDetail(const char* subelement) const +{ + if (strcmp(subelement,"X")==0) { + SoLineDetail* detail = new SoLineDetail(); + detail->setLineIndex(0); + return detail; + } else if (strcmp(subelement,"Y")==0) { + SoLineDetail* detail = new SoLineDetail(); + detail->setLineIndex(1); + return detail; + } else if (strcmp(subelement,"Z")==0) { + SoLineDetail* detail = new SoLineDetail(); + detail->setLineIndex(2); + return detail; + } + return NULL; +} + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumCS.h b/src/Mod/PartDesign/Gui/ViewProviderDatumCS.h index b26cc2ae0e..0a7602c7c5 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumCS.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumCS.h @@ -30,6 +30,10 @@ class SoFont; class SoTranslation; +namespace Gui { +class SoAutoZoomTranslation; +} + namespace PartDesignGui { class PartDesignGuiExport ViewProviderDatumCoordinateSystem : public PartDesignGui::ViewProviderDatum @@ -37,20 +41,34 @@ class PartDesignGuiExport ViewProviderDatumCoordinateSystem : public PartDesignG PROPERTY_HEADER(PartDesignGui::ViewProviderDatumCoordinateSystem); public: + App::PropertyFloatConstraint Zoom; + App::PropertyIntegerConstraint FontSize; + App::PropertyBool ShowLabel; + /// Constructor ViewProviderDatumCoordinateSystem(); virtual ~ViewProviderDatumCoordinateSystem(); virtual void attach ( App::DocumentObject *obj ); virtual void updateData(const App::Property*); + virtual void onChanged(const App::Property*); virtual void setExtents (Base::BoundBox3d bbox); + + virtual SoDetail* getDetail(const char* subelement) const; + virtual std::string getElement(const SoDetail* detail) const; + +private: + void setupLabels(); + private: SoCoordinate3 *coord; SoTranslation *axisLabelXTrans; SoTranslation *axisLabelXToYTrans; SoTranslation *axisLabelYToZTrans; SoFont* font; + SoSwitch *labelSwitch; + Gui::SoAutoZoomTranslation *autoZoom; }; } // namespace PartDesignGui