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.
This commit is contained in:
Zheng, Lei
2019-07-12 08:32:28 +08:00
committed by wmayer
parent a9b866caa5
commit bc26820837
15 changed files with 811 additions and 140 deletions

View File

@@ -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();

View File

@@ -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<App::Placement>;
}

View File

@@ -28,6 +28,7 @@
#include <Base/Placement.h>
#include "FeaturePython.h"
#include "GeoFeature.h"
#include "PropertyGeo.h"
@@ -66,6 +67,7 @@ public:
};
typedef App::FeaturePythonT<App::Placement> PlacementPython;

View File

@@ -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();

211
src/Gui/AxisOrigin.cpp Normal file
View File

@@ -0,0 +1,211 @@
/****************************************************************************
* Copyright (c) 2019 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* 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 <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoSwitch.h>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoMaterialBinding.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoIndexedPointSet.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/SoFullPath.h>
#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;i<length;++i) {
auto node = path->getNodeFromTail(i);
if(node->isOfType(SoFCSelection::getClassTypeId())) {
subname = static_cast<SoFCSelection*>(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<std::string,std::string> &labels) {
this->labels = labels;
node.reset();
nodeMap.clear();
}

109
src/Gui/AxisOrigin.h Normal file
View File

@@ -0,0 +1,109 @@
/****************************************************************************
* Copyright (c) 2019 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* 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<float,float> 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<std::string,std::string> &labels);
/// Obtain the axis component names
const std::map<std::string,std::string> &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<std::string, std::string> labels;
CoinPtr<SoGroup> node;
std::map<std::string, CoinPtr<SoNode> > nodeMap;
};
} // namepsace Gui
#endif //GUI_AxisOrigin_H

85
src/Gui/AxisOriginPy.xml Normal file
View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="AxisOriginPy"
Twin="AxisOrigin"
TwinPointer="AxisOrigin"
Include="Gui/AxisOrigin.h"
Namespace="Gui"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
<UserDocu>Class for creating a Coin3D representation of a coordinate system</UserDocu>
</Documentation>
<Methode Name="getElementPicked" Const="true">
<Documentation>
<UserDocu>getElementPicked(pickPoint): return the picked subelement</UserDocu>
</Documentation>
</Methode>
<Methode Name="getDetailPath" Const="true">
<Documentation>
<UserDocu>
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
</UserDocu>
</Documentation>
</Methode>
<Attribute Name="AxisLength">
<Documentation>
<UserDocu>Get/set the axis length</UserDocu>
</Documentation>
<Parameter Name="AxisLength" Type="Float" />
</Attribute>
<Attribute Name="LineWidth">
<Documentation>
<UserDocu>Get/set the axis line width for rendering</UserDocu>
</Documentation>
<Parameter Name="LineWidth" Type="Float" />
</Attribute>
<Attribute Name="PointSize">
<Documentation>
<UserDocu>Get/set the origin point size for rendering</UserDocu>
</Documentation>
<Parameter Name="PointSize" Type="Float" />
</Attribute>
<Attribute Name="Scale">
<Documentation>
<UserDocu>Get/set auto scaling factor, 0 to disable</UserDocu>
</Documentation>
<Parameter Name="Scale" Type="Float" />
</Attribute>
<Attribute Name="Plane">
<Documentation>
<UserDocu>Get/set axis plane size and distance to axis line</UserDocu>
</Documentation>
<Parameter Name="Plane" Type="Tuple" />
</Attribute>
<Attribute Name="Labels">
<Documentation>
<UserDocu>
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
</UserDocu>
</Documentation>
<Parameter Name="Labels" Type="Dict" />
</Attribute>
<Attribute Name="Node" ReadOnly='true'>
<Documentation>
<UserDocu>Get the Coin3D node</UserDocu>
</Documentation>
<Parameter Name="Node" Type="Object" />
</Attribute>
</PythonExport>
</GenerateModel>

170
src/Gui/AxisOriginPyImp.cpp Normal file
View File

@@ -0,0 +1,170 @@
/****************************************************************************
* Copyright (c) 2019 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* 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 <Inventor/nodes/SoGroup.h>
# include <Inventor/details/SoDetail.h>
# include <Inventor/SoFullPath.h>
#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 "<AxisOrigin>";
}
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<SoPickedPoint*>(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<SoPath*>(ptr);
if(!pPath)
throw Base::TypeError("type must be of coin.SoPath");
SoDetail *det = 0;
if(!getAxisOriginPtr()->getDetailPath(
sub,static_cast<SoFullPath*>(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<std::string,std::string> 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;
}

View File

@@ -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})

View File

@@ -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)));
}

View File

@@ -39,6 +39,8 @@ public:
SoAutoZoomTranslation();
//SoSFVec3f abPos;
SoSFFloat scaleFactor;
protected:
virtual ~SoAutoZoomTranslation() {};
virtual void doAction(SoAction * action);

View File

@@ -36,6 +36,7 @@
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoIndexedPointSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoDrawStyle.h>
#endif
@@ -45,6 +46,7 @@
#include <Inventor/details/SoLineDetail.h>
#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;i<pcRoot->getNumChildren();++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<AxisOrigin> 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<std::string,std::string> 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<const SoLineDetail*>(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<ViewProviderPlacement>;
}

View File

@@ -24,7 +24,9 @@
#ifndef GUI_ViewProviderPlacement_H
#define GUI_ViewProviderPlacement_H
#include "AxisOrigin.h"
#include "ViewProviderGeometryObject.h"
#include "ViewProviderPythonFeature.h"
#include <QObject>
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<ViewProviderPlacement> ViewProviderPlacementPython;
} //namespace Gui

View File

@@ -24,7 +24,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/nodes/SoAsciiText.h>
# include <Inventor/nodes/SoText2.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoFont.h>
@@ -32,8 +32,12 @@
# include <Inventor/nodes/SoRotation.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/nodes/SoSwitch.h>
# include <Inventor/details/SoLineDetail.h>
#endif
#include <App/Application.h>
#include <Gui/Inventor/SoAutoZoomTranslation.h>
#include "TaskDatumParameters.h"
#include <Mod/Part/Gui/SoBrepEdgeSet.h>
@@ -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<float>(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<const SoLineDetail*>(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;
}

View File

@@ -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