diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 76778d5088..9b38665969 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -7,7 +7,7 @@ - [Install Xcode Command line tools](#install-xcode-cli-tools) - [Install Conda](#install-conda) - [Run the shell script](#run-the-shell-script) -- [Building FreeCAD on macOS using homebrew packages with & without formual file](#homebrew-build-fc-on-macos) +- [Building FreeCAD on macOS using homebrew packages with & without formula file](#homebrew-build-fc-on-macos) - [Requirements](#homebrew-requirements) - [Install required FreeCAD dependencies](#homebrew-install-required-deps) - [Limitations of using freecad formula file](#homebrew-limits-of-formula-file) diff --git a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp index cd6f0b2b07..ea83984b97 100644 --- a/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp +++ b/src/3rdParty/salomesmesh/src/NETGENPlugin/NETGENPlugin_Mesher.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -700,7 +701,13 @@ double NETGENPlugin_Mesher::GetDefaultMinSize(const TopoDS_Shape& geom, BRep_Tool::Triangulation ( TopoDS::Face( fExp.Current() ), loc); if ( triangulation.IsNull() ) continue; const double fTol = BRep_Tool::Tolerance( TopoDS::Face( fExp.Current() )); +#if OCC_VERSION_HEX < 0x070600 const TColgp_Array1OfPnt& points = triangulation->Nodes(); +#else + auto points = [&triangulation](Standard_Integer index) { + return triangulation->Node(index); + }; +#endif const Poly_Array1OfTriangle& trias = triangulation->Triangles(); for ( int iT = trias.Lower(); iT <= trias.Upper(); ++iT ) { diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp index 24dc2d00a6..8e78712f4a 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_Mesh.cpp @@ -64,7 +64,7 @@ #include -#undef _Precision_HeaderFile +//#undef _Precision_HeaderFile #include #include #include diff --git a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp index 5a07308310..fbb1b25008 100644 --- a/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp +++ b/src/3rdParty/salomesmesh/src/SMESH/SMESH_MeshAlgos.cpp @@ -38,10 +38,13 @@ #include #include #include -#include -#include +#include +#include #include #include +#include +#include +#include #include #include diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp index 88970f36b5..7c51601c7b 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Adaptive1D.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -318,13 +319,26 @@ namespace // internal utils { myFaceTol = SMESH_MesherHelper::MaxTolerance( face ); myTree = triaTree; +#if OCC_VERSION_HEX < 0x070600 myNodes = & tr->Nodes(); +#else + TColgp_Array1OfPnt* trNodes = new TColgp_Array1OfPnt( 1, tr->NbNodes() ); + for (Standard_Integer i = myNodes->Lower(); i <= myNodes->Upper(); i++) + { + trNodes->SetValue(i, tr->Node(i)); + } + myNodes = trNodes; + myOwnNodes = true; +#endif myPolyTrias = & tr->Triangles(); myTriasDeflection = tr->Deflection(); if ( !loc.IsIdentity() ) // transform nodes if necessary { TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() ); trsfNodes->Assign( *myNodes ); +#if OCC_VERSION_HEX >= 0x070600 + delete myNodes; // it's already a copy +#endif myNodes = trsfNodes; myOwnNodes = true; const gp_Trsf& trsf = loc; diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp index f7ac411d9a..5d5c15c366 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_Quadrangle_2D.cpp @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp index 8ee0e26832..e9f4618305 100644 --- a/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp +++ b/src/3rdParty/salomesmesh/src/StdMeshers/StdMeshers_ViscousLayers.cpp @@ -44,7 +44,10 @@ #include "SMESH_subMeshEventListener.hxx" #include "StdMeshers_FaceSide.hxx" +#include +#if OCC_VERSION_HEX < 0x070600 #include +#endif #include #include #include @@ -1340,8 +1343,13 @@ namespace VISCOUS_3D //case GeomAbs_SurfaceOfExtrusion: case GeomAbs_OffsetSurface: { +#if OCC_VERSION_HEX < 0x070600 Handle(Adaptor3d_HSurface) base = surface.BasisSurface(); return getRovolutionAxis( base->Surface(), axis ); +#else + Handle(Adaptor3d_Surface) base = surface.BasisSurface(); + return getRovolutionAxis( *base, axis ); +#endif } default: return false; } diff --git a/src/App/ComplexGeoData.cpp b/src/App/ComplexGeoData.cpp index 658fc67110..da6890b96b 100644 --- a/src/App/ComplexGeoData.cpp +++ b/src/App/ComplexGeoData.cpp @@ -97,7 +97,7 @@ Base::Placement ComplexGeoData::getPlacement() const Base::Rotation(mat)); } -void ComplexGeoData::getLinesFromSubelement(const Segment*, +void ComplexGeoData::getLinesFromSubElement(const Segment*, std::vector &Points, std::vector &lines) const { @@ -105,7 +105,7 @@ void ComplexGeoData::getLinesFromSubelement(const Segment*, (void)lines; } -void ComplexGeoData::getFacesFromSubelement(const Segment*, +void ComplexGeoData::getFacesFromSubElement(const Segment*, std::vector &Points, std::vector &PointNormals, std::vector &faces) const diff --git a/src/App/ComplexGeoData.h b/src/App/ComplexGeoData.h index 6244096900..06bbf206bd 100644 --- a/src/App/ComplexGeoData.h +++ b/src/App/ComplexGeoData.h @@ -85,12 +85,12 @@ public: /// get subelement by combined name virtual Segment* getSubElementByName(const char* Name) const; /** Get lines from segment */ - virtual void getLinesFromSubelement( + virtual void getLinesFromSubElement( const Segment*, std::vector &Points, std::vector &lines) const; /** Get faces from segment */ - virtual void getFacesFromSubelement( + virtual void getFacesFromSubElement( const Segment*, std::vector &Points, std::vector &PointNormals, diff --git a/src/App/ComplexGeoDataPy.xml b/src/App/ComplexGeoDataPy.xml index c341734a18..2202ccf8d8 100644 --- a/src/App/ComplexGeoDataPy.xml +++ b/src/App/ComplexGeoDataPy.xml @@ -5,7 +5,7 @@ Name="ComplexGeoDataPy" Twin="ComplexGeoData" Include="App/ComplexGeoData.h" - TwinPointer="ComplexGeoData" + TwinPointer="ComplexGeoData" Namespace="Data" FatherInclude="Base/PersistencePy.h" FatherNamespace="Base" @@ -14,34 +14,79 @@ Father of all complex geometric data types - + + + Return a list of element types + + + + + Return the number of elements of a type + + + Return vertexes and faces from a sub-element - - - Get the BoundBox of the object - - - - - - Get the current transformation of the object as placement - - - - - - Get the current transformation of the object as matrix - - - - - - Geometry Tag - - - + + + Return vertexes and lines from a sub-element + + + + + Return a tuple of points and normals with a given accuracy + + + + + Return a tuple of points and lines with a given accuracy + + + + + Return a tuple of points and triangles with a given accuracy + + + + + Apply an additional translation to the placement + + + + + Apply an additional rotation to the placement + + + + + Apply a transformation to the underlying geometry + + + + + Get the BoundBox of the object + + + + + + Get the center of gravity + + + + + + Get the current transformation of the object as placement + + + + + + Geometry Tag + + + diff --git a/src/App/ComplexGeoDataPyImp.cpp b/src/App/ComplexGeoDataPyImp.cpp index a89e02b29d..867d3969c1 100644 --- a/src/App/ComplexGeoDataPyImp.cpp +++ b/src/App/ComplexGeoDataPyImp.cpp @@ -22,6 +22,9 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif #include "ComplexGeoData.h" @@ -38,29 +41,195 @@ using namespace Data; using namespace Base; // returns a string which represent the object e.g. when printed in python -std::string ComplexGeoDataPy::representation(void) const +std::string ComplexGeoDataPy::representation() const { return std::string(""); } -PyObject* ComplexGeoDataPy::getFacesFromSubelement(PyObject *args) +PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + + std::vector types = getComplexGeoDataPtr()->getElementTypes(); + Py::List list; + for (auto it : types) { + list.append(Py::String(it)); + } + return Py::new_reference_to(list); +} + +PyObject* ComplexGeoDataPy::countSubElements(PyObject *args) { char *type; - int index; - if (!PyArg_ParseTuple(args, "si", &type, &index)) - return 0; + if (!PyArg_ParseTuple(args, "s", &type)) + return nullptr; + + try { + unsigned long count = getComplexGeoDataPtr()->countSubElements(type); + return Py::new_reference_to(Py::Long(count)); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to count sub-elements from object"); + return nullptr; + } +} + +PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args) +{ + char *type; + unsigned long index; + if (!PyArg_ParseTuple(args, "sk", &type, &index)) + return nullptr; std::vector points; std::vector normals; std::vector facets; try { - Data::Segment* segm = getComplexGeoDataPtr()->getSubElement(type, index); - getComplexGeoDataPtr()->getFacesFromSubelement(segm, points, normals, facets); - delete segm; + std::unique_ptr segm(getComplexGeoDataPtr()->getSubElement(type, index)); + getComplexGeoDataPtr()->getFacesFromSubElement(segm.get(), points, normals, facets); } catch (...) { PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object"); - return 0; + return nullptr; + } + + Py::Tuple tuple(2); + Py::List vertex; + for (std::vector::const_iterator it = points.begin(); + it != points.end(); ++it) + vertex.append(Py::asObject(new Base::VectorPy(*it))); + tuple.setItem(0, vertex); + Py::List facet; + for (std::vector::const_iterator + it = facets.begin(); it != facets.end(); ++it) { + Py::Tuple f(3); + f.setItem(0,Py::Int(int(it->I1))); + f.setItem(1,Py::Int(int(it->I2))); + f.setItem(2,Py::Int(int(it->I3))); + facet.append(f); + } + tuple.setItem(1, facet); + return Py::new_reference_to(tuple); +} + +PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args) +{ + char *type; + int index; + if (!PyArg_ParseTuple(args, "si", &type, &index)) + return nullptr; + + std::vector points; + std::vector lines; + try { + std::unique_ptr segm(getComplexGeoDataPtr()->getSubElement(type, index)); + getComplexGeoDataPtr()->getLinesFromSubElement(segm.get(), points, lines); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object"); + return nullptr; + } + + Py::Tuple tuple(2); + Py::List vertex; + for (std::vector::const_iterator it = points.begin(); + it != points.end(); ++it) + vertex.append(Py::asObject(new Base::VectorPy(*it))); + tuple.setItem(0, vertex); + Py::List line; + for (std::vector::const_iterator + it = lines.begin(); it != lines.end(); ++it) { + Py::Tuple l(2); + l.setItem(0,Py::Int((int)it->I1)); + l.setItem(1,Py::Int((int)it->I2)); + line.append(l); + } + tuple.setItem(1, line); + return Py::new_reference_to(tuple); +} + +PyObject* ComplexGeoDataPy::getPoints(PyObject *args) +{ + double accuracy = 0.05; + if (!PyArg_ParseTuple(args, "d", &accuracy)) + return nullptr; + + std::vector points; + std::vector normals; + try { + getComplexGeoDataPtr()->getPoints(points, normals, accuracy); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object"); + return nullptr; + } + + Py::Tuple tuple(2); + Py::List vertex; + for (std::vector::const_iterator it = points.begin(); + it != points.end(); ++it) { + vertex.append(Py::asObject(new Base::VectorPy(*it))); + } + tuple.setItem(0, vertex); + + Py::List normal; + for (std::vector::const_iterator it = normals.begin(); + it != normals.end(); ++it) { + vertex.append(Py::asObject(new Base::VectorPy(*it))); + } + tuple.setItem(1, normal); + return Py::new_reference_to(tuple); +} + +PyObject* ComplexGeoDataPy::getLines(PyObject *args) +{ + double accuracy = 0.05; + if (!PyArg_ParseTuple(args, "d", &accuracy)) + return nullptr; + + std::vector points; + std::vector lines; + try { + getComplexGeoDataPtr()->getLines(points, lines, accuracy); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object"); + return nullptr; + } + + Py::Tuple tuple(2); + Py::List vertex; + for (std::vector::const_iterator it = points.begin(); + it != points.end(); ++it) + vertex.append(Py::asObject(new Base::VectorPy(*it))); + tuple.setItem(0, vertex); + Py::List line; + for (std::vector::const_iterator + it = lines.begin(); it != lines.end(); ++it) { + Py::Tuple l(2); + l.setItem(0,Py::Int((int)it->I1)); + l.setItem(1,Py::Int((int)it->I2)); + line.append(l); + } + tuple.setItem(1, line); + return Py::new_reference_to(tuple); +} + +PyObject* ComplexGeoDataPy::getFaces(PyObject *args) +{ + double accuracy = 0.05; + if (!PyArg_ParseTuple(args, "d", &accuracy)) + return nullptr; + + std::vector points; + std::vector facets; + try { + getComplexGeoDataPtr()->getFaces(points, facets, accuracy); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object"); + return nullptr; } Py::Tuple tuple(2); @@ -82,17 +251,76 @@ PyObject* ComplexGeoDataPy::getFacesFromSubelement(PyObject *args) return Py::new_reference_to(tuple); } -Py::Object ComplexGeoDataPy::getBoundBox(void) const +PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type),&obj)) + return nullptr; + + try { + Base::Vector3d move = static_cast(obj)->value(); + getComplexGeoDataPtr()->applyTranslation(move); + Py_Return; + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation"); + return nullptr; + } +} + +PyObject* ComplexGeoDataPy::applyRotation(PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type),&obj)) + return nullptr; + + try { + Base::Rotation rot = static_cast(obj)->value(); + getComplexGeoDataPtr()->applyRotation(rot); + Py_Return; + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation"); + return nullptr; + } +} + +PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj)) + return nullptr; + + try { + Base::Matrix4D mat = static_cast(obj)->value(); + getComplexGeoDataPtr()->transformGeometry(mat); + Py_Return; + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "failed to transform geometry"); + return nullptr; + } +} + +Py::Object ComplexGeoDataPy::getBoundBox() const { return Py::BoundingBox(getComplexGeoDataPtr()->getBoundBox()); } -Py::Object ComplexGeoDataPy::getPlacement(void) const +Py::Object ComplexGeoDataPy::getCenterOfGravity() const +{ + Base::Vector3d center; + if (getComplexGeoDataPtr()->getCenterOfGravity(center)) + return Py::Vector(center); + throw Py::RuntimeError("Cannot get center of gravity"); +} + +Py::Object ComplexGeoDataPy::getPlacement() const { return Py::Placement(getComplexGeoDataPtr()->getPlacement()); } -void ComplexGeoDataPy::setPlacement(Py::Object arg) +void ComplexGeoDataPy::setPlacement(Py::Object arg) { PyObject* p = arg.ptr(); if (PyObject_TypeCheck(p, &(Base::PlacementPy::Type))) { @@ -106,40 +334,40 @@ void ComplexGeoDataPy::setPlacement(Py::Object arg) } } -Py::Object ComplexGeoDataPy::getMatrix(void) const +Py::Int ComplexGeoDataPy::getTag() const { - return Py::Matrix(getComplexGeoDataPtr()->getTransform()); -} - -// FIXME would be better to call it setTransform() as in all other interfaces... -void ComplexGeoDataPy::setMatrix(Py::Object arg) -{ - PyObject* p = arg.ptr(); - if (PyObject_TypeCheck(p, &(Base::MatrixPy::Type))) { - Base::Matrix4D mat = static_cast(p)->value(); - getComplexGeoDataPtr()->setTransform(mat); - } - else { - std::string error = std::string("type must be 'Matrix', not "); - error += p->ob_type->tp_name; - throw Py::TypeError(error); - } -} - -Py::Int ComplexGeoDataPy::getTag() const { return Py::Int(getComplexGeoDataPtr()->Tag); } -void ComplexGeoDataPy::setTag(Py::Int tag) { +void ComplexGeoDataPy::setTag(Py::Int tag) +{ getComplexGeoDataPtr()->Tag = tag; } -PyObject *ComplexGeoDataPy::getCustomAttributes(const char* /*attr*/) const +PyObject* ComplexGeoDataPy::getCustomAttributes(const char* attr) const { - return 0; + // Support for backward compatibility + if (strcmp(attr, "Matrix") == 0) { + Py::Matrix mat(getComplexGeoDataPtr()->getTransform()); + return Py::new_reference_to(mat); + } + return nullptr; } -int ComplexGeoDataPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +int ComplexGeoDataPy::setCustomAttributes(const char* attr, PyObject* obj) { + // Support for backward compatibility + if (strcmp(attr, "Matrix") == 0) { + if (PyObject_TypeCheck(obj, &(Base::MatrixPy::Type))) { + Base::Matrix4D mat = static_cast(obj)->value(); + getComplexGeoDataPtr()->setTransform(mat); + return 1; + } + else { + std::string error = std::string("type must be 'Matrix', not "); + error += obj->ob_type->tp_name; + throw Py::TypeError(error); + } + } return 0; } diff --git a/src/Doc/ThirdPartyLibraries.html b/src/Doc/ThirdPartyLibraries.html index c83ba73957..833edfa871 100644 --- a/src/Doc/ThirdPartyLibraries.html +++ b/src/Doc/ThirdPartyLibraries.html @@ -56,7 +56,7 @@ DEALINGS IN THE SOFTWARE.

Coin3D

-

Web site: https://bitbucket.org/Coin3D/coin/

+

Web site: https://coin3d.github.io

Copyright: Coin is copyright (C) 1998-2013 Kongsberg Oil & Gas Technologies AS

License: BSD-3-clause

diff --git a/src/Gui/CommandT.h b/src/Gui/CommandT.h
index ee29102d9f..64154d8cca 100644
--- a/src/Gui/CommandT.h
+++ b/src/Gui/CommandT.h
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 namespace Gui {
@@ -40,11 +41,24 @@ public:
     static std::string str(const std::string& s) {
         return s;
     }
+    static std::string str(const char* s) {
+        return s;
+    }
+    static std::string str(const QString& s) {
+        return s.toStdString();
+    }
     static std::string str(const std::stringstream& s) {
         return s.str();
     }
+    static std::string str(const std::ostringstream& s) {
+        return s.str();
+    }
     static std::string str(const std::ostream& s) {
-        return dynamic_cast(s).str();
+        if (typeid(s) == typeid(std::ostringstream))
+            return dynamic_cast(s).str();
+        else if (typeid(s) == typeid(std::stringstream))
+            return dynamic_cast(s).str();
+        throw Base::TypeError("Not a std::stringstream or std::ostringstream");
     }
     static std::string toStr(boost::format& f) {
         return f.str();
@@ -152,6 +166,39 @@ inline void cmdAppDocument(const App::DocumentObject* obj, T&& cmd) {
     _cmdDocument(Gui::Command::Doc, obj, "App", std::forward(cmd));
 }
 
+/** Runs a command for accessing a document's attribute or method
+ * @param doc: pointer to a Document
+ * @param cmd: command string, supporting printf like formatter
+ *
+ * Example:
+ * @code{.cpp}
+ *      cmdAppDocumentArgs(obj, "addObject('%s')", "Part::Feature");
+ * @endcode
+ *
+ * Translates to command (assuming obj's document name is 'DocName':
+ * @code{.py}
+ *       App.getDocument('DocName').addObject('Part::Feature')
+ * @endcode
+ */
+template
+void cmdAppDocumentArgs(const App::Document* doc, const std::string& cmd, Args&&... args) {
+    std::string _cmd;
+    try {
+        boost::format fmt(cmd);
+        _cmd = FormatString::toStr(fmt, std::forward(args)...);
+        Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').%s",
+            doc->getName(), _cmd.c_str());
+    }
+    catch (const std::exception& e) {
+        Base::Console().Error("%s: %s\n", e.what(), cmd.c_str());
+    }
+    catch (const Base::Exception&) {
+        Base::Console().Error("App.getDocument('%s').%s\n",
+            doc->getName(), _cmd.c_str());
+        throw;
+    }
+}
+
 /** Runs a command for accessing an object's Gui::Document attribute or method
  * This function is an alternative to FCMD_VOBJ_DOC_CMD
  * @param obj: pointer to a DocumentObject
diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp
index e3a63ef978..8b725210fb 100644
--- a/src/Gui/CommandView.cpp
+++ b/src/Gui/CommandView.cpp
@@ -2824,7 +2824,7 @@ static std::vector getBoxSelection(
                     continue;
                 std::vector points;
                 std::vector lines;
-                data->getLinesFromSubelement(segment.get(),points,lines);
+                data->getLinesFromSubElement(segment.get(),points,lines);
                 if(lines.empty()) {
                     if(points.empty())
                         continue;
diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp
index 05801cbeb5..35a335e9c3 100644
--- a/src/Gui/MainWindow.cpp
+++ b/src/Gui/MainWindow.cpp
@@ -633,24 +633,27 @@ bool MainWindow::closeAllDocuments (bool close)
     auto docs = App::GetApplication().getDocuments();
     try {
         docs = App::Document::getDependentDocuments(docs, true);
-    }catch(Base::Exception &e) {
+    }
+    catch(Base::Exception &e) {
         e.ReportException();
     }
+
     bool checkModify = true;
     bool saveAll = false;
     int failedSaves = 0;
-    for(auto doc : docs) {
+
+    for (auto doc : docs) {
         auto gdoc = Application::Instance->getDocument(doc);
-        if(!gdoc)
+        if (!gdoc)
             continue;
-        if(!gdoc->canClose(false))
+        if (!gdoc->canClose(false))
             return false;
-        if(!gdoc->isModified()
+        if (!gdoc->isModified()
                 || doc->testStatus(App::Document::PartialDoc)
                 || doc->testStatus(App::Document::TempDoc))
             continue;
         bool save = saveAll;
-        if(!save && checkModify) {
+        if (!save && checkModify) {
             int res = confirmSave(doc->Label.getStrValue().c_str(), this, docs.size()>1);
             switch (res)
             {
@@ -658,6 +661,7 @@ bool MainWindow::closeAllDocuments (bool close)
                 return false;
             case ConfirmSaveResult::SaveAll:
                 saveAll = true;
+                /* FALLTHRU */
             case ConfirmSaveResult::Save:
                 save = true;
                 break;
@@ -666,7 +670,7 @@ bool MainWindow::closeAllDocuments (bool close)
             }
         }
 
-        if(save && !gdoc->save())
+        if (save && !gdoc->save())
             failedSaves++;
     }
 
@@ -681,9 +685,9 @@ bool MainWindow::closeAllDocuments (bool close)
             return false;
     }
 
-    if(close)
+    if (close)
         App::GetApplication().closeAllDocuments();
-    // d->mdiArea->closeAllSubWindows();
+
     return true;
 }
 
diff --git a/src/Gui/Splashscreen.cpp b/src/Gui/Splashscreen.cpp
index dbcd3cbd96..4b8e5b53fd 100644
--- a/src/Gui/Splashscreen.cpp
+++ b/src/Gui/Splashscreen.cpp
@@ -505,14 +505,14 @@ void AboutDialog::showLibraryInformation()
     // Coin3D
     li.name = QLatin1String("Coin3D");
     li.href = baseurl + QLatin1String("#_TocCoin3D");
-    li.url = QLatin1String("https://bitbucket.org/Coin3D/coin/");
+    li.url = QLatin1String("https://coin3d.github.io");
     li.version = QLatin1String(COIN_VERSION);
     libInfo << li;
 
     // Eigen3
     li.name = QLatin1String("Eigen3");
     li.href = baseurl + QLatin1String("#_TocEigen3");
-    li.url = QLatin1String("http://eigen.tuxfamily.org/");
+    li.url = QLatin1String("http://eigen.tuxfamily.org");
     li.version = QString::fromLatin1(FC_EIGEN3_VERSION);
     libInfo << li;
 
diff --git a/src/Gui/ToolBarManager.cpp b/src/Gui/ToolBarManager.cpp
index b96167114c..7221c1fbb3 100644
--- a/src/Gui/ToolBarManager.cpp
+++ b/src/Gui/ToolBarManager.cpp
@@ -250,6 +250,11 @@ void ToolBarManager::setup(ToolBarItem* toolBarItems)
         (*it)->hide();
         (*it)->toggleViewAction()->setVisible(false);
     }
+
+    hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
+        ->GetGroup("Preferences")->GetGroup("General");
+    bool lockToolBars = hPref->GetBool("LockToolBars", false);
+    setMovable(!lockToolBars);
 }
 
 void ToolBarManager::setup(ToolBarItem* item, QToolBar* toolbar) const
@@ -314,6 +319,12 @@ void ToolBarManager::restoreState() const
             toolbar->setVisible(hPref->GetBool(toolbarName.constData(), toolbar->isVisible()));
         }
     }
+
+
+    hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
+        ->GetGroup("Preferences")->GetGroup("General");
+    bool lockToolBars = hPref->GetBool("LockToolBars", false);
+    setMovable(!lockToolBars);
 }
 
 void ToolBarManager::retranslate() const
@@ -327,6 +338,13 @@ void ToolBarManager::retranslate() const
     }
 }
 
+void Gui::ToolBarManager::setMovable(bool moveable) const
+{
+    for (auto& tb : toolBars()) {
+        tb->setMovable(moveable);
+    }
+}
+
 QToolBar* ToolBarManager::findToolBar(const QList& toolbars, const QString& item) const
 {
     for (QList::ConstIterator it = toolbars.begin(); it != toolbars.end(); ++it) {
diff --git a/src/Gui/ToolBarManager.h b/src/Gui/ToolBarManager.h
index 82230044f6..ed92657642 100644
--- a/src/Gui/ToolBarManager.h
+++ b/src/Gui/ToolBarManager.h
@@ -80,6 +80,8 @@ public:
     void restoreState() const;
     void retranslate() const;
 
+    void setMovable(bool movable) const;
+
 protected:
     void setup(ToolBarItem*, QToolBar*) const;
     /** Returns a list of all currently existing toolbars. */
diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp
index 2db9575fd1..ca752a5194 100644
--- a/src/Gui/Widgets.cpp
+++ b/src/Gui/Widgets.cpp
@@ -26,6 +26,7 @@
 # include 
 # include 
 # include 
+# include 
 # include 
 # include 
 # include 
@@ -594,6 +595,7 @@ struct ColorButtonP
     bool allowChange;
     bool autoChange;
     bool drawFrame;
+    bool allowTransparency;
     bool modal;
     bool dirty;
 
@@ -602,6 +604,7 @@ struct ColorButtonP
         , allowChange(true)
         , autoChange(false)
         , drawFrame(true)
+        , allowTransparency(false)
         , modal(true)
         , dirty(true)
     {
@@ -671,6 +674,21 @@ bool ColorButton::drawFrame() const
     return d->drawFrame;
 }
 
+void Gui::ColorButton::setAllowTransparency(bool allow)
+{
+    d->allowTransparency = allow;
+    if (d->cd)
+        d->cd->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, allow);
+}
+
+bool Gui::ColorButton::allowTransparency() const
+{
+    if (d->cd)
+        return d->cd->testOption(QColorDialog::ColorDialogOption::ShowAlphaChannel);
+    else
+        return d->allowTransparency;
+}
+
 void ColorButton::setModal(bool b)
 {
     d->modal = b;
@@ -763,6 +781,7 @@ void ColorButton::onChooseColor()
         QColor currentColor = d->col;
         QColorDialog cd(d->col, this);
         cd.setOptions(QColorDialog::DontUseNativeDialog);
+        cd.setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, d->allowTransparency);
 
         if (d->autoChange) {
             connect(&cd, SIGNAL(currentColorChanged(const QColor &)),
@@ -788,6 +807,7 @@ void ColorButton::onChooseColor()
             d->old = d->col;
             d->cd = new QColorDialog(d->col, this);
             d->cd->setOptions(QColorDialog::DontUseNativeDialog);
+            d->cd->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, d->allowTransparency);
             d->cd->setAttribute(Qt::WA_DeleteOnClose);
             connect(d->cd, SIGNAL(rejected()),
                     this, SLOT(onRejected()));
@@ -812,16 +832,15 @@ void ColorButton::onRejected()
 
 // ------------------------------------------------------------------------------
 
-UrlLabel::UrlLabel(QWidget * parent, Qt::WindowFlags f)
-  : QLabel(parent, f)
+UrlLabel::UrlLabel(QWidget* parent, Qt::WindowFlags f)
+    : QLabel(parent, f)
+    , _url (QStringLiteral("http://localhost"))
     , _launchExternal(true)
 {
-    _url = QString::fromLatin1("http://localhost");
-    setToolTip(this->_url);
-
-    if (qApp->styleSheet().isEmpty()) {
-        setStyleSheet(QString::fromLatin1("Gui--UrlLabel {color: #0000FF;text-decoration: underline;}"));
-    }
+    setToolTip(this->_url);    
+    setCursor(Qt::PointingHandCursor);
+    if (qApp->styleSheet().isEmpty())
+        setStyleSheet(QStringLiteral("Gui--UrlLabel {color: #0000FF;text-decoration: underline;}"));
 }
 
 UrlLabel::~UrlLabel()
@@ -833,40 +852,10 @@ void Gui::UrlLabel::setLaunchExternal(bool l)
     _launchExternal = l;
 }
 
-void UrlLabel::enterEvent ( QEvent * )
-{
-    setCursor(Qt::PointingHandCursor);
-}
-
-void UrlLabel::leaveEvent ( QEvent * )
-{
-    setCursor(Qt::ArrowCursor);
-}
-
-void UrlLabel::mouseReleaseEvent (QMouseEvent *)
+void UrlLabel::mouseReleaseEvent(QMouseEvent*)
 {
     if (_launchExternal) {
-        // The webbrowser Python module allows to start the system browser in an OS-independent way
-        Base::PyGILStateLocker lock;
-        PyObject* module = PyImport_ImportModule("webbrowser");
-        if (module) {
-            // get the methods dictionary and search for the 'open' method
-            PyObject* dict = PyModule_GetDict(module);
-            PyObject* func = PyDict_GetItemString(dict, "open");
-            if (func) {
-                PyObject* args = Py_BuildValue("(s)", (const char*)this->_url.toLatin1());
-#if PY_VERSION_HEX < 0x03090000
-                PyObject* result = PyEval_CallObject(func, args);
-#else
-                PyObject* result = PyObject_CallObject(func, args);
-#endif
-                // decrement the args and module reference
-                Py_XDECREF(result);
-                Py_DECREF(args);
-                Py_DECREF(module);
-            }
-        }
-    }
+        QDesktopServices::openUrl(this->_url);
     else {
         // Someone else will deal with it...
         Q_EMIT linkClicked(_url);
diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h
index 93e9d22bd1..cc8760d81f 100644
--- a/src/Gui/Widgets.h
+++ b/src/Gui/Widgets.h
@@ -203,6 +203,7 @@ class GuiExport ColorButton : public QPushButton
     Q_PROPERTY( QColor color READ color WRITE setColor )
     Q_PROPERTY( bool allowChangeColor READ allowChangeColor WRITE setAllowChangeColor )
     Q_PROPERTY( bool drawFrame READ drawFrame WRITE setDrawFrame )
+    Q_PROPERTY( bool allowTransparency READ allowTransparency WRITE setAllowTransparency)
 
 public:
     ColorButton(QWidget* parent = 0);
@@ -217,6 +218,9 @@ public:
     void setDrawFrame(bool);
     bool drawFrame() const;
 
+    void setAllowTransparency(bool);
+    bool allowTransparency() const;
+
     void setModal(bool);
     bool isModal() const;
 
@@ -272,8 +276,6 @@ public Q_SLOTS:
   void setLaunchExternal(bool l);
 
 protected:
-  void enterEvent ( QEvent * );
-  void leaveEvent ( QEvent * );
   void mouseReleaseEvent ( QMouseEvent * );
 
 private:
diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp
index cb54091f82..c1a50ab638 100644
--- a/src/Gui/Workbench.cpp
+++ b/src/Gui/Workbench.cpp
@@ -562,7 +562,7 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const
             *item << "Separator" << "Std_SetAppearance" << "Std_ToggleVisibility"
                   << "Std_ToggleSelectability" << "Std_TreeSelection"
                   << "Std_RandomColor" << "Separator" << "Std_Delete"
-                  << "Std_SendToPythonConsole";
+                  << "Std_SendToPythonConsole" << "Std_TransformManip";
         }
     }
     else if (strcmp(recipient,"Tree") == 0)
diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py
index 452fb7e90d..083bec0aa3 100644
--- a/src/Mod/AddonManager/AddonManager.py
+++ b/src/Mod/AddonManager/AddonManager.py
@@ -200,11 +200,14 @@ class CommandAddonManager:
                 m.setWindowIcon(QtGui.QIcon(":/icons/AddonManager.svg"))
                 m.setText(translate("AddonsInstaller",
                                     "You must restart FreeCAD for changes to take "
-                                    "effect. Press Ok to restart FreeCAD now, or "
-                                    "Cancel to restart later."))
+                                    "effect."))
                 m.setIcon(m.Warning)
                 m.setStandardButtons(m.Ok | m.Cancel)
                 m.setDefaultButton(m.Cancel)
+                okBtn = m.button(QtGui.QMessageBox.StandardButton.Ok)
+                cancelBtn = m.button(QtGui.QMessageBox.StandardButton.Cancel)
+                okBtn.setText(translate("AddonsInstaller","Restart now"))
+                cancelBtn.setText(translate("AddonsInstaller","Restart later"))
                 ret = m.exec_()
                 if ret == m.Ok:
                     shutil.rmtree(self.macro_repo_dir, onerror=self.remove_readonly)
diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py
index 1c40171a93..ca778b1cee 100644
--- a/src/Mod/Arch/InitGui.py
+++ b/src/Mod/Arch/InitGui.py
@@ -51,37 +51,83 @@ class ArchWorkbench(FreeCADGui.Workbench):
         import Draft_rc
         import DraftTools
         import DraftGui
-        from draftguitools import gui_circulararray
-        from draftguitools import gui_polararray
-        from draftguitools import gui_orthoarray
-        from draftguitools import gui_arrays
         import Arch_rc
         import Arch
 
+        from ArchStructure import _ArchStructureGroupCommand
+        from ArchAxis import _ArchAxisGroupCommand
+        from ArchPanel import CommandPanelGroup
+        from ArchMaterial import _ArchMaterialToolsCommand
+        from ArchPipe import _ArchPipeGroupCommand
+
+        stru_group = _ArchStructureGroupCommand
+        axis_group = _ArchAxisGroupCommand
+        pan_group  = CommandPanelGroup
+        mat_group  = _ArchMaterialToolsCommand
+        pipe_group = _ArchPipeGroupCommand
+
         # Set up command lists
-        self.archtools = ["Arch_Wall", "Arch_StructureTools", "Arch_Rebar",
-                          "Arch_CurtainWall","Arch_BuildingPart",
-                          "Arch_Project", "Arch_Site", "Arch_Building",
-                          "Arch_Floor", "Arch_Reference",
-                          "Arch_Window", "Arch_Roof", "Arch_AxisTools",
-                          "Arch_SectionPlane", "Arch_Space", "Arch_Stairs",
-                          "Arch_PanelTools", "Arch_Equipment",
-                          "Arch_Frame", "Arch_Fence", "Arch_Truss",
-                          "Arch_Profile","Arch_MaterialTools",
-                          "Arch_Schedule", "Arch_PipeTools",
-                          "Arch_CutPlane", "Arch_CutLine",
-                          "Arch_Add", "Arch_Remove", "Arch_Survey"]
-        self.utilities = ["Arch_Component", "Arch_CloneComponent",
-                          "Arch_SplitMesh", "Arch_MeshToShape",
-                          "Arch_SelectNonSolidMeshes", "Arch_RemoveShape",
-                          "Arch_CloseHoles", "Arch_MergeWalls", "Arch_Check",
-                          "Arch_ToggleIfcBrepFlag", "Arch_3Views",
-                          "Arch_IfcSpreadsheet", "Arch_ToggleSubs"]
+        self.archtools = ["Arch_Wall",
+                          ([QT_TRANSLATE_NOOP("Arch", "Structure tools")],
+                              list(stru_group.GetCommands(stru_group))), # tuple len=2: submenu
+                          ("Arch_StructureTools", ),                     # tuple len=1: toolbar flyout
+                          "Arch_Rebar_Submenu",      # will be replaced or removed
+                          "Arch_Rebar",              # may be replaced
+                          "Arch_CurtainWall",
+                          "Arch_BuildingPart",
+                          "Arch_Project",
+                          "Arch_Site",
+                          "Arch_Building",
+                          "Arch_Floor",
+                          "Arch_Reference",
+                          "Arch_Window",
+                          "Arch_Roof",
+                          ([QT_TRANSLATE_NOOP("Arch", "Axis tools")],
+                              list(axis_group.GetCommands(axis_group))),
+                          ("Arch_AxisTools", ),
+                          "Arch_SectionPlane",
+                          "Arch_Space",
+                          "Arch_Stairs",
+                          ([QT_TRANSLATE_NOOP("Arch", "Panel tools")],
+                              list(pan_group.GetCommands(pan_group))),
+                          ("Arch_PanelTools", ),
+                          "Arch_Equipment",
+                          "Arch_Frame",
+                          "Arch_Fence",
+                          "Arch_Truss",
+                          "Arch_Profile",
+                          ([QT_TRANSLATE_NOOP("Arch", "Material tools")],
+                              list(mat_group.GetCommands(mat_group))),
+                          ("Arch_MaterialTools", ),
+                          "Arch_Schedule",
+                          ([QT_TRANSLATE_NOOP("Arch", "Pipe tools")],
+                              list(pipe_group.GetCommands(pipe_group))),
+                          ("Arch_PipeTools", ),
+                          "Arch_CutPlane",
+                          "Arch_CutLine",
+                          "Arch_Add",
+                          "Arch_Remove",
+                          "Arch_Survey"]
+
+        self.utilities = ["Arch_Component",
+                          "Arch_CloneComponent",
+                          "Arch_SplitMesh",
+                          "Arch_MeshToShape",
+                          "Arch_SelectNonSolidMeshes",
+                          "Arch_RemoveShape",
+                          "Arch_CloseHoles",
+                          "Arch_MergeWalls",
+                          "Arch_Check",
+                          "Arch_ToggleIfcBrepFlag",
+                          "Arch_3Views",
+                          "Arch_IfcSpreadsheet",
+                          "Arch_ToggleSubs"]
 
         # Add the rebar tools from the Reinforcement addon, if available
         try:
             import RebarTools
         except Exception:
+            del self.archtools[3] # remove "Arch_Rebar_Submenu"
             pass
         else:
             class RebarGroupCommand:
@@ -97,42 +143,57 @@ class ArchWorkbench(FreeCADGui.Workbench):
                 def IsActive(self):
                     return not FreeCAD.ActiveDocument is None
             FreeCADGui.addCommand('Arch_RebarTools', RebarGroupCommand())
-            self.archtools[2] = "Arch_RebarTools"
+            self.archtools[3] = ([QT_TRANSLATE_NOOP("Arch", "Rebar tools")],
+                                    RebarTools.RebarCommands + ["Arch_Rebar"])
+            self.archtools[4] = ("Arch_RebarTools", )
 
         # Set up Draft command lists
         import draftutils.init_tools as it
         self.draft_drawing_commands = it.get_draft_drawing_commands()
         self.draft_annotation_commands = it.get_draft_annotation_commands()
         self.draft_modification_commands = it.get_draft_modification_commands()
+        self.draft_utility_commands = it.get_draft_utility_commands_menu()
         self.draft_context_commands = it.get_draft_context_commands()
-        self.draft_line_commands = it.get_draft_line_commands()
-        self.draft_utility_commands = it.get_draft_utility_commands()
 
         # Set up toolbars
-        self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Arch tools"), self.archtools)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft creation tools"), self.draft_drawing_commands)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"), self.draft_annotation_commands)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft modification tools"), self.draft_modification_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Workbench", "Arch tools"),
+                        self.archtools)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft creation tools"),
+                        self.draft_drawing_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"),
+                        self.draft_annotation_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft modification tools"),
+                        self.draft_modification_commands)
 
         # Set up menus
-        self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Arch"),
-                         QT_TRANSLATE_NOOP("arch", "Utilities")],
-                        self.utilities)
-        self.appendMenu(QT_TRANSLATE_NOOP("arch", "&Arch"), self.archtools)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Arch"),
+                      QT_TRANSLATE_NOOP("Arch", "Utilities")],
+                     self.utilities)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Arch")],
+                     self.archtools)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Draft"),
+                      QT_TRANSLATE_NOOP("Arch", "Creation")],
+                     self.draft_drawing_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Draft"),
+                      QT_TRANSLATE_NOOP("Arch", "Annotation")],
+                     self.draft_annotation_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Draft"),
+                      QT_TRANSLATE_NOOP("Arch", "Modification")],
+                     self.draft_modification_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Arch", "&Draft"),
+                      QT_TRANSLATE_NOOP("Arch", "Utilities")],
+                     self.draft_utility_commands)
 
-        self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
-                         QT_TRANSLATE_NOOP("arch", "Creation")],
-                        self.draft_drawing_commands)
-        self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
-                         QT_TRANSLATE_NOOP("arch", "Annotation")],
-                        self.draft_annotation_commands)
-        self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
-                         QT_TRANSLATE_NOOP("arch", "Modification")],
-                        self.draft_modification_commands)
-        self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"),
-                         QT_TRANSLATE_NOOP("arch", "Utilities")],
-                        self.draft_utility_commands
-                        + self.draft_context_commands)
         FreeCADGui.addIconPath(":/icons")
         FreeCADGui.addLanguagePath(":/translations")
 
diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp
index b0d9b35c7b..62dafc99a1 100644
--- a/src/Mod/Assembly/App/opendcm/core/property.hpp
+++ b/src/Mod/Assembly/App/opendcm/core/property.hpp
@@ -110,7 +110,7 @@ namespace dcm {
  * @{ */
 
 /**
- * @brief Exeption for property errors
+ * @brief Exception for property errors
  *
  * This exception is thrown when a property related error is detected, for example if a objects is ask for a
  * property which it does not own. This exceptions own the error-code range from 300-399.
diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py
index 5287778e8e..992fb7c418 100644
--- a/src/Mod/Draft/Draft.py
+++ b/src/Mod/Draft/Draft.py
@@ -422,9 +422,9 @@ if App.GuiUp:
     from draftviewproviders.view_text import (ViewProviderText,
                                               ViewProviderDraftText)
 
-from draftobjects.hatch import (Draft_Hatch_Object)
-from draftmake.make_hatch import (make_hatch, makeHatch)
+from draftobjects.hatch import (Hatch)
+from draftmake.make_hatch import (make_hatch)
 if App.GuiUp:
-    from draftviewproviders.view_hatch import (Draft_Hatch_ViewProvider)
+    from draftviewproviders.view_hatch import (ViewProviderDraftHatch)
 
 ## @}
diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py
index 8802be6af4..1952d50e0c 100644
--- a/src/Mod/Draft/InitGui.py
+++ b/src/Mod/Draft/InitGui.py
@@ -95,22 +95,38 @@ class DraftWorkbench(FreeCADGui.Workbench):
         self.drawing_commands = it.get_draft_drawing_commands()
         self.annotation_commands = it.get_draft_annotation_commands()
         self.modification_commands = it.get_draft_modification_commands()
+        self.utility_commands_menu = it.get_draft_utility_commands_menu()
+        self.utility_commands_toolbar = it.get_draft_utility_commands_toolbar()
         self.context_commands = it.get_draft_context_commands()
         self.line_commands = it.get_draft_line_commands()
-        self.utility_commands = it.get_draft_utility_commands()
-        self.utility_small = it.get_draft_small_commands()
 
         # Set up toolbars
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft creation tools"), self.drawing_commands)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"), self.annotation_commands)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft modification tools"), self.modification_commands)
-        self.appendToolbar(QT_TRANSLATE_NOOP("Draft", "Draft utility tools"), self.utility_small)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft creation tools"),
+                        self.drawing_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft annotation tools"),
+                        self.annotation_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft modification tools"),
+                        self.modification_commands)
+        it.init_toolbar(self,
+                        QT_TRANSLATE_NOOP("Draft", "Draft utility tools"),
+                        self.utility_commands_toolbar)
 
         # Set up menus
-        self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Drafting"), self.drawing_commands)
-        self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Annotation"), self.annotation_commands)
-        self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Modification"), self.modification_commands)
-        self.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Utilities"), self.utility_commands + self.context_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Draft", "&Drafting")],
+                     self.drawing_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Draft", "&Annotation")],
+                     self.annotation_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Draft", "&Modification")],
+                     self.modification_commands)
+        it.init_menu(self,
+                     [QT_TRANSLATE_NOOP("Draft", "&Utilities")],
+                     self.utility_commands_menu)
 
         # Set up preferences pages
         if hasattr(FreeCADGui, "draftToolBar"):
diff --git a/src/Mod/Draft/Resources/ui/preferences-draftsnap.ui b/src/Mod/Draft/Resources/ui/preferences-draftsnap.ui
index 9b4634878c..b4c44cd836 100644
--- a/src/Mod/Draft/Resources/ui/preferences-draftsnap.ui
+++ b/src/Mod/Draft/Resources/ui/preferences-draftsnap.ui
@@ -17,7 +17,16 @@
    
     6
    
-   
+   
+    9
+   
+   
+    9
+   
+   
+    9
+   
+   
     9
    
    
@@ -252,9 +261,9 @@
        
       
      
-     
-     
-     
+     
+     
+     
     
    
    
@@ -323,6 +332,25 @@
         
        
       
+      
+       
+        
+         <html><head/><body><p>If checked, the outline of a human figure is displayed at the bottom left corner of the grid. This option is only effective if the BIM workbench is installed and if &quot;Show grid border&quot; option is enabled.</p></body></html>
+        
+        
+         Show human figure
+        
+        
+         true
+        
+        
+         gridShowHuman
+        
+        
+         Mod/Draft
+        
+       
+      
       
        
         
@@ -525,7 +553,7 @@
           
            The color of the grid
           
-          
+          
            
             50
             50
@@ -572,7 +600,16 @@
      
       
        
-        
+        
+         0
+        
+        
+         0
+        
+        
+         0
+        
+        
          0
         
         
@@ -618,22 +655,31 @@
           
            5
           
+          
+           10
+          
           
            DraftEditMaxObjects
           
           
            Mod/Draft
           
-          
-           10
-          
          
         
        
       
       
        
-        
+        
+         0
+        
+        
+         0
+        
+        
+         0
+        
+        
          0
         
         
diff --git a/src/Mod/Draft/draftguitools/gui_hatch.py b/src/Mod/Draft/draftguitools/gui_hatch.py
index a853188a47..2f7f2a27a5 100644
--- a/src/Mod/Draft/draftguitools/gui_hatch.py
+++ b/src/Mod/Draft/draftguitools/gui_hatch.py
@@ -25,10 +25,11 @@
 
 import os
 import FreeCAD
+import draftguitools.gui_base as gui_base
+
 from draftutils.translate import translate, QT_TRANSLATE_NOOP
 
-
-class Draft_Hatch:
+class Draft_Hatch(gui_base.GuiCommandSimplest):
 
 
     def GetResources(self):
@@ -36,7 +37,7 @@ class Draft_Hatch:
         return {'Pixmap'  : "Draft_Hatch",
                 'MenuText': QT_TRANSLATE_NOOP("Draft_Hatch", "Hatch"),
                 'Accel': "H, A",
-                'ToolTip' : QT_TRANSLATE_NOOP("Draft_Hatch", "Create hatches on selected faces")}
+                'ToolTip' : QT_TRANSLATE_NOOP("Draft_Hatch", "Creates hatches on the faces of a selected object")}
 
     def Activated(self):
 
@@ -89,7 +90,7 @@ class Draft_Hatch_TaskPanel:
             # create new hatch object
             FreeCAD.ActiveDocument.openTransaction("Create Hatch")
             FreeCADGui.addModule("Draft")
-            cmd = "Draft.makeHatch("
+            cmd = "Draft.make_hatch("
             cmd += "baseobject=FreeCAD.ActiveDocument.getObject(\""+self.baseobj.Name
             cmd += "\"),filename=\""+self.form.File.property("fileName")
             cmd += "\",pattern=\""+self.form.Pattern.currentText()
diff --git a/src/Mod/Draft/draftguitools/gui_rectangles.py b/src/Mod/Draft/draftguitools/gui_rectangles.py
index 9831700112..3d9776fb1a 100644
--- a/src/Mod/Draft/draftguitools/gui_rectangles.py
+++ b/src/Mod/Draft/draftguitools/gui_rectangles.py
@@ -125,7 +125,7 @@ class Rectangle(gui_base_original.Creator):
                 self.commit(translate("draft", "Create Plane"),
                             _cmd_list)
             else:
-                _cmd = 'Draft.makeRectangle'
+                _cmd = 'Draft.make_rectangle'
                 _cmd += '('
                 _cmd += 'length=' + str(length) + ', '
                 _cmd += 'height=' + str(height) + ', '
diff --git a/src/Mod/Draft/draftguitools/gui_texts.py b/src/Mod/Draft/draftguitools/gui_texts.py
index ef40496ffb..74efe4dab7 100644
--- a/src/Mod/Draft/draftguitools/gui_texts.py
+++ b/src/Mod/Draft/draftguitools/gui_texts.py
@@ -85,6 +85,9 @@ class Text(gui_base_original.Creator):
 
     def createObject(self):
         """Create the actual object in the current document."""
+        rot, sup, pts, fil = self.getStrings()
+        base = pts[1:-1]
+
         text_list = self.text
         text_list = [text.replace("\"","\\\"") for text in text_list]
 
@@ -108,9 +111,12 @@ class Text(gui_base_original.Creator):
         _cmd = 'Draft.make_text'
         _cmd += '('
         _cmd += string + ', '
-        _cmd += 'placement=' + DraftVecUtils.toString(self.node[0])
+        _cmd += 'placement=pl'
         _cmd += ')'
-        _cmd_list = ['_text_ = ' + _cmd,
+        _cmd_list = ['pl = FreeCAD.Placement()',
+                     'pl.Rotation.Q = ' + rot,
+                     'pl.Base = ' + base,
+                     '_text_ = ' + _cmd,
                      'Draft.autogroup(_text_)',
                      'FreeCAD.ActiveDocument.recompute()']
         self.commit(translate("draft", "Create Text"),
diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py
index 2756a6786c..ae5ed9a563 100644
--- a/src/Mod/Draft/draftguitools/gui_trackers.py
+++ b/src/Mod/Draft/draftguitools/gui_trackers.py
@@ -1009,6 +1009,13 @@ class gridTracker(Tracker):
         self.coords2 = coin.SoCoordinate3()
         self.lines2 = coin.SoLineSet() # big squares
 
+        # human figure
+        mat_human = coin.SoMaterial()
+        mat_human.transparency.setValue(0.3*(1-gtrans))
+        mat_human.diffuseColor.setValue(col)
+        self.coords_human = coin.SoCoordinate3()
+        self.human = coin.SoLineSet()
+
         # axes
         mat3 = coin.SoMaterial()
         mat3.transparency.setValue(gtrans)
@@ -1030,6 +1037,9 @@ class gridTracker(Tracker):
         s.addChild(mat2)
         s.addChild(self.coords2)
         s.addChild(self.lines2)
+        s.addChild(mat_human)
+        s.addChild(self.coords_human)
+        s.addChild(self.human)
         s.addChild(mbind3)
         s.addChild(mat3)
         s.addChild(self.coords3)
@@ -1105,17 +1115,6 @@ class gridTracker(Tracker):
                 self.text2.string = txt
                 self.textpos1.translation.setValue((-bound+self.space,-border+self.space,z))
                 self.textpos2.translation.setValue((-bound-self.space,-bound+self.space,z))
-                # human from BIM workbench
-                loc = FreeCAD.Vector(-bound+self.space/2,-bound+self.space/2,0)
-                try:
-                    import BimProject
-                    hpts = BimProject.getHuman(loc)
-                except Exception:
-                    # BIM not installed
-                    pass
-                else:
-                    mpts.extend([tuple(p) for p in hpts])
-                    midx.append(len(hpts))
             else:
                 self.text1.string = " "
                 self.text2.string = " "
@@ -1130,8 +1129,36 @@ class gridTracker(Tracker):
             self.coords3.point.setValues(apts)
             #self.lines3.numVertices.setValues(aidx)
             self.pts = pts
+            self.displayHumanFigure()
             self.setAxesColor()
 
+    def displayHumanFigure(self):
+        """ Display the human figure at the grid corner.
+        The silhouette is displayed only if:
+        - BIM Workbench is available;
+        - preference BaseApp/Preferences/Mod/Draft/gridShowHuman is True;
+        - the working plane normal is vertical.
+        """
+        numlines = self.numlines // self.mainlines // 2 * 2 * self.mainlines
+        bound = (numlines // 2) * self.space
+        pts = []
+        pidx = []
+        param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
+        if param.GetBool("gridShowHuman", True) and \
+            FreeCAD.DraftWorkingPlane.axis.getAngle(FreeCAD.Vector(0,0,1)) < 0.001:
+            try:
+                import BimProject
+                loc = FreeCAD.Vector(-bound+self.space/2,-bound+self.space/2,0)
+                hpts = BimProject.getHuman(loc)
+                pts.extend([tuple(p) for p in hpts])
+                pidx.append(len(hpts))                
+            except Exception:
+                # BIM not installed
+                return
+        self.human.numVertices.deleteValues(0)
+        self.coords_human.point.setValues(pts)
+        self.human.numVertices.setValues(pidx)
+
     def setAxesColor(self):
         """set axes color"""
         cols = [0,0]
@@ -1180,6 +1207,7 @@ class gridTracker(Tracker):
         P = FreeCAD.DraftWorkingPlane.position
         self.trans.rotation.setValue([Q[0], Q[1], Q[2], Q[3]])
         self.trans.translation.setValue([P.x, P.y, P.z])
+        self.displayHumanFigure()
         self.setAxesColor()
         self.on()
 
diff --git a/src/Mod/Draft/draftmake/make_ellipse.py b/src/Mod/Draft/draftmake/make_ellipse.py
index bb169f24ee..3a277dcd38 100644
--- a/src/Mod/Draft/draftmake/make_ellipse.py
+++ b/src/Mod/Draft/draftmake/make_ellipse.py
@@ -36,7 +36,7 @@ if App.GuiUp:
     from draftviewproviders.view_base import ViewProviderDraft
 
 
-def make_ellipse(majradius, minradius, placement=None, face=True, support=None):
+def make_ellipse(majradius, minradius, placement=None, face=None, support=None):
     """make_ellipse(majradius, minradius, [placement], [face], [support])
     
     Makes an ellipse with the given major and minor radius, and optionally
diff --git a/src/Mod/Draft/draftmake/make_hatch.py b/src/Mod/Draft/draftmake/make_hatch.py
index 8f834f7767..004082dd4a 100644
--- a/src/Mod/Draft/draftmake/make_hatch.py
+++ b/src/Mod/Draft/draftmake/make_hatch.py
@@ -23,12 +23,12 @@
 """This module contains FreeCAD commands for the Draft workbench"""
 
 import FreeCAD
-from draftobjects.hatch import Draft_Hatch_Object
-from draftviewproviders.view_hatch import Draft_Hatch_ViewProvider
+from draftobjects.hatch import Hatch
+from draftviewproviders.view_hatch import ViewProviderDraftHatch
 
-def makeHatch(baseobject, filename, pattern, scale, rotation):
+def make_hatch(baseobject, filename, pattern, scale, rotation):
 
-    """makeHatch(baseobject, filename, pattern, scale, rotation): Creates and returns a
+    """make_hatch(baseobject, filename, pattern, scale, rotation): Creates and returns a
     hatch object made by applying the given pattern of the given PAT file to the faces of
     the given base object. Given scale and rotation factors are applied to the hatch object.
     The result is a Part-based object created in the active document."""
@@ -36,13 +36,11 @@ def makeHatch(baseobject, filename, pattern, scale, rotation):
     if not FreeCAD.ActiveDocument:
         return
     obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Hatch")
-    Draft_Hatch_Object(obj)
+    Hatch(obj)
     obj.Base = baseobject
     obj.File = filename
     obj.Pattern = pattern
     obj.Scale = scale
     obj.Rotation = rotation
     if FreeCAD.GuiUp:
-        Draft_Hatch_ViewProvider(obj.ViewObject)
-
-make_hatch = makeHatch
+        ViewProviderDraftHatch(obj.ViewObject)
diff --git a/src/Mod/Draft/draftobjects/hatch.py b/src/Mod/Draft/draftobjects/hatch.py
index 3e3eb3a8c3..aed15db243 100644
--- a/src/Mod/Draft/draftobjects/hatch.py
+++ b/src/Mod/Draft/draftobjects/hatch.py
@@ -30,7 +30,7 @@ from draftutils.translate import translate, QT_TRANSLATE_NOOP
 
 
 
-class Draft_Hatch_Object:
+class Hatch:
 
 
     def __init__(self,obj):
@@ -41,12 +41,6 @@ class Draft_Hatch_Object:
     def setProperties(self,obj):
 
         pl = obj.PropertiesList
-        if not "Placement" in pl:
-            obj.addProperty("App::PropertyPlacement","Placement","Hatch",
-                            QT_TRANSLATE_NOOP("App::Property","The placement of this object"))
-        if not "Shape" in pl:
-            obj.addProperty("Part::PropertyPartShape","Shape","Hatch",
-                            QT_TRANSLATE_NOOP("App::Property","The shape of this object"))
         if not "Base" in pl:
             obj.addProperty("App::PropertyLink","Base","Hatch",
                             QT_TRANSLATE_NOOP("App::Property","The base object used by this object"))
@@ -103,23 +97,30 @@ class Draft_Hatch_Object:
         pla = obj.Placement
         shapes = []
         for face in obj.Base.Shape.Faces:
-            face = face.copy()
-            if obj.Translate:
-                bpoint = face.CenterOfMass
-                norm = face.normalAt(0,0)
-                fpla = FreeCAD.Placement(bpoint,FreeCAD.Rotation(FreeCAD.Vector(0,0,1),norm))
-                face.Placement = face.Placement.multiply(fpla.inverse())
-            if obj.Rotation:
-                face.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),obj.Rotation)
-            shape = TechDraw.makeGeomHatch(face,obj.Scale,obj.Pattern,obj.File)
-            if obj.Rotation:
-                shape.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),-obj.Rotation)
-            if obj.Translate:
-                shape.Placement = shape.Placement.multiply(fpla)
-            shapes.append(shape)
+            if face.findPlane(): # Only planar faces.
+                face = face.copy()
+                if obj.Translate:
+                    e = face.Edges[0] # Todo: check for almost zero-length edge.
+                    sta = e.firstVertex().Point
+                    end = e.lastVertex().Point
+                    u = end.sub(sta).normalize()
+                    w = face.normalAt(0, 0)
+                    v = w.cross(u)
+                    m = FreeCAD.Matrix(u.x, v.x, w.x, sta.x,
+                                       u.y, v.y, w.y, sta.y,
+                                       u.z, v.z, w.z, sta.z,
+                                       0.0, 0.0, 0.0, 1.0)
+                    face = face.transformGeometry(m.inverse()).Faces[0]
+                if obj.Rotation.Value:
+                    face.rotate(FreeCAD.Vector(), FreeCAD.Vector(0,0,1), -obj.Rotation)
+                shape = TechDraw.makeGeomHatch(face, obj.Scale, obj.Pattern, obj.File)
+                if obj.Rotation.Value:
+                    shape.rotate(FreeCAD.Vector(), FreeCAD.Vector(0,0,1), obj.Rotation)
+                if obj.Translate:
+                    shape = shape.transformGeometry(m)
+                shapes.append(shape)
         if shapes:
             obj.Shape = Part.makeCompound(shapes)
-            obj.Placement = pla
 
     def getPatterns(self,filename):
 
diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py
index 4812575d82..5851a91315 100644
--- a/src/Mod/Draft/draftutils/init_tools.py
+++ b/src/Mod/Draft/draftutils/init_tools.py
@@ -1,5 +1,6 @@
 # ***************************************************************************
-# *   (c) 2020 Eliud Cabrera Castillo            *
+# *   Copyright (c) 2020 Eliud Cabrera Castillo  *
+# *   Copyright (c) 2021 FreeCAD Developers                                 *
 # *                                                                         *
 # *   This file is part of the FreeCAD CAx development system.              *
 # *                                                                         *
@@ -20,13 +21,9 @@
 # *   USA                                                                   *
 # *                                                                         *
 # ***************************************************************************
-"""Provides lists of commands in order to set up toolbars of the workbench.
 
-This module returns lists of commands, so that the toolbars
-can be initialized by Draft, and by other workbenches.
-These commands should be defined in `DraftTools`, and in the individual
-modules in `draftguitools`.
-"""
+"""Provides functions and lists of commands to set up Draft menus and toolbars."""
+
 ## @package init_tools
 # \ingroup draftutils
 # \brief Provides lists of commands to set up toolbars of the workbench.
@@ -40,137 +37,188 @@ from PySide.QtCore import QT_TRANSLATE_NOOP
 
 def get_draft_drawing_commands():
     """Return the drawing commands list."""
-    return ["Draft_Line", "Draft_Wire", "Draft_Fillet",
-            "Draft_ArcTools",
-            "Draft_Circle", "Draft_Ellipse", "Draft_Rectangle",
-            "Draft_Polygon", "Draft_BSpline", "Draft_BezierTools",
-            "Draft_Point", "Draft_Facebinder",
-            "Draft_ShapeString","Draft_Hatch"]
+    from draftguitools import gui_arcs
+    from draftguitools import gui_beziers
+    arc_group = gui_arcs.ArcGroup
+    bez_group = gui_beziers.BezierGroup
+
+    return ["Draft_Line",
+            "Draft_Wire",
+            "Draft_Fillet",
+            ([QT_TRANSLATE_NOOP("Draft", "Arc tools")],
+                list(arc_group.GetCommands(arc_group))), # tuple len=2: submenu
+            ("Draft_ArcTools", ),                        # tuple len=1: toolbar flyout
+            "Draft_Circle",
+            "Draft_Ellipse",
+            "Draft_Rectangle",
+            "Draft_Polygon",
+            "Draft_BSpline",
+            ([QT_TRANSLATE_NOOP("Draft", "Bezier tools")],
+                list(bez_group.GetCommands(bez_group))),
+            ("Draft_BezierTools", ),
+            "Draft_Point",
+            "Draft_Facebinder",
+            "Draft_ShapeString",
+            "Draft_Hatch"]
 
 
 def get_draft_annotation_commands():
     """Return the annotation commands list."""
-    return ["Draft_Text", "Draft_Dimension",
-            "Draft_Label", "Draft_AnnotationStyleEditor"]
-
-
-def get_draft_array_commands():
-    """Return the array commands list."""
-    return ["Draft_ArrayTools"]
-
-
-def get_draft_small_commands():
-    """Return a list with only some utilities."""
-    return ["Draft_Layer",
-            "Draft_WorkingPlaneProxy",
-            "Draft_ToggleDisplayMode",
-            "Draft_AddNamedGroup",
-            "Draft_AddToGroup",
-            "Draft_SelectGroup",
-            "Draft_AddConstruction"]
+    return ["Draft_Text",
+            "Draft_Dimension",
+            "Draft_Label",
+            "Draft_AnnotationStyleEditor"]
 
 
 def get_draft_modification_commands():
     """Return the modification commands list."""
-    lst = ["Draft_Move", "Draft_Rotate",
-           "Draft_Scale", "Draft_Mirror",
-           "Draft_Offset", "Draft_Trimex",
-           "Draft_Stretch",
-           "Separator",
-           "Draft_Clone"]
-    lst += get_draft_array_commands()
-    lst += ["Separator",
-            "Draft_Edit", "Draft_SubelementHighlight",
+    from draftguitools import gui_arrays
+    arr_group = gui_arrays.ArrayGroup
+
+    return ["Draft_Move",
+            "Draft_Rotate",
+            "Draft_Scale",
+            "Draft_Mirror",
+            "Draft_Offset",
+            "Draft_Trimex",
+            "Draft_Stretch",
             "Separator",
-            "Draft_Join", "Draft_Split",
-            "Draft_Upgrade", "Draft_Downgrade",
+            "Draft_Clone",
+            ([QT_TRANSLATE_NOOP("Draft", "Array tools")],
+                list(arr_group.GetCommands(arr_group))), # tuple len=2: submenu
+            ("Draft_ArrayTools", ),                      # tuple len=1: toolbar flyout
             "Separator",
-            "Draft_WireToBSpline", "Draft_Draft2Sketch",
-            "Draft_Slope", "Draft_FlipDimension",
+            "Draft_Edit",
+            "Draft_SubelementHighlight",
+            "Separator",
+            "Draft_Join",
+            "Draft_Split",
+            "Draft_Upgrade",
+            "Draft_Downgrade",
+            "Separator",
+            "Draft_WireToBSpline",
+            "Draft_Draft2Sketch",
+            "Draft_Slope",
+            "Draft_FlipDimension",
             "Separator",
             "Draft_Shape2DView"]
-    return lst
 
 
-def get_draft_context_commands():
-    """Return the context menu commands list."""
-    return ["Draft_ApplyStyle", "Draft_ToggleDisplayMode",
-            "Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup",
-            "Draft_SelectPlane", "Draft_ShowSnapBar",
-            "Draft_ToggleGrid", "Draft_SetStyle"]
-
-
-def get_draft_line_commands():
-    """Return the line commands list."""
-    return ["Draft_UndoLine", "Draft_FinishLine",
-            "Draft_CloseLine"]
-
-
-def get_draft_utility_commands():
-    """Return the utility commands list."""
-    return ["Draft_Layer",
-            "Draft_Heal",
+def get_draft_utility_commands_menu():
+    """Return the utility commands list for the menu."""
+    return ["Draft_SetStyle",
+            "Draft_ApplyStyle",
+            "Separator",
+            "Draft_Layer",
+            "Draft_AddNamedGroup",
+            "Draft_AddToGroup",
+            "Draft_SelectGroup",
             "Draft_ToggleConstructionMode",
-            "Draft_ToggleContinueMode",
+            "Draft_AddConstruction",
+            "Separator",
+            "Draft_ToggleDisplayMode",
+            "Draft_ToggleGrid",
+            "Draft_SelectPlane",
             "Draft_WorkingPlaneProxy",
-            "Draft_AddConstruction"]
+            "Separator",
+            "Draft_Heal",
+            "Draft_ToggleContinueMode",
+            "Draft_ShowSnapBar"]
+
+
+def get_draft_utility_commands_toolbar():
+    """Return the utility commands list for the toolbar."""
+    return ["Draft_Layer",
+            "Draft_AddNamedGroup",
+            "Draft_AddToGroup",
+            "Draft_SelectGroup",
+            "Draft_AddConstruction",
+            "Draft_ToggleDisplayMode",
+            "Draft_WorkingPlaneProxy"]
 
 
 def get_draft_snap_commands():
     """Return the snapping commands list."""
     return ['Draft_Snap_Lock',
-            'Draft_Snap_Endpoint', 'Draft_Snap_Midpoint',
-            'Draft_Snap_Center', 'Draft_Snap_Angle',
-            'Draft_Snap_Intersection', 'Draft_Snap_Perpendicular',
-            'Draft_Snap_Extension', 'Draft_Snap_Parallel',
-            'Draft_Snap_Special', 'Draft_Snap_Near',
-            'Draft_Snap_Ortho', 'Draft_Snap_Grid',
-            'Draft_Snap_WorkingPlane', 'Draft_Snap_Dimensions',
-            'Separator', 'Draft_ToggleGrid'
-            ]
+            'Draft_Snap_Endpoint',
+            'Draft_Snap_Midpoint',
+            'Draft_Snap_Center',
+            'Draft_Snap_Angle',
+            'Draft_Snap_Intersection',
+            'Draft_Snap_Perpendicular',
+            'Draft_Snap_Extension',
+            'Draft_Snap_Parallel',
+            'Draft_Snap_Special',
+            'Draft_Snap_Near',
+            'Draft_Snap_Ortho',
+            'Draft_Snap_Grid',
+            'Draft_Snap_WorkingPlane',
+            'Draft_Snap_Dimensions',
+            'Separator', 'Draft_ToggleGrid']
 
 
-def init_draft_toolbars(workbench):
-    """Initialize the Draft toolbars.
+def get_draft_context_commands():
+    """Return the context menu commands list."""
+    return ["Draft_ApplyStyle",
+            "Draft_ToggleDisplayMode",
+            "Draft_AddNamedGroup",
+            "Draft_AddToGroup",
+            "Draft_SelectGroup",
+            "Draft_SelectPlane",
+            "Draft_ShowSnapBar",
+            "Draft_ToggleGrid",
+            "Draft_SetStyle"]
+
+
+def get_draft_line_commands():
+    """Return the line commands list."""
+    return ["Draft_UndoLine",
+            "Draft_FinishLine",
+            "Draft_CloseLine"]
+
+
+def init_toolbar(workbench, toolbar, cmd_list):
+    """Initialize a toolbar.
 
     Parameters
     ----------
     workbench: Gui.Workbench
-        The workbench class on which the commands have to be available.
-        If called from within the `Initialize` method
-        of a workbench class defined inside `InitGui.py`,
-        it can be used as `setup_draft_toolbars(self)`.
+        The workbench. The commands from cmd_list must be available.
+
+    toolbar: string
+        The name of the toolbar.
+
+    cmd_list: list of strings or list of strings and tuples
+        See f.e. the return value of get_draft_drawing_commands.
     """
-    workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
-                                              "Draft creation tools"),
-                            get_draft_drawing_commands())
-    workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
-                                              "Draft annotation tools"),
-                            get_draft_annotation_commands())
-    workbench.appendToolbar(QT_TRANSLATE_NOOP("Draft",
-                                              "Draft modification tools"),
-                            get_draft_modification_commands())
+    for cmd in cmd_list:
+        if isinstance(cmd, tuple):
+            if len(cmd) == 1:
+                workbench.appendToolbar(toolbar, [cmd[0]])
+        else:
+            workbench.appendToolbar(toolbar, [cmd])
 
 
-def init_draft_menus(workbench):
-    """Initialize the Draft menus.
+def init_menu(workbench, menu_list, cmd_list):
+    """Initialize a menu.
 
     Parameters
     ----------
     workbench: Gui.Workbench
-        The workbench class on which the commands have to be available.
-        If called from within the `Initialize` method
-        of a workbench class defined inside `InitGui.py`,
-        it can be used as `setup_draft_menus(self)`.
+        The workbench. The commands from cmd_list must be available.
+
+    menu_list: list of strings
+        The main and optional submenu(s). The commands, and additional
+        submenus (if any), are added to the last (sub)menu in the list.
+
+    cmd_list: list of strings or list of strings and tuples
+        See f.e. the return value of get_draft_drawing_commands.
     """
-    workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Drafting"),
-                         get_draft_drawing_commands())
-    workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Annotation"),
-                         get_draft_annotation_commands())
-    workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Modification"),
-                         get_draft_modification_commands())
-    workbench.appendMenu(QT_TRANSLATE_NOOP("Draft", "&Utilities"),
-                         get_draft_utility_commands()
-                         + get_draft_context_commands())
+    for cmd in cmd_list:
+        if isinstance(cmd, tuple):
+            if len(cmd) == 2:
+                workbench.appendMenu(menu_list + cmd[0], cmd[1])
+        else:
+            workbench.appendMenu(menu_list, [cmd])
 
 ## @}
diff --git a/src/Mod/Draft/draftviewproviders/view_hatch.py b/src/Mod/Draft/draftviewproviders/view_hatch.py
index 374cc06f3d..aa002cea04 100644
--- a/src/Mod/Draft/draftviewproviders/view_hatch.py
+++ b/src/Mod/Draft/draftviewproviders/view_hatch.py
@@ -27,7 +27,7 @@ import os
 import FreeCAD
 from draftguitools.gui_hatch import Draft_Hatch_TaskPanel
 
-class Draft_Hatch_ViewProvider:
+class ViewProviderDraftHatch:
 
 
     def __init__(self,vobj):
diff --git a/src/Mod/Drawing/App/DrawingExport.cpp b/src/Mod/Drawing/App/DrawingExport.cpp
index b87891ed50..7572be417c 100644
--- a/src/Mod/Drawing/App/DrawingExport.cpp
+++ b/src/Mod/Drawing/App/DrawingExport.cpp
@@ -64,10 +64,7 @@
 #include 
 
 #include 
-#include 
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
@@ -75,11 +72,19 @@
 #include 
 #include 
 #include 
+#include 
+#if OCC_VERSION_HEX < 0x070600
+#include 
+#endif
 
 #include "DrawingExport.h"
 #include 
 #include 
 
+#if OCC_VERSION_HEX >= 0x070600
+using BRepAdaptor_HCurve = BRepAdaptor_Curve;
+#endif
+
 using namespace Drawing;
 using namespace std;
 
diff --git a/src/Mod/Drawing/App/ProjectionAlgos.cpp b/src/Mod/Drawing/App/ProjectionAlgos.cpp
index 9afae7e9c0..da03d49057 100644
--- a/src/Mod/Drawing/App/ProjectionAlgos.cpp
+++ b/src/Mod/Drawing/App/ProjectionAlgos.cpp
@@ -61,10 +61,7 @@
 #include 
 #include 
 #include 
-#include 
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp
index 18f72e87d2..8003fd6d79 100644
--- a/src/Mod/Fem/App/FemConstraint.cpp
+++ b/src/Mod/Fem/App/FemConstraint.cpp
@@ -36,8 +36,6 @@
 # include 
 # include 
 # include 
-# include 
-# include 
 # include 
 # include 
 # include 
@@ -51,6 +49,11 @@
 # include 
 # include 
 # include 
+# include 
+# if OCC_VERSION_HEX < 0x070600
+# include 
+# include 
+# endif
 #endif
 
 #include "FemConstraint.h"
@@ -74,6 +77,11 @@ double round(double r) {
 }
 #endif
 
+#if OCC_VERSION_HEX >= 0x070600
+using Adaptor3d_HSurface = Adaptor3d_Surface;
+using BRepAdaptor_HSurface = BRepAdaptor_Surface;
+#endif
+
 PROPERTY_SOURCE(Fem::Constraint, App::DocumentObject)
 
 Constraint::Constraint()
diff --git a/src/Mod/Fem/App/FemConstraintFixed.cpp b/src/Mod/Fem/App/FemConstraintFixed.cpp
index 4d80945490..5b8874ec90 100644
--- a/src/Mod/Fem/App/FemConstraintFixed.cpp
+++ b/src/Mod/Fem/App/FemConstraintFixed.cpp
@@ -32,8 +32,6 @@
 #include 
 #include 
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
diff --git a/src/Mod/Fem/Gui/Resources/translations/Fem.ts b/src/Mod/Fem/Gui/Resources/translations/Fem.ts
index 4f4a6ffe68..d2d8413c0e 100755
--- a/src/Mod/Fem/Gui/Resources/translations/Fem.ts
+++ b/src/Mod/Fem/Gui/Resources/translations/Fem.ts
@@ -4,17 +4,12 @@
 
     BoundarySelector
     
-        
+        
         Select Faces/Edges/Vertexes
         
     
     
-        
-        To add references select them in the 3D view and then click "Add".
-        
-    
-    
-        
+        
         To add references: select them in the 3D view  and click "Add".
         
     
@@ -22,47 +17,47 @@
 
     ControlWidget
     
-        
+        
         Solver Control
         
     
     
-        
+        
         Working Directory
         
     
     
-        
+        
         Write
         
     
     
-        
+        
         Edit
         
     
     
-        
+        
         Elapsed Time:
         
     
     
-        
+        
         Run
         
     
     
-        
+        
         Re-write
         
     
     
-        
+        
         Re-run
         
     
     
-        
+        
         Abort
         
     
@@ -70,67 +65,32 @@
 
     GeometryElementsSelection
     
-        
+        
         Geometry reference selector for a
         
     
     
-        
-        Geometry reference selector for a 
-        
-    
-    
-        
+        
         Add
         
     
-    
-        
-        Click on "Add" and select geometric elements to add them to the list. If no geometry is added to the list, all remaining ones are used. The following geometry elements are allowed to select: 
-        
-    
-    
-        
-        Click on "Add" and select geometric elements to add them to the list.
-        
-    
-    
-        
-        The following geometry elements are allowed to select: 
-        
-    
     
         
         Click on "Add" and select geometric elements to add them to the list.{}The following geometry elements are allowed to select: {}{}{}
         
     
-    
-        
-        If no geometry is added to the list, all remaining ones are used.
-        
-    
-    
-        
-        Click on "Add" and select geometric elements to add to the list.
-        
-    
-    
-        
-        Click on 'Add' and select geometric elements to add them to the list.
-        
-    
     
         
         {}If no geometry is added to the list, all remaining ones are used.
         
     
     
-        
+        
         Selection mode
         
     
     
-        
+        
         Solid
         
     
@@ -138,17 +98,12 @@
 
     SolidSelector
     
-        
+        
         Select Solids
         
     
     
-        
-        Select elements part of the solid that shall be added to the list. To than add the solid click "Add".
-        
-    
-    
-        
+        
         Select elements part of the solid that shall be added to the list. To add the solid click "Add".
         
     
@@ -156,1310 +111,1421 @@
 
     _Selector
     
-        
+        
         Add
         
     
     
-        
+        
         Remove
         
     
 
-
-    FEM_Analysis
-    
-        
-        Analysis container
-        
-    
-    
-        
-        Creates an analysis container with standard solver CalculiX
-        
-    
-
-
-    FEM_ClippingPlaneAdd
-    
-        
-        Clipping plane on face
-        
-    
-    
-        
-        Add a clipping plane on a selected face
-        
-    
-
-
-    FEM_ClippingPlaneRemoveAll
-    
-        
-        Remove all clipping planes
-        
-    
-
-
-    FEM_ConstraintBodyHeatSource
-    
-        
-        Constraint body heat source
-        
-    
-    
-        
-        Creates a FEM constraint body heat source
-        
-    
-
-
-    FEM_ConstraintElectrostaticPotential
-    
-        
-        Constraint electrostatic potential
-        
-    
-    
-        
-        Creates a FEM constraint electrostatic potential
-        
-    
-
-
-    FEM_ConstraintFlowVelocity
-    
-        
-        Constraint flow velocity
-        
-    
-    
-        
-        Creates a FEM constraint flow velocity
-        
-    
-
-
-    FEM_ConstraintInitialFlowVelocity
-    
-        
-        Constraint initial flow velocity
-        
-    
-    
-        
-        Creates a FEM constraint initial flow velocity
-        
-    
-
-
-    FEM_ConstraintSelfWeight
-    
-        
-        Constraint self weight
-        
-    
-    
-        
-        Creates a FEM constraint self weight
-        
-    
-
-
-    FEM_ElementFluid1D
-    
-        
-        Fluid section for 1D flow
-        
-    
-    
-        
-        Creates a FEM Fluid section for 1D flow
-        
-    
-
-
-    FEM_ElementGeometry1D
-    
-        
-        Beam cross section
-        
-    
-    
-        
-        Creates a FEM beam cross section
-        
-    
-
-
-    FEM_ElementGeometry2D
-    
-        
-        Shell plate thickness
-        
-    
-    
-        
-        Creates a FEM shell plate thickness
-        
-    
-
-
-    FEM_ElementRotation1D
-    
-        
-        Beam rotation
-        
-    
-    
-        
-        Creates a FEM beam rotation
-        
-    
-
-
-    FEM_EquationElasticity
-    
-        
-        Elasticity equation
-        
-    
-    
-        
-        Creates a FEM equation for elasticity
-        
-    
-
-
-    FEM_EquationElectrostatic
-    
-        
-        Electrostatic equation
-        
-    
-    
-        
-        Creates a FEM equation for electrostatic
-        
-    
-
-
-    FEM_EquationFlow
-    
-        
-        Flow equation
-        
-    
-    
-        
-        Creates a FEM equation for flow
-        
-    
-
-
-    FEM_EquationFluxsolver
-    
-        
-        Fluxsolver equation
-        
-    
-    
-        
-        Creates a FEM equation for fluxsolver
-        
-    
-
-
-    FEM_EquationHeat
-    
-        
-        Fluxsolver heat
-        
-    
-
-
-    FEM_FEMMesh2Mesh
-    
-        
-        FEM mesh to mesh
-        
-    
-    
-        
-        Convert the surface of a FEM mesh to a mesh
-        
-    
-
-
-    FEM_MaterialFluid
-    
-        
-        Material for fluid
-        
-    
-    
-        
-        FEM material for Fluid
-        
-    
-    
-        
-        Creates a FEM material for Fluid
-        
-    
-
-
-    FEM_MaterialMechanicalNonlinear
-    
-        
-        Nonlinear mechanical material
-        
-    
-    
-        
-        Creates a nonlinear mechanical material
-        
-    
-
-
-    FEM_MaterialReinforced
-    
-        
-        Reinforced material (concrete)
-        
-    
-
-
-    FEM_MaterialSolid
-    
-        
-        Material for solid
-        
-    
-    
-        
-        FEM material for solid
-        
-    
-
-
-    FEM_MeshBoundaryLayer
-    
-        
-        FEM mesh boundary layer
-        
-    
-    
-        
-        Creates a FEM mesh boundary layer
-        
-    
-
-
-    FEM_MeshClear
-    
-        
-        Clear FEM mesh
-        
-    
-    
-        
-        Clear the Mesh of a FEM mesh object
-        
-    
-
-
-    FEM_MeshDisplayInfo
-    
-        
-        Display FEM mesh info
-        
-    
-
-
-    FEM_MeshGmshFromShape
-    
-        
-        FEM mesh from shape by Gmsh
-        
-    
-    
-        
-        Create a FEM mesh from a shape by Gmsh mesher
-        
-    
-    
-        
-        FEM mesh from shape by GMSH
-        
-    
-    
-        
-        Create a FEM mesh from a shape by GMSH mesher
-        
-    
-
-
-    FEM_MeshGroup
-    
-        
-        FEM mesh group
-        
-    
-    
-        
-        Creates a FEM mesh group
-        
-    
-
-
-    FEM_MeshNetgenFromShape
-    
-        
-        FEM mesh from shape by Netgen
-        
-    
-
-
-    FEM_MeshRegion
-    
-        
-        FEM mesh region
-        
-    
-    
-        
-        Creates a FEM mesh region
-        
-    
-
-
-    FEM_ResultShow
-    
-        
-        Show result
-        
-    
-    
-        
-        Shows and visualizes selected result data
-        
-    
-
-
-    FEM_ResultsPurge
-    
-        
-        Purge results
-        
-    
-    
-        
-        Purges all results from active analysis
-        
-    
-
-
-    FEM_SolverCalculiX
-    
-        
-        Solver CalculiX (experimental)
-        
-    
-    
-        
-        Creates a FEM solver CalculiX (experimental)
-        
-    
-
-
-    FEM_SolverCalculix
-    
-        
-        Solver CalculiX Standard
-        
-    
-    
-        
-        Creates a standard FEM solver CalculiX with ccx tools
-        
-    
-    
-        
-        Solver CalculiX
-        
-    
-    
-        
-        Creates a FEM solver CalculiX
-        
-    
-
-
-    FEM_SolverControl
-    
-        
-        Solver job control
-        
-    
-    
-        
-        Changes solver attributes and runs the calculations for the selected solver
-        
-    
-
-
-    FEM_SolverElmer
-    
-        
-        Solver Elmer
-        
-    
-
-
-    FEM_SolverRun
-    
-        
-        Run solver calculations
-        
-    
-    
-        
-        Runs the calculations for the selected solver
-        
-    
-
-
-    FEM_SolverZ88
-    
-        
-        Solver Z88
-        
-    
-    
-        
-        Creates a FEM solver Z88
-        
-    
-
-
-    Fem_Command
-    
-        
-        Default Fem Command MenuText
-        
-    
-    
-        
-        Default Fem Command ToolTip
-        
-    
-
-
-    Material_Editor
-    
-        
-        Material editor
-        
-    
-    
-        
-        Opens the FreeCAD material editor
-        
-    
-
-
-    FEM_MeshFromShape
-    
-        
-        FEM mesh from shape by Netgen
-        
-    
-    
-        
-        Create a FEM volume mesh from a solid or face shape by Netgen internal mesher
-        
-    
-
-
-    FEM_MeshPrintInfo
-    
-        
-        Print FEM mesh info
-        
-    
-
-
-    FEM_BeamSection
-    
-        
-        Beam cross section
-        
-    
-    
-        
-        Creates a FEM beam cross section
-        
-    
-
-
-    FEM_FluidSection
-    
-        
-        Fluid section for 1D flow
-        
-    
-    
-        
-        Creates a FEM Fluid section for 1D flow
-        
-    
-
-
-    FEM_ShellThickness
-    
-        
-        Shell plate thickness
-        
-    
-    
-        
-        Creates a FEM shell plate thickness
-        
-    
-
-
-    Fem_Analysis
-    
-        
-        Analysis container
-        
-    
-    
-        
-        Creates a analysis container with standard solver CalculiX
-        
-    
-    
-        
-        New mechanical analysis
-        
-    
-    
-        
-        Create a new mechanical analysis
-        
-    
-
-
-    Fem_BeamSection
-    
-        
-        Beam cross section
-        
-    
-    
-        
-        Creates a FEM beam cross section
-        
-    
-    
-        
-        FEM Beam Cross Section Definition ...
-        
-    
-    
-        
-        Creates a FEM Beam Cross Section
-        
-    
-
-
-    Fem_ClearMesh
-    
-        
-        Clear FEM mesh
-        
-    
-    
-        
-        Clear the Mesh of a FEM mesh object
-        
-    
-
-
-    Fem_ConstraintSelfWeight
-    
-        
-        Constraint self weigt
-        
-    
-    
-        
-        Creates a FEM constraint self weigt
-        
-    
-
-
-    Fem_ControlSolver
-    
-        
-        Solver job control
-        
-    
-    
-        
-        Changes solver attributes and runs the calculations for the selected solver
-        
-    
-
-
-    Fem_FemMesh2Mesh
-    
-        
-        FEM mesh to mesh
-        
-    
-    
-        
-        Convert the surface of a FEM mesh to a mesh
-        
-    
-
-
-    Fem_MaterialMechanicalNonlinear
-    
-        
-        Nonlinear mechanical material
-        
-    
-    
-        
-        Creates a nonlinear mechanical material
-        
-    
-
-
-    Fem_MechanicalMaterial
-    
-        
-        Mechanical material
-        
-    
-    
-        
-        Mechanical material...
-        
-    
-    
-        
-        Creates a mechanical material
-        
-    
-    
-        
-        Creates or edit the mechanical material definition.
-        
-    
-
-
-    Fem_MeshFromShape
-    
-        
-        FEM mesh from shape by Netgen
-        
-    
-    
-        
-        Create a FEM volume mesh from a solid or face shape by Netgen internal mesher
-        
-    
-
-
-    Fem_MeshGmshFromShape
-    
-        
-        FEM mesh from shape by GMSH
-        
-    
-    
-        
-        Create a FEM mesh from a shape by GMSH mesher
-        
-    
-
-
-    Fem_MeshRegion
-    
-        
-        FEM mesh region
-        
-    
-    
-        
-        Creates a FEM mesh region
-        
-    
-
-
-    Fem_PrintMeshInfo
-    
-        
-        Print FEM mesh info
-        
-    
-
-
-    Fem_PurgeResults
-    
-        
-        Purge results
-        
-    
-    
-        
-        Purge results from an analysis
-        
-    
-    
-        
-        Purges all results from active analysis
-        
-    
-
-
-    Fem_RunAnalysis
-    
-        
-        Run solver calculations
-        
-    
-    
-        
-        Runs the calculations for the selected solver
-        
-    
-
-
-    Fem_ShellThickness
-    
-        
-        Shell plate thickness
-        
-    
-    
-        
-        Creates a FEM shell plate thickness
-        
-    
-    
-        
-        FEM Shell Plate Thickness Definition ...
-        
-    
-    
-        
-        Creates a FEM Shell Thickness
-        
-    
-
-
-    Fem_ShowResult
-    
-        
-        Show result
-        
-    
-    
-        
-        Show result information of an analysis
-        
-    
-    
-        
-        Shows and visualizes selected result data
-        
-    
-
-
-    Fem_SolverCalculix
-    
-        
-        Solver CalculiX
-        
-    
-    
-        
-        Creates a FEM solver CalculiX
-        
-    
-    
-        
-        Create FEM Solver CalculiX ...
-        
-    
-    
-        
-        Creates FEM Solver CalculiX
-        
-    
-
-
-    Fem_SolverZ88
-    
-        
-        Solver Z88
-        
-    
-    
-        
-        Creates a FEM solver Z88
-        
-    
-
-
-    Fem_CreateFromShape
-    
-        
-        Create FEM mesh
-        
-    
-    
-        
-        Create FEM mesh from shape
-        
-    
-
-
-    Fem_NewMechanicalAnalysis
-    
-        
-        New mechanical analysis
-        
-    
-    
-        
-        Create a new mechanical analysis
-        
-    
-
-
-    Fem_Quick_Analysis
-    
-        
-        Run CalculiX ccx
-        
-    
-    
-        
-        Write .inp file and run CalculiX ccx
-        
-    
-
-
-    Fem_SolverJobControl
-    
-        
-        Start solver job control
-        
-    
-    
-        
-        Dialog to start the calculation of the selected solver
-        
-    
-
-
-    Fem_JobControl
-    
-        
-        Start solver job control
-        
-    
-    
-        
-        Dialog to start the calculation of the selected solver
-        
-    
-
-
-    Fem_Material
-    
-        
-        Mechanical material...
-        
-    
-    
-        
-        Creates or edit the mechanical material definition.
-        
-    
-
-
-    Fem_Result
-    
-        
-        Show result
-        
-    
-    
-        
-        Show result information of an analysis
-        
-    
-
-
-    CmdFemAddPart
-    
-        
-        Fem
-        Fem
-    
-    
-        
-        
-        Add a part to the Analysis
-        Add a part to the Analysis
-    
-
 
     CmdFemConstraintBearing
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM bearing constraint
-        Create FEM bearing constraint
+        
+        Constraint bearing
+        
     
     
-        
-        Create FEM constraint for a bearing
-        Create FEM constraint for a bearing
+        
+        Creates a FEM constraint for a bearing
+        
+    
+
+
+    CmdFemConstraintContact
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint contact
+        
+    
+    
+        
+        Creates a FEM constraint for contact between faces
+        
     
 
 
     CmdFemConstraintDisplacement
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM displacement constraint
-        Create FEM displacement constraint
+        
+        Constraint displacement
+        
     
     
-        
-        Create FEM constraint for a displacement acting on a face
-        Create FEM constraint for a displacement acting on a face
+        
+        Creates a FEM constraint for a displacement acting on a geometric entity
+        
     
 
 
     CmdFemConstraintFixed
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM fixed constraint
-        Create FEM fixed constraint
+        
+        Constraint fixed
+        
     
     
-        
-        Create FEM constraint for a fixed geometric entity
-        Create FEM constraint for a fixed geometric entity
+        
+        Creates a FEM constraint for a fixed geometric entity
+        
+    
+
+
+    CmdFemConstraintFluidBoundary
+    
+        
+        Fem
+        
+    
+    
+        
+        Fluid boundary condition
+        
+    
+    
+        
+        Create fluid boundary condition on face entity for Computional Fluid Dynamics
+        
     
 
 
     CmdFemConstraintForce
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM force constraint
-        Create FEM force constraint
+        
+        Constraint force
+        
     
     
-        
-        Create FEM constraint for a force acting on a geometric entity
-        Create FEM constraint for a force acting on a geometric entity
+        
+        Creates a FEM constraint for a force acting on a geometric entity
+        
     
 
 
     CmdFemConstraintGear
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM gear constraint
-        Create FEM gear constraint
+        
+        Constraint gear
+        
     
     
-        
-        Create FEM constraint for a gear
-        Create FEM constraint for a gear
+        
+        Creates a FEM constraint for a gear
+        
+    
+
+
+    CmdFemConstraintHeatflux
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint heatflux
+        
+    
+    
+        
+        Creates a FEM constraint for a heatflux acting on a face
+        
+    
+
+
+    CmdFemConstraintInitialTemperature
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint initial temperature
+        
+    
+    
+        
+        Creates a FEM constraint for initial temperature acting on a body
+        
+    
+
+
+    CmdFemConstraintPlaneRotation
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint plane rotation
+        
+    
+    
+        
+        Creates a FEM constraint for plane rotation face
+        
     
 
 
     CmdFemConstraintPressure
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM pressure constraint
-        Create FEM pressure constraint
+        
+        Constraint pressure
+        
     
     
-        
-        Create FEM constraint for a pressure acting on a face
-        Create FEM constraint for a pressure acting on a face
+        
+        Creates a FEM constraint for a pressure acting on a face
+        
     
 
 
     CmdFemConstraintPulley
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        Create FEM pulley constraint
-        Create FEM pulley constraint
+        
+        Constraint pulley
+        
     
     
-        
-        Create FEM constraint for a pulley
-        Create FEM constraint for a pulley
+        
+        Creates a FEM constraint for a pulley
+        
     
 
 
-    CmdFemCreateAnalysis
+    CmdFemConstraintSpring
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        
-        Create a FEM analysis
-        Create a FEM analysis
+        
+        Constraint spring
+        
+    
+    
+        
+        Creates a FEM constraint for a spring acting on a face
+        
+    
+
+
+    CmdFemConstraintTemperature
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint temperature
+        
+    
+    
+        
+        Creates a FEM constraint for a temperature/concentrated heat flux acting on a face
+        
+    
+
+
+    CmdFemConstraintTransform
+    
+        
+        Fem
+        
+    
+    
+        
+        Constraint transform
+        
+    
+    
+        
+        Create FEM constraint for transforming a face
+        
     
 
 
     CmdFemCreateNodesSet
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        
-        Define/create a nodes set...
-        Define/create a nodes set...
+        
+        Nodes set
+        
     
     
-        
+        
+        Creates a FEM mesh nodes set
+        
+    
+    
+        
         Wrong selection
-        Verkeerde keuse
+        
     
     
-        
+        
         Select a single FEM mesh or nodes set, please.
-        Select a single FEM mesh or nodes set, please.
-    
-
-
-    CmdFemCreateSolver
-    
-        
-        Fem
-        Fem
-    
-    
-        
-        
-        Add a solver to the Analysis
-        Add a solver to the Analysis
+        
     
 
 
     CmdFemDefineNodesSet
     
-        
+        
         Fem
-        Fem
+        
     
     
-        
-        
-        
+        
+        Node set by poly
+        
+    
+    
+        
+        
         Create node set by Poly
-        Create node set by Poly
+        
     
 
 
-    FemGui::DlgSettingsFemImp
+    CmdFemPostApllyChanges
     
-        
-        FEM
-        FEM
+        
+        Fem
+        
     
     
-        
+        
+        Apply changes to pipeline
+        
+    
+    
+        
+        Apply changes to parameters directly and not on recompute only...
+        
+    
+
+
+    CmdFemPostClipFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Region clip filter
+        
+    
+    
+        
+        Define/create a clip filter which uses functions to define the cliped region
+        
+    
+    
+        
+        Wrong selection
+        
+    
+    
+        
+        Select a pipeline, please.
+        
+    
+
+
+    CmdFemPostCreateDataAtPointFilter
+    
+        
+        Data At Point
+        
+    
+
+
+    CmdFemPostCutFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Function cut filter
+        
+    
+    
+        
+        Cut the data along an implicit function
+        
+    
+
+
+    CmdFemPostDataAlongLineFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Line clip filter
+        
+    
+    
+        
+        Define/create a clip filter which clips a field along a line
+        
+    
+
+
+    CmdFemPostDataAtPointFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Data at point clip filter
+        
+    
+    
+        
+        Define/create a clip filter which clips a field data at point
+        
+    
+
+
+    CmdFemPostFunctions
+    
+        
+        Fem
+        
+    
+    
+        
+        Filter functions
+        
+    
+    
+        
+        Functions for use in postprocessing filter...
+        
+    
+    
+        
+        Plane
+        
+    
+    
+        
+        Sphere
+        
+    
+
+
+    CmdFemPostLinearizedStressesFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Stress linearization plot
+        
+    
+    
+        
+        Define/create stress linearization plots
+        
+    
+    
+        
+        
+        Wrong selection
+        
+    
+    
+        
+        
+        Select a Clip filter which clips a STRESS field along a line, please.
+        
+    
+
+
+    CmdFemPostPipelineFromResult
+    
+        
+        Fem
+        
+    
+    
+        
+        Post pipeline from result
+        
+    
+    
+        
+        Creates a post processing pipeline from a result object
+        
+    
+    
+        
+        Wrong selection type
+        
+    
+    
+        
+        Select a result object, please.
+        
+    
+
+
+    CmdFemPostScalarClipFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Scalar clip filter
+        
+    
+    
+        
+        Define/create a clip filter which clips a field with a scalar value
+        
+    
+
+
+    CmdFemPostWarpVectorFilter
+    
+        
+        Fem
+        
+    
+    
+        
+        Warp filter
+        
+    
+    
+        
+        Warp the geometry along a vector field by a certain factor
+        
+    
+
+
+    Command
+    
+        
+        Make FEM constraint for bearing
+        
+    
+    
+        
+        Make FEM constraint contact on face
+        
+    
+    
+        
+        Make FEM constraint displacement on face
+        
+    
+    
+        
+        Make FEM constraint fixed geometry
+        
+    
+    
+        
+        Create fluid boundary condition
+        
+    
+    
+        
+        Make FEM constraint force on geometry
+        
+    
+    
+        
+        Make FEM constraint for gear
+        
+    
+    
+        
+        Make FEM constraint heatflux on face
+        
+    
+    
+        
+        Make FEM constraint initial temperature on body
+        
+    
+    
+        
+        Make FEM constraint Plane Rotation face
+        
+    
+    
+        
+        Make FEM constraint pressure on face
+        
+    
+    
+        
+        Make FEM constraint spring on face
+        
+    
+    
+        
+        Make FEM constraint for pulley
+        
+    
+    
+        
+        Make FEM constraint temperature on face
+        
+    
+    
+        
+        Make FEM constraint transform on face
+        
+    
+    
+        
+        Place robot
+        
+    
+    
+        
+        Edit nodes set
+        
+    
+    
+        
+        Create nodes set
+        
+    
+    
+        
+        Create filter
+        
+    
+    
+        
+        Create function
+        
+    
+    
+        
+        Create pipeline from result
+        
+    
+    
+        
+        Edit Mirror
+        
+    
+
+
+    Dialog
+    
+        
+        
+        
+        Dialog
+        
+    
+    
+        
+        Mesh groups detected. Please choose values for the different groups.
+        
+    
+    
+        
+        Id
+        
+    
+    
+        
+        Label
+        
+    
+    
+        
+        Elements
+        
+    
+    
+        
+        Not Marked
+        
+    
+    
+        
+        Marked
+        
+    
+    
+        
+        Select the vertices, lines and surfaces: 
+        
+    
+    
+        
+        
+        Temperature:
+        
+    
+    
+        
+        
+        25
+        
+    
+    
+        
+        
+        ºC
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        Insert component's
+ initial temperature:
+        
+    
+
+
+    FEM_PostCreateFunctions
+    
+        
+        Create a plane function, defined by its origin and normal
+        
+    
+    
+        
+        Create a sphere function, defined by its center and radius
+        
+    
+
+
+    FemGui::DlgSettingsFemCcxImp
+    
+        
+        
         CalculiX
-        CalculiX
+        
     
     
-        
-        Use internal editor for .inp files
-        Use internal editor for .inp files
-    
-    
-        
-        External editor:
-        External editor:
-    
-    
-        
+        
         Leave blank to use default CalculiX ccx binary file
-        Leave blank to use default CalculiX ccx binary file
+        
     
     
-        
-        ccx binary
-        ccx binary
+        
+        Input file Editor
+        
     
     
-        
-        Working directory
-        Working directory
+        
+        Use internal editor for *.inp files
+        
     
     
-        
-        Default analysis settings
-        Default analysis settings
+        
+        External editor:
+        
     
     
-        
-        Default type on analysis
-        Default type on analysis
+        
+        Search in known binary directories
+        
     
     
-        
-        Static
-        Static
+        
+        ccx binary path
+        
     
     
-        
-        Frequency
-        Frequency
+        
+        Input file splitting
+        
     
     
-        
-        Eigenmode number
-        Eigenmode number
+        
+        Split writing of  *.inp
+        
     
     
-        
+        
+        CalculiX binary
+        
+    
+    
+        
+        Analysis defaults
+        
+    
+    
+        
         Type
-        Soort
+        
     
     
-        
+        
+        Default type on analysis
+        
+    
+    
+        
+        Static
+        
+    
+    
+        
+        Frequency
+        
+    
+    
+        
+        Thermomech
+        
+    
+    
+        
+        Solver defaults
+        
+    
+    
+        
+        Time incrementation control parameter
+        
+    
+    
+        
+        Use non ccx defaults
+        
+    
+    
+        
+        Use non-linear geometry
+        
+    
+    
+        
+        Matrix solver
+        
+    
+    
+        
+        Number of CPU's to use (Spooles only)
+        
+    
+    
+        
+        Non-linear geometry
+        
+    
+    
+        
+        Default
+        
+    
+    
+        
+        Spooles
+        
+    
+    
+        
+        Iterative Scaling
+        
+    
+    
+        
+        Iterative Cholesky
+        
+    
+    
+        
+        Time Initial Step
+        
+    
+    
+        
+        Time End
+        
+    
+    
+        
+        3D Output, unchecked for 2D
+        
+    
+    
+        
+        Beam, shell element 3D output format 
+        
+    
+    
+        
+        Thermo mechanical defaults
+        
+    
+    
+        
+        Maximum number of iterations
+        
+    
+    
+        
+        Use steady state
+        
+    
+    
+        
+        Analysis type (transient or steady state)
+        
+    
+    
+        
+        Frequency defaults
+        
+    
+    
+        
+        Eigenmode number
+        
+    
+    
+        
         High frequency limit
-        High frequency limit
+        
     
     
-        
+        
         Low frequency limit
-        Low frequency limit
+        
     
     
-        
-        
+        
+        
         Hz
-        Hz
+        
+    
+
+
+    FemGui::DlgSettingsFemElmerImp
+    
+        
+        Elmer
+        
     
     
-        
-        Materials
-        Materials
+        
+        Elmer binaries
+        
     
     
-        
+        
+        Leave blank to use default ElmerGrid binary file
+        
+    
+    
+        
+        ElmerSolver binary path
+        
+    
+    
+        
+        ElmerGrid binary path
+        
+    
+    
+        
+        ElmerGrid:
+        
+    
+    
+        
+        
+        Search in known binary directories
+        
+    
+    
+        
+        ElmerSolver:
+        
+    
+    
+        
+        Leave blank to use default Elmer elmer binary file
+        
+    
+
+
+    FemGui::DlgSettingsFemExportAbaqus
+    
+        
+        INP
+        
+    
+    
+        
+        Export
+        
+    
+    
+        
+        Mesh groups are exported too.
+Every constraint and, if there are different materials, material
+consists of two mesh groups, faces and nodes where the
+constraint or material is applied.
+        
+    
+    
+        
+        Export group data
+        
+    
+    
+        
+        All: All elements will be exported.
+
+Highest: Only the highest elements will be exported. This means
+for means volumes for a volume mesh and faces for a shell mesh.
+
+FEM: Only FEM elements will be exported. This means only edges
+not belonging to faces and faces not belonging to volumes.
+        
+    
+    
+        
+        element parameter: All: all elements, highest: highest elements only, FEM: FEM elements only (only edges not belonging to faces and faces not belonging to volumes)
+        
+    
+    
+        
+        All
+        
+    
+    
+        
+        Highest
+        
+    
+    
+        
+        FEM
+        
+    
+    
+        
+        Which mesh elements to export
+        
+    
+
+
+    FemGui::DlgSettingsFemGeneralImp
+    
+        
+        General
+        
+    
+    
+        
+        Working directory for solving analysis and gmsh meshing
+        
+    
+    
+        
+        sdfsdfsdfds
+        
+    
+    
+        
+        Temporary directories
+        
+    
+    
+        
+        Let the application manage (create, delete) the working directories for all solver. Use temporary directories.
+        
+    
+    
+        
+        Beside .FCStd file
+        
+    
+    
+        
+        Create a directory in the same folder in which the FCStd file of the document is located. Use Subfolder for each solver (e.g. for a file ./mydoc.FCStd and a solver with the label Elmer002 use ./mydoc/Elmer002).
+        
+    
+    
+        
+        Use custom directory
+        
+    
+    
+        
+        Use directory set below. Create own subdirectory for every solver. Name directory after the solver label prefixed with the document name.
+        
+    
+    
+        
+        Path:
+        
+    
+    
+        
+        Overwrite solver working directory with the directory chosen above
+        
+    
+    
+        
+        Mesh
+        
+    
+    
+        
+        Create mesh groups for analysis reference shapes (highly experimental)
+        
+    
+    
+        
+        Results
+        
+    
+    
+        
+        Keep results on calculation re-run
+        
+    
+    
+        
+        Restore result dialog settings
+        
+    
+    
+        
+        Hide constraints when open result dialog
+        
+    
+
+
+    FemGui::DlgSettingsFemGmshImp
+    
+        
+        Gmsh
+        
+    
+    
+        
+        Gmsh binary
+        
+    
+    
+        
+        Search in known binary directories
+        
+    
+    
+        
+        gmsh
+        
+    
+    
+        
+        gmsh binary path
+        
+    
+    
+        
+        Leave blank to use default gmsh binary file
+        
+    
+
+
+    FemGui::DlgSettingsFemInOutVtk
+    
+        
+        VTK
+        
+    
+    
+        
+        Import
+        
+    
+    
+        
+        Which object to import into
+        
+    
+    
+        
+        VTK result object: A FreeCAD FEM VTK result object will be imported
+(equals to the object which was exported).
+
+FEM mesh object: The results in the VTK file will be omitted, only the
+mesh data will be imported and a FreeCAD FEM mesh object will be created.
+
+FreeCAD result object: The imported data will be converted into a
+FreeCAD FEM Result object. Note: this setting needs the exact result
+component names and thus it only works properly with VTK files
+exported from FreeCAD.
+        
+    
+    
+        
+        Choose in which object to import into
+        
+    
+    
+        
+        VTK result object
+        
+    
+    
+        
+        FEM mesh object
+        
+    
+    
+        
+        FreeCAD result object
+        
+    
+
+
+    FemGui::DlgSettingsFemMaterialImp
+    
+        
+        Material
+        
+    
+    
+        
+        Card resources
+        
+    
+    
+        
         Use built-in materials
-        Use built-in materials
+        
     
     
-        
-        Use materials from .FreeCAD/Materials directory
-        Use materials from .FreeCAD/Materials directory
+        
+        Use materials from Materials directory in users FreeCAD user pref directory.
+        
     
     
-        
+        
         Use materials from user defined directory
-        Use materials from user defined directory
+        
     
     
-        
+        
         User directory
-        User directory
+        
+    
+    
+        
+        Card sorting and duplicates
+        
+    
+    
+        
+        Delete card duplicates
+        
+    
+    
+        
+        Sort by resources (opposite would be sort by cards)
+        
+    
+
+
+    FemGui::DlgSettingsFemMystranImp
+    
+        
+        
+        Mystran
+        
+    
+    
+        
+        Mystran binary
+        
+    
+    
+        
+        Search in known binary directories
+        
+    
+    
+        
+        Mystran binary path
+        
+    
+    
+        
+        Leave blank to use default Mystran binary file location
+        
+    
+    
+        
+        Comments
+        
+    
+    
+        
+        write comments to input file
+        
+    
+
+
+    FemGui::DlgSettingsFemZ88Imp
+    
+        
+        Z88
+        
+    
+    
+        
+        Z88 binary
+        
+    
+    
+        
+        Search in known binary directories
+        
+    
+    
+        
+        z88r
+        
+    
+    
+        
+        z88r binary path
+        
+    
+    
+        
+        Leave blank to use default Z88 z88r binary file
+        
     
 
 
     FemGui::TaskAnalysisInfo
     
-        
+        
         Nodes set
-        Nodes set
+        
     
 
 
     FemGui::TaskCreateNodeSet
     
-        
+        
         Nodes set
-        Nodes set
+        
     
 
 
     FemGui::TaskDlgFemConstraint
     
-        
-        
+        
+        
         Input error
-        Invoerfout
+        
     
     
-        
+        
         You must specify at least one reference
-        You must specify at least one reference
+        
     
 
 
     FemGui::TaskDlgFemConstraintBearing
     
-        
+        
         Input error
-        Invoerfout
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintContact
+    
+        
+        Input error
+        
     
 
 
@@ -1467,691 +1533,2019 @@
     
         
         Input error
-        Invoerfout
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintFluidBoundary
+    
+        
+        Input error
+        
     
 
 
     FemGui::TaskDlgFemConstraintForce
     
-        
-        
+        
+        
         Input error
-        Invoerfout
+        
     
     
-        
+        
         Please specify a force greater than 0
-        Please specify a force greater than 0
+        
     
 
 
     FemGui::TaskDlgFemConstraintGear
     
-        
+        
         Input error
-        Invoerfout
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintHeatflux
+    
+        
+        Input error
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintInitialTemperature
+    
+        
+        
+        Input error
+        
     
 
 
     FemGui::TaskDlgFemConstraintPressure
     
-        
-        
+        
         Input error
-        Invoerfout
-    
-    
-        
-        Please specify a pressure greater than 0
-        Please specify a pressure greater than 0
+        
     
 
 
     FemGui::TaskDlgFemConstraintPulley
     
-        
+        
         Input error
-        Invoerfout
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintSpring
+    
+        
+        Input error
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintTemperature
+    
+        
+        Input error
+        
+    
+
+
+    FemGui::TaskDlgFemConstraintTransform
+    
+        
+        Input error
+        
     
 
 
     FemGui::TaskDlgMeshShapeNetgen
     
-        
+        
         Edit FEM mesh
-        Edit FEM mesh
+        
     
     
-        
+        
         Meshing failure
-        Meshing failure
+        
+    
+
+
+    FemGui::TaskDlgPost
+    
+        
+        Input error
+        
     
 
 
     FemGui::TaskDriver
     
-        
+        
         Nodes set
-        Nodes set
+        
     
 
 
     FemGui::TaskFemConstraint
     
-        
+        
         FEM constraint parameters
-        FEM constraint parameters
+        
+    
+    
+        
+        Delete
+        
     
 
 
     FemGui::TaskFemConstraintBearing
     
-        
-        Delete
-        Vee uit
-    
-    
-        
-        
-        
-        
-        
-        
+        
+        
+        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
+        
         Please use only a single reference for bearing constraint
-        Please use only a single reference for bearing constraint
+        
     
     
-        
+        
         Only faces can be picked
-        Only faces can be picked
+        
     
     
-        
+        
         Only cylindrical faces can be picked
-        Only cylindrical faces can be picked
+        
     
     
-        
+        
         Only planar faces can be picked
-        Only planar faces can be picked
+        
     
     
-        
+        
         Only linear edges can be picked
-        Only linear edges can be picked
+        
     
     
-        
+        
         Only faces and edges can be picked
-        Only faces and edges can be picked
+        
+    
+
+
+    FemGui::TaskFemConstraintContact
+    
+        
+        
+        Delete
+        
+    
+    
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        Only one face in object! - moved to master face
+        
+    
+    
+        
+        
+        Only one master face and one slave face for a contact constraint!
+        
+    
+    
+        
+        
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Only one slave face for a contact constraint!
+        
+    
+    
+        
+        
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        
+        Only faces can be picked
+        
+    
+    
+        
+        Only one master for a contact constraint!
+        
+    
+    
+        
+        Only one master face for a contact constraint!
+        
     
 
 
     FemGui::TaskFemConstraintDisplacement
     
-        
-        Delete
-        Vee uit
-    
-    
-        
-        
-        
-        
+        
+        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
-        
+        
+        
         Nothing selected!
-        Nothing selected!
+        
     
     
-        
-        
+        
+        
         Selected object is not a part!
-        Selected object is not a part!
+        
+    
+    
+        
+        Only one type of selection (vertex,face or edge) per constraint allowed!
+        
     
 
 
     FemGui::TaskFemConstraintFixed
     
-        
-        Delete
-        Vee uit
-    
-    
-        
-        
+        
+        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
-        Mixed shape types are not possible. Use a second constraint instead
-        Mixed shape types are not possible. Use a second constraint instead
+        
+        
+        Nothing selected!
+        
     
     
-        
-        Only faces, edges and vertices can be picked
-        Only faces, edges and vertices can be picked
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        Only one type of selection (vertex,face or edge) per constraint allowed!
+        
+    
+
+
+    FemGui::TaskFemConstraintFluidBoundary
+    
+        
+        Basic
+        
+    
+    
+        
+        Turbulence
+        
+    
+    
+        
+        Thermal
+        
+    
+    
+        
+        select boundary type, faces and set value
+        
+    
+    
+        
+        Intensity [0~1]
+        
+    
+    
+        
+        Dissipation Rate [m2/s3]
+        
+    
+    
+        
+        Length Scale[m]
+        
+    
+    
+        
+        Viscosity Ratio [1]
+        
+    
+    
+        
+        Hydraulic Diameter [m]
+        
+    
+    
+        
+        
+        Gradient [K/m]
+        
+    
+    
+        
+        Flux [W/m2]
+        
+    
+    
+        
+        Empty selection
+        
+    
+    
+        
+        Select an edge or a face, please.
+        
+    
+    
+        
+        
+        
+        
+        
+        Wrong selection
+        
+    
+    
+        
+        Selected object is not a part object!
+        
+    
+    
+        
+        Only one planar face or edge can be selected!
+        
+    
+    
+        
+        Only planar faces can be picked for 3D
+        
+    
+    
+        
+        Only planar edges can be picked for 2D
+        
+    
+    
+        
+        Only faces for 3D part or edges for 2D can be picked
+        
+    
+    
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        Only one type of selection (vertex,face or edge) per constraint allowed!
+        
     
 
 
     FemGui::TaskFemConstraintForce
     
-        
-        Delete
-        Vee uit
-    
-    
-        
-        Point load
-        Point load
-    
-    
-        
-        Line load
-        Line load
-    
-    
-        
-        Area load
-        Area load
-    
-    
-        
-        
-        
-        
-        
+        
+        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
-        Mixed shape types are not possible. Use a second constraint instead
-        Mixed shape types are not possible. Use a second constraint instead
+        
+        
+        Nothing selected!
+        
     
     
-        
-        Only faces, edges and vertices can be picked
-        Only faces, edges and vertices can be picked
+        
+        
+        Selected object is not a part!
+        
     
     
-        
-        Only planar faces can be picked
-        Only planar faces can be picked
+        
+        Only one type of selection (vertex,face or edge) per constraint allowed!
+        
     
     
-        
-        Only linear edges can be picked
-        Only linear edges can be picked
+        
+        
+        Wrong selection
+        
     
     
-        
-        Only faces and edges can be picked
-        Only faces and edges can be picked
+        
+        Select an edge or a face, please.
+        
     
 
 
     FemGui::TaskFemConstraintGear
     
-        
-        
-        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
+        
         Only planar faces can be picked
-        Only planar faces can be picked
+        
     
     
-        
+        
         Only linear edges can be picked
-        Only linear edges can be picked
+        
     
     
-        
+        
         Only faces and edges can be picked
-        Only faces and edges can be picked
+        
+    
+
+
+    FemGui::TaskFemConstraintHeatflux
+    
+        
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        
+        Selection must only consist of faces!
+        
+    
+
+
+    FemGui::TaskFemConstraintPlaneRotation
+    
+        
+        
+        
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Only one face can be selected for a plane rotation constraint!
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        Only faces can be picked
+        
+    
+    
+        
+        Only planar faces can be picked
+        
     
 
 
     FemGui::TaskFemConstraintPressure
     
-        
-        Delete
-        Vee uit
-    
-    
-        
+        
+        
+        
+        
+        
         Selection error
-        Selection error
+        
     
     
-        
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
         Only faces can be picked
-        Only faces can be picked
+        
     
 
 
     FemGui::TaskFemConstraintPulley
     
-        
+        
         Pulley diameter
-        Pulley diameter
+        
     
     
-        
+        
         Torque [Nm]
-        Torque [Nm]
+        
+    
+
+
+    FemGui::TaskFemConstraintSpring
+    
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        Only faces can be picked
+        
+    
+
+
+    FemGui::TaskFemConstraintTemperature
+    
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+
+
+    FemGui::TaskFemConstraintTransform
+    
+        
+        Constraint update error
+        
+    
+    
+        
+        The transformable faces have changed. Please add only the transformable faces and remove non-transformable faces!
+        
+    
+    
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        Selection error
+        
+    
+    
+        
+        
+        Nothing selected!
+        
+    
+    
+        
+        
+        Only one face for rectangular transform constraint!
+        
+    
+    
+        
+        
+        Selected object is not a part!
+        
+    
+    
+        
+        Only one face for transform constraint!
+        
+    
+    
+        
+        Only faces can be picked
+        
+    
+    
+        
+        Only cylindrical faces can be picked
+        
+    
+    
+        
+        Only transformable faces can be selected! Apply displacement constraint to surface first then apply constraint to surface
+        
     
 
 
     FemGui::TaskObjectName
     
-        
+        
         TaskObjectName
-        TaskObjectName
+        
+    
+
+
+    FemGui::TaskPostClip
+    
+        
+        Clip region, choose implicit function
+        
+    
+
+
+    FemGui::TaskPostCut
+    
+        
+        Function cut, choose implicit function
+        
+    
+
+
+    FemGui::TaskPostDataAlongLine
+    
+        
+        Data along a line options
+        
+    
+
+
+    FemGui::TaskPostDataAtPoint
+    
+        
+        Data at point options
+        
+    
+
+
+    FemGui::TaskPostDisplay
+    
+        
+        Result display options
+        
+    
+
+
+    FemGui::TaskPostFunction
+    
+        
+        Implicit function
+        
+    
+
+
+    FemGui::TaskPostScalarClip
+    
+        
+        Scalar clip options
+        
+    
+
+
+    FemGui::TaskPostWarpVector
+    
+        
+        Warp options
+        
     
 
 
     FemGui::TaskTetParameter
     
-        
+        
         Tet Parameter
-        Tet Parameter
+        
     
 
 
     FemGui::ViewProviderFemAnalysis
     
-        
+        
         Activate analysis
-        Activate analysis
+        
     
 
 
     FemGui::ViewProviderFemMeshShapeNetgen
     
-        
+        
         Meshing failure
-        Meshing failure
+        
     
     
-        
+        
         The FEM module is built without NETGEN support. Meshing will not work!!!
-        The FEM module is built without NETGEN support. Meshing will not work!!!
+        
+    
+
+
+    FemMaterial
+    
+        
+        
+        FEM material
+        
+    
+    
+        
+        
+        
+        Material
+        
+    
+    
+        
+        Category
+        
+    
+    
+        
+        choose...
+        
+    
+    
+        
+        Material card
+        
+    
+    
+        
+        Material name
+        
+    
+    
+        
+        
+        
+        TextLabel
+        
+    
+    
+        
+        Material Description
+        
+    
+    
+        
+        Editing material
+        
+    
+    
+        
+        use FreeCAD material editor
+        
+    
+    
+        
+        use this task panel
+        
+    
+    
+        
+        Basic Properties
+        
+    
+    
+        
+        Density                     
+        
+    
+    
+        
+        8000 kg/m^3
+        
+    
+    
+        
+        Mechanical Properties
+        
+    
+    
+        
+        Young's Modulus:
+        
+    
+    
+        
+        200 GPa
+        
+    
+    
+        
+        Poisson Ratio:
+        
+    
+    
+        
+        Fluidic Properties
+        
+    
+    
+        
+        Kinematic viscosity:
+        
+    
+    
+        
+        0.000001 m^2/s
+        
+    
+    
+        
+        Thermal  Properties
+        
+    
+    
+        
+        Thermal Conductivity:
+        
+    
+    
+        
+        50 W/m/K
+        
+    
+    
+        
+        Expansion Coefficient:
+        
+    
+    
+        
+        12 um/m/K
+        
+    
+    
+        
+        Specific Heat:
+        
+    
+    
+        
+        500 J/kg/K
+        
+    
+    
+        
+        Vol Expansion Coeff
+        
+    
+    
+        
+        0.001 m/m/K
+        
+    
+    
+        
+        Matrix Material
+        
+    
+    
+        
+        
+        Choose
+        
+    
+    
+        
+        
+        Name
+        
+    
+    
+        
+        
+        Edit
+        
+    
+    
+        
+        
+        Properties
+        
+    
+    
+        
+        
+        Description
+        
+    
+    
+        
+        Reinforcement Material
+        
     
 
 
     Form
     
-        
-        
+        
         Form
-        Vorm
+        
     
     
-        
-        Cross Section
-        Cross Section
+        
+        Fluid Section Parameter
+        
     
     
-        
-        
-        Use FreeCAD Property Editor
-        Use FreeCAD Property Editor
+        
+        Liquid Section Parameter
+        
     
     
-        
-        to edit the cross section values
-        to edit the cross section values
+        
+        Pipe Area 
+        
     
     
-        
-        
-        References
-        References
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        0 mm^2
+        
     
     
-        
-        
-        Leave references blank 
-        Leave references blank 
+        
+        
+        Hydraulic Radius
+        
     
     
-        
-        
-        to choose all remaining shapes
-        to choose all remaining shapes
+        
+        
+        
+        0 mm
+        
     
     
-        
-        
-        Add reference
-        Add reference
+        
+        Manning Coefficient
+        
     
     
-        
-        Thickness
-        Dikte
+        
+        
+        Initial Area
+        
     
     
-        
-        to edit the thickness value
-        to edit the thickness value
+        
+        Enlarged Area
+        
+    
+    
+        
+        Contracted Area
+        
+    
+    
+        
+        Inlet Pressure
+        
+    
+    
+        
+        
+        Pressure
+        
+    
+    
+        
+        Inlet Mass Flow Rate
+        
+    
+    
+        
+        
+        Mass flow rate
+        
+    
+    
+        
+        
+        1 kg/s
+        
+    
+    
+        
+        Outlet Pressure
+        
+    
+    
+        
+        Outlet Mass Flow Rate
+        
+    
+    
+        
+        
+        
+        
+        
+        Pipe Area
+        
+    
+    
+        
+        Entrance Area
+        
+    
+    
+        
+        Diaphragm Area
+        
+    
+    
+        
+        Bend Radius/Pipe Diameter
+        
+    
+    
+        
+        Bend Angle
+        
+    
+    
+        
+        Head loss coefficient
+        
+    
+    
+        
+        Gate valve closing coefficient
+        
+    
+    
+        
+        Pump Characteristic
+        
+    
+    
+        
+        1
+        
+    
+    
+        
+        2
+        
+    
+    
+        
+        3
+        
+    
+    
+        
+        4
+        
+    
+    
+        
+        5
+        
+    
+    
+        
+        Flow rate [mm^3/s]
+        
+    
+    
+        
+        Head Loss[mm]
+        
+    
+    
+        
+        Grain diameter
+        
+    
+    
+        
+        Cross section form factor
+        
+    
+    
+        
+        Gas Section Parameter
+        
+    
+    
+        
+        Open Channel Section Parameter
+        
+    
+    
+        
+        Centrif parameter
+        
+    
+    
+        
+        
+        
+        
+        
+        Parameter
+        
+    
+    
+        
+        Rotation frequency f<sub>rot</sub> [rps]
+        
+    
+    
+        
+        revolutions per second
+        
+    
+    
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        0.0
+        
+    
+    
+        
+        1/s
+        
+    
+    
+        
+        SectionPrint parameter
+        
+    
+    
+        
+        Tie parameter
+        
+    
+    
+        
+        Tolerance:     
+        
+    
+    
+        
+        
+        
+        Constraint Properties
+        
+    
+    
+        
+        Potential:
+        
+    
+    
+        
+        Potential Constant
+        
+    
+    
+        
+        Farfield / Electric infinity
+        
+    
+    
+        
+        
+        
+        
+        
+        
+        
+        
+        unspecified
+        
+    
+    
+        
+        V
+        
+    
+    
+        
+        Capacity Body: 
+        Enabled by 'Calculate Capacity Matrix' in Electrostatic equation
+        
+    
+    
+        
+        Calculate Electric Force
+        
+    
+    
+        
+        Beam section parameter
+        
+    
+    
+        
+        
+        Cross section parameter
+        
+    
+    
+        
+        Width:   
+        
+    
+    
+        
+        Height:     
+        
+    
+    
+        
+        
+        Diameter:   
+        
+    
+    
+        
+        Thickness:
+        
+    
+    
+        
+        Shell thickness parameter
+        
+    
+    
+        
+        Thickness:     
+        
+    
+    
+        
+        Beam section rotation
+        
+    
+    
+        
+        Rotation:     
+        
+    
+    
+        
+        
+        Velocity x:
+        
+    
+    
+        
+        
+        Velocity y:
+        
+    
+    
+        
+        
+        Velocity z:
+        
+    
+    
+        
+        
+        
+        
+        
+        
+        m/s
+        
+    
+    
+        
+        normal to boundary
+        
+    
+    
+        
+        Mesh boundary layer settings
+        
+    
+    
+        
+        Max Layers
+        
+    
+    
+        
+        1.0
+        
+    
+    
+        
+        Min/1st thickness
+        
+    
+    
+        
+        Growth ratio
+        
+    
+    
+        
+        Mesh group
+        
+    
+    
+        
+        Identifier used for mesh export
+        
+    
+    
+        
+        Name
+        
+    
+    
+        
+        Label
+        
+    
+    
+        
+        Mesh region
+        
+    
+    
+        
+        Max element size:
+        
     
 
 
-    MechanicalMaterial
+    GmshMesh
     
-        
-        Mechanical analysis
-        Mechanical analysis
+        
+        FEM Mesh by Gmsh
+        
     
     
-        
-        Working directory
-        Working directory
+        
+        FEM Mesh Parameter
+        
     
     
-        
-        ...
-        ...
+        
+        Element dimension:
+        
     
     
-        
-        Analysis type
-        Analysis type
+        
+        Max element size (0.0 = Auto):
+        
     
     
-        
-        Static
-        Static
+        
+        
+        0.0
+        
     
     
-        
-        Frequency
-        Frequency
+        
+        Min element size (0.0 = Auto):
+        
     
     
-        
-        Write .inp file
-        Write .inp file
+        
+        Element order:
+        
     
     
-        
-        Edit .inp file
-        Edit .inp file
+        
+        Gmsh
+        
     
     
-        
-        Run Calculix
-        Run Calculix
-    
-    
-        
+        
         Time:
-        Time:
+        
     
     
-        
-        Mechanical material
-        Mechanical material
+        
+        Gmsh version
+        
+    
+
+
+    PlaneWidget
+    
+        
+        Form
+        
     
     
-        
-        Material
-        Materiaal
+        
+        Origin
+        
     
     
-        
-        choose...
-        choose...
-    
-    
-        
-        Material Description
-        Material Description
-    
-    
-        
-        References
-        References
-    
-    
-        
-        Leave references blank 
-        Leave references blank 
-    
-    
-        
-        to choose all remaining shapes
-        to choose all remaining shapes
-    
-    
-        
-        Add reference
-        Add reference
-    
-    
-        
-        Properties
-        Properties
-    
-    
-        
-        Young's Modulus:
-        Young's Modulus:
-    
-    
-        
-        Poisson Ratio:
-        Poisson Ratio:
-    
-    
-        
-        Density
-        Density
-    
-    
-        
-        External material resources
-        External material resources
-    
-    
-        
-        MatWeb database...
-        MatWeb database...
+        
+        Normal
+        
     
 
 
     QObject
     
-        
+        
         No active Analysis
-        No active Analysis
+        
     
     
-        
+        
         You need to create or activate a Analysis
-        You need to create or activate a Analysis
+        
     
     
-        
-        
-        
-        
-        
-        Wrong selection
-        Verkeerde keuse
-    
-    
-        
-        
-        
-        Your FreeCAD is build without NETGEN support. Meshing will not work....
-        Your FreeCAD is build without NETGEN support. Meshing will not work....
-    
-    
-        
-        
-        Select an edge, face or body. Only one body is allowed.
-        Kies 'n rand, vlak of liggaam. Slegs een liggaam word toegelaat.
-    
-    
-        
-        
-        Wrong object type
-        Verkeerde voorwerpsoort
-    
-    
-        
-        
-        Fillet works only on parts
-        Ronding werk slegs op onderdele
-    
-    
-        
+        
         Ok
-        Ok
+        
     
     
-        
+        
         Cancel
-        Kanselleer
+        
     
     
-        
+        
         Edit constraint
-        Edit constraint
+        
     
     
-        
-        
-        
-        
-        
+        
+        
+        
+        
+        
+        
+        
+        
         A dialog is already open in the task panel
-        'n Dialoog is reeds oop in die taakpaneel
+        
     
     
-        
-        
-        
-        
-        
+        
+        
+        
+        
+        
+        
+        
+        
         Do you want to close this dialog?
-        Wil jy hierdie dialoog toe maak?
+        
     
     
-        
+        
         Meshing
-        Meshing
+        
     
     
-        
+        
         Constraint force
-        Constraint force
+        
     
     
-        
-        
-        Constraint normal stress
-        Constraint normal stress
+        
+        
+        
+        
+        
+        
+        
+        FEM
+        
     
     
-        
-        [Nodes: %1, Edges: %2, Faces: %3, Polygons: %4, Volumes: %5, Polyhedrons: %6]
-        [Nodes: %1, Edges: %2, Faces: %3, Polygons: %4, Volumes: %5, Polyhedrons: %6]
+        
+        
+        Import-Export
+        
+    
+    
+        
+        [Nodes: %1, Edges: %2, Faces: %3, Polygons: %4, Volumes: %5, Polyhedrons: %6, Groups: %7]
+        
+    
+    
+        
+        Constraint Contact
+        
+    
+    
+        
+        Constraint displacement
+        
+    
+    
+        
+        Constraint fixed
+        
+    
+    
+        
+        Constraint fluid boundary
+        
+    
+    
+        
+        Constraint heat flux
+        
+    
+    
+        
+        Constraint initial temperature
+        
+    
+    
+        
+        Constraint planerotation
+        
+    
+    
+        
+        Constraint pressure
+        
+    
+    
+        
+        Constraint pulley
+        
+    
+    
+        
+        Constraint spring
+        
+    
+    
+        
+        Constraint temperature
+        
+    
+    
+        
+        Constraint transform
+        
+    
+    
+        
+        Edit post processing object
+        
     
 
 
     ShowDisplacement
     
-        
+        
         Show result
-        Show result
+        
     
     
-        
+        
         Result type
-        Result type
+        
     
     
-        
-        Y displacement
-        Y displacement
+        
+        Displacement Magnitude
+        
     
     
-        
-        X displacement
-        X displacement
-    
-    
-        
-        Z displacement
-        Z displacement
-    
-    
-        
+        
         None
-        Geen
+        
     
     
-        
-        Von Mises stress
-        Von Mises stress
+        
+        Displacement Y
+        
     
     
-        
-        Abs displacement
-        Abs displacement
+        
+        Displacement X
+        
     
     
-        
-        Avg:
-        Avg:
+        
+        Peeq
+        
     
     
-        
-        Max:
-        Max:
+        
+        Displacement Z
+        
     
     
-        
+        
+        Temperature
+        
+    
+    
+        
+        von Mises Stress
+        
+    
+    
+        
+        Max Principal Stress
+        
+    
+    
+        
+        Min Principal Stress
+        
+    
+    
+        
+        Max Shear Stress (Tresca)
+        
+    
+    
+        
+        Mass Flow Rate
+        
+    
+    
+        
+        Network Pressure
+        
+    
+    
+        
         Min:
-        Min:
+        
     
     
-        
+        
+        Max:
+        
+    
+    
+        
+        Histogram
+        
+    
+    
+        
         Displacement
-        Displacement
+        
     
     
-        
+        
         Show
-        Show
+        
     
     
-        
+        
         Factor:
-        Factor:
+        
     
     
-        
+        
         Slider max:
-        Slider max:
+        
+    
+    
+        
+        User defined equation
+        
+    
+    
+        
+        Calculate and plot
+        
+    
+    
+        
+        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">P1-P3 # Stress intensity stress equation. Available values are numpy array format. Calculation np.function can be used on available values. </span></p></body></html>
+        
+    
+    
+        
+        Hints user defined equations
+        
+    
+    
+        
+        Available result types:
+        
+    
+    
+        
+        displacement: x, y, z
+        
+    
+    
+        
+        mass flow rate: MF
+        
+    
+    
+        
+        network pressure: NP
+        
+    
+    
+        
+        von Mises stress: vM
+        
+    
+    
+        
+        temperature: T
+        
+    
+    
+        
+        min. principal stress vector: s1x, s1y, s1z
+        
+    
+    
+        
+        principal stresses: P1, P2, P3
+        
+    
+    
+        
+        reinforcement ratio: rx, ry, rz
+        
+    
+    
+        
+        equivalent plastic strain: Peeq
+        
+    
+    
+        
+        med. principal stress vector: s2x, s2y, s2z
+        
+    
+    
+        
+        stress: sxx, syy, szz, sxy, sxz, syz
+        
+    
+    
+        
+        strain: exx, eyy, ezz, exy, exz, eyz
+        
+    
+    
+        
+        Mohr Coulomb: mc
+        
+    
+    
+        
+        max. principal stress vector: s3x, s3y, s3z
+        
+    
+
+
+    SolverCalculix
+    
+        
+        Mechanical analysis
+        
+    
+    
+        
+        Working directory
+        
+    
+    
+        
+        ...
+        
+    
+    
+        
+        Analysis type
+        
+    
+    
+        
+        Thermo mechanical
+        
+    
+    
+        
+        Check Mesh
+        
+    
+    
+        
+        Frequency
+        
+    
+    
+        
+        Static
+        
+    
+    
+        
+        Buckling
+        
+    
+    
+        
+        Write .inp file
+        
+    
+    
+        
+        Edit .inp file
+        
+    
+    
+        
+        Run CalculiX
+        
+    
+    
+        
+        Time:
+        
+    
+
+
+    SphereWidget
+    
+        
+        Form
+        
+    
+    
+        
+        Radius
+        
+    
+    
+        
+        Center
+        
     
 
 
@@ -2159,17 +3553,17 @@
     
         
         Form
-        Vorm
+        
     
     
         
         Meshes:
-        Meshes:
+        
     
     
         
         Constraints
-        Beperkings
+        
     
 
 
@@ -2177,57 +3571,57 @@
     
         
         Form
-        Vorm
+        
     
     
         
         Volume
-        Volume
+        
     
     
         
         Surface
-        Surface
+        
     
     
         
         Nodes: 0
-        Nodes: 0
+        
     
     
         
         Poly
-        Poly
+        
     
     
         
         Box
-        Boks
+        
     
     
         
         Pick
-        Pick
+        
     
     
         
         Add
-        Voeg by
+        
     
     
         
         Angle-search
-        Angle-search
+        
     
     
         
-        Collect adjancent nodes
-        Collect adjancent nodes
+        Collect adjacent nodes
+        
     
     
         
         Stop angle:
-        Stop angle:
+        
     
 
 
@@ -2235,7 +3629,7 @@
     
         
         Form
-        Vorm
+        
     
 
 
@@ -2243,52 +3637,52 @@
     
         
         Form
-        Vorm
+        
     
     
         
         Add reference
-        Add reference
+        
     
     
         
         Load [N]
-        Load [N]
+        
     
     
         
         Diameter
-        Diameter
+        
     
     
         
         Other diameter
-        Other diameter
+        
     
     
         
         Center distance
-        Center distance
+        
     
     
         
         Direction
-        Rigting
+        
     
     
         
         Reverse direction
-        Omgekeerde rigting
+        
     
     
         
         Location
-        Location
+        
     
     
         
         Distance
-        Afstand
+        
     
 
 
@@ -2296,72 +3690,112 @@
     
         
         Form
-        Vorm
+        
     
     
         
         Add reference
-        Add reference
+        
     
     
         
         Gear diameter
-        Gear diameter
+        
     
     
         
-        Other pulley dia
-        Other pulley dia
+        Other pulley diameter
+        
     
     
         
         Center distance
-        Center distance
+        
     
     
         
         Force
-        Force
+        
     
     
         
         Belt tension force
-        Belt tension force
+        
     
     
         
         Driven pulley
-        Driven pulley
+        
     
     
         
         Force location [deg]
-        Force location [deg]
+        
     
     
         
         Force Direction
-        Force Direction
+        
     
     
         
         Reversed direction
-        Reversed direction
+        
     
     
         
         Axial free
-        Axial free
+        
     
     
         
         Location
-        Location
+        
     
     
         
         Distance
-        Afstand
+        
+    
+
+
+    TaskFemConstraintContact
+    
+        
+        Form
+        
+    
+    
+        
+        Select master face, click Add or Remove
+        
+    
+    
+        
+        
+        Add
+        
+    
+    
+        
+        
+        Remove
+        
+    
+    
+        
+        Select slave face, click Add or Remove
+        
+    
+    
+        
+        Contact Stiffness
+        
+    
+    
+        
+        Friction coefficient
+        
     
 
 
@@ -2369,27 +3803,27 @@
     
         
         Prescribed Displacement
-        Prescribed Displacement
+        
     
     
         
         Select multiple face(s), click Add or Remove
-        Select multiple face(s), click Add or Remove
+        
     
     
         
         Add
-        Voeg by
+        
     
     
         
         Remove
-        Verwyder
+        
     
     
         
         Displacement x
-        Displacement x
+        
     
     
         
@@ -2399,7 +3833,7 @@
         
         
         Free
-        Free
+        
     
     
         
@@ -2409,37 +3843,37 @@
         
         
         Fixed
-        Fixed
+        
     
     
         
         Displacement y
-        Displacement y
+        
     
     
         
         Displacement z
-        Displacement z
+        
     
     
         
         Rotations are only valid for Beam and Shell elements.
-        Rotations are only valid for Beam and Shell elements.
+        
     
     
         
         Rotation x
-        Rotation x
+        
     
     
         
         Rotation y
-        Rotation y
+        
     
     
         
         Rotation z
-        Rotation z
+        
     
 
 
@@ -2447,40 +3881,281 @@
     
         
         Form
-        Vorm
+        
     
     
         
-        Add reference
-        Add reference
+        Select multiple face(s), click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+
+
+    TaskFemConstraintFluidBoundary
+    
+        
+        Form
+        
+    
+    
+        
+        Boundary 
+        
+    
+    
+        
+        Subtype
+        
+    
+    
+        
+        Select multiple face(s), click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        Help text
+        
+    
+    
+        
+        Tab 1
+        
+    
+    
+        
+        Value [Unit]
+        
+    
+    
+        
+        Select a planar edge or face, then press this button
+        
+    
+    
+        
+        Direction 
+        
+    
+    
+        
+        The direction of the edge or the direction of the
+normal vector of the face is used as direction
+        
+    
+    
+        
+        Reverse direction
+        
+    
+    
+        
+        Page
+        
+    
+    
+        
+        Turbulence specification
+        
+    
+    
+        
+        Intensity    
+        
+    
+    
+        
+        Length [m]
+        
+    
+    
+        
+        Tab 2
+        
+    
+    
+        
+         Type 
+        
+    
+    
+        
+        Temperature[K]
+        
+    
+    
+        
+        Heat flux [W/m2]
+        
+    
+    
+        
+        HT coeff
+        
     
 
 
     TaskFemConstraintForce
-    
-        
-        Form
-        Vorm
-    
-    
-        
-        Add reference
-        Add reference
-    
     
         
+        Prescribed Force
+        
+    
+    
+        
+        Select multiple face(s), click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
         Load [N]
-        Load [N]
+        
     
     
-        
+        
+        Select a planar edge or face, then press this button
+        
+    
+    
+        
         Direction
-        Rigting
+        
     
     
-        
+        
+        The direction of the edge or the direction of the
+normal vector of the face is used as direction
+        
+    
+    
+        
         Reverse direction
-        Omgekeerde rigting
+        
+    
+
+
+    TaskFemConstraintHeatflux
+    
+        
+        TaskFemConstraintHeatflux
+        
+    
+    
+        
+        Select multiple face(s), click Add or Remove:
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        Surface Convection
+        
+    
+    
+        
+        
+        Surface heat flux
+        
+    
+    
+        
+        Film coefficient
+        
+    
+    
+        
+        1 W/m^2/K
+        
+    
+    
+        
+        Ambient Temperature
+        
+    
+    
+        
+        
+        300 K
+        
+    
+
+
+    TaskFemConstraintInitialTemperature
+    
+        
+        Dialog
+        
+    
+    
+        
+        Insert component's initial temperature:
+        
+    
+    
+        
+        300 K
+        
+    
+
+
+    TaskFemConstraintPlaneRotation
+    
+        
+        Form
+        
+    
+    
+        
+        Select a single face, click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
     
 
 
@@ -2488,27 +4163,168 @@
     
         
         Form
-        Vorm
+        
     
     
         
-        Add reference
-        Add reference
+        Select multiple face(s), click Add or Remove
+        
     
     
-        
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
         Pressure
-        Pressure
+        
     
     
-        
-        1 MPa
-        1 MPa
+        
+        0 MPa
+        
     
     
-        
-        Reverse direction
-        Omgekeerde rigting
+        
+        Reverse Direction
+        
+    
+
+
+    TaskFemConstraintSpring
+    
+        
+        Form
+        
+    
+    
+        
+        Select multiple face(s), click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        0 
+        
+    
+    
+        
+        Normal Stiffness
+        
+    
+    
+        
+        Tangential Stiffness
+        
+    
+
+
+    TaskFemConstraintTemperature
+    
+        
+        Form
+        
+    
+    
+        
+        Select multiple face(s), click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        
+        Temperature
+        
+    
+    
+        
+        Concentrated heat flux
+        
+    
+    
+        
+        300 K
+        
+    
+
+
+    TaskFemConstraintTransform
+    
+        
+        Form
+        
+    
+    
+        
+        Rectangular transform
+        
+    
+    
+        
+        Cylindrical transform
+        
+    
+    
+        
+        Select a face, click Add or Remove
+        
+    
+    
+        
+        Add
+        
+    
+    
+        
+        Remove
+        
+    
+    
+        
+        Rotation about X-Axis
+        
+    
+    
+        
+        Rotation about Y-Axis
+        
+    
+    
+        
+        Rotation about Z-Axis
+        
+    
+    
+        
+        
+        Transformable surfaces
+        
     
 
 
@@ -2516,7 +4332,292 @@
     
         
         Form
-        Vorm
+        
+    
+
+
+    TaskPostClip
+    
+        
+        Form
+        
+    
+    
+        
+        Create
+        
+    
+    
+        
+        Inside Out
+        
+    
+    
+        
+        Cut Cells
+        
+    
+
+
+    TaskPostCut
+    
+        
+        Form
+        
+    
+    
+        
+        Create
+        
+    
+
+
+    TaskPostDataAlongLine
+    
+        
+        Form
+        
+    
+    
+        
+        Point1
+        
+    
+    
+        
+        Point2
+        
+    
+    
+        
+        Select Points
+        
+    
+    
+        
+        Resolution
+        
+    
+    
+        
+        Mode
+        
+    
+    
+        
+        Field
+        
+    
+    
+        
+        Vector
+        
+    
+    
+        
+        Create Plot
+        
+    
+
+
+    TaskPostDataAtPoint
+    
+        
+        Form
+        
+    
+    
+        
+        Center
+        
+    
+    
+        
+        Select Point
+        
+    
+    
+        
+        Field
+        
+    
+
+
+    TaskPostDisplay
+    
+        
+        Form
+        
+    
+    
+        
+        Mode
+        
+    
+    
+        
+        
+        Outline
+        
+    
+    
+        
+        
+        Surface
+        
+    
+    
+        
+        
+        Surface with Edges
+        
+    
+    
+        
+        
+        Wireframe
+        
+    
+    
+        
+        Coloring
+        
+    
+    
+        
+        Field
+        
+    
+    
+        
+        Vector
+        
+    
+    
+        
+        Magnitute
+        
+    
+    
+        
+        X
+        
+    
+    
+        
+        Y
+        
+    
+    
+        
+        Z
+        
+    
+    
+        
+        Styling
+        
+    
+    
+        
+        Transparency
+        
+    
+
+
+    TaskPostScalarClip
+    
+        
+        Form
+        
+    
+    
+        
+        Scalar
+        
+    
+    
+        
+        Outline
+        
+    
+    
+        
+        Surface
+        
+    
+    
+        
+        Surface with Edges
+        
+    
+    
+        
+        Wireframe
+        
+    
+    
+        
+        Min scalar
+        
+    
+    
+        
+        Clip scalar
+        
+    
+    
+        
+        Max scalar
+        
+    
+    
+        
+        -100000
+        
+    
+    
+        
+        0
+        
+    
+    
+        
+        Clip inside out
+        
+    
+
+
+    TaskPostWarpVector
+    
+        
+        Form
+        
+    
+    
+        
+        Vector
+        
+    
+    
+        
+        warp vectors
+        
+    
+    
+        
+        Min warp
+        
+    
+    
+        
+        Warp factor
+        
+    
+    
+        
+        Max warp
+        
     
 
 
@@ -2524,87 +4625,87 @@
     
         
         Form
-        Vorm
+        
     
     
         
         Max. Size:
-        Max. Size:
+        
     
     
         
         Second order
-        Second order
+        
     
     
         
         Fineness:
-        Fineness:
+        
     
     
         
         VeryCoarse
-        VeryCoarse
+        
     
     
         
         Coarse
-        Coarse
+        
     
     
         
         Moderate
-        Moderate
+        
     
     
         
         Fine
-        Fine
+        
     
     
         
         VeryFine
-        VeryFine
+        
     
     
         
         UserDefined
-        UserDefined
+        
     
     
         
         Growth Rate:
-        Growth Rate:
+        
     
     
         
         Nbr. Segs per Edge:
-        Nbr. Segs per Edge:
+        
     
     
         
         Nbr. Segs per Radius:
-        Nbr. Segs per Radius:
+        
     
     
         
         Optimize
-        Optimize
+        
     
     
         
         Node count: 
-        Node count: 
+        
     
     
         
         Triangle count:
-        Triangle count:
+        
     
     
         
-        Tetraeder count:
-        Tetraeder count:
+        Tetrahedron count:
+        
     
 
 
@@ -2612,12 +4713,170 @@
     
         
         FEM
-        FEM
+        
     
     
         
         &FEM
-        &FEM
+        
+    
+    
+        
+        Model
+        
+    
+    
+        
+        M&odel
+        
+    
+    
+        
+        Materials
+        
+    
+    
+        
+        &Materials
+        
+    
+    
+        
+        Element Geometry
+        
+    
+    
+        
+        &Element Geometry
+        
+    
+    
+        
+        Electrostatic Constraints
+        
+    
+    
+        
+        &Electrostatic Constraints
+        
+    
+    
+        
+        Fluid Constraints
+        
+    
+    
+        
+        &Fluid Constraints
+        
+    
+    
+        
+        Geometrical Constraints
+        
+    
+    
+        
+        &Geometrical Constraints
+        
+    
+    
+        
+        Mechanical Constraints
+        
+    
+    
+        
+        &Mechanical Constraints
+        
+    
+    
+        
+        Thermal Constraints
+        
+    
+    
+        
+        &Thermal Constraints
+        
+    
+    
+        
+        Constraints without solver
+        
+    
+    
+        
+        &Constraints without solver
+        
+    
+    
+        
+        Overwrite Constants
+        
+    
+    
+        
+        &Overwrite Constants
+        
+    
+    
+        
+        Mesh
+        
+    
+    
+        
+        M&esh
+        
+    
+    
+        
+        Solve
+        
+    
+    
+        
+        &Solve
+        
+    
+    
+        
+        Results
+        
+    
+    
+        
+        &Results
+        
+    
+    
+        
+        Filter functions
+        
+    
+    
+        
+        &Filter functions
+        
+    
+    
+        
+        Utilities
+        
+    
+
+
+    setupFilter
+    
+        
+        Error: Wrong or no or to many vtk post processing objects.
+        
+    
+    
+        
+        The filter could not set up. Select one vtk post processing pipeline object, or select nothing and make sure there is exact one vtk post processing pipline object in the document.
+        
     
 
 
diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py
index 64565ebd6a..782fffc61f 100644
--- a/src/Mod/Fem/femcommands/commands.py
+++ b/src/Mod/Fem/femcommands/commands.py
@@ -49,7 +49,7 @@ class _Analysis(CommandManager):
 
     def __init__(self):
         super(_Analysis, self).__init__()
-        self.menuetext = "Analysis container"
+        self.menutext = "Analysis container"
         self.accel = "S, A"
         self.tooltip = "Creates an analysis container with standard solver CalculiX"
         self.is_active = "with_document"
@@ -74,7 +74,7 @@ class _ClippingPlaneAdd(CommandManager):
 
     def __init__(self):
         super(_ClippingPlaneAdd, self).__init__()
-        self.menuetext = "Clipping plane on face"
+        self.menutext = "Clipping plane on face"
         self.tooltip = "Add a clipping plane on a selected face"
         self.is_active = "with_document"
 
@@ -119,11 +119,11 @@ class _ClippingPlaneAdd(CommandManager):
 
 
 class _ClippingPlaneRemoveAll(CommandManager):
-    "The FEM_ClippingPlaneemoveAll command definition"
+    "The FEM_ClippingPlaneRemoveAll command definition"
 
     def __init__(self):
         super(_ClippingPlaneRemoveAll, self).__init__()
-        self.menuetext = "Remove all clipping planes"
+        self.menutext = "Remove all clipping planes"
         self.tooltip = "Remove all clipping planes"
         self.is_active = "with_document"
 
@@ -143,7 +143,7 @@ class _ConstantVacuumPermittivity(CommandManager):
     def __init__(self):
         super(_ConstantVacuumPermittivity, self).__init__()
         self.pixmap = "fem-solver-analysis-thermomechanical.svg"
-        self.menuetext = "Constant vacuum permittivity"
+        self.menutext = "Constant vacuum permittivity"
         self.tooltip = "Creates a FEM constant vacuum permittivity to overwrite standard value"
         self.is_active = "with_document"
         self.is_active = "with_analysis"
@@ -156,7 +156,7 @@ class _ConstraintBodyHeatSource(CommandManager):
     def __init__(self):
         super(_ConstraintBodyHeatSource, self).__init__()
         self.pixmap = "FEM_ConstraintHeatflux"  # the heatflux icon is used
-        self.menuetext = "Constraint body heat source"
+        self.menutext = "Constraint body heat source"
         self.tooltip = "Creates a FEM constraint body heat source"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_noset_edit"
@@ -167,7 +167,7 @@ class _ConstraintCentrif(CommandManager):
 
     def __init__(self):
         super(_ConstraintCentrif, self).__init__()
-        self.menuetext = "Constraint centrif"
+        self.menutext = "Constraint centrif"
         self.tooltip = "Creates a FEM constraint centrif"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -178,7 +178,7 @@ class _ConstraintElectrostaticPotential(CommandManager):
 
     def __init__(self):
         super(_ConstraintElectrostaticPotential, self).__init__()
-        self.menuetext = "Constraint electrostatic potential"
+        self.menutext = "Constraint electrostatic potential"
         self.tooltip = "Creates a FEM constraint electrostatic potential"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -189,7 +189,7 @@ class _ConstraintFlowVelocity(CommandManager):
 
     def __init__(self):
         super(_ConstraintFlowVelocity, self).__init__()
-        self.menuetext = "Constraint flow velocity"
+        self.menutext = "Constraint flow velocity"
         self.tooltip = "Creates a FEM constraint flow velocity"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -200,7 +200,7 @@ class _ConstraintInitialFlowVelocity(CommandManager):
 
     def __init__(self):
         super(_ConstraintInitialFlowVelocity, self).__init__()
-        self.menuetext = "Constraint initial flow velocity"
+        self.menutext = "Constraint initial flow velocity"
         self.tooltip = "Creates a FEM constraint initial flow velocity"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -211,7 +211,7 @@ class _ConstraintSectionPrint(CommandManager):
 
     def __init__(self):
         super(_ConstraintSectionPrint, self).__init__()
-        self.menuetext = "Constraint sectionprint"
+        self.menutext = "Constraint sectionprint"
         self.tooltip = "Creates a FEM constraint sectionprint"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -222,7 +222,7 @@ class _ConstraintSelfWeight(CommandManager):
 
     def __init__(self):
         super(_ConstraintSelfWeight, self).__init__()
-        self.menuetext = "Constraint self weight"
+        self.menutext = "Constraint self weight"
         self.tooltip = "Creates a FEM constraint self weight"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_noset_edit"
@@ -233,7 +233,7 @@ class _ConstraintTie(CommandManager):
 
     def __init__(self):
         super(_ConstraintTie, self).__init__()
-        self.menuetext = "Constraint tie"
+        self.menutext = "Constraint tie"
         self.tooltip = "Creates a FEM constraint tie"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -244,7 +244,7 @@ class _ElementFluid1D(CommandManager):
 
     def __init__(self):
         super(_ElementFluid1D, self).__init__()
-        self.menuetext = "Fluid section for 1D flow"
+        self.menutext = "Fluid section for 1D flow"
         self.tooltip = "Creates a FEM fluid section for 1D flow"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -255,7 +255,7 @@ class _ElementGeometry1D(CommandManager):
 
     def __init__(self):
         super(_ElementGeometry1D, self).__init__()
-        self.menuetext = "Beam cross section"
+        self.menutext = "Beam cross section"
         self.tooltip = "Creates a FEM beam cross section"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -266,7 +266,7 @@ class _ElementGeometry2D(CommandManager):
 
     def __init__(self):
         super(_ElementGeometry2D, self).__init__()
-        self.menuetext = "Shell plate thickness"
+        self.menutext = "Shell plate thickness"
         self.tooltip = "Creates a FEM shell plate thickness"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -277,7 +277,7 @@ class _ElementRotation1D(CommandManager):
 
     def __init__(self):
         super(_ElementRotation1D, self).__init__()
-        self.menuetext = "Beam rotation"
+        self.menutext = "Beam rotation"
         self.tooltip = "Creates a FEM beam rotation"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_noset_edit"
@@ -288,7 +288,7 @@ class _EquationElectrostatic(CommandManager):
 
     def __init__(self):
         super(_EquationElectrostatic, self).__init__()
-        self.menuetext = "Electrostatic equation"
+        self.menutext = "Electrostatic equation"
         self.tooltip = "Creates a FEM equation for electrostatic"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -299,7 +299,7 @@ class _EquationElasticity(CommandManager):
 
     def __init__(self):
         super(_EquationElasticity, self).__init__()
-        self.menuetext = "Elasticity equation"
+        self.menutext = "Elasticity equation"
         self.tooltip = "Creates a FEM equation for elasticity"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -310,7 +310,7 @@ class _EquationFlow(CommandManager):
 
     def __init__(self):
         super(_EquationFlow, self).__init__()
-        self.menuetext = "Flow equation"
+        self.menutext = "Flow equation"
         self.tooltip = "Creates a FEM equation for flow"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -321,7 +321,7 @@ class _EquationFlux(CommandManager):
 
     def __init__(self):
         super(_EquationFlux, self).__init__()
-        self.menuetext = "Flux equation"
+        self.menutext = "Flux equation"
         self.tooltip = "Creates a FEM equation for flux"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -332,7 +332,7 @@ class _EquationElectricforce(CommandManager):
 
     def __init__(self):
         super(_EquationElectricforce, self).__init__()
-        self.menuetext = "Electricforce equation"
+        self.menutext = "Electricforce equation"
         self.tooltip = "Creates a FEM equation for electric forces"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -343,7 +343,7 @@ class _EquationHeat(CommandManager):
 
     def __init__(self):
         super(_EquationHeat, self).__init__()
-        self.menuetext = "Heat equation"
+        self.menutext = "Heat equation"
         self.tooltip = "Creates a FEM equation for heat"
         self.is_active = "with_solver_elmer"
         self.do_activated = "add_obj_on_gui_selobj_noset_edit"
@@ -355,7 +355,7 @@ class _Examples(CommandManager):
     def __init__(self):
         super(_Examples, self).__init__()
         self.pixmap = "FemWorkbench"
-        self.menuetext = "Open FEM examples"
+        self.menutext = "Open FEM examples"
         self.tooltip = "Open FEM examples"
         self.is_active = "always"
 
@@ -370,7 +370,7 @@ class _MaterialEditor(CommandManager):
     def __init__(self):
         super(_MaterialEditor, self).__init__()
         self.pixmap = "Arch_Material_Group"
-        self.menuetext = "Material editor"
+        self.menutext = "Material editor"
         self.tooltip = "Opens the FreeCAD material editor"
         self.is_active = "always"
 
@@ -384,7 +384,7 @@ class _MaterialFluid(CommandManager):
 
     def __init__(self):
         super(_MaterialFluid, self).__init__()
-        self.menuetext = "Material for fluid"
+        self.menutext = "Material for fluid"
         self.tooltip = "Creates a FEM material for fluid"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -395,7 +395,7 @@ class _MaterialMechanicalNonlinear(CommandManager):
 
     def __init__(self):
         super(_MaterialMechanicalNonlinear, self).__init__()
-        self.menuetext = "Nonlinear mechanical material"
+        self.menutext = "Nonlinear mechanical material"
         self.tooltip = "Creates a nonlinear mechanical material"
         self.is_active = "with_material_solid"
 
@@ -459,7 +459,7 @@ class _MaterialReinforced(CommandManager):
 
     def __init__(self):
         super(_MaterialReinforced, self).__init__()
-        self.menuetext = "Reinforced material (concrete)"
+        self.menutext = "Reinforced material (concrete)"
         self.tooltip = "Creates a material for reinforced matrix material such as concrete"
         self.is_active = "with_analysis"
         self.do_activated = "add_obj_on_gui_set_edit"
@@ -470,7 +470,7 @@ class _MaterialSolid(CommandManager):
 
     def __init__(self):
         super(_MaterialSolid, self).__init__()
-        self.menuetext = "Material for solid"
+        self.menutext = "Material for solid"
         self.accel = "M, S"
         self.tooltip = "Creates a FEM material for solid"
         self.is_active = "with_analysis"
@@ -482,7 +482,7 @@ class _FEMMesh2Mesh(CommandManager):
 
     def __init__(self):
         super(_FEMMesh2Mesh, self).__init__()
-        self.menuetext = "FEM mesh to mesh"
+        self.menutext = "FEM mesh to mesh"
         self.tooltip = "Convert the surface of a FEM mesh to a mesh"
         self.is_active = "with_femmesh_andor_res"
 
@@ -523,7 +523,7 @@ class _MeshBoundaryLayer(CommandManager):
 
     def __init__(self):
         super(_MeshBoundaryLayer, self).__init__()
-        self.menuetext = "FEM mesh boundary layer"
+        self.menutext = "FEM mesh boundary layer"
         self.tooltip = "Creates a FEM mesh boundary layer"
         self.is_active = "with_gmsh_femmesh"
         self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -534,7 +534,7 @@ class _MeshClear(CommandManager):
 
     def __init__(self):
         super(_MeshClear, self).__init__()
-        self.menuetext = "Clear FEM mesh"
+        self.menutext = "Clear FEM mesh"
         self.tooltip = "Clear the Mesh of a FEM mesh object"
         self.is_active = "with_femmesh"
 
@@ -553,7 +553,7 @@ class _MeshDisplayInfo(CommandManager):
 
     def __init__(self):
         super(_MeshDisplayInfo, self).__init__()
-        self.menuetext = "Display FEM mesh info"
+        self.menutext = "Display FEM mesh info"
         self.tooltip = "Display FEM mesh info"
         self.is_active = "with_femmesh"
 
@@ -576,7 +576,7 @@ class _MeshGmshFromShape(CommandManager):
 
     def __init__(self):
         super(_MeshGmshFromShape, self).__init__()
-        self.menuetext = "FEM mesh from shape by Gmsh"
+        self.menutext = "FEM mesh from shape by Gmsh"
         self.tooltip = "Create a FEM mesh from a shape by Gmsh mesher"
         self.is_active = "with_part_feature"
 
@@ -615,7 +615,7 @@ class _MeshGroup(CommandManager):
 
     def __init__(self):
         super(_MeshGroup, self).__init__()
-        self.menuetext = "FEM mesh group"
+        self.menutext = "FEM mesh group"
         self.tooltip = "Creates a FEM mesh group"
         self.is_active = "with_gmsh_femmesh"
         self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -626,7 +626,7 @@ class _MeshNetgenFromShape(CommandManager):
 
     def __init__(self):
         super(_MeshNetgenFromShape, self).__init__()
-        self.menuetext = "FEM mesh from shape by Netgen"
+        self.menutext = "FEM mesh from shape by Netgen"
         self.tooltip = "Create a FEM mesh from a solid or face shape by Netgen internal mesher"
         self.is_active = "with_part_feature"
 
@@ -665,7 +665,7 @@ class _MeshRegion(CommandManager):
 
     def __init__(self):
         super(_MeshRegion, self).__init__()
-        self.menuetext = "FEM mesh region"
+        self.menutext = "FEM mesh region"
         self.tooltip = "Creates a FEM mesh region"
         self.is_active = "with_gmsh_femmesh"
         self.do_activated = "add_obj_on_gui_selobj_set_edit"
@@ -676,7 +676,7 @@ class _ResultShow(CommandManager):
 
     def __init__(self):
         super(_ResultShow, self).__init__()
-        self.menuetext = "Show result"
+        self.menutext = "Show result"
         self.accel = "R, S"
         self.tooltip = "Shows and visualizes selected result data"
         self.is_active = "with_selresult"
@@ -690,7 +690,7 @@ class _ResultsPurge(CommandManager):
 
     def __init__(self):
         super(_ResultsPurge, self).__init__()
-        self.menuetext = "Purge results"
+        self.menutext = "Purge results"
         self.accel = "R, P"
         self.tooltip = "Purges all results from active analysis"
         self.is_active = "with_results"
@@ -706,7 +706,7 @@ class _SolverCxxtools(CommandManager):
     def __init__(self):
         super(_SolverCxxtools, self).__init__()
         self.pixmap = "FEM_SolverStandard"
-        self.menuetext = "Solver CalculiX Standard"
+        self.menutext = "Solver CalculiX Standard"
         self.accel = "S, X"
         self.tooltip = "Creates a standard FEM solver CalculiX with ccx tools"
         self.is_active = "with_analysis"
@@ -741,7 +741,7 @@ class _SolverCalculix(CommandManager):
     def __init__(self):
         super(_SolverCalculix, self).__init__()
         self.pixmap = "FEM_SolverStandard"
-        self.menuetext = "Solver CalculiX (new framework)"
+        self.menutext = "Solver CalculiX (new framework)"
         self.accel = "S, C"
         self.tooltip = "Creates a FEM solver CalculiX new framework (less result error handling)"
         self.is_active = "with_analysis"
@@ -754,7 +754,7 @@ class _SolverControl(CommandManager):
 
     def __init__(self):
         super(_SolverControl, self).__init__()
-        self.menuetext = "Solver job control"
+        self.menutext = "Solver job control"
         self.accel = "S, T"
         self.tooltip = "Changes solver attributes and runs the calculations for the selected solver"
         self.is_active = "with_solver"
@@ -768,7 +768,7 @@ class _SolverElmer(CommandManager):
 
     def __init__(self):
         super(_SolverElmer, self).__init__()
-        self.menuetext = "Solver Elmer"
+        self.menutext = "Solver Elmer"
         self.accel = "S, E"
         self.tooltip = "Creates a FEM solver Elmer"
         self.is_active = "with_analysis"
@@ -781,7 +781,7 @@ class _SolverMystran(CommandManager):
     def __init__(self):
         super(_SolverMystran, self).__init__()
         self.pixmap = "FEM_SolverStandard"
-        self.menuetext = "Solver Mystran"
+        self.menutext = "Solver Mystran"
         self.accel = "S, M"
         self.tooltip = "Creates a FEM solver Mystran"
         self.is_active = "with_analysis"
@@ -793,7 +793,7 @@ class _SolverRun(CommandManager):
 
     def __init__(self):
         super(_SolverRun, self).__init__()
-        self.menuetext = "Run solver calculations"
+        self.menutext = "Run solver calculations"
         self.accel = "S, R"
         self.tooltip = "Runs the calculations for the selected solver"
         self.is_active = "with_solver"
@@ -810,7 +810,7 @@ class _SolverZ88(CommandManager):
 
     def __init__(self):
         super(_SolverZ88, self).__init__()
-        self.menuetext = "Solver Z88"
+        self.menutext = "Solver Z88"
         self.accel = "S, Z"
         self.tooltip = "Creates a FEM solver Z88"
         self.is_active = "with_analysis"
diff --git a/src/Mod/Fem/femcommands/manager.py b/src/Mod/Fem/femcommands/manager.py
index 508b251bc3..d13d8a95dc 100644
--- a/src/Mod/Fem/femcommands/manager.py
+++ b/src/Mod/Fem/femcommands/manager.py
@@ -46,9 +46,9 @@ class CommandManager(object):
 
         self.command = "FEM" + self.__class__.__name__
         self.pixmap = self.command
-        self.menuetext = self.__class__.__name__.lstrip("_")
+        self.menutext = self.__class__.__name__.lstrip("_")
         self.accel = ""
-        self.tooltip = "Creates a {}".format(self.menuetext)
+        self.tooltip = "Creates a {}".format(self.menutext)
         self.resources = None
 
         self.is_active = None
@@ -61,7 +61,7 @@ class CommandManager(object):
         if self.resources is None:
             self.resources = {
                 "Pixmap": self.pixmap,
-                "MenuText": QtCore.QT_TRANSLATE_NOOP(self.command, self.menuetext),
+                "MenuText": QtCore.QT_TRANSLATE_NOOP(self.command, self.menutext),
                 "Accel": self.accel,
                 "ToolTip": QtCore.QT_TRANSLATE_NOOP(self.command, self.tooltip)
             }
diff --git a/src/Mod/Fem/feminout/exportNastranMesh.py b/src/Mod/Fem/feminout/exportNastranMesh.py
index 2da80c520e..ef1eb35450 100644
--- a/src/Mod/Fem/feminout/exportNastranMesh.py
+++ b/src/Mod/Fem/feminout/exportNastranMesh.py
@@ -91,7 +91,7 @@ def write(
     mesh_pynas_code += missing_code_pnynasmesh
 
     # pynas file
-    basefilename = filename[:len(filename) - 4]  # TODO basename is more failsave
+    basefilename = filename[:len(filename) - 4]  # TODO basename is more failsafe
     pynasf = open(basefilename + ".py", "w")
     pynasf.write("# written by FreeCAD\n\n\n")
     pynasf.write("from pyNastran.bdf.bdf import BDF\n")
diff --git a/src/Mod/Fem/femsolver/settings.py b/src/Mod/Fem/femsolver/settings.py
index 7590b97a06..36e43ec149 100644
--- a/src/Mod/Fem/femsolver/settings.py
+++ b/src/Mod/Fem/femsolver/settings.py
@@ -195,7 +195,7 @@ class _SolverDlg(object):
 
         # set the binary path to the FreeCAD defaults
         # ATM pure unix shell commands without path names are used as standard
-        # TODO the binaries provieded with the FreeCAD distribution should be found
+        # TODO the binaries provided with the FreeCAD distribution should be found
         # without any additional user input
         # see ccxttols, it works for Windows and Linux there
         binary = self.default
diff --git a/src/Mod/Fem/femsolver/writerbase.py b/src/Mod/Fem/femsolver/writerbase.py
index 05bd29ae50..3728ce9b1b 100644
--- a/src/Mod/Fem/femsolver/writerbase.py
+++ b/src/Mod/Fem/femsolver/writerbase.py
@@ -55,19 +55,30 @@ class FemInputWriter():
         self.analysis_type = self.solver_obj.AnalysisType
         self.document = self.analysis.Document
         # working dir
-        self.dir_name = dir_name
         # if dir_name was not given or if it exists but is not empty: create a temporary dir
         # Purpose: makes sure the analysis can be run even on wired situation
-        if not dir_name:
+        make_tmp_dir = False
+        if dir_name is None:
             FreeCAD.Console.PrintWarning(
-                "Error: FemInputWriter has no working_dir --> "
-                "we are going to make a temporary one!\n"
+                "Error: The working_dir in base input file writer class was not set. "
+                "A temporary directory is used.\n"
             )
-            self.dir_name = self.document.TransientDir.replace(
-                "\\", "/"
-            ) + "/FemAnl_" + analysis_obj.Uid[-4:]
-        if not os.path.isdir(self.dir_name):
-            os.mkdir(self.dir_name)
+            make_tmp_dir = True
+        elif not os.path.isdir(dir_name):
+            FreeCAD.Console.PrintWarning(
+                "Error: The working_dir: '{}' given to "
+                "base input file writer class does not exist. "
+                "A temporary directory is used.\n".format(dir_name)
+            )
+            make_tmp_dir = True
+        if make_tmp_dir is True:
+            from tempfile import mkdtemp
+            dir_name = mkdtemp(prefix="fcfem_")
+            FreeCAD.Console.PrintWarning(
+                "The working directory '{}' was created and will be used."
+                .format(dir_name)
+            )
+        self.dir_name = dir_name
 
         # new class attributes
         self.fc_ver = FreeCAD.Version()
diff --git a/src/Mod/Import/App/ExportOCAF.cpp b/src/Mod/Import/App/ExportOCAF.cpp
index 2baa95e2f4..3a76769b42 100644
--- a/src/Mod/Import/App/ExportOCAF.cpp
+++ b/src/Mod/Import/App/ExportOCAF.cpp
@@ -58,7 +58,7 @@
 # include 
 # include 
 # include 
-# include 
+# include 
 # include 
 # include 
 # include 
@@ -95,6 +95,17 @@
 #include 
 #include 
 
+#if OCC_VERSION_HEX >= 0x070500
+// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
+#   define OCC_COLOR_SPACE Quantity_TOC_sRGB
+#else
+#   define OCC_COLOR_SPACE Quantity_TOC_RGB
+#endif
+
+static inline Quantity_ColorRGBA convertColor(const App::Color &c)
+{
+    return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0 - c.a);
+}
 
 using namespace Import;
 
@@ -284,7 +295,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector& co
 */
 
     // Add color information
-    Quantity_Color col;
+    Quantity_ColorRGBA col;
 
     std::set face_index;
     TopTools_IndexedMapOfShape faces;
@@ -317,11 +328,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector& co
 
                 if (!faceLabel.IsNull()) {
                     const App::Color& color = colors[index-1];
-                    Standard_Real mat[3];
-                    mat[0] = color.r;
-                    mat[1] = color.g;
-                    mat[2] = color.b;
-                    col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
+                    col = convertColor(color);
                     aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
                 }
             }
@@ -330,11 +337,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector& co
     }
     else if (!colors.empty()) {
         App::Color color = colors.front();
-        Standard_Real mat[3];
-        mat[0] = color.r;
-        mat[1] = color.g;
-        mat[2] = color.b;
-        col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
+        col = convertColor(color);
         aColorTool->SetColor(shapeLabel, col, XCAFDoc_ColorGen);
     }
 
@@ -400,7 +403,7 @@ void ExportOCAF::reallocateFreeShape(std::vector  hierarch
             TopoDS_Shape baseShape = part->Shape.getValue();
 
             // Add color information
-            Quantity_Color col;
+            Quantity_ColorRGBA col;
 
             std::set face_index;
             TopTools_IndexedMapOfShape faces;
@@ -433,11 +436,7 @@ void ExportOCAF::reallocateFreeShape(std::vector  hierarch
 
                         if (!faceLabel.IsNull()) {
                             const App::Color& color = colors[index-1];
-                            Standard_Real mat[3];
-                            mat[0] = color.r;
-                            mat[1] = color.g;
-                            mat[2] = color.b;
-                            col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
+                            col = convertColor(color);
                             aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
                         }
                     }
@@ -447,11 +446,7 @@ void ExportOCAF::reallocateFreeShape(std::vector  hierarch
             }
             else if (!colors.empty()) {
                 App::Color color = colors.front();
-                Standard_Real mat[3];
-                mat[0] = color.r;
-                mat[1] = color.g;
-                mat[2] = color.b;
-                col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
+                col = convertColor(color);
                 aColorTool->SetColor(label, col, XCAFDoc_ColorGen);
             }
         }
diff --git a/src/Mod/Import/App/ImpExpDxf.cpp b/src/Mod/Import/App/ImpExpDxf.cpp
index 09827bd928..dcd88ef138 100644
--- a/src/Mod/Import/App/ImpExpDxf.cpp
+++ b/src/Mod/Import/App/ImpExpDxf.cpp
@@ -29,7 +29,6 @@
 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -47,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -55,6 +55,9 @@
 #include 
 #include 
 #include 
+#if OCC_VERSION_HEX < 0x070600
+#include 
+#endif
 
 #include 
 #include 
@@ -68,6 +71,10 @@
 
 using namespace Import;
 
+#if OCC_VERSION_HEX >= 0x070600
+using BRepAdaptor_HCurve = BRepAdaptor_Curve;
+#endif
+
 
 //******************************************************************************
 // reading
diff --git a/src/Mod/Import/App/ImportOCAF.cpp b/src/Mod/Import/App/ImportOCAF.cpp
index 17cc74f906..a6c392f0b7 100644
--- a/src/Mod/Import/App/ImportOCAF.cpp
+++ b/src/Mod/Import/App/ImportOCAF.cpp
@@ -60,7 +60,7 @@
 # include 
 # include 
 # include 
-# include 
+# include 
 # include 
 # include 
 # include 
@@ -108,6 +108,23 @@
 
 using namespace Import;
 
+#if OCC_VERSION_HEX >= 0x070500
+// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
+#   define OCC_COLOR_SPACE Quantity_TOC_sRGB
+#else
+#   define OCC_COLOR_SPACE Quantity_TOC_RGB
+#endif
+
+static inline App::Color convertColor(const Quantity_ColorRGBA &c)
+{
+    Standard_Real r, g, b;
+    c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
+    return App::Color(static_cast(r),
+                      static_cast(g),
+                      static_cast(b),
+                      1.0f - static_cast(c.Alpha()));
+}
+
 #define OCAF_KEEP_PLACEMENT
 
 ImportOCAF::ImportOCAF(Handle(TDocStd_Document) h, App::Document* d, const std::string& name)
@@ -439,14 +456,12 @@ void ImportOCAF::createShape(const TopoDS_Shape& aShape, const TopLoc_Location&
 
 void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
 {
-    Quantity_Color aColor;
+    Quantity_ColorRGBA aColor;
     App::Color color(0.8f,0.8f,0.8f);
     if (aColorTool->GetColor(aShape, XCAFDoc_ColorGen, aColor) ||
         aColorTool->GetColor(aShape, XCAFDoc_ColorSurf, aColor) ||
         aColorTool->GetColor(aShape, XCAFDoc_ColorCurv, aColor)) {
-        color.r = (float)aColor.Red();
-        color.g = (float)aColor.Green();
-        color.b = (float)aColor.Blue();
+        color = convertColor(aColor);
         std::vector colors;
         colors.push_back(color);
         applyColors(part, colors);
@@ -468,9 +483,7 @@ void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
             aColorTool->GetColor(xp.Current(), XCAFDoc_ColorSurf, aColor) ||
             aColorTool->GetColor(xp.Current(), XCAFDoc_ColorCurv, aColor)) {
             int index = faces.FindIndex(xp.Current());
-            color.r = (float)aColor.Red();
-            color.g = (float)aColor.Green();
-            color.b = (float)aColor.Blue();
+            color = convertColor(aColor);
             faceColors[index-1] = color;
             found_face_color = true;
         }
@@ -551,7 +564,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
     part = static_cast(doc->addObject("Part::Feature", default_name.c_str()));
     part->Label.setValue(default_name);
     part->Shape.setValue(shape);
-    std::map::const_iterator jt;
+    std::map::const_iterator jt;
     jt = myColorMap.find(shape.HashCode(INT_MAX));
 
     App::Color partColor(0.8f,0.8f,0.8f);
@@ -596,11 +609,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
             jt = myColorMap.find(xp.Current().HashCode(INT_MAX));
             if (jt != myColorMap.end()) {
                 int index = faces.FindIndex(xp.Current());
-                App::Color color;
-                color.r = (float)jt->second.Red();
-                color.g = (float)jt->second.Green();
-                color.b = (float)jt->second.Blue();
-                faceColors[index-1] = color;
+                faceColors[index-1] = convertColor(jt->second);
                 found_face_color = true;
             }
             xp.Next();
@@ -653,7 +662,7 @@ void ImportXCAF::loadShapes(const TDF_Label& label)
         }
 
         // getting color
-        Quantity_Color col;
+        Quantity_ColorRGBA col;
         if (hColors->GetColor(label, XCAFDoc_ColorGen, col) ||
             hColors->GetColor(label, XCAFDoc_ColorSurf, col) ||
             hColors->GetColor(label, XCAFDoc_ColorCurv, col)) {
diff --git a/src/Mod/Import/App/ImportOCAF.h b/src/Mod/Import/App/ImportOCAF.h
index 8c4d609265..4f30d921a9 100644
--- a/src/Mod/Import/App/ImportOCAF.h
+++ b/src/Mod/Import/App/ImportOCAF.h
@@ -27,7 +27,7 @@
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -117,7 +117,7 @@ private:
     std::map myShells;
     std::map myCompds;
     std::map myShapes;
-    std::map myColorMap;
+    std::map myColorMap;
     std::map myNameMap;
 };
 
diff --git a/src/Mod/Import/App/ImportOCAF2.cpp b/src/Mod/Import/App/ImportOCAF2.cpp
index 4de3b10adb..1c803be05c 100644
--- a/src/Mod/Import/App/ImportOCAF2.cpp
+++ b/src/Mod/Import/App/ImportOCAF2.cpp
@@ -41,7 +41,7 @@
 # include 
 # include 
 # include 
-# include 
+# include 
 # include 
 # include 
 # include 
@@ -50,6 +50,7 @@
 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -71,12 +72,40 @@
 #include 
 #include 
 
+#if OCC_VERSION_HEX >= 0x070500
+// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
+#   define OCC_COLOR_SPACE Quantity_TOC_sRGB
+#else
+#   define OCC_COLOR_SPACE Quantity_TOC_RGB
+#endif
+
 FC_LOG_LEVEL_INIT("Import",true,true)
 
 using namespace Import;
 
 /////////////////////////////////////////////////////////////////////
 
+static inline App::Color convertColor(const Quantity_ColorRGBA &c)
+{
+    Standard_Real r, g, b;
+    c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
+    return App::Color(static_cast(r),
+                      static_cast(g),
+                      static_cast(b),
+                      1.0f - static_cast(c.Alpha()));
+}
+
+static inline Quantity_ColorRGBA convertColor(const App::Color &c)
+{
+    return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0f - c.a);
+}
+
+static inline std::ostream& operator<<(std::ostream& os, const Quantity_ColorRGBA &c) {
+    App::Color color = convertColor(c);
+    auto toHex = [](float v) {return boost::format("%02X") % static_cast(v*255);};
+    return os << "#" << toHex(color.r) << toHex(color.g) << toHex(color.b) << toHex(color.a);
+}
+
 static std::string labelName(TDF_Label label) {
     std::string txt;
     Handle(TDataStd_Name) name;
@@ -116,13 +145,13 @@ static void printLabel(TDF_Label label, Handle(XCAFDoc_ShapeTool) aShapeTool,
             ss << ", " << Part::TopoShape::shapeName(shape.ShapeType(),true);
     }
     if(aShapeTool->IsShape(label)) {
-        Quantity_Color c;
+        Quantity_ColorRGBA c;
         if(aColorTool->GetColor(label,XCAFDoc_ColorGen,c))
-            ss << ", gc: " << c.StringName(c.Name());
+            ss << ", gc: " << c;
         if(aColorTool->GetColor(label,XCAFDoc_ColorSurf,c))
-            ss << ", sc: " << c.StringName(c.Name());
+            ss << ", sc: " << c;
         if(aColorTool->GetColor(label,XCAFDoc_ColorCurv,c))
-            ss << ", cc: " << c.StringName(c.Name());
+            ss << ", cc: " << c;
     }
 
     ss << std::endl;
@@ -229,12 +258,11 @@ void ImportOCAF2::setObjectName(Info &info, TDF_Label label) {
     }
 }
 
-
 bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bool noDefault) {
     bool ret = false;
-    Quantity_Color aColor;
+    Quantity_ColorRGBA aColor;
     if(aColorTool->GetColor(shape, XCAFDoc_ColorSurf, aColor)) {
-        App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
+        App::Color c = convertColor(aColor);
         if(!check || info.faceColor!=c) {
             info.faceColor = c;
             info.hasFaceColor = true;
@@ -242,7 +270,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
         }
     }
     if(!noDefault && !info.hasFaceColor && aColorTool->GetColor(shape, XCAFDoc_ColorGen, aColor)) {
-        App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
+        App::Color c = convertColor(aColor);
         if(!check || info.faceColor!=c) {
             info.faceColor = c;
             info.hasFaceColor = true;
@@ -250,7 +278,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
         }
     }
     if(aColorTool->GetColor(shape, XCAFDoc_ColorCurv, aColor)) {
-        App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
+        App::Color c = convertColor(aColor);
         // Some STEP include a curve color with the same value of the face
         // color. And this will look weird in FC. So for shape with face
         // we'll ignore the curve color, if it is the same as the face color.
@@ -365,15 +393,15 @@ bool ImportOCAF2::createObject(App::Document *doc, TDF_Label label,
 
                 bool foundFaceColor=false,foundEdgeColor=false;
                 App::Color faceColor,edgeColor;
-                Quantity_Color aColor;
+                Quantity_ColorRGBA aColor;
                 if(aColorTool->GetColor(l, XCAFDoc_ColorSurf, aColor) ||
                    aColorTool->GetColor(l, XCAFDoc_ColorGen, aColor))
                 {
-                    faceColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
+                    faceColor = convertColor(aColor);
                     foundFaceColor = true;
                 }
                 if(aColorTool->GetColor(l, XCAFDoc_ColorCurv, aColor)) {
-                    edgeColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
+                    edgeColor = convertColor(aColor);
                     foundEdgeColor = true;
                     if(j==0 && foundFaceColor && faceColors.size() && edgeColor==faceColor) {
                         // Do not set edge the same color as face
@@ -648,11 +676,11 @@ void ImportOCAF2::getSHUOColors(TDF_Label label,
             subname += App::DocumentObject::hiddenMarker();
             colors.emplace(subname,App::Color());
         } else {
-            Quantity_Color aColor;
+            Quantity_ColorRGBA aColor;
             if(aColorTool->GetColor(slabel, XCAFDoc_ColorSurf, aColor) ||
                aColorTool->GetColor(slabel, XCAFDoc_ColorGen, aColor))
             {
-                colors.emplace(subname,App::Color(aColor.Red(),aColor.Green(),aColor.Blue()));
+                colors.emplace(subname,convertColor(aColor));
             }
         }
     }
@@ -782,12 +810,9 @@ bool ImportOCAF2::createAssembly(App::Document *_doc,
         childInfo.vis.push_back(vis);
         childInfo.labels.push_back(childLabel);
         childInfo.plas.emplace_back(Part::TopoShape::convert(childShape.Location().Transformation()));
-        Quantity_Color aColor;
+        Quantity_ColorRGBA aColor;
         if (aColorTool->GetColor(childShape, XCAFDoc_ColorSurf, aColor)) {
-            auto &color = childInfo.colors[childInfo.plas.size()-1];
-            color.r = (float)aColor.Red();
-            color.g = (float)aColor.Green();
-            color.b = (float)aColor.Blue();
+            childInfo.colors[childInfo.plas.size()-1] = convertColor(aColor); 
         }
     }
     assert(visibilities.size() == children.size());
@@ -1036,7 +1061,7 @@ void ExportOCAF2::setupObject(TDF_Label label, App::DocumentObject *obj,
                 continue;
             }
             const App::Color& c = vv.second;
-            Quantity_Color color(c.r,c.g,c.b,Quantity_TOC_RGB);
+            Quantity_ColorRGBA color = convertColor(c);
             auto colorType = vv.first[0]=='F'?XCAFDoc_ColorSurf:XCAFDoc_ColorCurv;
             if(vv.first=="Face" || vv.first=="Edge") {
                 aColorTool->SetColor(nodeLabel, color, colorType);
@@ -1219,8 +1244,17 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
             // not call setupObject() on a non-located baseshape like above,
             // because OCCT does not respect shape style sharing when not
             // exporting assembly
-            if(!keepPlacement) 
+            if(!keepPlacement || shape.getPlacement() == Base::Placement())
                 shape.setShape(shape.getShape().Located(TopLoc_Location()));
+            else {
+                Base::Matrix4D mat = shape.getTransform();
+                shape.setShape(shape.getShape().Located(TopLoc_Location()));
+                // Transform with copy to conceal the transformation
+                shape.transformShape(mat, true);
+                // Even if the shape has no transformation, TopoShape still sets
+                // a TopLoc_Location, so we need to clear it again.
+                shape.setShape(shape.getShape().Located(TopLoc_Location()));
+            }
             label = aShapeTool->AddShape(shape.getShape(),Standard_False, Standard_False);
             auto o = name?parentObj:obj;
             if(o!=linked)
@@ -1277,7 +1311,7 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
             // Work around OCCT bug. If no color setting here, it will crash.
             // The culprit is at STEPCAFControl_Writer::1093 as shown below
             //
-            // surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,Quantity_TOC_RGB),DPDCs,ColRGBs);
+            // surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,OCC_COLOR_SPACE),DPDCs,ColRGBs);
             // PSA = Styles.MakeColorPSA ( item, surfColor, curvColor, isComponent );
             // if ( isComponent )
             //     setDefaultInstanceColor( override, PSA);
@@ -1287,13 +1321,13 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
             //     setDefaultInstanceColor( override, PSA);
             //
             auto childShape = aShapeTool->GetShape(childLabel);
-            Quantity_Color col;
+            Quantity_ColorRGBA col;
             if(!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorGen,col) &&
                !aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorSurf,col) &&
                !aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorCurv,col)) 
             {
                 auto &c = defaultColor;
-                aColorTool->SetColor(childLabel, Quantity_Color(c.r,c.g,c.b,Quantity_TOC_RGB), XCAFDoc_ColorGen);
+                aColorTool->SetColor(childLabel, convertColor(c), XCAFDoc_ColorGen);
                 FC_WARN(labelName(childLabel) << " set default color");
             }
             aColorTool->SetVisibility(childLabel,Standard_False);
diff --git a/src/Mod/Import/Gui/AppImportGuiPy.cpp b/src/Mod/Import/Gui/AppImportGuiPy.cpp
index 6601973cc2..72e5de3417 100644
--- a/src/Mod/Import/Gui/AppImportGuiPy.cpp
+++ b/src/Mod/Import/Gui/AppImportGuiPy.cpp
@@ -322,9 +322,10 @@ private:
             return;
         }
         // vp->MapFaceColor.setValue(false);
-        if(colors.size() == 1)
+        if(colors.size() == 1) {
             vp->ShapeColor.setValue(colors.front());
-        else 
+            vp->Transparency.setValue(100 * colors.front().a);
+        } else 
             vp->DiffuseColor.setValues(colors);
     }
     virtual void applyEdgeColors(Part::Feature* part, const std::vector& colors) override {
diff --git a/src/Mod/Mesh/App/AppMesh.cpp b/src/Mod/Mesh/App/AppMesh.cpp
index 7a6d759612..e179e90de6 100644
--- a/src/Mod/Mesh/App/AppMesh.cpp
+++ b/src/Mod/Mesh/App/AppMesh.cpp
@@ -76,6 +76,7 @@ PyMOD_INIT_FUNC(Mesh)
     Mesh::PropertyMeshKernel    ::init();
 
     Mesh::MeshObject            ::init();
+    Mesh::MeshSegment           ::init();
 
     Mesh::Feature               ::init();
     Mesh::FeatureCustom         ::init();
diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt
index 2d661aea12..c987d475f1 100644
--- a/src/Mod/Mesh/App/CMakeLists.txt
+++ b/src/Mod/Mesh/App/CMakeLists.txt
@@ -399,6 +399,8 @@ endif ()
 
 add_library(Mesh SHARED ${Core_SRCS} ${WildMagic4_SRCS} ${Mesh_SRCS})
 target_link_libraries(Mesh ${Mesh_LIBS})
+set_target_properties(Mesh PROPERTIES CXX_STANDARD_REQUIRED ON)
+set_target_properties(Mesh PROPERTIES CXX_STANDARD 17)
 
 
 SET_BIN_DIR(Mesh Mesh /Mod/Mesh)
diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp
index 2c1655a588..09d1ad91dc 100644
--- a/src/Mod/Mesh/App/Core/MeshIO.cpp
+++ b/src/Mod/Mesh/App/Core/MeshIO.cpp
@@ -46,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp
index bc533ecaa5..e045a221cc 100644
--- a/src/Mod/Mesh/App/Mesh.cpp
+++ b/src/Mod/Mesh/App/Mesh.cpp
@@ -62,6 +62,7 @@ using namespace Mesh;
 float MeshObject::Epsilon = 1.0e-5f;
 
 TYPESYSTEM_SOURCE(Mesh::MeshObject, Data::ComplexGeoData)
+TYPESYSTEM_SOURCE(Mesh::MeshSegment, Data::Segment)
 
 MeshObject::MeshObject()
 {
@@ -93,7 +94,7 @@ MeshObject::~MeshObject()
 std::vector MeshObject::getElementTypes() const
 {
     std::vector temp;
-    temp.push_back("Face"); // that's the mesh itself
+    temp.push_back("Mesh");
     temp.push_back("Segment");
 
     return temp;
@@ -102,31 +103,47 @@ std::vector MeshObject::getElementTypes() const
 unsigned long MeshObject::countSubElements(const char* Type) const
 {
     std::string element(Type);
-    if (element == "Face")
+    if (element == "Mesh")
         return 1;
     else if (element == "Segment")
         return countSegments();
     return 0;
 }
 
-Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long /*n*/) const
+Data::Segment* MeshObject::getSubElement(const char* Type, unsigned long n) const
 {
-    //TODO
     std::string element(Type);
-    if (element == "Face")
-        return nullptr;
-    else if (element == "Segment")
-        return nullptr;
+    if (element == "Mesh" && n == 0) {
+        MeshSegment* segm = new MeshSegment();
+        segm->mesh = new MeshObject(*this);
+        return segm;
+    }
+    else if (element == "Segment" && n < countSegments()) {
+        MeshSegment* segm = new MeshSegment();
+        segm->mesh = new MeshObject(*this);
+        const Segment& faces = getSegment(n);
+        segm->segment.reset(new Segment(static_cast(segm->mesh), faces.getIndices(), false));
+        return segm;
+    }
+
     return nullptr;
 }
 
-void MeshObject::getFacesFromSubelement(const Data::Segment* /*segm*/,
-                                        std::vector &Points,
-                                        std::vector &/*PointNormals*/,
+void MeshObject::getFacesFromSubElement(const Data::Segment* element,
+                                        std::vector &points,
+                                        std::vector &/*pointNormals*/,
                                         std::vector &faces) const
 {
-    //TODO
-    this->getFaces(Points, faces, 0.0f);
+    if (element && element->getTypeId() == MeshSegment::getClassTypeId()) {
+        const MeshSegment* segm = static_cast(element);
+        if (segm->segment) {
+            Base::Reference submesh(segm->mesh->meshFromSegment(segm->segment->getIndices()));
+            submesh->getFaces(points, faces, 0.0f);
+        }
+        else {
+            segm->mesh->getFaces(points, faces, 0.0f);
+        }
+    }
 }
 
 void MeshObject::transformGeometry(const Base::Matrix4D &rclMat)
@@ -161,6 +178,14 @@ Base::BoundBox3d MeshObject::getBoundBox()const
     return Bnd2;
 }
 
+bool MeshObject::getCenterOfGravity(Base::Vector3d& center) const
+{
+    MeshCore::MeshAlgorithm alg(_kernel);
+    Base::Vector3f pnt = alg.GetGravityPoint();
+    center = transformToOutside(pnt);
+    return true;
+}
+
 void MeshObject::copySegments(const MeshObject& mesh)
 {
     // After copying the segments the mesh pointers must be adjusted
diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h
index 7b307b2e78..b2fa4c1fda 100644
--- a/src/Mod/Mesh/App/Mesh.h
+++ b/src/Mod/Mesh/App/Mesh.h
@@ -60,6 +60,21 @@ class AbstractPolygonTriangulator;
 
 namespace Mesh
 {
+
+class MeshObject;
+class MeshExport MeshSegment : public Data::Segment
+{
+    TYPESYSTEM_HEADER();
+
+public:
+    virtual std::string getName() const {
+        return "MeshSegment";
+    }
+
+    Base::Reference mesh;
+    std::unique_ptr segment;
+};
+
 /**
  * The MeshObject class provides an interface for the underlying MeshKernel class and
  * most of its algorithm on it.
@@ -97,7 +112,7 @@ public:
     /// get the subelement by type and number
     virtual Data::Segment* getSubElement(const char* Type, unsigned long) const;
     /** Get faces from segment */
-    virtual void getFacesFromSubelement(
+    virtual void getFacesFromSubElement(
         const Data::Segment*,
         std::vector &Points,
         std::vector &PointNormals,
@@ -142,7 +157,8 @@ public:
     const MeshCore::MeshKernel& getKernel() const
     { return _kernel; }
 
-    virtual Base::BoundBox3d getBoundBox()const;
+    virtual Base::BoundBox3d getBoundBox() const;
+    virtual bool getCenterOfGravity(Base::Vector3d& center) const;
 
     /** @name I/O */
     //@{
diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml
index b0f2992ad9..9cfacb9a84 100644
--- a/src/Mod/Mesh/App/MeshPy.xml
+++ b/src/Mod/Mesh/App/MeshPy.xml
@@ -184,7 +184,12 @@ lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001])
 				
 			
 		
-		
+        
+            
+                Add a list of facet indices that describes a segment to the mesh
+            
+        
+        
 			
 				Get the number of segments which may also be 0
 			
diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp
index 7f368488b7..30b1277b3c 100644
--- a/src/Mod/Mesh/App/MeshPyImp.cpp
+++ b/src/Mod/Mesh/App/MeshPyImp.cpp
@@ -845,6 +845,27 @@ PyObject*  MeshPy::getPointNormals(PyObject *args)
     } PY_CATCH;
 }
 
+PyObject* MeshPy::addSegment(PyObject *args)
+{
+    PyObject* pylist;
+    if (!PyArg_ParseTuple(args, "O", &pylist))
+        return nullptr;
+
+    Py::Sequence list(pylist);
+    std::vector segment;
+    unsigned long numFacets = getMeshObjectPtr()->countFacets();
+    segment.reserve(list.size());
+    for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
+        Py::Long value(*it);
+        Mesh::FacetIndex index = static_cast(value);
+        if (index < numFacets)
+            segment.push_back(index);
+    }
+
+    getMeshObjectPtr()->addSegment(segment);
+    Py_Return;
+}
+
 PyObject* MeshPy::countSegments(PyObject *args)
 {
     if (!PyArg_ParseTuple(args, ""))
diff --git a/src/Mod/Mesh/App/MeshTestsApp.py b/src/Mod/Mesh/App/MeshTestsApp.py
index 9091e4d74e..a43f982e79 100644
--- a/src/Mod/Mesh/App/MeshTestsApp.py
+++ b/src/Mod/Mesh/App/MeshTestsApp.py
@@ -5,6 +5,7 @@
 #  LGPL
 
 import FreeCAD, os, sys, unittest, Mesh
+from FreeCAD import Base
 import time, tempfile, math
 # http://python-kurs.eu/threads.php
 try:
@@ -46,6 +47,43 @@ class MeshTopoTestCases(unittest.TestCase):
         planarMeshObject = Mesh.Mesh(self.planarMesh)
         planarMeshObject.collapseFacets(range(18))
 
+    def testCorruptedFacet(self):
+        v = FreeCAD.Vector
+        mesh = Mesh.Mesh()
+        mesh.addFacet(
+        v(1.0e1, -1.0e1, 1.0e1),
+        v(1.0e1, +1.0e1, 1.0e1),
+        v(0.0e0, 0.0e0, 1.0e1))
+
+        mesh.addFacet(
+        v(-1.0e1, -1.0e1, 1.0e1),
+        v(-1.0e1, +1.0e1, 1.0e1),
+        v(0e0, 0.0e0, 1.0e1))
+
+        mesh.addFacet(
+        v(+1.0e1, +1.0e1, 1.0e1),
+        v(-1.0e1, +1.0e1, 1.0e1),
+        v(.0e0, 0.0e0, 1.0e1))
+
+        mesh.addFacet(
+        v(+1.0e1, -1.0e1, 1.0e1),
+        v(-1.0e1, -1.0e1, 1.0e1),
+        v(.0e0, 0.0e0, 1.0e1))
+
+        mesh.addFacet(
+        v(-1.0e1, +1.0e1, 1.0e1),
+        v(+1.0e1, +1.0e1, 1.0e1),
+        v(+1.0e1, +1.0e1, 1.0e1))
+
+        mesh.addFacet(
+        v(+1.0e1, +1.0e1, 1.0e1),
+        v(+1.0e1, 00.0e1, 1.0e1),
+        v(+1.0e1, -1.0e1, 1.0e1))
+
+        self.assertEqual(mesh.CountFacets, 6)
+        mesh.fixIndices()
+        self.assertEqual(mesh.CountFacets, 5)
+
 
 class MeshSplitTestCases(unittest.TestCase):
     def setUp(self):
@@ -363,3 +401,43 @@ class NastranReader(unittest.TestCase):
 
     def tearDown(self):
         pass
+
+class MeshSubElement(unittest.TestCase):
+    def setUp(self):
+        self.mesh = Mesh.createBox(1.0, 1.0, 1.0)
+
+    def testCenterOfGravity(self):
+        c = self.mesh.CenterOfGravity
+        self.assertEqual(c, Base.Vector(0.0, 0.0, 0.0))
+
+    def testSubElements(self):
+        types = self.mesh.getElementTypes()
+        self.assertIn("Mesh", types)
+        self.assertIn("Segment", types)
+
+    def testCountSubElements(self):
+        self.assertEqual(self.mesh.countSubElements("Mesh"), 1)
+        self.assertEqual(self.mesh.countSubElements("Segment"), 0)
+
+    def testFacesFromSubElement(self):
+        element = self.mesh.getFacesFromSubElement("Mesh", 0)
+        self.assertIsInstance(element, tuple)
+        self.assertEqual(len(element), 2)
+        self.assertEqual(len(element[0]), 8)
+        self.assertEqual(len(element[1]), 12)
+
+    def testSegmentSubElement(self):
+        self.mesh.addSegment([0, 2, 4, 6, 8])
+        self.assertEqual(self.mesh.countSegments(), 1)
+        self.assertEqual(self.mesh.countSubElements("Segment"), 1)
+        element = self.mesh.getFacesFromSubElement("Segment", 0)
+        self.assertIsInstance(element, tuple)
+        self.assertEqual(len(element), 2)
+        self.assertEqual(len(element[0]), 7)
+        self.assertEqual(len(element[1]), 5)
+        segment = self.mesh.meshFromSegment(self.mesh.getSegment(0))
+        self.assertEqual(segment.CountPoints, 7)
+        self.assertEqual(segment.CountFacets, 5)
+
+    def tearDown(self):
+        pass
diff --git a/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp b/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp
index c68f78c959..0f5fd76c5f 100644
--- a/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp
+++ b/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp
@@ -569,7 +569,7 @@ int System::Write8be (FILE* pkFile, int iQuantity, const void* pvData)
 const char* System::GetPath (const char* acDirectory, const char* acFilename)
 {
     // #0000656: WildMagic4 doesn't build on 64-bit Mac OS
-#if defined(__APPLE__) && !defined(__x86_64__)
+#if defined(__APPLE__) && !defined(__aarch64__) && !defined(__x86_64__)
     // An application-relative path is needed for the applications to be able
     // to find the input data sets.  Unfortunately, there is no exact way to
     // predict which directory the application is run from, since this depends
diff --git a/src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui b/src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui
index 93912ea157..9c3f770d31 100644
--- a/src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui
+++ b/src/Mod/OpenSCAD/Resources/ui/openscadprefs-base.ui
@@ -237,7 +237,7 @@
            
           
           
-           The path to the directory for transfering files to and from OpenSCAD
+           The path to the directory for transferring files to and from OpenSCAD
           
           
            transferdirectory
diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp
index 08e3e9fd47..f16ae7e221 100644
--- a/src/Mod/Part/App/AppPartPy.cpp
+++ b/src/Mod/Part/App/AppPartPy.cpp
@@ -134,6 +134,7 @@
 #include "PartFeature.h"
 #include "PartPyCXX.h"
 #include "modelRefine.h"
+#include "Tools.h"
 
 #ifdef FCUseFreeType
 #  include "FT2FC.h"
@@ -804,33 +805,24 @@ private:
         auto theShape = static_cast(shape)->getTopoShapePtr()->getShape();
         for (TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) {
             TopoDS_Face currentFace = TopoDS::Face(ex.Current());
-            TopLoc_Location loc;
-            Handle(Poly_Triangulation) facets = BRep_Tool::Triangulation(currentFace, loc);
-            const TopAbs_Orientation anOrientation = currentFace.Orientation();
-            bool flip = (anOrientation == TopAbs_REVERSED);
-            if (!facets.IsNull()) {
-                const TColgp_Array1OfPnt& nodes = facets->Nodes();
-                const Poly_Array1OfTriangle& triangles = facets->Triangles();
-                for (int i = 1; i <= triangles.Length(); i++) {
+
+            std::vector points;
+            std::vector facets;
+            if (Tools::getTriangulation(currentFace, points, facets)) {
+                for (const auto& it : facets) {
                     Standard_Integer n1,n2,n3;
-                    triangles(i).Get(n1, n2, n3);
-                    gp_Pnt p1 = nodes(n1);
-                    gp_Pnt p2 = nodes(n2);
-                    gp_Pnt p3 = nodes(n3);
-                    p1.Transform(loc.Transformation());
-                    p2.Transform(loc.Transformation());
-                    p3.Transform(loc.Transformation());
+                    it.Get(n1, n2, n3);
+
+                    gp_Pnt p1 = points[n1];
+                    gp_Pnt p2 = points[n2];
+                    gp_Pnt p3 = points[n3];
+
                     // TODO: verify if tolerance should be hard coded
                     if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) {
                         PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z()));
                         PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z()));
                         PyObject *t3 = PyTuple_Pack(3, PyFloat_FromDouble(p3.X()), PyFloat_FromDouble(p3.Y()), PyFloat_FromDouble(p3.Z()));
-                        if (flip) {
-                            list.append(Py::asObject(PyTuple_Pack(3, t2, t1, t3)));
-                        }
-                        else {
-                            list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
-                        }
+                        list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
                     }
                 }
             }
diff --git a/src/Mod/Part/App/GeomPlate/CurveConstraintPyImp.cpp b/src/Mod/Part/App/GeomPlate/CurveConstraintPyImp.cpp
index 3271f3651a..b63227d537 100644
--- a/src/Mod/Part/App/GeomPlate/CurveConstraintPyImp.cpp
+++ b/src/Mod/Part/App/GeomPlate/CurveConstraintPyImp.cpp
@@ -24,10 +24,13 @@
 #include "PreCompiled.h"
 #ifndef _PreComp_
 # include 
-# include 
 # include 
-# include 
 # include 
+# include 
+# if OCC_VERSION_HEX < 0x070600
+# include 
+# include 
+# endif
 #endif
 
 #include "GeomPlate/CurveConstraintPy.h"
@@ -76,6 +79,16 @@ int CurveConstraintPy::PyInit(PyObject* args, PyObject* kwds)
                 return -1;
             }
 
+#if OCC_VERSION_HEX >= 0x070600
+            Handle(Adaptor3d_Curve) hCurve;
+            if (curve->getTypeId().isDerivedFrom(GeomTrimmedCurve::getClassTypeId())) {
+                GeomTrimmedCurve* trim = static_cast(curve);
+                hCurve = new GeomAdaptor_Curve(handle, trim->getFirstParameter(), trim->getLastParameter());
+            }
+            else {
+                hCurve = new GeomAdaptor_Curve(handle);
+            }
+#else
             Handle(Adaptor3d_HCurve) hCurve;
             if (curve->getTypeId().isDerivedFrom(GeomTrimmedCurve::getClassTypeId())) {
                 GeomTrimmedCurve* trim = static_cast(curve);
@@ -86,6 +99,7 @@ int CurveConstraintPy::PyInit(PyObject* args, PyObject* kwds)
                 GeomAdaptor_Curve adapt(handle);
                 hCurve = new GeomAdaptor_HCurve(adapt);
             }
+#endif
 
             ptr.reset(new GeomPlate_CurveConstraint(hCurve, order, nbPts, tolDist, tolAng, tolCurv));
         }
@@ -212,11 +226,15 @@ PyObject* CurveConstraintPy::curve3d(PyObject *args)
         return nullptr;
 
     try {
-        Handle(Adaptor3d_HCurve) hAdapt = getGeomPlate_CurveConstraintPtr()->Curve3d();
+        auto hAdapt = getGeomPlate_CurveConstraintPtr()->Curve3d();
         if (hAdapt.IsNull())
             Py_Return;
 
+#if OCC_VERSION_HEX >= 0x070600
+        const Adaptor3d_Curve& a3d = *hAdapt;
+#else
         const Adaptor3d_Curve& a3d = hAdapt->Curve();
+#endif
         std::unique_ptr ptr(Part::makeFromCurveAdaptor(a3d));
         return ptr->getPyObject();
     }
@@ -282,6 +300,16 @@ PyObject* CurveConstraintPy::setProjectedCurve(PyObject *args)
             return nullptr;
         }
 
+#if OCC_VERSION_HEX >= 0x070600
+        Handle(Adaptor2d_Curve2d) hCurve;
+        if (handle->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
+            Handle(Geom2d_TrimmedCurve) aTC (Handle(Geom2d_TrimmedCurve)::DownCast (handle));
+            hCurve = new Geom2dAdaptor_Curve(handle, aTC->FirstParameter(), aTC->LastParameter());
+        }
+        else {
+            hCurve = new Geom2dAdaptor_Curve(handle);
+        }
+#else
         Handle(Adaptor2d_HCurve2d) hCurve;
         if (handle->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve))) {
             Handle(Geom2d_TrimmedCurve) aTC (Handle(Geom2d_TrimmedCurve)::DownCast (handle));
@@ -292,6 +320,7 @@ PyObject* CurveConstraintPy::setProjectedCurve(PyObject *args)
             Geom2dAdaptor_Curve adapt(handle);
             hCurve = new Geom2dAdaptor_HCurve(adapt);
         }
+#endif
 
         getGeomPlate_CurveConstraintPtr()->SetProjectedCurve(hCurve, tolU, tolV);
         Py_Return;
@@ -308,11 +337,15 @@ PyObject* CurveConstraintPy::projectedCurve(PyObject *args)
         return nullptr;
 
     try {
-        Handle(Adaptor2d_HCurve2d) hAdapt = getGeomPlate_CurveConstraintPtr()->ProjectedCurve();
+        auto hAdapt = getGeomPlate_CurveConstraintPtr()->ProjectedCurve();
         if (hAdapt.IsNull())
             Py_Return;
 
+#if OCC_VERSION_HEX >= 0x070600
+        const Adaptor2d_Curve2d& a2d = *hAdapt;
+#else
         const Adaptor2d_Curve2d& a2d = hAdapt->Curve2d();
+#endif
         std::unique_ptr ptr(Part::makeFromCurveAdaptor2d(a2d));
         return ptr->getPyObject();
     }
diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp
index e6d6396ca9..1d1d67d4f0 100644
--- a/src/Mod/Part/App/Geometry.cpp
+++ b/src/Mod/Part/App/Geometry.cpp
@@ -51,7 +51,6 @@
 # include 
 # include 
 # include 
-# include 
 # include 
 # include 
 # include 
@@ -101,6 +100,9 @@
 # include 
 # include 
 # include 
+# if OCC_VERSION_HEX < 0x070600
+# include 
+# endif
 
 # include 
 # include 
@@ -144,6 +146,9 @@
 
 #include "Geometry.h"
 
+#if OCC_VERSION_HEX >= 0x070600
+using GeomAdaptor_HCurve = GeomAdaptor_Curve;
+#endif
 
 using namespace Part;
 
diff --git a/src/Mod/Part/App/GeometrySurfacePy.xml b/src/Mod/Part/App/GeometrySurfacePy.xml
index 339ad0eef2..ecf36059f7 100644
--- a/src/Mod/Part/App/GeometrySurfacePy.xml
+++ b/src/Mod/Part/App/GeometrySurfacePy.xml
@@ -22,6 +22,11 @@
 				Return the shape for the geometry.
 			
 		
+        
+            
+                Make a shell of the surface.
+            
+        
         
             
                 Returns the point of given parameter
diff --git a/src/Mod/Part/App/GeometrySurfacePyImp.cpp b/src/Mod/Part/App/GeometrySurfacePyImp.cpp
index 67bfe22da1..a7dddde693 100644
--- a/src/Mod/Part/App/GeometrySurfacePyImp.cpp
+++ b/src/Mod/Part/App/GeometrySurfacePyImp.cpp
@@ -25,6 +25,7 @@
 
 #ifndef _PreComp_
 # include 
+# include 
 # include 
 # include 
 # include 
@@ -74,6 +75,7 @@
 #include 
 #include 
 #include 
+#include 
 
 namespace Part {
 const Py::Object makeTrimmedCurvePy(const Handle(Geom_Curve)& c, double f, double l)
@@ -153,6 +155,52 @@ PyObject* GeometrySurfacePy::toShape(PyObject *args)
     return 0;
 }
 
+PyObject* GeometrySurfacePy::toShell(PyObject *args, PyObject* kwds)
+{
+    PyObject* bound = nullptr;
+    PyObject* segm = nullptr;
+    static char *kwlist[] = {"Bounds", "Segment", nullptr};
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!", kwlist,
+        &PyTuple_Type, &bound, &PyBool_Type, &segm))
+        return nullptr;
+
+    Handle(Geom_Geometry) g = getGeometryPtr()->handle();
+    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(g);
+    try {
+        if (!s.IsNull()) {
+            if (segm) {
+                Standard_Boolean segment = PyObject_IsTrue(segm) ? Standard_True : Standard_False;
+                BRepBuilderAPI_MakeShell mkBuilder(s, segment);
+                TopoDS_Shape sh = mkBuilder.Shape();
+                return new TopoShapeShellPy(new TopoShape(sh));
+            }
+            else {
+                double u1,u2,v1,v2;
+                s->Bounds(u1,u2,v1,v2);
+
+                if (bound) {
+                    Py::Tuple tuple(bound);
+                    u1 = double(Py::Float(tuple[0]));
+                    u2 = double(Py::Float(tuple[1]));
+                    v1 = double(Py::Float(tuple[2]));
+                    v2 = double(Py::Float(tuple[3]));
+                }
+
+                BRepBuilderAPI_MakeShell mkBuilder(s, u1, u2, v1, v2);
+                TopoDS_Shape sh = mkBuilder.Shape();
+                return new TopoShapeShellPy(new TopoShape(sh));
+            }
+        }
+    }
+    catch (Standard_Failure& e) {
+        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
+        return nullptr;
+    }
+
+    PyErr_SetString(PartExceptionOCCError, "Geometry is not a surface");
+    return nullptr;
+}
+
 PyObject* GeometrySurfacePy::getD0(PyObject *args)
 {
     Handle(Geom_Geometry) g = getGeometryPtr()->handle();
diff --git a/src/Mod/Part/App/OpenCascadeAll.h b/src/Mod/Part/App/OpenCascadeAll.h
index 0bdd759f57..c4967fb54f 100644
--- a/src/Mod/Part/App/OpenCascadeAll.h
+++ b/src/Mod/Part/App/OpenCascadeAll.h
@@ -216,6 +216,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp
index 2dc503bdf2..4d9e1fc0f9 100644
--- a/src/Mod/Part/App/PartFeatures.cpp
+++ b/src/Mod/Part/App/PartFeatures.cpp
@@ -25,9 +25,7 @@
 #ifndef _PreComp_
 # include 
 # include 
-# include 
 # include 
-# include 
 # include 
 # include 
 # include 
@@ -43,7 +41,7 @@
 # include 
 # include 
 # include 
-# include 
+# include 
 #endif
 
 
@@ -170,22 +168,18 @@ App::DocumentObjectExecReturn *RuledSurface::execute(void)
 
         if (Orientation.getValue() == 0) {
             // Automatic
-            Handle(Adaptor3d_HCurve) a1;
-            Handle(Adaptor3d_HCurve) a2;
+            std::unique_ptr a1;
+            std::unique_ptr a2;
             if (!isWire) {
-                BRepAdaptor_Curve adapt1(TopoDS::Edge(S1));
-                BRepAdaptor_Curve adapt2(TopoDS::Edge(S2));
-                a1 = new BRepAdaptor_HCurve(adapt1);
-                a2 = new BRepAdaptor_HCurve(adapt2);
+                a1 = std::make_unique(TopoDS::Edge(S1));
+                a2 = std::make_unique(TopoDS::Edge(S2));
             }
             else {
-                BRepAdaptor_CompCurve adapt1(TopoDS::Wire(S1));
-                BRepAdaptor_CompCurve adapt2(TopoDS::Wire(S2));
-                a1 = new BRepAdaptor_HCompCurve(adapt1);
-                a2 = new BRepAdaptor_HCompCurve(adapt2);
+                a1 = std::make_unique(TopoDS::Wire(S1));
+                a2 = std::make_unique(TopoDS::Wire(S2));
             }
 
-            if (!a1.IsNull() && !a2.IsNull()) {
+            if (a1 && a2) {
                 // get end points of 1st curve
                 Standard_Real first, last;
                 first = a1->FirstParameter();
diff --git a/src/Mod/Part/App/PreCompiled.h b/src/Mod/Part/App/PreCompiled.h
index bb9b1cb04f..636b5ea3cb 100644
--- a/src/Mod/Part/App/PreCompiled.h
+++ b/src/Mod/Part/App/PreCompiled.h
@@ -94,6 +94,7 @@
 #include "OpenCascadeAll.h"
 #include 
 #include 
+#include 
 
 #elif defined(FC_OS_WIN32)
 #define WIN32_LEAN_AND_MEAN
diff --git a/src/Mod/Part/App/Tools.cpp b/src/Mod/Part/App/Tools.cpp
index b02c056045..d95e49eaf4 100644
--- a/src/Mod/Part/App/Tools.cpp
+++ b/src/Mod/Part/App/Tools.cpp
@@ -25,25 +25,35 @@
 # include 
 # include 
 # include 
-# include 
+# include 
 # include 
 # include 
-# include 
 # include 
+# include 
 # include 
 # include 
+# include 
+# include 
 # include 
 # include 
 # include 
 # include 
 # include 
+# include 
+# include 
 # include 
 # include 
 # include 
+# include 
 # include 
 # include 
 # include 
 # include 
+# include 
+# if OCC_VERSION_HEX < 0x070600
+# include 
+# include 
+# endif
 #endif
 
 #include 
@@ -138,6 +148,20 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
                 assert (0);
                 Standard_ConstructionError::Raise ("Tools::makeSurface()");
             }
+#if OCC_VERSION_HEX >= 0x070600
+            else if (aCur->IsKind (STANDARD_TYPE (Adaptor3d_CurveOnSurface))) {
+                //G1 constraint
+                Handle(Adaptor3d_CurveOnSurface) aHCOS (Handle(Adaptor3d_CurveOnSurface)::DownCast (aCur));
+                Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHCOS, 1 /*GeomAbs_G1*/,aNbPnts, aTol3d, anAngTol, aCurvTol);
+                aPlateBuilder.Add (aConst);
+            }
+            else if (aCur->IsKind (STANDARD_TYPE (GeomAdaptor_Curve))) {
+                //G0 constraint
+                Handle(GeomAdaptor_Curve) aHC (Handle(GeomAdaptor_Curve)::DownCast (aCur));
+                Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHC, 0 /*GeomAbs_G0*/, aNbPnts, aTol3d);
+                aPlateBuilder.Add (aConst);
+            }
+#else
             else if (aCur->IsKind (STANDARD_TYPE (Adaptor3d_HCurveOnSurface))) {
                 //G1 constraint
                 Handle(Adaptor3d_HCurveOnSurface) aHCOS (Handle(Adaptor3d_HCurveOnSurface)::DownCast (aCur));
@@ -150,6 +174,7 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
                 Handle (GeomPlate_CurveConstraint) aConst = new GeomPlate_CurveConstraint (aHC, 0 /*GeomAbs_G0*/, aNbPnts, aTol3d);
                 aPlateBuilder.Add (aConst);
             }
+#endif
             else if (aCur->IsKind (STANDARD_TYPE (Geom_Point))) {
                 //Point constraint
                 Handle(Geom_Point) aGP (Handle(Geom_Point)::DownCast (aCur));
@@ -190,3 +215,378 @@ Part::Tools::makeSurface(const TColStd_ListOfTransient &theBoundaries,
 
     return aRes;
 }
+
+bool Part::Tools::getTriangulation(const TopoDS_Face& face, std::vector& points, std::vector& facets)
+{
+    TopLoc_Location loc;
+    Handle(Poly_Triangulation) hTria = BRep_Tool::Triangulation(face, loc);
+    if (hTria.IsNull())
+        return false;
+
+    // getting the transformation of the face
+    gp_Trsf transf;
+    bool identity = true;
+    if (!loc.IsIdentity()) {
+        identity = false;
+        transf = loc.Transformation();
+    }
+
+    // check orientation
+    TopAbs_Orientation orient = face.Orientation();
+
+    Standard_Integer nbNodes = hTria->NbNodes();
+    Standard_Integer nbTriangles = hTria->NbTriangles();
+#if OCC_VERSION_HEX < 0x070600
+    const TColgp_Array1OfPnt& nodes = hTria->Nodes();
+    const Poly_Array1OfTriangle& triangles = hTria->Triangles();
+#endif
+
+    points.reserve(nbNodes);
+    facets.reserve(nbTriangles);
+
+    // cycling through the poly mesh
+    //
+    for (int i = 1; i <= nbNodes; i++) {
+#if OCC_VERSION_HEX < 0x070600
+        gp_Pnt p = nodes(i);
+#else
+        gp_Pnt p = hTria->Node(i);
+#endif
+
+        // transform the vertices to the location of the face
+        if (!identity) {
+            p.Transform(transf);
+        }
+
+        points.push_back(p);
+    }
+
+    for (int i = 1; i <= nbTriangles; i++) {
+        // Get the triangle
+        Standard_Integer n1,n2,n3;
+#if OCC_VERSION_HEX < 0x070600
+        triangles(i).Get(n1, n2, n3);
+#else
+        hTria->Triangle(i).Get(n1, n2, n3);
+#endif
+        --n1; --n2; --n3;
+
+        // change orientation of the triangles
+        if (orient != TopAbs_FORWARD) {
+            std::swap(n1, n2);
+        }
+
+        facets.emplace_back(n1, n2, n3);
+    }
+
+    return true;
+}
+
+bool Part::Tools::getPolygonOnTriangulation(const TopoDS_Edge& edge, const TopoDS_Face& face, std::vector& points)
+{
+    TopLoc_Location loc;
+    Handle(Poly_Triangulation) hTria = BRep_Tool::Triangulation(face, loc);
+    if (hTria.IsNull())
+        return false;
+
+    // this holds the indices of the edge's triangulation to the actual points
+    Handle(Poly_PolygonOnTriangulation) hPoly = BRep_Tool::PolygonOnTriangulation(edge, hTria, loc);
+    if (hPoly.IsNull())
+        return false;
+
+    // getting the transformation of the edge
+    gp_Trsf transf;
+    bool identity = true;
+    if (!loc.IsIdentity()) {
+        identity = false;
+        transf = loc.Transformation();
+    }
+
+    // getting size and create the array
+    Standard_Integer nbNodes = hPoly->NbNodes();
+    points.reserve(nbNodes);
+    const TColStd_Array1OfInteger& indices = hPoly->Nodes();
+#if OCC_VERSION_HEX < 0x070600
+    const TColgp_Array1OfPnt& Nodes = hTria->Nodes();
+#endif
+
+    // go through the index array
+    for (Standard_Integer i = indices.Lower(); i <= indices.Upper(); i++) {
+#if OCC_VERSION_HEX < 0x070600
+        gp_Pnt p = Nodes(indices(i));
+#else
+        gp_Pnt p = hTria->Node(indices(i));
+#endif
+        if (!identity) {
+            p.Transform(transf);
+        }
+
+        points.push_back(p);
+    }
+
+    return true;
+}
+
+bool Part::Tools::getPolygon3D(const TopoDS_Edge& edge, std::vector& points)
+{
+    TopLoc_Location loc;
+    Handle(Poly_Polygon3D) hPoly = BRep_Tool::Polygon3D(edge, loc);
+    if (hPoly.IsNull())
+        return false;
+
+    // getting the transformation of the edge
+    gp_Trsf transf;
+    bool identity = true;
+    if (!loc.IsIdentity()) {
+        identity = false;
+        transf = loc.Transformation();
+    }
+
+    // getting size and create the array
+    Standard_Integer nbNodes = hPoly->NbNodes();
+    points.reserve(nbNodes);
+    const TColgp_Array1OfPnt& nodes = hPoly->Nodes();
+
+    for (int i = 1; i <= nbNodes; i++) {
+        gp_Pnt p = nodes(i);
+
+        // transform the vertices to the location of the face
+        if (!identity) {
+            p.Transform(transf);
+        }
+
+        points.push_back(p);
+    }
+
+    return true;
+}
+
+void Part::Tools::getPointNormals(const std::vector& points, const std::vector& facets, std::vector& vertexnormals)
+{
+    vertexnormals.resize(points.size());
+
+    for (const auto& it : facets) {
+        // Get the triangle
+        Standard_Integer n1,n2,n3;
+        it.Get(n1,n2,n3);
+
+        // Calculate triangle normal
+        gp_Vec v1(points[n1].XYZ());
+        gp_Vec v2(points[n2].XYZ());
+        gp_Vec v3(points[n3].XYZ());
+        gp_Vec n = (v2 - v1) ^ (v3 - v1);
+
+        // add the triangle normal to the vertex normal for all points of this triangle
+        vertexnormals[n1] += n;
+        vertexnormals[n2] += n;
+        vertexnormals[n3] += n;
+    }
+
+    for (auto& it : vertexnormals)
+        it.Normalize();
+}
+
+void Part::Tools::getPointNormals(const std::vector& points, const TopoDS_Face& face, std::vector& vertexnormals)
+{
+    if (points.size() != vertexnormals.size())
+        return;
+
+    Handle(Geom_Surface) hSurface = BRep_Tool::Surface(face);
+    if (hSurface.IsNull())
+        return;
+
+    // normalize all vertex normals
+    for (std::size_t i = 0; i < points.size(); i++) {
+        try {
+            GeomAPI_ProjectPointOnSurf ProPntSrf(points[i], hSurface);
+            Standard_Real u, v;
+            ProPntSrf.Parameters(1, u, v);
+
+            GeomLProp_SLProps propOfFace(hSurface, u, v, 2, gp::Resolution());
+
+            gp_Dir normal = propOfFace.Normal();
+            gp_Vec temp = normal;
+            if (temp * vertexnormals[i] < 0.0)
+                temp = -temp;
+            vertexnormals[i] = temp;
+
+        }
+        catch (...) {
+        }
+
+        vertexnormals[i].Normalize();
+    }
+}
+
+void Part::Tools::getPointNormals(const TopoDS_Face& theFace, Handle(Poly_Triangulation) aPolyTri, TColgp_Array1OfDir& theNormals)
+{
+#if OCC_VERSION_HEX < 0x070600
+    const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
+
+    if(aPolyTri->HasNormals())
+    {
+        // normals pre-computed in triangulation structure
+        const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
+        const Standard_ShortReal*       aNormArr = &(aNormals.Value(aNormals.Lower()));
+
+        for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
+        {
+            const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
+            const gp_Dir aNorm(aNormArr[anId + 0],
+                               aNormArr[anId + 1],
+                               aNormArr[anId + 2]);
+            theNormals(aNodeIter) = aNorm;
+        }
+
+        if(theFace.Orientation() == TopAbs_REVERSED)
+        {
+            for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
+            {
+                theNormals.ChangeValue(aNodeIter).Reverse();
+            }
+        }
+    }
+    else {
+        // take in face the surface location
+        Poly_Connect thePolyConnect(aPolyTri);
+        const TopoDS_Face      aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
+        Handle(Geom_Surface)   aSurf     = BRep_Tool::Surface(aZeroFace);
+        const Standard_Real    aTol      = Precision::Confusion();
+        Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal(1, aPolyTri->NbNodes() * 3);
+        const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
+        const TColgp_Array1OfPnt2d*  aNodesUV   = aPolyTri->HasUVNodes() && !aSurf.IsNull()
+                ? &aPolyTri->UVNodes()
+                : nullptr;
+        Standard_Integer aTri[3];
+
+        for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
+        {
+            // try to retrieve normal from real surface first, when UV coordinates are available
+            if (!aNodesUV || GeomLib::NormEstim(aSurf, aNodesUV->Value(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
+            {
+                // compute flat normals
+                gp_XYZ eqPlan(0.0, 0.0, 0.0);
+
+                for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
+                {
+                    aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
+                    const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
+                    const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
+                    const gp_XYZ vv = v1 ^ v2;
+                    const Standard_Real aMod = vv.Modulus();
+
+                    if(aMod >= aTol)
+                    {
+                        eqPlan += vv / aMod;
+                    }
+                }
+
+                const Standard_Real aModMax = eqPlan.Modulus();
+                theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
+            }
+
+            const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
+            aNormals->SetValue(anId + 1, (Standard_ShortReal)theNormals(aNodeIter).X());
+            aNormals->SetValue(anId + 2, (Standard_ShortReal)theNormals(aNodeIter).Y());
+            aNormals->SetValue(anId + 3, (Standard_ShortReal)theNormals(aNodeIter).Z());
+        }
+
+        aPolyTri->SetNormals(aNormals);
+
+        if(theFace.Orientation() == TopAbs_REVERSED)
+        {
+            for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
+            {
+                theNormals.ChangeValue(aNodeIter).Reverse();
+            }
+        }
+    }
+#else
+    Standard_Integer numNodes = aPolyTri->NbNodes();
+
+    if(aPolyTri->HasNormals())
+    {
+        for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
+        {
+            theNormals(aNodeIter) = aPolyTri->Normal(aNodeIter);
+        }
+
+        if(theFace.Orientation() == TopAbs_REVERSED)
+        {
+            for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
+            {
+                theNormals.ChangeValue(aNodeIter).Reverse();
+            }
+        }
+    }
+    else {
+        // take in face the surface location
+        Poly_Connect thePolyConnect(aPolyTri);
+        const TopoDS_Face      aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
+        Handle(Geom_Surface)   aSurf     = BRep_Tool::Surface(aZeroFace);
+        const Standard_Real    aTol      = Precision::Confusion();
+        Standard_Boolean hasNodesUV      = aPolyTri->HasUVNodes() && !aSurf.IsNull();
+        Standard_Integer aTri[3];
+
+        aPolyTri->AddNormals();
+        for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
+        {
+            // try to retrieve normal from real surface first, when UV coordinates are available
+            if (!hasNodesUV || GeomLib::NormEstim(aSurf, aPolyTri->UVNode(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
+            {
+                // compute flat normals
+                gp_XYZ eqPlan(0.0, 0.0, 0.0);
+
+                for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
+                {
+                    aPolyTri->Triangle(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
+                    const gp_XYZ v1(aPolyTri->Node(aTri[1]).Coord() - aPolyTri->Node(aTri[0]).Coord());
+                    const gp_XYZ v2(aPolyTri->Node(aTri[2]).Coord() - aPolyTri->Node(aTri[1]).Coord());
+                    const gp_XYZ vv = v1 ^ v2;
+                    const Standard_Real aMod = vv.Modulus();
+
+                    if(aMod >= aTol)
+                    {
+                        eqPlan += vv / aMod;
+                    }
+                }
+
+                const Standard_Real aModMax = eqPlan.Modulus();
+                theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
+            }
+
+            aPolyTri->SetNormal(aNodeIter, theNormals(aNodeIter));
+        }
+
+        if(theFace.Orientation() == TopAbs_REVERSED)
+        {
+            for(Standard_Integer aNodeIter = 1; aNodeIter <= numNodes; ++aNodeIter)
+            {
+                theNormals.ChangeValue(aNodeIter).Reverse();
+            }
+        }
+    }
+#endif
+}
+
+void Part::Tools::getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, std::vector& normals)
+{
+    TColgp_Array1OfDir dirs (1, aPoly->NbNodes());
+    getPointNormals(face, aPoly, dirs);
+    normals.reserve(aPoly->NbNodes());
+
+    for (int i = dirs.Lower(); i <= dirs.Upper(); ++i) {
+        normals.emplace_back(dirs(i).XYZ());
+    }
+}
+
+void Part::Tools::applyTransformationOnNormals(const TopLoc_Location& loc, std::vector& normals)
+{
+    if (!loc.IsIdentity()) {
+        gp_Trsf myTransf = loc.Transformation();
+
+        for (auto& it : normals) {
+            it.Transform(myTransf);
+        }
+    }
+}
diff --git a/src/Mod/Part/App/Tools.h b/src/Mod/Part/App/Tools.h
index a936c352c6..425032a12d 100644
--- a/src/Mod/Part/App/Tools.h
+++ b/src/Mod/Part/App/Tools.h
@@ -30,7 +30,14 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 class gp_Lin;
 class gp_Pln;
@@ -104,7 +111,72 @@ public:
                                      const Standard_Integer theNbPnts,
                                      const Standard_Integer theNbIter,
                                      const Standard_Integer theMaxDeg);
-
+    /*!
+     * @brief getTriangulation
+     * The indexes of the triangles are adjusted to the points vector.
+     * @param face
+     * @param points
+     * @param facets
+     * @return true if a triangulation exists or false otherwise
+     */
+    static bool getTriangulation(const TopoDS_Face& face, std::vector& points, std::vector& facets);
+    /*!
+     * \brief getPolygonOnTriangulation
+     * Get the polygon of edge.
+     * \note \a edge must belong to face.
+     * \param edge
+     * \param face
+     * \param points
+     * \return true if a triangulation exists or false otherwise
+     */
+    static bool getPolygonOnTriangulation(const TopoDS_Edge& edge, const TopoDS_Face& face, std::vector& points);
+    /*!
+     * \brief getPolygon3D
+     * \param edge
+     * \param points
+     * \return true if a polygon exists or false otherwise
+     */
+    static bool getPolygon3D(const TopoDS_Edge& edge, std::vector& points);
+    /*!
+     * \brief getPointNormals
+     * Calculate the point normals of the given triangulation.
+     * \param points
+     * \param facets
+     * \param normals
+     */
+    static void getPointNormals(const std::vector& points, const std::vector& facets, std::vector& vertexnormals);
+    /*!
+     * \brief getPointNormals
+     * Computes the more accurate surface normals for the points. If the calculation for a point fails then the precomputed
+     * point normal of the triangulation is used.
+     * \param points
+     * \param face
+     * \param vertexnormals
+     */
+    static void getPointNormals(const std::vector& points, const TopoDS_Face& face, std::vector& vertexnormals);
+    /*!
+     * \brief getPointNormals
+     * Computes the exact surface normals for the points by using the UV coordinates of the mesh vertexes.
+     * \param face
+     * \param aPoly
+     * \param vertexnormals
+     */
+    static void getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, TColgp_Array1OfDir& normals);
+    /*!
+     * \brief getPointNormals
+     * Computes the exact surface normals for the points by using the UV coordinates of the mesh vertexes.
+     * \param face
+     * \param aPoly
+     * \param vertexnormals
+     */
+    static void getPointNormals(const TopoDS_Face& face, Handle(Poly_Triangulation) aPoly, std::vector& normals);
+    /*!
+     * \brief applyTransformationOnNormals
+     * Apply the transformation to the vectors
+     * \param loc
+     * \param normals
+     */
+    static void applyTransformationOnNormals(const TopLoc_Location& loc, std::vector& normals);
 };
 
 } //namespace Part
diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp
index 60183e64ca..b7617a3943 100644
--- a/src/Mod/Part/App/TopoShape.cpp
+++ b/src/Mod/Part/App/TopoShape.cpp
@@ -38,8 +38,6 @@
 # include 
 # include 
 # include 
-# include 
-# include 
 # include 
 # include 
 # include 
@@ -186,6 +184,12 @@
 #if OCC_VERSION_HEX >= 0x070300
 # include 
 #endif
+
+#if OCC_VERSION_HEX < 0x070600
+# include 
+# include 
+#endif
+
 #endif // _PreComp_
 
 #include 
@@ -1097,65 +1101,27 @@ void TopoShape::exportFaceSet(double dev, double ca,
     for (ex.Init(this->_Shape, TopAbs_FACE); ex.More(); ex.Next(), index++) {
         // get the shape and mesh it
         const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
-        Standard_Integer nbNodesInFace,nbTriInFace;
+        std::vector points;
+        std::vector facets;
+        if (!Tools::getTriangulation(aFace, points, facets))
+            continue;
+
         std::vector vertices;
         std::vector indices;
+        vertices.resize(points.size());
+        indices.resize(4 * facets.size());
 
-        // doing the meshing and checking the result
-        TopLoc_Location aLoc;
-        Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
-        if (aPoly.IsNull()) continue;
-
-        // getting the transformation of the shape/face
-        gp_Trsf myTransf;
-        Standard_Boolean identity = true;
-        if (!aLoc.IsIdentity()) {
-            identity = false;
-            myTransf = aLoc.Transformation();
+        for (std::size_t i = 0; i < points.size(); i++) {
+            vertices[i] = Base::convertTo(points[i]);
         }
 
-        // getting size and create the array
-        nbNodesInFace = aPoly->NbNodes();
-        nbTriInFace = aPoly->NbTriangles();
-        vertices.resize(nbNodesInFace);
-        indices.resize(4*nbTriInFace);
-
-        // check orientation
-        TopAbs_Orientation orient = aFace.Orientation();
-
-        // cycling through the poly mesh
-        const Poly_Array1OfTriangle& Triangles = aPoly->Triangles();
-        const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
-        for (int i=1;i<=nbTriInFace;i++) {
-            // Get the triangle
-            Standard_Integer N1,N2,N3;
-            Triangles(i).Get(N1,N2,N3);
-
-            // change orientation of the triangles
-            if (orient != TopAbs_FORWARD) {
-                Standard_Integer tmp = N1;
-                N1 = N2;
-                N2 = tmp;
-            }
-
-            gp_Pnt V1 = Nodes(N1);
-            gp_Pnt V2 = Nodes(N2);
-            gp_Pnt V3 = Nodes(N3);
-
-            // transform the vertices to the place of the face
-            if (!identity) {
-                V1.Transform(myTransf);
-                V2.Transform(myTransf);
-                V3.Transform(myTransf);
-            }
-
-            vertices[N1-1].Set((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
-            vertices[N2-1].Set((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
-            vertices[N3-1].Set((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
-
-            int j = i - 1;
-            N1--; N2--; N3--;
-            indices[4*j] = N1; indices[4*j+1] = N2; indices[4*j+2] = N3; indices[4*j+3] = -1;
+        for (std::size_t i = 0; i < facets.size(); i++) {
+            Standard_Integer n1,n2,n3;
+            facets[i].Get(n1, n2, n3);
+            indices[4 * i    ] = n1;
+            indices[4 * i + 1] = n2;
+            indices[4 * i + 2] = n3;
+            indices[4 * i + 3] = -1;
         }
 
         builder.beginSeparator();
@@ -1170,7 +1136,7 @@ void TopoShape::exportFaceSet(double dev, double ca,
         builder.endPoints();
         builder.addIndexedFaceSet(indices);
         builder.endSeparator();
-    } // end of face loop
+    }
 }
 
 void TopoShape::exportLineSet(std::ostream& str) const
@@ -1183,72 +1149,27 @@ void TopoShape::exportLineSet(std::ostream& str) const
     // build up map edge->face
     TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
     TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
-    for (int i=0; i points;
 
-        // try to triangulate the edge
-        Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc);
-
-        std::vector vertices;
-        Standard_Integer nbNodesInFace;
-
-        // triangulation succeeded?
-        if (!aPoly.IsNull()) {
-            if (!aLoc.IsIdentity()) {
-                myTransf = aLoc.Transformation();
-            }
-            nbNodesInFace = aPoly->NbNodes();
-            vertices.resize(nbNodesInFace);
-
-            const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
-
-            gp_Pnt V;
-            for (Standard_Integer i=0;i < nbNodesInFace;i++) {
-                V = Nodes(i+1);
-                V.Transform(myTransf);
-                vertices[i].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z()));
-            }
-        }
-        else {
+        if (!Tools::getPolygon3D(aEdge, points)) {
             // the edge has not its own triangulation, but then a face the edge is attached to
             // must provide this triangulation
 
             // Look for one face in our map (it doesn't care which one we take)
             const TopoDS_Face& aFace = TopoDS::Face(edge2Face.FindFromKey(aEdge).First());
-
-            // take the face's triangulation instead
-            Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
-            if (!aLoc.IsIdentity()) {
-                myTransf = aLoc.Transformation();
-            }
-
-            if (aPolyTria.IsNull()) break;
-
-            // this holds the indices of the edge's triangulation to the actual points
-            Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(aEdge, aPolyTria, aLoc);
-            if (aPoly.IsNull())
-                continue; // polygon does not exist
-
-            // getting size and create the array
-            nbNodesInFace = aPoly->NbNodes();
-            vertices.resize(nbNodesInFace);
-
-            const TColStd_Array1OfInteger& indices = aPoly->Nodes();
-            const TColgp_Array1OfPnt& Nodes = aPolyTria->Nodes();
-
-            gp_Pnt V;
-            int pos = 0;
-            // go through the index array
-            for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) {
-                V = Nodes(indices(i));
-                V.Transform(myTransf);
-                vertices[pos++].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z()));
-            }
+            if (!Tools::getPolygonOnTriangulation(aEdge, aFace, points))
+                continue;
         }
 
+        std::vector vertices;
+        vertices.reserve(points.size());
+        std::for_each(points.begin(), points.end(), [&vertices](const gp_Pnt& p) {
+            vertices.push_back(Base::convertTo(p));
+        });
+
         builder.addLineSet(vertices, 2, 0, 0, 0);
     }
 }
@@ -2216,12 +2137,20 @@ TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdeg
     if (this->_Shape.IsNull())
         Standard_Failure::Raise("Cannot sweep along empty spine");
 
+#if OCC_VERSION_HEX >= 0x070600
+    Handle(Adaptor3d_Curve) myPath;
+    if (this->_Shape.ShapeType() == TopAbs_EDGE) {
+        const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape);
+        myPath = new BRepAdaptor_Curve(path_edge);
+    }
+#else
     Handle(Adaptor3d_HCurve) myPath;
     if (this->_Shape.ShapeType() == TopAbs_EDGE) {
         const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape);
         BRepAdaptor_Curve path_adapt(path_edge);
         myPath = new BRepAdaptor_HCurve(path_adapt);
     }
+#endif
     //else if (this->_Shape.ShapeType() == TopAbs_WIRE) {
     //    const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape);
     //    BRepAdaptor_CompCurve path_adapt(path_wire);
@@ -3443,46 +3372,40 @@ void TopoShape::getDomains(std::vector& domains) const
     for (TopExp_Explorer xp(this->_Shape, TopAbs_FACE); xp.More(); xp.Next()) {
         TopoDS_Face face = TopoDS::Face(xp.Current());
 
-        TopLoc_Location loc;
-        Handle(Poly_Triangulation) theTriangulation = BRep_Tool::Triangulation(face, loc);
-        if (theTriangulation.IsNull()) {
+        std::vector points;
+        std::vector facets;
+        if (!Tools::getTriangulation(face, points, facets)) {
             // For a face that cannot be meshed append an empty domain.
             // It's important for some algorithms (e.g. color mapping) that the numbers of
             // faces and domains match
             Domain domain;
             domains.push_back(domain);
-            continue;
         }
+        else {
+            Domain domain;
+            // copy the points
+            domain.points.reserve(points.size());
+            for (const auto& it : points) {
+                Standard_Real X, Y, Z;
+                it.Coord (X, Y, Z);
+                domain.points.emplace_back(X, Y, Z);
+            }
 
-        Domain domain;
-        // copy the points
-        const TColgp_Array1OfPnt& points = theTriangulation->Nodes();
-        domain.points.reserve(points.Length());
-        for (int i = 1; i <= points.Length(); i++) {
-            gp_Pnt p = points(i);
-            p.Transform(loc.Transformation());
-            Standard_Real X, Y, Z;
-            p.Coord (X, Y, Z);
-            domain.points.emplace_back(X, Y, Z);
+            // copy the triangles
+            domain.facets.reserve(facets.size());
+            for (const auto& it : facets) {
+                Standard_Integer N1, N2, N3;
+                it.Get(N1, N2, N3);
+
+                Facet tria;
+                tria.I1 = N1;
+                tria.I2 = N2;
+                tria.I3 = N3;
+                domain.facets.push_back(tria);
+            }
+
+            domains.push_back(domain);
         }
-
-        // copy the triangles
-        const TopAbs_Orientation anOrientation = face.Orientation();
-        bool flip = (anOrientation == TopAbs_REVERSED);
-        const Poly_Array1OfTriangle& faces = theTriangulation->Triangles();
-        domain.facets.reserve(faces.Length());
-        for (int i = 1; i <= faces.Length(); i++) {
-            Standard_Integer N1, N2, N3;
-            faces(i).Get(N1, N2, N3);
-
-            Facet tria;
-            tria.I1 = N1-1; tria.I2 = N2-1; tria.I3 = N3-1;
-            if (flip)
-                std::swap(tria.I1, tria.I2);
-            domain.facets.push_back(tria);
-        }
-
-        domains.push_back(domain);
     }
 }
 
@@ -3845,7 +3768,7 @@ void TopoShape::getPoints(std::vector &Points,
         Normals.clear();
 }
 
-void TopoShape::getLinesFromSubelement(const Data::Segment* element,
+void TopoShape::getLinesFromSubElement(const Data::Segment* element,
                                        std::vector &vertices,
                                        std::vector &lines) const
 {
@@ -3866,72 +3789,32 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
         for(TopExp_Explorer exp(shape,TopAbs_EDGE);exp.More();exp.Next()) {
 
             TopoDS_Edge aEdge = TopoDS::Edge(exp.Current());
-            TopLoc_Location aLoc;
-            Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc);
+            std::vector points;
 
-            gp_Trsf myTransf;
-            Standard_Integer nbNodesInFace;
-
-            auto line_start = vertices.size();
-
-            // triangulation succeeded?
-            if (!aPoly.IsNull()) {
-                if (!aLoc.IsIdentity()) {
-                    myTransf = aLoc.Transformation();
-                }
-                nbNodesInFace = aPoly->NbNodes();
-
-                const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
-
-                gp_Pnt V;
-                for (Standard_Integer i=0;i < nbNodesInFace;i++) {
-                    V = Nodes(i+1);
-                    V.Transform(myTransf);
-                    vertices.emplace_back(V.X(),V.Y(),V.Z());
-                }
-            }
-            else {
+            if (!Tools::getPolygon3D(aEdge, points)) {
                 // the edge has not its own triangulation, but then a face the edge is attached to
                 // must provide this triangulation
 
                 // Look for one face in our map (it doesn't care which one we take)
                 int index = edge2Face.FindIndex(aEdge);
-                if(!index)
+                if (index < 1)
                     continue;
                 const auto &faces = edge2Face.FindFromIndex(index);
-                if(!faces.Extent())
+                if (faces.Extent() == 0)
                     continue;
                 const TopoDS_Face& aFace = TopoDS::Face(faces.First());
 
-                // take the face's triangulation instead
-                Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
-                if (!aLoc.IsIdentity()) {
-                    myTransf = aLoc.Transformation();
-                }
-
-                if (aPolyTria.IsNull()) break;
-
-                // this holds the indices of the edge's triangulation to the actual points
-                Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(aEdge, aPolyTria, aLoc);
-                if (aPoly.IsNull())
-                    continue; // polygon does not exist
-
-                // getting size and create the array
-                nbNodesInFace = aPoly->NbNodes();
-
-                const TColStd_Array1OfInteger& indices = aPoly->Nodes();
-                const TColgp_Array1OfPnt& Nodes = aPolyTria->Nodes();
-
-                gp_Pnt V;
-                // go through the index array
-                for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) {
-                    V = Nodes(indices(i));
-                    V.Transform(myTransf);
-                    vertices.emplace_back(V.X(),V.Y(),V.Z());
-                }
+                if (!Part::Tools::getPolygonOnTriangulation(aEdge, aFace, points))
+                    continue;
             }
 
-            if(line_start+1 < vertices.size()) {
+            auto line_start = vertices.size();
+            vertices.reserve(vertices.size() + points.size());
+            std::for_each(points.begin(), points.end(), [&vertices](const gp_Pnt& p) {
+                vertices.push_back(Base::convertTo(p));
+            });
+
+            if (line_start+1 < vertices.size()) {
                 lines.emplace_back();
                 lines.back().I1 = line_start;
                 lines.back().I2 = vertices.size()-1;
@@ -3940,7 +3823,7 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
     }
 }
 
-void TopoShape::getFacesFromSubelement(const Data::Segment* element,
+void TopoShape::getFacesFromSubElement(const Data::Segment* element,
                                        std::vector &points,
                                        std::vector &pointNormals,
                                        std::vector &faces) const
diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h
index f720dae87d..9d50ec0da6 100644
--- a/src/Mod/Part/App/TopoShape.h
+++ b/src/Mod/Part/App/TopoShape.h
@@ -135,12 +135,12 @@ public:
     /// get the subelement by type and number
     virtual Data::Segment* getSubElement(const char* Type, unsigned long) const;
     /** Get lines from segment */
-    virtual void getLinesFromSubelement(
+    virtual void getLinesFromSubElement(
         const Data::Segment*,
         std::vector &Points,
         std::vector &lines) const;
     /** Get faces from segment */
-    virtual void getFacesFromSubelement(
+    virtual void getFacesFromSubElement(
         const Data::Segment*,
         std::vector &Points,
         std::vector &PointNormals,
diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp
index ea6cd98bdf..63e8bead74 100644
--- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp
+++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp
@@ -493,6 +493,15 @@ PyObject* TopoShapeFacePy::getUVNodes(PyObject *args)
         return Py::new_reference_to(list);
     }
 
+#if OCC_VERSION_HEX >= 0x070600
+    for (int i=1; i<=mesh->NbNodes(); i++) {
+        gp_Pnt2d pt2d = mesh->UVNode(i);
+        Py::Tuple uv(2);
+        uv.setItem(0, Py::Float(pt2d.X()));
+        uv.setItem(1, Py::Float(pt2d.Y()));
+        list.append(uv);
+    }
+#else
     const TColgp_Array1OfPnt2d& aNodesUV = mesh->UVNodes();
     for (int i=aNodesUV.Lower(); i<=aNodesUV.Upper(); i++) {
         gp_Pnt2d pt2d = aNodesUV(i);
@@ -501,6 +510,7 @@ PyObject* TopoShapeFacePy::getUVNodes(PyObject *args)
         uv.setItem(1, Py::Float(pt2d.Y()));
         list.append(uv);
     }
+#endif
 
     return Py::new_reference_to(list);
 }
diff --git a/src/Mod/Part/App/TopoShapeWirePyImp.cpp b/src/Mod/Part/App/TopoShapeWirePyImp.cpp
index 95c1aff681..a1f32d6d03 100644
--- a/src/Mod/Part/App/TopoShapeWirePyImp.cpp
+++ b/src/Mod/Part/App/TopoShapeWirePyImp.cpp
@@ -344,9 +344,9 @@ PyObject* TopoShapeWirePy::approximate(PyObject *args, PyObject *kwds)
         return 0;
     try {
         BRepAdaptor_CompCurve adapt(TopoDS::Wire(getTopoShapePtr()->getShape()));
-        Handle(Adaptor3d_HCurve) hcurve = adapt.Trim(adapt.FirstParameter(),
-                                                    adapt.LastParameter(),
-                                                    tol2d);
+        auto hcurve = adapt.Trim(adapt.FirstParameter(),
+                                 adapt.LastParameter(),
+                                 tol2d);
         Approx_Curve3d approx(hcurve, tol3d, GeomAbs_C0, maxseg, maxdeg);
         if (approx.IsDone()) {
             return new BSplineCurvePy(new GeomBSplineCurve(approx.Curve()));
diff --git a/src/Mod/Part/Gui/ShapeFromMesh.cpp b/src/Mod/Part/Gui/ShapeFromMesh.cpp
index f031582a6d..c570f6cf2b 100644
--- a/src/Mod/Part/Gui/ShapeFromMesh.cpp
+++ b/src/Mod/Part/Gui/ShapeFromMesh.cpp
@@ -28,7 +28,7 @@
 
 #include "ShapeFromMesh.h"
 #include "ui_ShapeFromMesh.h"
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,8 +46,7 @@ ShapeFromMesh::ShapeFromMesh(QWidget* parent, Qt::WindowFlags fl)
 
     double STD_OCC_TOLERANCE = 1e-6;
 
-    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
-    int decimals = hGrp->GetInt("Decimals");
+    int decimals = Base::UnitsApi::getDecimals();
     double tolerance_from_decimals = pow(10., -decimals);
 
     double minimal_tolerance = tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals;
@@ -81,7 +80,7 @@ void ShapeFromMesh::perform()
         std::string mesh = (*it)->getNameInDocument();
         std::string name = doc->getUniqueObjectName(mesh.c_str());
 
-        Gui::cmdAppDocument(doc, std::ostringstream() << "addObject(\"Part::Feature\", \"" << name << "\")");
+        Gui::cmdAppDocumentArgs(doc, "addObject('%s', '%s')", "Part::Feature",  name);
         std::string partObj = App::DocumentObjectT(doc, name).getObjectPython();
         std::string meshObj = App::DocumentObjectT(doc, mesh).getObjectPython();
 
diff --git a/src/Mod/Part/Gui/TaskCheckGeometry.cpp b/src/Mod/Part/Gui/TaskCheckGeometry.cpp
index 5de7c16920..aaef13d9d0 100644
--- a/src/Mod/Part/Gui/TaskCheckGeometry.cpp
+++ b/src/Mod/Part/Gui/TaskCheckGeometry.cpp
@@ -711,8 +711,10 @@ int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, Resu
 #if OCC_VERSION_HEX >= 0x060900
 #if OCC_VERSION_HEX < 0x070500
   BOPCheck.SetProgressIndicator(theProgress);
-#else
+#elif OCC_VERSION_HEX < 0x070600
   BOPCheck.SetProgressIndicator(theScope);
+#else
+  Q_UNUSED(theScope)
 #endif // 0x070500
 #else
   Q_UNUSED(theProgress);
@@ -740,7 +742,7 @@ int TaskCheckGeometryResults::goBOPSingleCheck(const TopoDS_Shape& shapeIn, Resu
   Base::TimeInfo start_time;
 #endif
 
-BOPCheck.Perform();
+  BOPCheck.Perform();
 
 #ifdef FC_DEBUG
   float bopAlgoTime = Base::TimeInfo::diffTimeF(start_time,Base::TimeInfo());
diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp
index ba197f1811..daf355e909 100644
--- a/src/Mod/Part/Gui/ViewProviderExt.cpp
+++ b/src/Mod/Part/Gui/ViewProviderExt.cpp
@@ -125,6 +125,7 @@
 
 #include 
 #include 
+#include 
 
 FC_LOG_LEVEL_INIT("Part", true, true)
 
@@ -133,94 +134,6 @@ using namespace PartGui;
 PROPERTY_SOURCE(PartGui::ViewProviderPartExt, Gui::ViewProviderGeometryObject)
 
 
-void ViewProviderPartExt::getNormals(const TopoDS_Face&  theFace,
-                                     const Handle(Poly_Triangulation)& aPolyTri,
-                                     TColgp_Array1OfDir& theNormals)
-{
-    const TColgp_Array1OfPnt& aNodes = aPolyTri->Nodes();
-
-    if(aPolyTri->HasNormals())
-    {
-        // normals pre-computed in triangulation structure
-        const TShort_Array1OfShortReal& aNormals = aPolyTri->Normals();
-        const Standard_ShortReal*       aNormArr = &(aNormals.Value(aNormals.Lower()));
-
-        for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
-        {
-            const Standard_Integer anId = 3 * (aNodeIter - aNodes.Lower());
-            const gp_Dir aNorm(aNormArr[anId + 0],
-                               aNormArr[anId + 1],
-                               aNormArr[anId + 2]);
-            theNormals(aNodeIter) = aNorm;
-        }
-
-        if(theFace.Orientation() == TopAbs_REVERSED)
-        {
-            for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
-            {
-                theNormals.ChangeValue(aNodeIter).Reverse();
-            }
-        }
-
-        return;
-    }
-
-    // take in face the surface location
-    Poly_Connect thePolyConnect(aPolyTri);
-    const TopoDS_Face      aZeroFace = TopoDS::Face(theFace.Located(TopLoc_Location()));
-    Handle(Geom_Surface)   aSurf     = BRep_Tool::Surface(aZeroFace);
-    const Standard_Real    aTol      = Precision::Confusion();
-    Handle(TShort_HArray1OfShortReal) aNormals = new TShort_HArray1OfShortReal(1, aPolyTri->NbNodes() * 3);
-    const Poly_Array1OfTriangle& aTriangles = aPolyTri->Triangles();
-    const TColgp_Array1OfPnt2d*  aNodesUV   = aPolyTri->HasUVNodes() && !aSurf.IsNull()
-            ? &aPolyTri->UVNodes()
-            : NULL;
-    Standard_Integer aTri[3];
-
-    for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
-    {
-        // try to retrieve normal from real surface first, when UV coordinates are available
-        if(aNodesUV == NULL
-                || GeomLib::NormEstim(aSurf, aNodesUV->Value(aNodeIter), aTol, theNormals(aNodeIter)) > 1)
-        {
-            // compute flat normals
-            gp_XYZ eqPlan(0.0, 0.0, 0.0);
-
-            for(thePolyConnect.Initialize(aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
-            {
-                aTriangles(thePolyConnect.Value()).Get(aTri[0], aTri[1], aTri[2]);
-                const gp_XYZ v1(aNodes(aTri[1]).Coord() - aNodes(aTri[0]).Coord());
-                const gp_XYZ v2(aNodes(aTri[2]).Coord() - aNodes(aTri[1]).Coord());
-                const gp_XYZ vv = v1 ^ v2;
-                const Standard_Real aMod = vv.Modulus();
-
-                if(aMod >= aTol)
-                {
-                    eqPlan += vv / aMod;
-                }
-            }
-
-            const Standard_Real aModMax = eqPlan.Modulus();
-            theNormals(aNodeIter) = (aModMax > aTol) ? gp_Dir(eqPlan) : gp::DZ();
-        }
-
-        const Standard_Integer anId = (aNodeIter - aNodes.Lower()) * 3;
-        aNormals->SetValue(anId + 1, (Standard_ShortReal)theNormals(aNodeIter).X());
-        aNormals->SetValue(anId + 2, (Standard_ShortReal)theNormals(aNodeIter).Y());
-        aNormals->SetValue(anId + 3, (Standard_ShortReal)theNormals(aNodeIter).Z());
-    }
-
-    aPolyTri->SetNormals(aNormals);
-
-    if(theFace.Orientation() == TopAbs_REVERSED)
-    {
-        for(Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
-        {
-            theNormals.ChangeValue(aNodeIter).Reverse();
-        }
-    }
-}
-
 //**************************************************************************
 // Construction/Destruction
 
@@ -443,24 +356,19 @@ void ViewProviderPartExt::onChanged(const App::Property* prop)
     else if (prop == &ShapeMaterial || prop == &ShapeColor) {
         pcFaceBind->value = SoMaterialBinding::OVERALL;
         ViewProviderGeometryObject::onChanged(prop);
-        DiffuseColor.setValue(ShapeColor.getValue());
+        App::Color c = ShapeColor.getValue();
+        c.a = Transparency.getValue()/100.0f;
+        DiffuseColor.setValue(c);
     }
     else if (prop == &Transparency) {
         const App::Material& Mat = ShapeMaterial.getValue();
         long value = (long)(100*Mat.transparency);
         if (value != Transparency.getValue()) {
             float trans = Transparency.getValue()/100.0f;
-            if (pcFaceBind->value.getValue() == SoMaterialBinding::PER_PART) {
-                int cnt = pcShapeMaterial->diffuseColor.getNum();
-                pcShapeMaterial->transparency.setNum(cnt);
-                float *t = pcShapeMaterial->transparency.startEditing();
-                for (int i=0; itransparency.finishEditing();
-            }
-            else {
-                pcShapeMaterial->transparency = trans;
-            }
+            auto colors = DiffuseColor.getValues();
+            for (auto &c : colors)
+                c.a = trans;
+            DiffuseColor.setValues(colors);
 
             App::PropertyContainer* parent = ShapeMaterial.getContainer();
             ShapeMaterial.setContainer(0);
@@ -729,7 +637,7 @@ void ViewProviderPartExt::setHighlightedFaces(const std::vector& col
     else if (colors.size() == 1) {
         pcFaceBind->value = SoMaterialBinding::OVERALL;
         pcShapeMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b);
-        //pcShapeMaterial->transparency = colors[0].a; do not get transparency from DiffuseColor in this case
+        pcShapeMaterial->transparency = Transparency.getValue()/100.f;
     }
 }
 
@@ -795,6 +703,7 @@ std::map ViewProviderPartExt::getElementColors(const cha
             }
             if(size && singleColor) {
                 color = DiffuseColor[0];
+                color.a = Transparency.getValue()/100.0f;
                 ret.clear();
             }
             ret["Face"] = color;
@@ -1170,16 +1079,25 @@ void ViewProviderPartExt::updateVisual()
 
 
             // cycling through the poly mesh
+#if OCC_VERSION_HEX < 0x070600
             const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
             const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
             TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
+#else
+            int numNodes =  mesh->NbNodes();
+            TColgp_Array1OfDir Normals (1, numNodes);
+#endif
             if (NormalsFromUV)
-                getNormals(actFace, mesh, Normals);
+                Part::Tools::getPointNormals(actFace, mesh, Normals);
             
             for (int g=1;g<=nbTriInFace;g++) {
                 // Get the triangle
                 Standard_Integer N1,N2,N3;
+#if OCC_VERSION_HEX < 0x070600
                 Triangles(g).Get(N1,N2,N3);
+#else
+                mesh->Triangle(g).Get(N1,N2,N3);
+#endif
 
                 // change orientation of the triangle if the face is reversed
                 if ( orient != TopAbs_FORWARD ) {
@@ -1189,7 +1107,11 @@ void ViewProviderPartExt::updateVisual()
                 }
 
                 // get the 3 points of this triangle
+#if OCC_VERSION_HEX < 0x070600
                 gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
+#else
+                gp_Pnt V1(mesh->Node(N1)), V2(mesh->Node(N2)), V3(mesh->Node(N3));
+#endif
 
                 // get the 3 normals of this triangle
                 gp_Vec NV1, NV2, NV3;
@@ -1266,7 +1188,11 @@ void ViewProviderPartExt::updateVisual()
                         // rare cases where some points are only referenced by the polygon
                         // but not by any triangle. Thus, we must apply the coordinates to
                         // make sure that everything is properly set.
+#if OCC_VERSION_HEX < 0x070600
                         gp_Pnt p(Nodes(nodeIndex));
+#else
+                        gp_Pnt p(mesh->Node(nodeIndex));
+#endif
                         if (!identity)
                             p.Transform(myTransf);
                         verts[index].setValue((float)(p.X()),(float)(p.Y()),(float)(p.Z()));
diff --git a/src/Mod/Part/Gui/ViewProviderExt.h b/src/Mod/Part/Gui/ViewProviderExt.h
index d890e9a716..2cb55c1873 100644
--- a/src/Mod/Part/Gui/ViewProviderExt.h
+++ b/src/Mod/Part/Gui/ViewProviderExt.h
@@ -158,8 +158,6 @@ protected:
     virtual void onChanged(const App::Property* prop) override;
     bool loadParameter();
     void updateVisual();
-    void getNormals(const TopoDS_Face&  theFace, const Handle(Poly_Triangulation)& aPolyTri,
-                    TColgp_Array1OfDir& theNormals);
 
     // nodes for the data representation
     SoMaterialBinding * pcFaceBind;
diff --git a/src/Mod/PartDesign/App/json.hpp b/src/Mod/PartDesign/App/json.hpp
index 1c15051070..fb83a5cca0 100644
--- a/src/Mod/PartDesign/App/json.hpp
+++ b/src/Mod/PartDesign/App/json.hpp
@@ -43,6 +43,7 @@ SOFTWARE.
 #include  // unique_ptr
 #include  // accumulate
 #include  // string, stoi, to_string
+#include  // string_view
 #include  // declval, forward, move, pair, swap
 #include  // vector
 
diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp
index 83b13b9874..8a52a037c7 100644
--- a/src/Mod/PartDesign/Gui/Command.cpp
+++ b/src/Mod/PartDesign/Gui/Command.cpp
@@ -43,6 +43,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1257,7 +1258,10 @@ void CmdPartDesignPad::activated(int iMsg)
 
         Part::Part2DObject* sketch = dynamic_cast(profile);
 
-        FCMD_OBJ_CMD(Feat, "ReferenceAxis = (" << getObjectCmd(sketch) << ",['N_Axis'])");
+        if (sketch) {
+            std::ostringstream str;
+            Gui::cmdAppObject(Feat, str << "ReferenceAxis = (" << getObjectCmd(sketch) << ",['N_Axis'])");
+        }
 
         finishProfileBased(cmd, sketch, Feat);
         cmd->adjustCameraPosition();
diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
index e20d1b8624..fc4d95354c 100644
--- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
+++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
@@ -775,7 +775,10 @@ void TaskPadParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector<
     int num = ui->directionCB->currentIndex();
     const App::PropertyLinkSub& lnk = *(axesInList[num]);
     if (lnk.getValue() == 0) {
-        throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet");
+        // Note: Is is possible that a face of an object is directly padded without defining a profile shape
+        obj = nullptr;
+        sub.clear();
+        //throw Base::RuntimeError("Still in reference selection mode; reference wasn't selected yet");
     }
     else {
         PartDesign::ProfileBased* pcDirection = static_cast(vp->getObject());
diff --git a/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp b/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp
index 85bcf6e551..2e2d2a55e5 100644
--- a/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp
+++ b/src/Mod/PartDesign/Gui/ViewProviderAddSub.cpp
@@ -40,7 +40,8 @@
 #endif
 
 #include "ViewProviderAddSub.h"
-#include "Mod/Part/Gui/SoBrepFaceSet.h"
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -115,9 +116,6 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
         return;
     }
 
-    int numTriangles=0,numNodes=0,numNorms=0,numFaces=0;
-    std::set faceEdges;
-
     try {
         // calculating the deflection value
         Bnd_Box bounds;
@@ -125,16 +123,14 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
         bounds.SetGap(0.0);
         Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
         bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
-        Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 *
-            Deviation.getValue();
+        Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
 
         // create or use the mesh on the data structure
 #if OCC_VERSION_HEX >= 0x060600
         Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
-        BRepMesh_IncrementalMesh(cShape,deflection,Standard_False,
-                                    AngDeflectionRads,Standard_True);
+        BRepMesh_IncrementalMesh(cShape, deflection, Standard_False, AngDeflectionRads, Standard_True);
 #else
-        BRepMesh_IncrementalMesh(cShape,deflection);
+        BRepMesh_IncrementalMesh(cShape, deflection);
 #endif
         // We must reset the location here because the transformation data
         // are set in the placement property
@@ -142,6 +138,7 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
         cShape.Location(aLoc);
 
         // count triangles and nodes in the mesh
+        int numTriangles=0,numNodes=0,numNorms=0,numFaces=0;
         TopExp_Explorer Ex;
         for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) {
             Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
@@ -159,11 +156,12 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
         previewNorm    ->vector     .setNum(numNorms);
         previewFaceSet ->coordIndex .setNum(numTriangles*4);
         previewFaceSet ->partIndex  .setNum(numFaces);
+
         // get the raw memory for fast fill up
-        SbVec3f* verts = previewCoords  ->point       .startEditing();
-        SbVec3f* previewNorms = previewNorm    ->vector      .startEditing();
-        int32_t* index = previewFaceSet ->coordIndex  .startEditing();
-        int32_t* parts = previewFaceSet ->partIndex   .startEditing();
+        SbVec3f* verts = previewCoords      ->point      .startEditing();
+        SbVec3f* previewNorms = previewNorm ->vector     .startEditing();
+        int32_t* index = previewFaceSet     ->coordIndex .startEditing();
+        int32_t* parts = previewFaceSet     ->partIndex  .startEditing();
 
         // preset the previewNormal vector with null vector
         for (int i=0;i < numNorms;i++)
@@ -171,76 +169,46 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
 
         int ii = 0,faceNodeOffset=0,faceTriaOffset=0;
         for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) {
-            TopLoc_Location aLoc;
             const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
-            // get the mesh of the shape
-            Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
-            if (mesh.IsNull()) continue;
 
-            // getting the transformation of the shape/face
-            gp_Trsf myTransf;
-            Standard_Boolean identity = true;
-            if (!aLoc.IsIdentity()) {
-                identity = false;
-                myTransf = aLoc.Transformation();
-            }
+            TopLoc_Location loc;
+            Handle(Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace, loc);
+            if (mesh.IsNull())
+                continue;
+
+            // get triangulation
+            std::vector points;
+            std::vector facets;
+            Part::Tools::getTriangulation(actFace, points, facets);
+
+            // get normal per vertex
+            std::vector vertexnormals;
+            Part::Tools::getPointNormals(actFace, mesh, vertexnormals);
+            Part::Tools::applyTransformationOnNormals(loc, vertexnormals);
 
             // getting size of node and triangle array of this face
-            int nbNodesInFace = mesh->NbNodes();
-            int nbTriInFace   = mesh->NbTriangles();
-            // check orientation
-            TopAbs_Orientation orient = actFace.Orientation();
+            std::size_t nbNodesInFace = points.size();
+            std::size_t nbTriInFace   = facets.size();
 
+            for (std::size_t i = 0; i < points.size(); i++) {
+                verts[faceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z());
+            }
+
+            for (std::size_t i = 0; i < vertexnormals.size(); i++) {
+                previewNorms[faceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z());
+            }
 
             // cycling through the poly mesh
-            const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
-            const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
-            TColgp_Array1OfDir Normals (Nodes.Lower(), Nodes.Upper());
-            getNormals(actFace, mesh, Normals);
-
-            for (int g=1;g<=nbTriInFace;g++) {
+            for (std::size_t g=0; g < nbTriInFace; g++) {
                 // Get the triangle
                 Standard_Integer N1,N2,N3;
-                Triangles(g).Get(N1,N2,N3);
-
-                // change orientation of the triangle if the face is reversed
-                if ( orient != TopAbs_FORWARD ) {
-                    Standard_Integer tmp = N1;
-                    N1 = N2;
-                    N2 = tmp;
-                }
-
-                // get the 3 points of this triangle
-                gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
-
-                // get the 3 previewNormals of this triangle
-                gp_Dir NV1(Normals(N1)), NV2(Normals(N2)), NV3(Normals(N3));
-
-                // transform the vertices and previewNormals to the place of the face
-                if(!identity) {
-                    V1.Transform(myTransf);
-                    V2.Transform(myTransf);
-                    V3.Transform(myTransf);
-                    NV1.Transform(myTransf);
-                    NV2.Transform(myTransf);
-                    NV3.Transform(myTransf);
-                }
-
-                // add the previewNormals for all points of this triangle
-                previewNorms[faceNodeOffset+N1-1] += SbVec3f(NV1.X(),NV1.Y(),NV1.Z());
-                previewNorms[faceNodeOffset+N2-1] += SbVec3f(NV2.X(),NV2.Y(),NV2.Z());
-                previewNorms[faceNodeOffset+N3-1] += SbVec3f(NV3.X(),NV3.Y(),NV3.Z());
-
-                // set the vertices
-                verts[faceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
-                verts[faceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
-                verts[faceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
+                facets[g].Get(N1,N2,N3);
 
                 // set the index vector with the 3 point indexes and the end delimiter
-                index[faceTriaOffset*4+4*(g-1)]   = faceNodeOffset+N1-1;
-                index[faceTriaOffset*4+4*(g-1)+1] = faceNodeOffset+N2-1;
-                index[faceTriaOffset*4+4*(g-1)+2] = faceNodeOffset+N3-1;
-                index[faceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
+                index[faceTriaOffset*4+4*g]   = faceNodeOffset+N1;
+                index[faceTriaOffset*4+4*g+1] = faceNodeOffset+N2;
+                index[faceTriaOffset*4+4*g+2] = faceNodeOffset+N3;
+                index[faceTriaOffset*4+4*g+3] = SO_END_FACE_INDEX;
             }
 
             parts[ii] = nbTriInFace; // new part
diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp
index 0d402d0b71..0e3b7f0b06 100644
--- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp
+++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp
@@ -55,6 +55,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -198,162 +199,131 @@ void ViewProviderTransformed::recomputeFeature(bool recompute)
     }
 
     // Display the rejected transformations in red
-
     if (rejected > 0) {
-        try {
-            // calculating the deflection value
-            Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
-            {
-                Bnd_Box bounds;
-                BRepBndLib::Add(cShape, bounds);
-                bounds.SetGap(0.0);
-                bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
-            }
-            Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
-
-            // create or use the mesh on the data structure
-            // Note: This DOES have an effect on cShape
-#if OCC_VERSION_HEX >= 0x060600
-            Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
-            BRepMesh_IncrementalMesh(cShape,deflection,Standard_False,
-                                        AngDeflectionRads,Standard_True);
-#else
-            BRepMesh_IncrementalMesh(cShape,deflection);
-#endif
-            // We must reset the location here because the transformation data
-            // are set in the placement property
-            TopLoc_Location aLoc;
-            cShape.Location(aLoc);
-
-            // count triangles and nodes in the mesh
-            int nbrTriangles=0, nbrNodes=0;
-            TopExp_Explorer Ex;
-            for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) {
-                Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
-                // Note: we must also count empty faces
-                if (!mesh.IsNull()) {
-                    nbrTriangles += mesh->NbTriangles();
-                    nbrNodes     += mesh->NbNodes();
-                }
-            }
-
-            // create memory for the nodes and indexes
-            SoCoordinate3* rejectedCoords = new SoCoordinate3();
-            rejectedCoords  ->point      .setNum(nbrNodes);
-            SoNormal* rejectedNorms = new SoNormal();
-            rejectedNorms   ->vector     .setNum(nbrNodes);
-            SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet();
-            rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
-
-            // get the raw memory for fast fill up
-            SbVec3f* verts = rejectedCoords  ->point      .startEditing();
-            SbVec3f* norms = rejectedNorms   ->vector     .startEditing();
-            int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
-
-            // preset the normal vector with null vector
-            for (int i=0; i < nbrNodes; i++)
-                norms[i]= SbVec3f(0.0,0.0,0.0);
-
-            int ii = 0,FaceNodeOffset=0,FaceTriaOffset=0;
-            for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) {
-                TopLoc_Location aLoc;
-                const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
-                // get the mesh of the shape
-                Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc);
-                if (mesh.IsNull()) continue;
-
-                // getting the transformation of the shape/face
-                gp_Trsf myTransf;
-                Standard_Boolean identity = true;
-                if (!aLoc.IsIdentity()) {
-                    identity = false;
-                    myTransf = aLoc.Transformation();
-                }
-
-                // getting size of node and triangle array of this face
-                int nbNodesInFace = mesh->NbNodes();
-                int nbTriInFace   = mesh->NbTriangles();
-                // check orientation
-                TopAbs_Orientation orient = actFace.Orientation();
-
-                // cycling through the poly mesh
-                const Poly_Array1OfTriangle& Triangles = mesh->Triangles();
-                const TColgp_Array1OfPnt& Nodes = mesh->Nodes();
-                for (int g=1; g <= nbTriInFace; g++) {
-                    // Get the triangle
-                    Standard_Integer N1,N2,N3;
-                    Triangles(g).Get(N1,N2,N3);
-
-                    // change orientation of the triangle if the face is reversed
-                    if ( orient != TopAbs_FORWARD ) {
-                        Standard_Integer tmp = N1;
-                        N1 = N2;
-                        N2 = tmp;
-                    }
-
-                    // get the 3 points of this triangle
-                    gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3));
-
-                    // transform the vertices to the place of the face
-                    if (!identity) {
-                        V1.Transform(myTransf);
-                        V2.Transform(myTransf);
-                        V3.Transform(myTransf);
-                    }
-
-                    // calculating per vertex normals
-                    // Calculate triangle normal
-                    gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
-                    gp_Vec Normal = (v2-v1)^(v3-v1);
-
-                    // add the triangle normal to the vertex normal for all points of this triangle
-                    norms[FaceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
-                    norms[FaceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
-                    norms[FaceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z());
-
-                    // set the vertices
-                    verts[FaceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z()));
-                    verts[FaceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z()));
-                    verts[FaceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z()));
-
-                    // set the index vector with the 3 point indexes and the end delimiter
-                    index[FaceTriaOffset*4+4*(g-1)]   = FaceNodeOffset+N1-1;
-                    index[FaceTriaOffset*4+4*(g-1)+1] = FaceNodeOffset+N2-1;
-                    index[FaceTriaOffset*4+4*(g-1)+2] = FaceNodeOffset+N3-1;
-                    index[FaceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX;
-                }
-
-                // counting up the per Face offsets
-                FaceNodeOffset += nbNodesInFace;
-                FaceTriaOffset += nbTriInFace;
-
-
-                // normalize all normals
-                for (int i=0; i < nbrNodes; i++)
-                    norms[i].normalize();
-
-                // end the editing of the nodes
-                rejectedCoords  ->point      .finishEditing();
-                rejectedNorms   ->vector     .finishEditing();
-                rejectedFaceSet ->coordIndex .finishEditing();
-
-                // fill in the transformation matrices
-                SoMultipleCopy* rejectedTrfms = new SoMultipleCopy();
-
-
-                rejectedTrfms->matrix.finishEditing();
-                rejectedTrfms->addChild(rejectedFaceSet);
-                SoSeparator* sep = new SoSeparator();
-                sep->addChild(rejectedCoords);
-                sep->addChild(rejectedNorms);
-                sep->addChild(rejectedTrfms);
-                pcRejectedRoot->addChild(sep);
-            }
-        }
-        catch (...) {
-            Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
-                                    pcTransformed->getNameInDocument());
-        }
+        showRejectedShape(cShape);
     }
 }
 
+void ViewProviderTransformed::showRejectedShape(TopoDS_Shape shape)
+{
+    try {
+        // calculating the deflection value
+        Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
+        {
+            Bnd_Box bounds;
+            BRepBndLib::Add(shape, bounds);
+            bounds.SetGap(0.0);
+            bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
+        }
+        Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue();
+
+        // create or use the mesh on the data structure
+        // Note: This DOES have an effect on shape
+#if OCC_VERSION_HEX >= 0x060600
+        Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI;
+        BRepMesh_IncrementalMesh(shape, deflection, Standard_False, AngDeflectionRads, Standard_True);
+#else
+        BRepMesh_IncrementalMesh(shape, deflection);
+#endif
+        // We must reset the location here because the transformation data
+        // are set in the placement property
+        TopLoc_Location aLoc;
+        shape.Location(aLoc);
+
+        // count triangles and nodes in the mesh
+        int nbrTriangles=0, nbrNodes=0;
+        TopExp_Explorer Ex;
+        for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
+            Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc);
+            // Note: we must also count empty faces
+            if (!mesh.IsNull()) {
+                nbrTriangles += mesh->NbTriangles();
+                nbrNodes     += mesh->NbNodes();
+            }
+        }
+
+        // create memory for the nodes and indexes
+        SoCoordinate3* rejectedCoords = new SoCoordinate3();
+        rejectedCoords  ->point      .setNum(nbrNodes);
+        SoNormal* rejectedNorms = new SoNormal();
+        rejectedNorms   ->vector     .setNum(nbrNodes);
+        SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet();
+        rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4);
+
+        // get the raw memory for fast fill up
+        SbVec3f* verts = rejectedCoords  ->point      .startEditing();
+        SbVec3f* norms = rejectedNorms   ->vector     .startEditing();
+        int32_t* index = rejectedFaceSet ->coordIndex .startEditing();
+
+        // preset the normal vector with null vector
+        for (int i=0; i < nbrNodes; i++)
+            norms[i]= SbVec3f(0.0,0.0,0.0);
+
+        int FaceNodeOffset=0,FaceTriaOffset=0;
+        for (Ex.Init(shape, TopAbs_FACE); Ex.More(); Ex.Next()) {
+            const TopoDS_Face &actFace = TopoDS::Face(Ex.Current());
+
+            // get triangulation
+            std::vector points;
+            std::vector facets;
+            if (!Part::Tools::getTriangulation(actFace, points, facets))
+                continue;
+
+            // get normal per vertex
+            std::vector vertexnormals;
+            Part::Tools::getPointNormals(points, facets, vertexnormals);
+
+            // getting size of node and triangle array of this face
+            std::size_t nbNodesInFace = points.size();
+            std::size_t nbTriInFace   = facets.size();
+
+            for (std::size_t i = 0; i < points.size(); i++) {
+                verts[FaceNodeOffset+i] = SbVec3f(points[i].X(), points[i].Y(), points[i].Z());
+            }
+
+            for (std::size_t i = 0; i < vertexnormals.size(); i++) {
+                norms[FaceNodeOffset+i] = SbVec3f(vertexnormals[i].X(), vertexnormals[i].Y(), vertexnormals[i].Z());
+            }
+
+            // cycling through the poly mesh
+            for (std::size_t g=0; g < nbTriInFace; g++) {
+                // Get the triangle
+                Standard_Integer N1,N2,N3;
+                facets[g].Get(N1,N2,N3);
+
+                // set the index vector with the 3 point indexes and the end delimiter
+                index[FaceTriaOffset*4+4*g]   = FaceNodeOffset+N1;
+                index[FaceTriaOffset*4+4*g+1] = FaceNodeOffset+N2;
+                index[FaceTriaOffset*4+4*g+2] = FaceNodeOffset+N3;
+                index[FaceTriaOffset*4+4*g+3] = SO_END_FACE_INDEX;
+            }
+
+            // counting up the per Face offsets
+            FaceNodeOffset += nbNodesInFace;
+            FaceTriaOffset += nbTriInFace;
+
+            // normalize all normals
+            for (int i=0; i < nbrNodes; i++)
+                norms[i].normalize();
+
+            // end the editing of the nodes
+            rejectedCoords  ->point      .finishEditing();
+            rejectedNorms   ->vector     .finishEditing();
+            rejectedFaceSet ->coordIndex .finishEditing();
+
+            // fill in the transformation matrices
+            SoMultipleCopy* rejectedTrfms = new SoMultipleCopy();
+            rejectedTrfms->matrix.finishEditing();
+            rejectedTrfms->addChild(rejectedFaceSet);
+            SoSeparator* sep = new SoSeparator();
+            sep->addChild(rejectedCoords);
+            sep->addChild(rejectedNorms);
+            sep->addChild(rejectedTrfms);
+            pcRejectedRoot->addChild(sep);
+        }
+    }
+    catch (...) {
+        Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n",
+                              getObject()->getNameInDocument());
+    }
+}
diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h
index 50a72ca1ae..ec4b8e1226 100644
--- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h
+++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h
@@ -68,6 +68,9 @@ protected:
 public:
     void recomputeFeature(bool recompute=true);
     QString getMessage() const {return diagMessage;}
+
+private:
+    void showRejectedShape(TopoDS_Shape shape);
 };
 
 
diff --git a/src/Mod/Path/App/AppPathPy.cpp b/src/Mod/Path/App/AppPathPy.cpp
index 6e0c72d2f5..ce912b4474 100644
--- a/src/Mod/Path/App/AppPathPy.cpp
+++ b/src/Mod/Path/App/AppPathPy.cpp
@@ -49,10 +49,7 @@
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
-#include 
+#include 
 
 #include "CommandPy.h"
 #include "PathPy.h"
diff --git a/src/Mod/Points/Gui/Command.cpp b/src/Mod/Points/Gui/Command.cpp
index b3fa151137..9069c9d075 100644
--- a/src/Mod/Points/Gui/Command.cpp
+++ b/src/Mod/Points/Gui/Command.cpp
@@ -33,6 +33,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -197,10 +198,16 @@ CmdPointsConvert::CmdPointsConvert()
 void CmdPointsConvert::activated(int iMsg)
 {
     Q_UNUSED(iMsg);
+    double STD_OCC_TOLERANCE = 1e-6;
+
+    int decimals = Base::UnitsApi::getDecimals();
+    double tolerance_from_decimals = pow(10., -decimals);
+
+    double minimal_tolerance = tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals;
 
     bool ok;
     double tol = QInputDialog::getDouble(Gui::getMainWindow(), QObject::tr("Distance"),
-        QObject::tr("Enter maximum distance:"), 0.1, 0.05, 10.0, 2, &ok, Qt::MSWindowsFixedSizeDialogHint);
+        QObject::tr("Enter maximum distance:"), 0.1, minimal_tolerance, 10.0, decimals, &ok, Qt::MSWindowsFixedSizeDialogHint);
     if (!ok)
         return;
 
diff --git a/src/Mod/Raytracing/App/LuxTools.cpp b/src/Mod/Raytracing/App/LuxTools.cpp
index 881317f137..86db2ee16f 100644
--- a/src/Mod/Raytracing/App/LuxTools.cpp
+++ b/src/Mod/Raytracing/App/LuxTools.cpp
@@ -44,6 +44,7 @@
 
 #include "PovTools.h"
 #include "LuxTools.h"
+#include 
 
 using Base::Console;
 
@@ -95,35 +96,34 @@ void LuxTools::writeShape(std::ostream &out, const char *PartName, const TopoDS_
         // get the shape and mesh it
         const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
 
-        // this block mesh the face and transfers it in a C array of vertices and face indexes
-        Standard_Integer nbNodesInFace,nbTriInFace;
-        gp_Vec* vertices=0;
-        gp_Vec* vertexnormals=0;
-        long* cons=0;
+        std::vector points;
+        std::vector vertexnormals;
+        std::vector facets;
+        if (!Part::Tools::getTriangulation(aFace, points, facets)) {
+            break;
+        }
 
-        PovTools::transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
+        Part::Tools::getPointNormals(points, facets, vertexnormals);
+        Part::Tools::getPointNormals(points, aFace, vertexnormals);
 
-        if (!vertices) break;
         // writing vertices
-        for (int i=0; i < nbNodesInFace; i++) {
-            P << vertices[i].X() << " " << vertices[i].Y() << " " << vertices[i].Z() << " ";
+        for (std::size_t i=0; i < points.size(); i++) {
+            P << points[i].X() << " " << points[i].Y() << " " << points[i].Z() << " ";
         }
 
         // writing per vertex normals
-        for (int j=0; j < nbNodesInFace; j++) {
+        for (std::size_t j=0; j < vertexnormals.size(); j++) {
             N << vertexnormals[j].X() << " "  << vertexnormals[j].Y() << " " << vertexnormals[j].Z() << " ";
         }
 
         // writing triangle indices
-        for (int k=0; k < nbTriInFace; k++) {
-            triindices << cons[3*k]+vi << " " << cons[3*k+2]+vi << " " << cons[3*k+1]+vi << " ";
+        for (std::size_t k=0; k < facets.size(); k++) {
+            Standard_Integer n1, n2, n3;
+            facets[k].Get(n1, n2, n3);
+            triindices << n1 + vi << " " << n3 + vi << " " << n2 + vi << " ";
         }
         
-        vi = vi + nbNodesInFace;
-        
-        delete [] vertexnormals;
-        delete [] vertices;
-        delete [] cons;
+        vi = vi + points.size();
 
         seq.next();
 
diff --git a/src/Mod/Raytracing/App/PovTools.cpp b/src/Mod/Raytracing/App/PovTools.cpp
index 1402a68530..049308c8b9 100644
--- a/src/Mod/Raytracing/App/PovTools.cpp
+++ b/src/Mod/Raytracing/App/PovTools.cpp
@@ -41,6 +41,7 @@
 
 
 #include "PovTools.h"
+#include 
 
 using Base::Console;
 
@@ -158,7 +159,7 @@ void PovTools::writeData(const char *FileName, const char *PartName,
         std::vector normals;
         std::vector facets;
         Data::Segment* segm = data->getSubElement("Face", i);
-        data->getFacesFromSubelement(segm, points, normals, facets);
+        data->getFacesFromSubElement(segm, points, normals, facets);
         delete segm;
 
         // writing per face header
@@ -242,53 +243,53 @@ void PovTools::writeShape(std::ostream &out, const char *PartName,
         // get the shape and mesh it
         const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
 
-        // this block mesh the face and transfers it in a C array of vertices and face indexes
-        Standard_Integer nbNodesInFace,nbTriInFace;
-        gp_Vec* vertices=0;
-        gp_Vec* vertexnormals=0;
-        long* cons=0;
+        std::vector points;
+        std::vector vertexnormals;
+        std::vector facets;
+        if (!Part::Tools::getTriangulation(aFace, points, facets)) {
+            break;
+        }
+        Part::Tools::getPointNormals(points, facets, vertexnormals);
+        Part::Tools::getPointNormals(points, aFace, vertexnormals);
 
-        transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
-
-        if (!vertices) break;
         // writing per face header
         out << "// face number" << l << " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
         << "#declare " << PartName << l << " = mesh2{" << endl
         << "  vertex_vectors {" << endl
-        << "    " << nbNodesInFace << "," << endl;
+        << "    " << points.size() << "," << endl;
         // writing vertices
-        for (int i=0; i < nbNodesInFace; i++) {
-            out << "    <" << vertices[i].X() << ","
-            << vertices[i].Z() << ","
-            << vertices[i].Y() << ">,"
-            << endl;
+        for (std::size_t i=0; i < points.size(); i++) {
+            out << "    <"
+                << points[i].X() << ","
+                << points[i].Z() << ","
+                << points[i].Y() << ">,"
+                << endl;
         }
         out << "  }" << endl
         // writing per vertex normals
         << "  normal_vectors {" << endl
-        << "    " << nbNodesInFace << "," << endl;
-        for (int j=0; j < nbNodesInFace; j++) {
-            out << "    <" << vertexnormals[j].X() << ","
-            << vertexnormals[j].Z() << ","
-            << vertexnormals[j].Y() << ">,"
-            << endl;
+        << "    " << vertexnormals.size() << "," << endl;
+        for (std::size_t j=0; j < vertexnormals.size(); j++) {
+            out << "    <"
+                << vertexnormals[j].X() << ","
+                << vertexnormals[j].Z() << ","
+                << vertexnormals[j].Y() << ">,"
+                << endl;
         }
 
         out << "  }" << endl
         // writing triangle indices
         << "  face_indices {" << endl
-        << "    " << nbTriInFace << "," << endl;
-        for (int k=0; k < nbTriInFace; k++) {
-            out << "    <" << cons[3*k] << ","<< cons[3*k+2] << ","<< cons[3*k+1] << ">," << endl;
+        << "    " << facets.size() << "," << endl;
+        for (std::size_t k=0; k < facets.size(); k++) {
+            Standard_Integer n1, n2, n3;
+            facets[k].Get(n1, n2, n3);
+            out << "    <" << n1 << ","<< n3 << "," << n2 << ">," << endl;
         }
         // end of face
         out << "  }" << endl
         << "} // end of Face"<< l << endl << endl;
 
-        delete [] vertexnormals;
-        delete [] vertices;
-        delete [] cons;
-
         seq.next();
 
     } // end of face loop
@@ -323,36 +324,32 @@ void PovTools::writeShapeCSV(const char *FileName,
     Base::SequencerLauncher seq("Writing file", l);
 
     // write the file
-    l = 1;
-    for (ex.Init(Shape, TopAbs_FACE); ex.More(); ex.Next(),l++) {
+    for (ex.Init(Shape, TopAbs_FACE); ex.More(); ex.Next()) {
 
         // get the shape and mesh it
         const TopoDS_Face& aFace = TopoDS::Face(ex.Current());
 
-        // this block mesh the face and transfers it in a C array of vertices and face indexes
-        Standard_Integer nbNodesInFace,nbTriInFace;
-        gp_Vec* vertices=0;
-        gp_Vec* vertexnormals=0;
-        long* cons=0;
-
-        transferToArray(aFace,&vertices,&vertexnormals,&cons,nbNodesInFace,nbTriInFace);
-
-        if (!vertices) break;
-        // writing per face header
-        // writing vertices
-        for (int i=0; i < nbNodesInFace; i++) {
-            fout << vertices[i].X() << cSeperator
-            << vertices[i].Z() << cSeperator
-            << vertices[i].Y() << cSeperator
-            << vertexnormals[i].X() * fLength < points;
+        std::vector vertexnormals;
+        std::vector facets;
+        if (!Part::Tools::getTriangulation(aFace, points, facets)) {
+            break;
         }
 
-        delete [] vertexnormals;
-        delete [] vertices;
-        delete [] cons;
+        Part::Tools::getPointNormals(points, facets, vertexnormals);
+        Part::Tools::getPointNormals(points, aFace, vertexnormals);
+
+        // writing per face header
+        // writing vertices
+        for (std::size_t i=0; i < points.size(); i++) {
+            fout << points[i].X() << cSeperator
+                 << points[i].Z() << cSeperator
+                 << points[i].Y() << cSeperator
+                 << vertexnormals[i].X() * fLength << cSeperator
+                 << vertexnormals[i].Z() * fLength << cSeperator
+                 << vertexnormals[i].Y() * fLength << cSeperator
+                 << endl;
+        }
 
         seq.next();
 
@@ -360,130 +357,3 @@ void PovTools::writeShapeCSV(const char *FileName,
 
     fout.close();
 }
-
-void PovTools::transferToArray(const TopoDS_Face& aFace,gp_Vec** vertices,gp_Vec** vertexnormals, long** cons,int &nbNodesInFace,int &nbTriInFace )
-{
-    TopLoc_Location aLoc;
-
-    // doing the meshing and checking the result
-    //BRepMesh_IncrementalMesh MESH(aFace,fDeflection);
-    Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
-    if (aPoly.IsNull()) {
-        Base::Console().Log("Empty face triangulation\n");
-        nbNodesInFace =0;
-        nbTriInFace = 0;
-        vertices = 0l;
-        cons = 0l;
-        return;
-    }
-
-    // getting the transformation of the shape/face
-    gp_Trsf myTransf;
-    Standard_Boolean identity = true;
-    if (!aLoc.IsIdentity())  {
-        identity = false;
-        myTransf = aLoc.Transformation();
-    }
-
-    Standard_Integer i;
-    // getting size and create the array
-    nbNodesInFace = aPoly->NbNodes();
-    nbTriInFace = aPoly->NbTriangles();
-    *vertices = new gp_Vec[nbNodesInFace];
-    *vertexnormals = new gp_Vec[nbNodesInFace];
-    for (i=0; i < nbNodesInFace; i++) {
-        (*vertexnormals)[i]= gp_Vec(0.0,0.0,0.0);
-    }
-
-    *cons = new long[3*(nbTriInFace)+1];
-
-    // check orientation
-    TopAbs_Orientation orient = aFace.Orientation();
-
-    // cycling through the poly mesh
-    const Poly_Array1OfTriangle& Triangles = aPoly->Triangles();
-    const TColgp_Array1OfPnt& Nodes = aPoly->Nodes();
-    for (i=1; i<=nbTriInFace; i++) {
-        // Get the triangle
-        Standard_Integer N1,N2,N3;
-        Triangles(i).Get(N1,N2,N3);
-
-        // change orientation of the triangles
-        if ( orient != TopAbs_FORWARD )
-        {
-            Standard_Integer tmp = N1;
-            N1 = N2;
-            N2 = tmp;
-        }
-
-        gp_Pnt V1 = Nodes(N1);
-        gp_Pnt V2 = Nodes(N2);
-        gp_Pnt V3 = Nodes(N3);
-
-        // transform the vertices to the place of the face
-        if (!identity) {
-            V1.Transform(myTransf);
-            V2.Transform(myTransf);
-            V3.Transform(myTransf);
-        }
-
-        // Calculate triangle normal
-        gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z());
-        gp_Vec Normal = (v2-v1)^(v3-v1);
-
-        //Standard_Real Area = 0.5 * Normal.Magnitude();
-
-        // add the triangle normal to the vertex normal for all points of this triangle
-        (*vertexnormals)[N1-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
-        (*vertexnormals)[N2-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
-        (*vertexnormals)[N3-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z());
-
-        (*vertices)[N1-1].SetX((float)(V1.X()));
-        (*vertices)[N1-1].SetY((float)(V1.Y()));
-        (*vertices)[N1-1].SetZ((float)(V1.Z()));
-        (*vertices)[N2-1].SetX((float)(V2.X()));
-        (*vertices)[N2-1].SetY((float)(V2.Y()));
-        (*vertices)[N2-1].SetZ((float)(V2.Z()));
-        (*vertices)[N3-1].SetX((float)(V3.X()));
-        (*vertices)[N3-1].SetY((float)(V3.Y()));
-        (*vertices)[N3-1].SetZ((float)(V3.Z()));
-
-        int j = i - 1;
-        N1--;
-        N2--;
-        N3--;
-        (*cons)[3*j] = N1;
-        (*cons)[3*j+1] = N2;
-        (*cons)[3*j+2] = N3;
-    }
-
-    // normalize all vertex normals
-    for (i=0; i < nbNodesInFace; i++) {
-
-        gp_Dir clNormal;
-
-        try {
-            Handle(Geom_Surface) Surface = BRep_Tool::Surface(aFace);
-
-            gp_Pnt vertex((*vertices)[i].XYZ());
-//     gp_Pnt vertex((*vertices)[i][0], (*vertices)[i][1], (*vertices)[i][2]);
-            GeomAPI_ProjectPointOnSurf ProPntSrf(vertex, Surface);
-            Standard_Real fU, fV;
-            ProPntSrf.Parameters(1, fU, fV);
-
-            GeomLProp_SLProps clPropOfFace(Surface, fU, fV, 2, gp::Resolution());
-
-            clNormal = clPropOfFace.Normal();
-            gp_Vec temp = clNormal;
-            //Base::Console().Log("unterschied:%.2f",temp.dot((*vertexnormals)[i]));
-            if ( temp * (*vertexnormals)[i] < 0 )
-                temp = -temp;
-            (*vertexnormals)[i] = temp;
-
-        }
-        catch (...) {
-        }
-
-        (*vertexnormals)[i].Normalize();
-    }
-}
diff --git a/src/Mod/Raytracing/App/PovTools.h b/src/Mod/Raytracing/App/PovTools.h
index d499e003a0..09088c5755 100644
--- a/src/Mod/Raytracing/App/PovTools.h
+++ b/src/Mod/Raytracing/App/PovTools.h
@@ -110,9 +110,6 @@ public:
                               const TopoDS_Shape& Shape,
                               float fMeshDeviation,
                               float fLength);
-
-
-    static void transferToArray(const TopoDS_Face& aFace,gp_Vec** vertices,gp_Vec** vertexnormals, long** cons,int &nbNodesInFace,int &nbTriInFace );
 };
 
 
diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt
index 2be18fd827..317d91c208 100644
--- a/src/Mod/Sketcher/Gui/CMakeLists.txt
+++ b/src/Mod/Sketcher/Gui/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SketcherGui_UIC_SRCS
     SketchRectangularArrayDialog.ui
     SketcherRegularPolygonDialog.ui
     ConstraintMultiFilterDialog.ui
+    ConstraintSettingsDialog.ui
 )
 
 if(BUILD_QT5)
@@ -120,6 +121,8 @@ SET(SketcherGui_SRCS
     SketcherRegularPolygonDialog.cpp
     ConstraintMultiFilterDialog.h
     ConstraintMultiFilterDialog.cpp
+    ConstraintSettingsDialog.h
+    ConstraintSettingsDialog.cpp
     TaskDlgEditSketch.cpp
     TaskDlgEditSketch.h
     ViewProviderPython.cpp
diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
index beac215516..d0db2dfb97 100644
--- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
+++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp
@@ -337,6 +337,7 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
 
     getSelection().clearSelection();
 
+    std::vector constraintSubNames;
     // go through the selected subelements
     for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
         // only handle edges
@@ -349,13 +350,15 @@ void CmdSketcherSelectConstraints::activated(int iMsg)
                  it != vals.end(); ++it,++i)
             {
                 if ((*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId) {
-                    Gui::Selection().addSelection(doc_name.c_str(),
-                                                  obj_name.c_str(),
-                                                  Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
+                    constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
                 }
             }
         }
     }
+
+    if(!constraintSubNames.empty())
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
+
 }
 
 bool CmdSketcherSelectConstraints::isActive(void)
@@ -533,17 +536,20 @@ void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
     getSelection().clearSelection();
 
     // push the constraints
+    std::vector constraintSubNames;
+
     int i = 0;
     for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
         for(std::vector< int >::const_iterator itc= solverredundant.begin();itc != solverredundant.end(); ++itc) {
             if ((*itc) - 1 == i) {
-                Gui::Selection().addSelection(doc_name.c_str(),
-                                              obj_name.c_str(),
-                                              Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
+                constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
                 break;
             }
         }
     }
+
+    if(!constraintSubNames.empty())
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
 }
 
 bool CmdSketcherSelectRedundantConstraints::isActive(void)
@@ -587,17 +593,19 @@ void CmdSketcherSelectMalformedConstraints::activated(int iMsg)
     getSelection().clearSelection();
 
     // push the constraints
+    std::vector constraintSubNames;
     int i = 0;
     for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
         for(std::vector< int >::const_iterator itc= solvermalformed.begin();itc != solvermalformed.end(); ++itc) {
             if ((*itc) - 1 == i) {
-                Gui::Selection().addSelection(doc_name.c_str(),
-                                              obj_name.c_str(),
-                                              Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
+                constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
                 break;
             }
         }
     }
+
+    if(!constraintSubNames.empty())
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
 }
 
 bool CmdSketcherSelectMalformedConstraints::isActive(void)
@@ -641,17 +649,19 @@ void CmdSketcherSelectPartiallyRedundantConstraints::activated(int iMsg)
     getSelection().clearSelection();
 
     // push the constraints
+    std::vector constraintSubNames;
     int i = 0;
     for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
         for(std::vector< int >::const_iterator itc= solverpartiallyredundant.begin();itc != solverpartiallyredundant.end(); ++itc) {
             if ((*itc) - 1 == i) {
-                Gui::Selection().addSelection(doc_name.c_str(),
-                                              obj_name.c_str(),
-                                              Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
+                constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
                 break;
             }
         }
     }
+
+    if(!constraintSubNames.empty())
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
 }
 
 bool CmdSketcherSelectPartiallyRedundantConstraints::isActive(void)
@@ -693,17 +703,19 @@ void CmdSketcherSelectConflictingConstraints::activated(int iMsg)
     getSelection().clearSelection();
 
     // push the constraints
+    std::vector constraintSubNames;
     int i = 0;
     for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) {
         for (std::vector< int >::const_iterator itc= solverconflicting.begin();itc != solverconflicting.end(); ++itc) {
             if ((*itc) - 1 == i) {
-                Gui::Selection().addSelection(doc_name.c_str(),
-                                              obj_name.c_str(),
-                                              Sketcher::PropertyConstraintList::getConstraintName(i).c_str());
+                constraintSubNames.push_back(Sketcher::PropertyConstraintList::getConstraintName(i));
                 break;
             }
         }
     }
+
+    if(!constraintSubNames.empty())
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
 }
 
 bool CmdSketcherSelectConflictingConstraints::isActive(void)
@@ -747,8 +759,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
     std::string obj_name = Obj->getNameInDocument();
     std::stringstream ss;
 
-    int selected = 0;
-
+    std::vector elementSubNames;
     // go through the selected subelements
     for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
         // only handle constraints
@@ -772,9 +783,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
                                 ss << "Vertex" <<  vertex + 1;
                             break;
                     }
-
-                    Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
-                    selected++;
+                    elementSubNames.push_back(ss.str());
                 }
 
                 if(vals[ConstrId]->Second!=Constraint::GeoUndef){
@@ -794,8 +803,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
                             break;
                     }
 
-                    Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
-                    selected++;
+                    elementSubNames.push_back(ss.str());
                 }
 
                 if(vals[ConstrId]->Third!=Constraint::GeoUndef){
@@ -815,17 +823,20 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
                             break;
                     }
 
-                    Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
-                    selected++;
+                    elementSubNames.push_back(ss.str());
                 }
             }
         }
     }
 
-    if (selected == 0) {
+    if (elementSubNames.empty()) {
         QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No constraint selected"),
                              QObject::tr("At least one constraint must be selected"));
     }
+    else {
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
+    }
+
 }
 
 bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void)
@@ -866,22 +877,24 @@ void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
 
     auto geos = Obj->getInternalGeometry();
 
-    auto testselectvertex = [&Obj, &ss, &doc_name, &obj_name](int geoId, PointPos pos) {
+    std::vector elementSubNames;
+
+    auto testselectvertex = [&Obj, &ss, &elementSubNames](int geoId, PointPos pos) {
         ss.str(std::string());
 
         int vertex = Obj->getVertexIndexGeoPos(geoId, pos);
         if (vertex > -1) {
             ss << "Vertex" <<  vertex + 1;
 
-            Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+            elementSubNames.push_back(ss.str());
         }
     };
 
-    auto testselectedge = [&ss, &doc_name, &obj_name](int geoId) {
+    auto testselectedge = [&ss, &elementSubNames](int geoId) {
         ss.str(std::string());
 
         ss << "Edge" <<  geoId + 1;
-        Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
+        elementSubNames.push_back(ss.str());
     };
 
     int geoid = 0;
@@ -911,6 +924,10 @@ void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
         geoid++;
     }
 
+    if (!elementSubNames.empty()) {
+        Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
+    }
+
 }
 
 bool CmdSketcherSelectElementsWithDoFs::isActive(void)
diff --git a/src/Mod/Sketcher/Gui/ConstraintFilters.h b/src/Mod/Sketcher/Gui/ConstraintFilters.h
index 5517592305..68370e2c71 100644
--- a/src/Mod/Sketcher/Gui/ConstraintFilters.h
+++ b/src/Mod/Sketcher/Gui/ConstraintFilters.h
@@ -36,19 +36,19 @@ namespace ConstraintFilter {
         Datums = 2,
         Named = 3,
         NonDriving = 4,
-        Horizontal = 5,
-        Vertical = 6,
-        Coincident = 7,
-        PointOnObject = 8,
+        Coincident = 5,
+        PointOnObject = 6,
+        Vertical = 7,
+        Horizontal = 8,
         Parallel = 9,
         Perpendicular = 10,
         Tangent = 11,
         Equality = 12,
         Symmetric = 13,
         Block = 14,
-        Distance = 15,
-        HorizontalDistance = 16,
-        VerticalDistance = 17,
+        HorizontalDistance = 15,
+        VerticalDistance = 16,
+        Distance = 17,
         Radius = 18,
         Weight = 19,
         Diameter = 20,
@@ -60,6 +60,8 @@ namespace ConstraintFilter {
 
     enum SpecialFilterValue {
         Multiple = 24,
+        Selection = 25,
+        AssociatedConstraints = 26,
         NumSpecialFilterValue
     };
 
@@ -73,22 +75,22 @@ namespace ConstraintFilter {
         1 << FilterValue::Geometric | 1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident |
         1 << FilterValue::PointOnObject | 1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent |
         1 << FilterValue::Equality | 1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::InternalAlignment, // Geometric = All others not being datums (1)
-        1 << FilterValue::Datums | 1 << FilterValue::NonDriving | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2)
+        1 << FilterValue::Datums | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2)
         1 << FilterValue::Named, // Named = Just this (3)
         1 << FilterValue::NonDriving, // NonDriving = Just this (4)
-        1 << FilterValue::Horizontal, // Horizontal = Just this (5)
-        1 << FilterValue::Vertical, // Vertical = Just this (6)
-        1 << FilterValue::Coincident, // Coincident = Just this (7)
-        1 << FilterValue::PointOnObject, // PointOnObject = Just this (8)
+        1 << FilterValue::Coincident, // Coincident = Just this (5)
+        1 << FilterValue::PointOnObject, // PointOnObject = Just this (6)
+        1 << FilterValue::Vertical, // Vertical = Just this (7)
+        1 << FilterValue::Horizontal, // Horizontal = Just this (8)
         1 << FilterValue::Parallel, // Parallel = Just this (9)
         1 << FilterValue::Perpendicular, // Perpendicular = Just this (10)
         1 << FilterValue::Tangent, // Tangent = Just this (11)
         1 << FilterValue::Equality, // Equality = Just this (12)
         1 << FilterValue::Symmetric, // Symmetric = Just this (13)
         1 << FilterValue::Block, // Block = Just this (14)
-        1 << FilterValue::Distance, // Distance = Just this (15)
-        1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (16)
-        1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (17)
+        1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (15)
+        1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (16)
+        1 << FilterValue::Distance, // Distance = Just this (17)
         1 << FilterValue::Radius, // Radius = Just this (18)
         1 << FilterValue::Weight, // Weight = Just this (19)
         1 << FilterValue::Diameter, // Diameter = Just this (20)
diff --git a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp
index 22e74bc5b8..88beca930f 100644
--- a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp
+++ b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.cpp
@@ -93,15 +93,43 @@ void ConstraintMultiFilterDialog::on_listMultiFilter_itemChanged(QListWidgetItem
 {
     int filterindex = ui->listMultiFilter->row(item);
 
-    auto aggregate = filterAggregates[filterindex];
+    auto itemAggregate = filterAggregates[filterindex];
 
     ui->listMultiFilter->blockSignals(true);
-    if(item->checkState() == Qt::Checked) {
-        for(int i = 0; i < ui->listMultiFilter->count(); i++) {
-            if(aggregate[i])
-                ui->listMultiFilter->item(i)->setCheckState(Qt::Checked);
+
+    for(int i = 0; i < ui->listMultiFilter->count(); i++) {
+        // any filter comprised on the filter of the activated item, gets the same check state
+        if(itemAggregate[i])
+            ui->listMultiFilter->item(i)->setCheckState(item->checkState());
+
+        // if unchecking, in addition uncheck any group comprising the unchecked item
+        if(item->checkState() == Qt::Unchecked) {
+            if(filterAggregates[i][filterindex])
+                 ui->listMultiFilter->item(i)->setCheckState(Qt::Unchecked);
         }
     }
+
+    // Now that all filters are correctly updated to match dependencies,
+    // if checking, in addition check any group comprising all items that are checked, and check it if all checked.
+    if(item->checkState() == Qt::Checked) {
+        for(int i = 0; i < ui->listMultiFilter->count(); i++) {
+            if(filterAggregates[i][filterindex]) { // only for groups comprising the changed filter
+                bool mustBeChecked = true;
+
+                for(int j = 0; j < FilterValue::NumFilterValue; j++) {
+                    if (i == j)
+                        continue;
+
+                    if (filterAggregates[i][j]) // if it is in group
+                        mustBeChecked = mustBeChecked && ui->listMultiFilter->item(j)->checkState() == Qt::Checked;
+                }
+
+                if(mustBeChecked)
+                    ui->listMultiFilter->item(i)->setCheckState(Qt::Checked);
+            }
+        }
+    }
+
     ui->listMultiFilter->blockSignals(false);
 }
 
diff --git a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.ui b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.ui
index 62a7396c33..80dab0c6de 100644
--- a/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.ui
+++ b/src/Mod/Sketcher/Gui/ConstraintMultiFilterDialog.ui
@@ -9,22 +9,16 @@
    
     0
     0
-    325
+    274
     600
    
   
   
-   
+   
     0
     0
    
   
-  
-   
-    16777215
-    700
-   
-  
   
    Multiple filter selection
   
@@ -39,16 +33,13 @@
    
     
      
-      
+      
        0
        0
       
      
-     
-      
-       0
-       500
-      
+     
+      QAbstractScrollArea::AdjustToContents
      
      
       QAbstractItemView::NoSelection
@@ -78,17 +69,7 @@
      
      
       
-       Non-Driving
-      
-     
-     
-      
-       Horizontal
-      
-     
-     
-      
-       Vertical
+       Reference
       
      
      
@@ -101,6 +82,16 @@
        Point on Object
       
      
+     
+      
+       Vertical
+      
+     
+     
+      
+       Horizontal
+      
+     
      
       
        Parallel
@@ -131,11 +122,6 @@
        Block
       
      
-     
-      
-       Distance
-      
-     
      
       
        Horizontal Distance
@@ -146,6 +132,11 @@
        Vertical Distance
       
      
+     
+      
+       Distance
+      
+     
      
       
        Radius
@@ -217,19 +208,6 @@
      
     
    
-   
-    
-     
-      Qt::Vertical
-     
-     
-      
-       0
-       0
-      
-     
-    
-   
    
     
      
diff --git a/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.cpp b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.cpp
new file mode 100644
index 0000000000..b107047610
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+ *   Copyright (c) 2021 Abdullah Tahiri      *
+ *                                                                         *
+ *   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 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "ui_ConstraintSettingsDialog.h"
+#include "ConstraintSettingsDialog.h"
+
+using namespace SketcherGui;
+
+ConstraintSettingsDialog::ConstraintSettingsDialog(void)
+  : QDialog(Gui::getMainWindow()), ui(new Ui_ConstraintSettingsDialog)
+{
+    ui->setupUi(this);
+
+    { // in case any signal is connected before this
+        QSignalBlocker block(this);
+        loadSettings();
+        snapshotInitialSettings();
+    }
+
+    QObject::connect(
+        ui->filterInternalAlignment, SIGNAL(stateChanged(int)),
+        this                     , SLOT  (on_filterInternalAlignment_stateChanged(int))
+        );
+    QObject::connect(
+        ui->extendedInformation, SIGNAL(stateChanged(int)),
+                     this                     , SLOT  (on_extendedInformation_stateChanged(int))
+        );
+    QObject::connect(
+        ui->visualisationTrackingFilter, SIGNAL(stateChanged(int)),
+        this                     , SLOT  (on_visualisationTrackingFilter_stateChanged(int))
+        );
+}
+
+void ConstraintSettingsDialog::saveSettings()
+{
+    ui->extendedInformation->onSave();
+    ui->filterInternalAlignment->onSave();
+    ui->visualisationTrackingFilter->onSave();
+}
+
+void ConstraintSettingsDialog::loadSettings()
+{
+    ui->extendedInformation->onRestore();
+    ui->filterInternalAlignment->onRestore();
+    ui->visualisationTrackingFilter->onRestore();
+}
+
+void ConstraintSettingsDialog::snapshotInitialSettings()
+{
+    auto isChecked = [] (auto prefwidget) {return prefwidget->checkState() == Qt::Checked;};
+
+    extendedInformation = isChecked(ui->extendedInformation);
+    filterInternalAlignment = isChecked(ui->filterInternalAlignment);
+    visualisationTrackingFilter = isChecked(ui->visualisationTrackingFilter);
+}
+
+void ConstraintSettingsDialog::restoreInitialSettings()
+{
+    auto restoreCheck = [] (auto prefwidget, bool initialvalue) {
+        if( initialvalue != (prefwidget->checkState() == Qt::Checked)) // if the state really changed
+            initialvalue ? prefwidget->setCheckState(Qt::Checked) : prefwidget->setCheckState(Qt::Unchecked);
+    };
+
+    restoreCheck(ui->extendedInformation, extendedInformation);
+    restoreCheck(ui->filterInternalAlignment, filterInternalAlignment);
+    restoreCheck(ui->visualisationTrackingFilter, visualisationTrackingFilter);
+}
+
+void ConstraintSettingsDialog::accept()
+{
+    saveSettings();
+    QDialog::accept();
+}
+
+void ConstraintSettingsDialog::reject()
+{
+    restoreInitialSettings();
+    saveSettings();
+    QDialog::reject();
+}
+
+void ConstraintSettingsDialog::on_filterInternalAlignment_stateChanged(int state)
+{
+    ui->filterInternalAlignment->onSave();
+    Q_EMIT emit_filterInternalAlignment_stateChanged(state);
+}
+
+void ConstraintSettingsDialog::on_visualisationTrackingFilter_stateChanged(int state)
+{
+    ui->visualisationTrackingFilter->onSave();
+    Q_EMIT emit_visualisationTrackingFilter_stateChanged(state);
+}
+
+void ConstraintSettingsDialog::on_extendedInformation_stateChanged(int state)
+{
+    ui->extendedInformation->onSave();
+    Q_EMIT emit_extendedInformation_stateChanged(state);
+}
+
+ConstraintSettingsDialog::~ConstraintSettingsDialog()
+{
+}
+
+#include "moc_ConstraintSettingsDialog.cpp"
diff --git a/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.h b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.h
new file mode 100644
index 0000000000..e190692ddd
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *   Copyright (c) 2021 Abdullah Tahiri      *
+ *                                                                         *
+ *   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 SKETCHERGUI_ConstraintSettingsDialog_H
+#define SKETCHERGUI_ConstraintSettingsDialog_H
+
+#include 
+
+#include "ConstraintFilters.h"
+
+namespace SketcherGui {
+
+using namespace ConstraintFilter;
+
+class Ui_ConstraintSettingsDialog;
+class ConstraintSettingsDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    ConstraintSettingsDialog(void);
+    ~ConstraintSettingsDialog();
+
+Q_SIGNALS:
+    void emit_filterInternalAlignment_stateChanged(int);
+    void emit_extendedInformation_stateChanged(int);
+    void emit_visualisationTrackingFilter_stateChanged(int);
+
+public Q_SLOTS:
+    void accept();
+    void reject();
+    void on_filterInternalAlignment_stateChanged(int state);
+    void on_extendedInformation_stateChanged(int state);
+    void on_visualisationTrackingFilter_stateChanged(int state);
+
+private:
+    void saveSettings();
+    void loadSettings();
+    void snapshotInitialSettings();
+    void restoreInitialSettings();
+
+private:
+    std::unique_ptr ui;
+    bool extendedInformation;
+    bool filterInternalAlignment;
+    bool visualisationTrackingFilter;
+};
+
+}
+
+#endif // SKETCHERGUI_ConstraintSettingsDialog_H
diff --git a/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.ui b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.ui
new file mode 100644
index 0000000000..340305ed43
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/ConstraintSettingsDialog.ui
@@ -0,0 +1,195 @@
+
+
+ SketcherGui::ConstraintSettingsDialog
+ 
+  
+   Qt::WindowModal
+  
+  
+   
+    0
+    0
+    275
+    215
+   
+  
+  
+   
+    0
+    0
+   
+  
+  
+   Constraint widget settings
+  
+  
+   
+    
+     
+      
+       0
+       0
+      
+     
+     
+      List control
+     
+     
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Internal alignments will be hidden
+        
+        
+         Hide internal alignment
+        
+        
+         true
+        
+        
+         HideInternalAlignment
+        
+        
+         Mod/Sketcher
+        
+       
+      
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Extended information will be added to the list
+        
+        
+         Extended information
+        
+        
+         false
+        
+        
+         ExtendedConstraintInformation
+        
+        
+         Mod/Sketcher
+        
+       
+      
+     
+    
+   
+   
+    
+     
+      
+       0
+       0
+      
+     
+     
+      3D view control
+     
+     
+      
+       
+        
+         
+          0
+          0
+         
+        
+        
+         Constraint visualisation tracks filter selection so that filtered out constraints are hidden
+        
+        
+         Show only filtered constraints
+        
+        
+         false
+        
+        
+         VisualisationTrackingFilter
+        
+        
+         Mod/Sketcher
+        
+       
+      
+     
+    
+   
+   
+    
+     
+      Qt::Vertical
+     
+     
+      
+       20
+       0
+      
+     
+    
+   
+   
+    
+     
+      QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+     
+    
+   
+  
+ 
+ 
+  
+   Gui::PrefCheckBox
+   QCheckBox
+   
Gui/PrefWidgets.h
+
+
+ + + + buttonBox + accepted() + SketcherGui::ConstraintSettingsDialog + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + rejected() + SketcherGui::ConstraintSettingsDialog + reject() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index bd93ed58b2..eed7a6cc87 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -238,6 +238,9 @@ icons/tools/Sketcher_SelectVerticalAxis.svg icons/tools/Sketcher_Symmetry.svg + + icons/dialogs/Sketcher_Settings.svg + translations/Sketcher_af.qm translations/Sketcher_ar.qm diff --git a/src/Mod/Sketcher/Gui/Resources/icons/dialogs/Sketcher_Settings.svg b/src/Mod/Sketcher/Gui/Resources/icons/dialogs/Sketcher_Settings.svg new file mode 100644 index 0000000000..a6183e8b0a --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/dialogs/Sketcher_Settings.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Preferences System + + + preferences + settings + control panel + tweaks + system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp index 6848c25815..cd67fc5f72 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp @@ -58,6 +58,7 @@ #include #include "ConstraintMultiFilterDialog.h" +#include "ConstraintSettingsDialog.h" using namespace SketcherGui; using namespace Gui::TaskView; @@ -453,13 +454,18 @@ void ConstraintView::contextMenuEvent (QContextMenuEvent* event) // Sync the FreeCAD selection with the selection in the ConstraintView widget if (didRelease) { Gui::Selection().clearSelection(); + std::string doc_name = static_cast(item)->sketchView->getSketchObject()->getDocument()->getName(); + std::string obj_name = static_cast(item)->sketchView->getSketchObject()->getNameInDocument(); + + std::vector constraintSubNames; for (auto&& it : items) { auto ci = static_cast(it); std::string constraint_name = Sketcher::PropertyConstraintList::getConstraintName(ci->ConstraintNbr); - std::string doc_name = ci->sketchView->getSketchObject()->getDocument()->getName(); - std::string obj_name = ci->sketchView->getSketchObject()->getNameInDocument(); - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), constraint_name.c_str()); + constraintSubNames.push_back(constraint_name.c_str()); } + + if(!constraintSubNames.empty()) + Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames); } bool isQuantity = false; @@ -637,6 +643,8 @@ TaskSketcherConstrains::TaskSketcherConstrains(ViewProviderSketch *sketchView) : ui->listWidgetConstraints->setEditTriggers(QListWidget::EditKeyPressed); //QMetaObject::connectSlotsByName(this); + createVisibilityButtonActions(); + // connecting the needed signals QObject::connect( ui->comboBoxFilter, SIGNAL(currentIndexChanged(int)), @@ -666,14 +674,6 @@ TaskSketcherConstrains::TaskSketcherConstrains(ViewProviderSketch *sketchView) : ui->listWidgetConstraints, SIGNAL(onUpdateActiveStatus(QListWidgetItem *, bool)), this , SLOT (on_listWidgetConstraints_updateActiveStatus(QListWidgetItem *, bool)) ); - QObject::connect( - ui->filterInternalAlignment, SIGNAL(stateChanged(int)), - this , SLOT (on_filterInternalAlignment_stateChanged(int)) - ); - QObject::connect( - ui->extendedInformation, SIGNAL(stateChanged(int)), - this , SLOT (on_extendedInformation_stateChanged(int)) - ); QObject::connect( ui->showAllButton, SIGNAL(clicked(bool)), this , SLOT (on_showAllButton_clicked(bool)) @@ -690,23 +690,29 @@ TaskSketcherConstrains::TaskSketcherConstrains(ViewProviderSketch *sketchView) : ui->listWidgetConstraints, SIGNAL(emitShowSelection3DVisibility()), this , SLOT (on_listWidgetConstraints_emitShowSelection3DVisibility()) ); - QObject::connect( - ui->visualisationTrackingFilter, SIGNAL(stateChanged(int)), - this , SLOT (on_visualisationTrackingFilter_stateChanged(int)) - ); QObject::connect( ui->multipleFilterButton, SIGNAL(clicked(bool)), this , SLOT (on_multipleFilterButton_clicked(bool)) ); + QObject::connect( + ui->settingsDialogButton, SIGNAL(clicked(bool)), + this , SLOT (on_settingsDialogButton_clicked(bool)) + ); + QObject::connect( + ui->visibilityButton, SIGNAL(clicked(bool)), + this , SLOT (on_visibilityButton_clicked(bool)) + ); + + QObject::connect( + ui->visibilityButton->actions()[0], SIGNAL(changed()), + this , SLOT (on_visibilityButton_trackingaction_changed()) + ); connectionConstraintsChanged = sketchView->signalConstraintsChanged.connect( boost::bind(&SketcherGui::TaskSketcherConstrains::slotConstraintsChanged, this)); this->groupLayout()->addWidget(proxy); - this->ui->filterInternalAlignment->onRestore(); - this->ui->extendedInformation->onRestore(); - multiFilterStatus.set(); // Match 'All' selection, all bits set. slotConstraintsChanged(); @@ -714,24 +720,84 @@ TaskSketcherConstrains::TaskSketcherConstrains(ViewProviderSketch *sketchView) : TaskSketcherConstrains::~TaskSketcherConstrains() { - this->ui->filterInternalAlignment->onSave(); - this->ui->extendedInformation->onSave(); connectionConstraintsChanged.disconnect(); } -void TaskSketcherConstrains::updateMultiFilter() + +void TaskSketcherConstrains::createVisibilityButtonActions() { - int filterindex = ui->comboBoxFilter->currentIndex(); + QAction* action = new QAction(QString::fromLatin1("Show only filtered Constraints"),this); - multiFilterStatus.reset(); + action->setCheckable(true); - multiFilterStatus.set(filterindex); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool visibilityTracksFilter = hGrp->GetBool("VisualisationTrackingFilter",false); + + { + QSignalBlocker block(this); + action->setChecked(visibilityTracksFilter); + } + + ui->visibilityButton->addAction(action); +} + +void TaskSketcherConstrains::updateSelectionFilter() +{ + // Snapshot current selection + auto items = ui->listWidgetConstraints->selectedItems(); + + selectionFilter.clear(); + + for(const auto & item : items) + selectionFilter.push_back(static_cast(item)->ConstraintNbr); +} + +void TaskSketcherConstrains::updateAssociatedConstraintsFilter() +{ + associatedConstraintsFilter.clear(); + + assert(sketchView); + + std::vector selection; + selection = Gui::Selection().getSelectionEx(0, Sketcher::SketchObject::getClassTypeId()); + + // only one sketch with its subelements are allowed to be selected + if (selection.size() != 1) { + return; + } + + // get the needed lists and objects + const std::vector &SubNames = selection[0].getSubNames(); + const Sketcher::SketchObject * Obj = sketchView->getSketchObject(); + const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); + + std::vector constraintSubNames; + // go through the selected subelements + for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { + // only handle edges + if (it->size() > 4 && it->substr(0,4) == "Edge") { + int GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; + + // push all the constraints + int i = 0; + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it,++i) + { + if ((*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId) { + associatedConstraintsFilter.push_back(i); + } + } + } + } + + updateList(); } void TaskSketcherConstrains::updateList() { // enforce constraint visibility - bool visibilityTracksFilter = ui->visualisationTrackingFilter->isChecked(); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool visibilityTracksFilter = hGrp->GetBool("VisualisationTrackingFilter",false); if(visibilityTracksFilter) change3DViewVisibilityToTrackFilter(); // it will call slotConstraintChanged via update mechanism @@ -759,6 +825,26 @@ void TaskSketcherConstrains::on_multipleFilterButton_clicked(bool) } } +void TaskSketcherConstrains::on_settingsDialogButton_clicked(bool) +{ + ConstraintSettingsDialog cs; + + QObject::connect( + &cs, SIGNAL(emit_filterInternalAlignment_stateChanged(int)), + this , SLOT (on_filterInternalAlignment_stateChanged(int)) + ); + QObject::connect( + &cs, SIGNAL(emit_extendedInformation_stateChanged(int)), + this , SLOT (on_extendedInformation_stateChanged(int)) + ); + QObject::connect( + &cs, SIGNAL(emit_visualisationTrackingFilter_stateChanged(int)), + this , SLOT (on_visualisationTrackingFilter_stateChanged(int)) + ); + + cs.exec(); // The dialog reacted on any change, so the result of running the dialog is already reflected on return. +} + void TaskSketcherConstrains::changeFilteredVisibility(bool show, ActionTarget target) { assert(sketchView); @@ -854,11 +940,25 @@ void TaskSketcherConstrains::on_listWidgetConstraints_emitShowSelection3DVisibil void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg) { + assert(sketchView); + std::string temp; if (msg.Type == Gui::SelectionChanges::ClrSelection) { ui->listWidgetConstraints->blockSignals(true); - ui->listWidgetConstraints->clearSelection (); + ui->listWidgetConstraints->clearSelection(); ui->listWidgetConstraints->blockSignals(false); + + if(isFilter(ConstraintFilter::SpecialFilterValue::Selection)) { + updateSelectionFilter(); + + bool block = this->blockConnection(true); // avoid to be notified by itself + updateList(); + this->blockConnection(block); + } + else if (isFilter(ConstraintFilter::SpecialFilterValue::AssociatedConstraints)) { + associatedConstraintsFilter.clear(); + updateList(); + } } else if (msg.Type == Gui::SelectionChanges::AddSelection || msg.Type == Gui::SelectionChanges::RmvSelection) { @@ -870,7 +970,7 @@ void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg QRegExp rx(QString::fromLatin1("^Constraint(\\d+)$")); QString expr = QString::fromLatin1(msg.pSubName); int pos = expr.indexOf(rx); - if (pos > -1) { + if (pos > -1) { // is a constraint bool ok; int ConstrId = rx.cap(1).toInt(&ok) - 1; if (ok) { @@ -885,6 +985,25 @@ void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg break; } } + + if(isFilter(ConstraintFilter::SpecialFilterValue::Selection)) { + updateSelectionFilter(); + bool block = this->blockConnection(true); // avoid to be notified by itself + updateList(); + this->blockConnection(block); + } + } + } + else if(isFilter(ConstraintFilter::SpecialFilterValue::AssociatedConstraints)) { // is NOT a constraint + int geoid = Sketcher::Constraint::GeoUndef; + Sketcher::PointPos pointpos = Sketcher::none; + getSelectionGeoId(expr, geoid, pointpos); + + if(geoid != Sketcher::Constraint::GeoUndef && pointpos == Sketcher::none){ + // It is not possible to update on single addition/removal of a geometric element, + // as one removal may imply removing a constraint that should be added by a different element + // that is still selected. The necessary checks outweight a full rebuild of the filter. + updateAssociatedConstraintsFilter(); } } } @@ -895,9 +1014,47 @@ void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg } } - -void TaskSketcherConstrains::on_comboBoxFilter_currentIndexChanged(int) +void TaskSketcherConstrains::getSelectionGeoId(QString expr, int & geoid, Sketcher::PointPos & pointpos) { + QRegExp rxEdge(QString::fromLatin1("^Edge(\\d+)$")); + int pos = expr.indexOf(rxEdge); + geoid = Sketcher::Constraint::GeoUndef; + pointpos = Sketcher::none; + + if (pos > -1) { + bool ok; + int edgeId = rxEdge.cap(1).toInt(&ok) - 1; + if (ok) { + geoid = edgeId; + } + } + else { + QRegExp rxVertex(QString::fromLatin1("^Vertex(\\d+)$")); + pos = expr.indexOf(rxVertex); + + if (pos > -1) { + bool ok; + int vertexId = rxVertex.cap(1).toInt(&ok) - 1; + if (ok) { + const Sketcher::SketchObject * sketch = sketchView->getSketchObject(); + sketch->getGeoVertexIndex(vertexId, geoid, pointpos); + } + } + } +} + +void TaskSketcherConstrains::on_comboBoxFilter_currentIndexChanged(int filterindex) +{ + selectionFilter.clear(); // reset the stored selection filter + associatedConstraintsFilter.clear(); + + if(filterindex == ConstraintFilter::SpecialFilterValue::Selection) { + updateSelectionFilter(); + } + else if(filterindex == ConstraintFilter::SpecialFilterValue::AssociatedConstraints) { + updateAssociatedConstraintsFilter(); + } + updateList(); } @@ -909,14 +1066,43 @@ void TaskSketcherConstrains::on_filterInternalAlignment_stateChanged(int state) void TaskSketcherConstrains::on_visualisationTrackingFilter_stateChanged(int state) { - if(state) + // Synchronise button drop state + { + QSignalBlocker block(this); + + if(ui->visibilityButton->actions()[0]->isChecked() != (state == Qt::Checked)) + ui->visibilityButton->actions()[0]->setChecked(state); + } + + if(state == Qt::Checked) change3DViewVisibilityToTrackFilter(); } +void TaskSketcherConstrains::on_visibilityButton_trackingaction_changed() +{ + // synchronise VisualisationTrackingFilter parameter + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool visibilityTracksFilter = hGrp->GetBool("VisualisationTrackingFilter",false); + + bool bstate = ui->visibilityButton->actions()[0]->isChecked(); + + if(visibilityTracksFilter != bstate) { + hGrp->SetBool("VisualisationTrackingFilter", bstate); + } + + // Act + if(bstate) + change3DViewVisibilityToTrackFilter(); +} + +void TaskSketcherConstrains::on_visibilityButton_clicked(bool) +{ + change3DViewVisibilityToTrackFilter(); +} + void TaskSketcherConstrains::on_extendedInformation_stateChanged(int state) { Q_UNUSED(state); - this->ui->extendedInformation->onSave(); slotConstraintsChanged(); } @@ -932,12 +1118,17 @@ void TaskSketcherConstrains::on_listWidgetConstraints_itemSelectionChanged(void) bool block = this->blockConnection(true); // avoid to be notified by itself Gui::Selection().clearSelection(); + + std::vector constraintSubNames; QList items = ui->listWidgetConstraints->selectedItems(); for (QList::iterator it = items.begin(); it != items.end(); ++it) { std::string constraint_name(Sketcher::PropertyConstraintList::getConstraintName(static_cast(*it)->ConstraintNbr)); - - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), constraint_name.c_str()); + constraintSubNames.push_back(constraint_name); } + + if(!constraintSubNames.empty()) + Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames); + this->blockConnection(block); } @@ -1120,12 +1311,14 @@ bool TaskSketcherConstrains::isConstraintFiltered(QListWidgetItem * item) const Sketcher::Constraint * constraint = vals[it->ConstraintNbr]; int Filter = ui->comboBoxFilter->currentIndex(); - bool hideInternalAlignment = this->ui->filterInternalAlignment->isChecked(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool hideInternalAlignment = hGrp->GetBool("HideInternalAlignment",false); bool visible = true; bool showAll = (Filter == FilterValue::All); bool showGeometric = (Filter == FilterValue::Geometric); - bool showDatums = (Filter == FilterValue::Datums); + bool showDatums = (Filter == FilterValue::Datums && constraint->isDriving); bool showNamed = (Filter == FilterValue::Named && !(constraint->Name.empty())); bool showNonDriving = (Filter == FilterValue::NonDriving && !constraint->isDriving); @@ -1210,6 +1403,14 @@ bool TaskSketcherConstrains::isConstraintFiltered(QListWidgetItem * item) break; } + // Constraint Type independent, selection filter + visible = visible || (Filter == SpecialFilterValue::Selection && + std::find(selectionFilter.begin(), selectionFilter.end(), it->ConstraintNbr) != selectionFilter.end()); + + // Constraint Type independent, associated Constraints Filter + visible = visible || (Filter == SpecialFilterValue::AssociatedConstraints && + std::find(associatedConstraintsFilter.begin(), associatedConstraintsFilter.end(), it->ConstraintNbr) != associatedConstraintsFilter.end()); + return !visible; } @@ -1274,6 +1475,11 @@ void TaskSketcherConstrains::changeEvent(QEvent *e) } } +template +bool TaskSketcherConstrains::isFilter(T filterValue) { + return (ui->comboBoxFilter->currentIndex() == filterValue); +} + #include "moc_TaskSketcherConstrains.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h index e4bbebf5bf..00e9d1715d 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.h @@ -29,6 +29,8 @@ #include #include +#include + #include "ConstraintFilters.h" namespace App { @@ -92,8 +94,15 @@ private: bool isConstraintFiltered(QListWidgetItem * item); void change3DViewVisibilityToTrackFilter(); void changeFilteredVisibility(bool show, ActionTarget target = ActionTarget::All); - void updateMultiFilter(); + void updateSelectionFilter(); + void updateAssociatedConstraintsFilter(); void updateList(); + void createVisibilityButtonActions(); + + template + bool isFilter(T filterValue); + + void getSelectionGeoId(QString expr, int & geoid, Sketcher::PointPos & pos); public Q_SLOTS: void on_comboBoxFilter_currentIndexChanged(int); @@ -106,11 +115,14 @@ public Q_SLOTS: void on_filterInternalAlignment_stateChanged(int state); void on_extendedInformation_stateChanged(int state); void on_visualisationTrackingFilter_stateChanged(int state); + void on_visibilityButton_trackingaction_changed(); + void on_visibilityButton_clicked(bool); void on_showAllButton_clicked(bool); void on_hideAllButton_clicked(bool); void on_listWidgetConstraints_emitShowSelection3DVisibility(); void on_listWidgetConstraints_emitHideSelection3DVisibility(); void on_multipleFilterButton_clicked(bool); + void on_settingsDialogButton_clicked(bool); protected: void changeEvent(QEvent *e); @@ -123,6 +135,8 @@ private: bool inEditMode; std::unique_ptr ui; std::bitset multiFilterStatus; + std::vector selectionFilter; + std::vector associatedConstraintsFilter; }; } //namespace SketcherGui diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.ui b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.ui index e7a3d82462..7730655b4a 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.ui +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.ui @@ -6,7 +6,7 @@ 0 0 - 325 + 417 388
@@ -30,6 +30,12 @@ + + + 0 + 0 + + Filter: @@ -37,6 +43,12 @@ + + + 0 + 0 + + 0 @@ -67,7 +79,12 @@ - Horizontal + Coincident + + + + + Point on Object @@ -77,12 +94,7 @@ - Coincident - - - - - Point on Object + Horizontal @@ -115,11 +127,6 @@ Block - - - Distance - - Horizontal Distance @@ -130,6 +137,11 @@ Vertical Distance + + + Distance + + Radius @@ -165,6 +177,16 @@ Multiple Filters + + + Selection Filter + + + + + Associated Constraint Filter + +
@@ -181,54 +203,42 @@ 0 + + Click to select multiple filters + - ... + Select Multiple + + + + + + + + 0 + 0 + + + + Settings + + + + + + + :/icons/dialogs/Sketcher_Settings.svg:/icons/dialogs/Sketcher_Settings.svg - - - - 0 - 0 - - - - - 0 - 95 - - - - - - - 0 - - - - - 0 - 0 - - - - View - + + - - - 10 - 10 - 135 - 27 - - - + 0 0 @@ -240,17 +250,11 @@ Show Listed + + - - - 150 - 10 - 135 - 27 - - - + 0 0 @@ -262,132 +266,39 @@ Hide Listed - - - - Controls visualisation in the 3D view - - - Automation - - - - - 0 - 0 - 271 - 36 - - + + + - + 0 0 - Constraint visualisation tracks filter selection so that filtered out constraints are hidden + Restricts 3D visibility to the listed elements - Show only filtered constraints + Restrict Visibility - - false + + QToolButton::MenuButtonPopup - - VisualisationTrackingFilter - - - Mod/Sketcher + + Qt::ToolButtonTextOnly - - - - - 0 - 0 - - - - - 0 - 0 - - - - Controls widget list behaviour - - - List - - - - - 0 - 30 - 189 - 36 - - - - - 0 - 0 - - - - Extended information will be added to the list - - - Extended information - - - false - - - ExtendedConstraintInformation - - - Mod/Sketcher - - - - - - 0 - 0 - 189 - 36 - - - - - 0 - 0 - - - - Internal alignments will be hidden - - - Hide internal alignment - - - true - - - HideInternalAlignment - - - Mod/Sketcher - - - - + + + + + 0 + 0 + + 0 @@ -401,12 +312,9 @@ QListWidget
QListWidget
- - Gui::PrefCheckBox - QCheckBox -
Gui/PrefWidgets.h
-
- + + + diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 4bd186264a..f19ffbd650 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -512,6 +512,8 @@ void TaskSketcherElements::on_listWidgetElements_itemSelectionChanged(void) bool block = this->blockConnection(true); // avoid to be notified by itself Gui::Selection().clearSelection(); + std::vector elementSubNames; + for (int i=0;ilistWidgetElements->count(); i++) { ElementItem * ite=static_cast(ui->listWidgetElements->item(i)); @@ -566,7 +568,7 @@ void TaskSketcherElements::on_listWidgetElements_itemSelectionChanged(void) if (ite->isLineSelected) { ss << "Edge" << ite->ElementNbr + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + elementSubNames.push_back(ss.str()); } if (ite->isStartingPointSelected) { @@ -574,7 +576,7 @@ void TaskSketcherElements::on_listWidgetElements_itemSelectionChanged(void) vertex= ite->StartingVertex; if (vertex!=-1) { ss << "Vertex" << vertex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + elementSubNames.push_back(ss.str()); } } @@ -583,7 +585,7 @@ void TaskSketcherElements::on_listWidgetElements_itemSelectionChanged(void) vertex= ite->EndVertex; if (vertex!=-1) { ss << "Vertex" << vertex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + elementSubNames.push_back(ss.str()); } } @@ -592,11 +594,15 @@ void TaskSketcherElements::on_listWidgetElements_itemSelectionChanged(void) vertex= ite->MidVertex; if (vertex!=-1) { ss << "Vertex" << vertex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); + elementSubNames.push_back(ss.str()); } } } + if (!elementSubNames.empty()) { + Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames); + } + this->blockConnection(block); ui->listWidgetElements->blockSignals(false); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index a63a7bf104..698dadd0a4 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -4425,7 +4425,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoSeparator *sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every information visual node gets its own material for to-be-implemented preselection and selection @@ -4478,7 +4478,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoSeparator *sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every information visual node gets its own material for to-be-implemented preselection and selection @@ -4608,7 +4608,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoSeparator *sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every information visual node gets its own material for to-be-implemented preselection and selection @@ -4702,7 +4702,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoSeparator *sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every information visual node gets its own material for to-be-implemented preselection and selection @@ -4771,7 +4771,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer SoSeparator* sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every information visual node gets its own material for to-be-implemented preselection and selection @@ -5966,7 +5966,7 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) // root separator for one constraint SoSeparator *sep = new SoSeparator(); sep->ref(); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures sep->renderCaching = SoSeparator::OFF; // every constrained visual node gets its own material for preselection and selection @@ -6799,7 +6799,7 @@ void ViewProviderSketch::createEditInventorNodes(void) ps->style.setValue(SoPickStyle::UNPICKABLE); Coordsep->addChild(ps); Coordsep->setName("CoordSeparator"); - // no caching for fluctuand data structures + // no caching for frequently-changing data structures Coordsep->renderCaching = SoSeparator::OFF; SoMaterial *CoordTextMaterials = new SoMaterial; diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index c4798e74d1..8a6fa6542d 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -341,25 +341,26 @@ void PropertySheet::Restore(Base::XMLReader &reader) signaller.tryInvoke(); } -void PropertySheet::copyCells(Base::Writer &writer, const std::vector &ranges) const { +void PropertySheet::copyCells(Base::Writer& writer, const std::vector& ranges) const { writer.Stream() << "" << std::endl; writer.Stream() << "" << std::endl; writer.incInd(); - for(auto range : ranges) { - auto r = range; - int count = 0; - do { - if(getValue(*r)) - ++count; - }while(r.next()); + for (auto range : ranges) { writer.Stream() << writer.ind() << "" << std::endl; + << "\" to=\"" << range.toCellString() << "\" count=\"" << range.size() << "\">" << std::endl; writer.incInd(); do { auto cell = getValue(*range); - if(cell) + if (cell) { cell->save(writer); - }while(range.next()); + } + else { + // The cell is empty, so when it's pasted it needs to clear the existing contents + writer.Stream() << writer.ind() << ""; + } + } while (range.next()); writer.decInd(); writer.Stream() << writer.ind() << "" << std::endl; } @@ -367,71 +368,51 @@ void PropertySheet::copyCells(Base::Writer &writer, const std::vector &ra writer.Stream() << "" << std::endl; } -void PropertySheet::pasteCells(XMLReader &reader, const CellAddress &addr) { +void PropertySheet::pasteCells(XMLReader& reader, const CellAddress& addr) { AtomicPropertyChange signaller(*this); bool first = true; - int roffset=0,coffset=0; + int roffset = 0, coffset = 0; reader.readElement("Cells"); - int rangeCount = reader.getAttributeAsInteger("count"); - - for(;rangeCount;--rangeCount) { + for (int rangeCount = reader.getAttributeAsInteger("count"); rangeCount > 0; --rangeCount) { reader.readElement("Range"); CellAddress from(reader.getAttribute("from")); CellAddress to(reader.getAttribute("to")); - int cellCount = reader.getAttributeAsInteger("count"); - Range range(from,to); - bool hasCells = !!cellCount; - for(;cellCount;--cellCount) { - reader.readElement("Cell"); - CellAddress src(reader.getAttribute("address")); - if(first) { + Range range(from, to); + for (int cellCount = reader.getAttributeAsInteger("count"); cellCount > 0; --cellCount) { + if (first) { first = false; roffset = addr.row() - from.row(); coffset = addr.col() - from.col(); - }else - if (!range.next()) - break; - while(src!=*range) { - CellAddress dst(*range); - dst.setRow(dst.row()+roffset); - dst.setCol(dst.col()+coffset); - owner->clear(dst); - owner->cellUpdated(dst); - if (!range.next()) - break; } - CellAddress dst(src.row()+roffset, src.col()+coffset); + reader.readElement("Cell"); + CellAddress src(reader.getAttribute("address")); + CellAddress dst(src.row() + roffset, src.col() + coffset); + owner->clear(dst); + owner->cellUpdated(dst); + auto cell = owner->getNewCell(dst); - cell->setSpans(-1,-1); - cell->restore(reader,true); + cell->setSpans(-1, -1); + cell->restore(reader, true); int rows, cols; - if (cell->getSpans(rows, cols) && (rows > 1 || cols > 1)) + if (cell->getSpans(rows, cols) && (rows > 1 || cols > 1)) mergeCells(dst, CellAddress(dst.row() + rows - 1, dst.col() + cols - 1)); - if(roffset || coffset) { + if (roffset || coffset) { OffsetCellsExpressionVisitor visitor(*this, roffset, coffset); cell->visit(visitor); - if(visitor.changed()) + if (visitor.changed()) recomputeDependencies(dst); } dirty.insert(dst); owner->cellUpdated(dst); } - if(!hasCells || range.next()) { - do { - CellAddress dst(*range); - dst.setRow(dst.row()+roffset); - dst.setCol(dst.col()+coffset); - owner->clear(dst); - owner->cellUpdated(dst); - }while(range.next()); - } } signaller.tryInvoke(); } + Cell * PropertySheet::cellAt(CellAddress address) { std::map::const_iterator j = mergedCells.find(address); diff --git a/src/Mod/Spreadsheet/Gui/DlgSettings.ui b/src/Mod/Spreadsheet/Gui/DlgSettings.ui index 8d140c0b2c..39eaa4d4ed 100644 --- a/src/Mod/Spreadsheet/Gui/DlgSettings.ui +++ b/src/Mod/Spreadsheet/Gui/DlgSettings.ui @@ -6,181 +6,175 @@ 0 0 - 555 - 413 + 322 + 149 + + + 0 + 0 + + Spreadsheet - - - - 10 - 10 - 531 - 161 - - - - Import/Export Settings - - - - - 156 - 70 - 142 - 25 - - - - <html><head/><body><p>Character used to delimit strings, typically is single quote (') or double quote (&quot;). Must be a single character.</p></body></html> - - - - - - " - - - ImportExportQuoteCharacter - - - Mod/Spreadsheet - - - - - - 13 - 33 - 137 - 17 - - - - - 0 - 0 - - - - Delimiter Character: - - - - - - 156 - 113 - 142 - 25 - - - - <html><head/><body><p>Escape character, typically the backslash (\), used to indicate special unprintable characters, e.g. \t = tab. Must be a single character.</p></body></html> - - - \ - - - ImportExportEscapeCharacter - - - Mod/Spreadsheet - - - - - - 13 - 113 - 124 - 17 - - - - - 0 - 0 - - - - Escape Character: - - - - - - 156 - 33 - 142 - 25 - - - - <html><head/><body><p>Character to use as field delimiter. Default is tab, but also commonly used are commas (,) and semicolons (;). Select from the list or enter your own in the field. Must be a single character or the words <span style=" font-style:italic;">tab</span>, <span style=" font-style:italic;">comma</span>, or <span style=" font-style:italic;">semicolon</span>.</p></body></html> - - - true - - - tab - - - ImportExportDelimiter - - - Mod/Spreadsheet - - - - tab + + + + + Import/Export Settings - - - - ; + + + + + + 0 + 0 + + + + Escape Character: + + + + + + + <html><head/><body><p>Character used to delimit strings, typically is single quote (') or double quote (&quot;). Must be a single character.</p></body></html> + + + + + + " + + + ImportExportQuoteCharacter + + + Mod/Spreadsheet + + + + + + + + 0 + 0 + + + + Delimiter Character: + + + + + + + <html><head/><body><p>Escape character, typically the backslash (\), used to indicate special unprintable characters, e.g. \t = tab. Must be a single character.</p></body></html> + + + \ + + + ImportExportEscapeCharacter + + + Mod/Spreadsheet + + + + + + + + 0 + 0 + + + + Quote Character: + + + + + + + <html><head/><body><p>Character to use as field delimiter. Default is tab, but also commonly used are commas (,) and semicolons (;). Select from the list or enter your own in the field. Must be a single character or the words <span style=" font-style:italic;">tab</span>, <span style=" font-style:italic;">comma</span>, or <span style=" font-style:italic;">semicolon</span>.</p></body></html> + + + true + + + tab + + + ImportExportDelimiter + + + Mod/Spreadsheet + + + + tab + + + + + ; + + + + + , + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + +
+ + + + Qt::Vertical - - - - , + + + 20 + 20 + - - - - - - 13 - 70 - 117 - 17 - - - - - 0 - 0 - - - - Quote Character: - - - + + + - Gui::PrefLineEdit - QLineEdit + Gui::PrefComboBox + QComboBox
Gui/PrefWidgets.h
- Gui::PrefComboBox - QComboBox + Gui::PrefLineEdit + QLineEdit
Gui/PrefWidgets.h
diff --git a/src/Mod/Start/StartPage/StartPage.py b/src/Mod/Start/StartPage/StartPage.py index f1270a8bc4..88556f1fb4 100644 --- a/src/Mod/Start/StartPage/StartPage.py +++ b/src/Mod/Start/StartPage/StartPage.py @@ -147,7 +147,11 @@ def getInfo(filename): files=zfile.namelist() # check for meta-file if it's really a FreeCAD document if files[0] == "Document.xml": - doc = str(zfile.read(files[0])) + try: + doc = str(zfile.read(files[0])) + except OSError as e: + print ("Fail to load corrupted FCStd file: '{0}' with this error: {1}".format(filename, str(e))) + return None doc = doc.replace("\n"," ") r = re.findall("Property name=\"CreatedBy.*?String value=\"(.*?)\"/>",doc) if r: diff --git a/src/Mod/Surface/Gui/TaskFilling.cpp b/src/Mod/Surface/Gui/TaskFilling.cpp index 3b07bee830..bc25c3a0b7 100644 --- a/src/Mod/Surface/Gui/TaskFilling.cpp +++ b/src/Mod/Surface/Gui/TaskFilling.cpp @@ -548,7 +548,7 @@ void FillingPanel::on_listBoundary_itemDoubleClicked(QListWidgetItem* item) ui->comboBoxFaces->addItem(text, text.toLatin1()); } - // activste face and continuity + // activate face and continuity if (data.size() == 5) { int index = ui->comboBoxFaces->findData(data[3]); ui->comboBoxFaces->setCurrentIndex(index); diff --git a/src/Mod/TechDraw/App/DrawPage.cpp b/src/Mod/TechDraw/App/DrawPage.cpp index 7d944593e8..f35835c0f6 100644 --- a/src/Mod/TechDraw/App/DrawPage.cpp +++ b/src/Mod/TechDraw/App/DrawPage.cpp @@ -100,7 +100,6 @@ DrawPage::DrawPage(void) "Auto-numbering for Balloons"); Scale.setConstraints(&scaleRange); - balloonPlacing = false; balloonParent = nullptr; } diff --git a/src/Mod/TechDraw/App/DrawPage.h b/src/Mod/TechDraw/App/DrawPage.h index 17b2c383bd..f9973b9d3a 100644 --- a/src/Mod/TechDraw/App/DrawPage.h +++ b/src/Mod/TechDraw/App/DrawPage.h @@ -94,7 +94,6 @@ public: bool isUnsetting(void) { return nowUnsetting; } void requestPaint(void); std::vector getAllViews(void) ; - bool balloonPlacing; DrawViewPart *balloonParent; //could be many balloons on page? int getNextBalloonIndex(void); diff --git a/src/Mod/TechDraw/App/DrawViewBalloon.cpp b/src/Mod/TechDraw/App/DrawViewBalloon.cpp index 684cbc934b..0bad648181 100644 --- a/src/Mod/TechDraw/App/DrawViewBalloon.cpp +++ b/src/Mod/TechDraw/App/DrawViewBalloon.cpp @@ -87,6 +87,7 @@ const char* DrawViewBalloon::balloonTypeEnums[]= {"Circular", "Hexagon", "Square", "Rectangle", + "Line", NULL}; DrawViewBalloon::DrawViewBalloon(void) diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index b6c3637137..59a92d7e51 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -28,13 +28,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -58,14 +58,16 @@ #include #include #include +#include #include #include #include #include #include #include -#include - +#if OCC_VERSION_HEX < 0x070600 +#include +#endif #include #endif // #ifndef _PreComp_ @@ -86,6 +88,10 @@ using namespace TechDraw; using namespace std; +#if OCC_VERSION_HEX >= 0x070600 +using BRepAdaptor_HCurve = BRepAdaptor_Curve; +#endif + #define GEOMETRYEDGE 0 #define COSMETICEDGE 1 #define CENTERLINE 2 diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp index 49cf9170d0..e512a96e1a 100644 --- a/src/Mod/TechDraw/Gui/Command.cpp +++ b/src/Mod/TechDraw/Gui/Command.cpp @@ -87,14 +87,19 @@ #include #include "DrawGuiUtil.h" -#include "PreferencesGui.h" #include "MDIViewPage.h" +#include "PreferencesGui.h" +#include "QGIViewPart.h" +#include "Rez.h" #include "TaskProjGroup.h" #include "TaskSectionView.h" #include "TaskActiveView.h" #include "TaskDetail.h" #include "ViewProviderPage.h" +#include "ViewProviderViewPart.h" + +class Vertex; using namespace TechDrawGui; using namespace TechDraw; using namespace std; @@ -801,6 +806,42 @@ bool _checkDrawViewPartBalloon(Gui::Command* cmd) { return true; } +bool _checkDirectPlacement(const QGIViewPart *viewPart, const std::vector &subNames, QPointF &placement) +{ + // Let's see, if we can help speed up the placement of the balloon: + // As of now we support: + // Single selected vertex: place the ballon tip end here + // Single selected edge: place the ballon tip at its midpoint (suggested placement for e.g. chamfer dimensions) + // + // Single selected faces are currently not supported, but maybe we could in this case use the center of mass? + + if (subNames.size() != 1) { + // If nothing or more than one subjects are selected, let the user decide, where to place the balloon + return false; + } + + std::string geoType = TechDraw::DrawUtil::getGeomTypeFromName(subNames[0]); + if (geoType == "Vertex") { + int index = TechDraw::DrawUtil::getIndexFromName(subNames[0]); + TechDraw::Vertex *vertex = static_cast(viewPart->getViewObject())->getProjVertexByIndex(index); + if (vertex) { + placement = viewPart->mapToScene(Rez::guiX(vertex->x()), Rez::guiX(vertex->y())); + return true; + } + } + else if (geoType == "Edge") { + int index = TechDraw::DrawUtil::getIndexFromName(subNames[0]); + TechDraw::BaseGeom *geo = static_cast(viewPart->getViewObject())->getGeomByIndex(index); + if (geo) { + Base::Vector3d midPoint(Rez::guiX(geo->getMidPoint())); + placement = viewPart->mapToScene(midPoint.x, midPoint.y); + return true; + } + } + + return false; +} + DEF_STD_CMD_A(CmdTechDrawBalloon) CmdTechDrawBalloon::CmdTechDrawBalloon() @@ -826,6 +867,7 @@ void CmdTechDrawBalloon::activated(int iMsg) return; std::vector selection = getSelection().getSelectionEx(); + auto objFeat( dynamic_cast(selection[0].getObject()) ); if( objFeat == nullptr ) { return; @@ -833,10 +875,25 @@ void CmdTechDrawBalloon::activated(int iMsg) TechDraw::DrawPage* page = objFeat->findParentPage(); std::string PageName = page->getNameInDocument(); - - page->balloonParent = objFeat; - page->balloonPlacing = true; + page->balloonParent = objFeat; + + Gui::Document *guiDoc = Gui::Application::Instance->getDocument(page->getDocument()); + ViewProviderPage *pageVP = dynamic_cast(guiDoc->getViewProvider(page)); + ViewProviderViewPart *partVP = dynamic_cast(guiDoc->getViewProvider(objFeat)); + + if (pageVP && partVP) { + QGVPage *viewPage = pageVP->getGraphicsView(); + if (viewPage) { + viewPage->startBalloonPlacing(); + + QGIViewPart *viewPart = dynamic_cast(partVP->getQView()); + QPointF placement; + if (viewPart && _checkDirectPlacement(viewPart, selection[0].getSubNames(), placement)) { + viewPage->createBalloon(placement, objFeat); + } + } + } } bool CmdTechDrawBalloon::isActive(void) diff --git a/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp b/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp index ba33bab420..0363e6e3d0 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionPack.cpp @@ -134,9 +134,9 @@ void CmdTechDrawExtensionCircleCenterLines::activated(int iMsg) std::string line1tag = objFeat->addCosmeticEdge(right/scale, left/scale); std::string line2tag = objFeat->addCosmeticEdge(top/scale, bottom/scale); TechDraw::CosmeticEdge* horiz = objFeat->getCosmeticEdge(line1tag); - _setStyleAndWeight(horiz,4,0.35); + _setStyleAndWeight(horiz,4,0.35f); TechDraw::CosmeticEdge* vert = objFeat->getCosmeticEdge(line2tag); - _setStyleAndWeight(vert,4,0.35); + _setStyleAndWeight(vert,4,0.35f); } } } @@ -191,7 +191,7 @@ void CmdTechDrawExtensionThreadHoleSide::activated(int iMsg) } const std::vector SubNames = selection[0].getSubNames(); if (SubNames.size() >= 2) { - _createThreadLines(SubNames, objFeat, 1.176); + _createThreadLines(SubNames, objFeat, 1.176f); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); @@ -244,7 +244,7 @@ void CmdTechDrawExtensionThreadBoltSide::activated(int iMsg) } const std::vector SubNames = selection[0].getSubNames(); if (SubNames.size() >= 2) { - _createThreadLines(SubNames, objFeat, 0.85); + _createThreadLines(SubNames, objFeat, 0.85f); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); @@ -297,7 +297,7 @@ void CmdTechDrawExtensionThreadHoleBottom::activated(int iMsg) } const std::vector SubNames = selection[0].getSubNames(); for (std::string Name : SubNames) { - _createThreadCircle(Name, objFeat, 1.177); + _createThreadCircle(Name, objFeat, 1.177f); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); @@ -350,7 +350,7 @@ void CmdTechDrawExtensionThreadBoltBottom::activated(int iMsg) } const std::vector SubNames = selection[0].getSubNames(); for (std::string Name : SubNames) { - _createThreadCircle(Name, objFeat, 0.85); + _createThreadCircle(Name, objFeat, 0.85f); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); @@ -390,7 +390,7 @@ void _createThreadCircle(std::string Name, TechDraw::DrawViewPart* objFeat, floa TechDraw::BaseGeom* threadArc = new TechDraw::AOC(center/scale, radius*factor/scale, 255.0, 165.0); std::string arcTag = objFeat->addCosmeticEdge(threadArc); TechDraw::CosmeticEdge* arc = objFeat->getCosmeticEdge(arcTag); - _setStyleAndWeight(arc,1,0.35); + _setStyleAndWeight(arc,1,0.35f); } } } @@ -429,8 +429,8 @@ void _createThreadLines(std::vector SubNames, TechDraw::DrawViewPar std::string line1Tag = objFeat->addCosmeticEdge((start1+delta)/scale, (end1+delta)/scale); TechDraw::CosmeticEdge* cosTag0 = objFeat->getCosmeticEdge(line0Tag); TechDraw::CosmeticEdge* cosTag1 = objFeat->getCosmeticEdge(line1Tag); - _setStyleAndWeight(cosTag0,1,0.35); - _setStyleAndWeight(cosTag1,1,0.35); + _setStyleAndWeight(cosTag0,1,0.35f); + _setStyleAndWeight(cosTag1,1,0.35f); } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Side"), diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui index 0e6d4f080d..1f484413a9 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawAnnotation.ui @@ -424,6 +424,15 @@ :/icons/rectangle.svg:/icons/rectangle.svg + + + Line + + + + :/icons/bottomline.svg:/icons/bottomline.svg + + diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index 71d7fe6913..70c7f2d2e3 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -118,8 +118,6 @@ QGIView::QGIView() m_lockWidth = (double) sizeLock.width(); m_lockHeight = (double) sizeLock.height(); m_lock->hide(); - - setCursor(Qt::ArrowCursor); } QGIView::~QGIView() diff --git a/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp b/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp index a100894875..6a06f65beb 100644 --- a/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp @@ -676,6 +676,7 @@ void QGIViewBalloon::drawBalloon(bool dragged) float scale = balloon->ShapeScale.getValue(); double offsetLR = 0; + double offsetUD = 0; QPainterPath balloonPath; if (strcmp(balloonType, "Circular") == 0) { @@ -747,16 +748,26 @@ void QGIViewBalloon::drawBalloon(bool dragged) balloonPath.moveTo(lblCenter.x + (radius * cos(startAngle)), lblCenter.y + (radius * sin(startAngle))); balloonPath.addPolygon(triangle); } + else if (strcmp(balloonType, "Line") == 0) { + textHeight = textHeight*scale + Rez::guiX(0.5); + textWidth = textWidth*scale + Rez::guiX(1.0); + + offsetLR = textWidth/2.0; + offsetUD = textHeight/2.0; + + balloonPath.moveTo(lblCenter.x - textWidth/2.0, lblCenter.y + offsetUD); + balloonPath.lineTo(lblCenter.x + textWidth/2.0, lblCenter.y + offsetUD); + } balloonShape->setPath(balloonPath); offsetLR = (lblCenter.x < arrowTipX) ? offsetLR : -offsetLR ; - if (DrawUtil::fpCompare(kinkLength, 0.0)) { //if no kink, then dLine start sb on line from center to arrow + if (DrawUtil::fpCompare(kinkLength, 0.0) && strcmp(balloonType, "Line")) { //if no kink, then dLine start sb on line from center to arrow dLineStart = lblCenter; kinkPoint = dLineStart; } else { - dLineStart.y = lblCenter.y; + dLineStart.y = lblCenter.y + offsetUD; dLineStart.x = lblCenter.x + offsetLR ; kinkLength = (lblCenter.x < arrowTipX) ? kinkLength : -kinkLength; kinkPoint.y = dLineStart.y; diff --git a/src/Mod/TechDraw/Gui/QGVPage.cpp b/src/Mod/TechDraw/Gui/QGVPage.cpp index 76e84a9748..903f9354fc 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.cpp +++ b/src/Mod/TechDraw/Gui/QGVPage.cpp @@ -57,6 +57,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -126,6 +132,7 @@ QGVPage::QGVPage(ViewProviderPage *vp, QGraphicsScene* s, QWidget *parent) m_renderer(Native), drawBkg(true), m_vpPage(0), + balloonPlacing(false), panningActive(false) { assert(vp); @@ -166,13 +173,13 @@ QGVPage::QGVPage(ViewProviderPage *vp, QGraphicsScene* s, QWidget *parent) setAlignment(Qt::AlignCenter); setDragMode(ScrollHandDrag); - setCursor(QCursor(Qt::ArrowCursor)); + resetCursor(); setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); bkgBrush = new QBrush(getBackgroundColor()); balloonCursor = new QLabel(this); - balloonCursor->setPixmap(QPixmap(QString::fromUtf8(":/icons/TechDraw_Balloon.svg"))); + balloonCursor->setPixmap(prepareCursorPixmap("TechDraw_Balloon.svg", balloonHotspot = QPoint(8, 59))); balloonCursor->hide(); resetCachedContent(); @@ -184,11 +191,17 @@ QGVPage::~QGVPage() } +void QGVPage::startBalloonPlacing(void) +{ + balloonPlacing = true; + activateCursor(QCursor(*balloonCursor->pixmap(), balloonHotspot.x(), balloonHotspot.y())); +} + void QGVPage::cancelBalloonPlacing(void) { - getDrawPage()->balloonPlacing = false; - balloonCursor->hide(); - QApplication::restoreOverrideCursor(); + balloonPlacing = false; + balloonCursor->hide(); + resetCursor(); } void QGVPage::drawBackground(QPainter *p, const QRectF &) @@ -448,12 +461,13 @@ QGIView * QGVPage::addViewBalloon(TechDraw::DrawViewBalloon *balloon) QGIView *parent = 0; parent = findParent(vBalloon); - if(parent) + if (parent) { addBalloonToParent(vBalloon,parent); + } - if (getDrawPage()->balloonPlacing) { - vBalloon->placeBalloon(balloon->origin); - cancelBalloonPlacing(); + if (balloonPlacing) { + vBalloon->placeBalloon(balloon->origin); + cancelBalloonPlacing(); } return vBalloon; @@ -470,6 +484,29 @@ void QGVPage::addBalloonToParent(QGIViewBalloon* balloon, QGIView* parent) balloon->setZValue(ZVALUE::DIMENSION); } +void QGVPage::createBalloon(QPointF origin, DrawViewPart *parent) +{ + std::string featName = getDrawPage()->getDocument()->getUniqueObjectName("Balloon"); + std::string pageName = getDrawPage()->getNameInDocument(); + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Balloon")); + Command::doCommand(Command::Doc, "App.activeDocument().addObject('TechDraw::DrawViewBalloon','%s')", featName.c_str()); + Command::doCommand(Command::Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", pageName.c_str(), featName.c_str()); + + TechDraw::DrawViewBalloon *balloon = dynamic_cast(getDrawPage()->getDocument()->getObject(featName.c_str())); + if (!balloon) { + throw Base::TypeError("CmdTechDrawNewBalloon - balloon not found\n"); + } + + balloon->SourceView.setValue(parent); + balloon->origin = origin; + + Gui::Command::commitCommand(); + + parent->touch(true); + Gui::Command::updateActive(); +} + QGIView * QGVPage::addViewDimension(TechDraw::DrawViewDimension *dim) { auto dimGroup( new QGIViewDimension ); @@ -1119,21 +1156,14 @@ void QGVPage::kbPanScroll(int xMove, int yMove) void QGVPage::enterEvent(QEvent *event) { QGraphicsView::enterEvent(event); - if(getDrawPage()->balloonPlacing) { + if (balloonPlacing) { balloonCursor->hide(); - QApplication::setOverrideCursor(QCursor(QPixmap(QString::fromUtf8(":/icons/TechDraw_Balloon.svg")),0,32)); - } else { - QApplication::restoreOverrideCursor(); - viewport()->setCursor(Qt::ArrowCursor); } } void QGVPage::leaveEvent(QEvent * event) { - QApplication::restoreOverrideCursor(); - if(getDrawPage()->balloonPlacing) { - - + if (balloonPlacing) { int left_x; if (balloonCursorPos.x() < 32) left_x = 0; @@ -1192,33 +1222,9 @@ void QGVPage::mouseMoveEvent(QMouseEvent *event) void QGVPage::mouseReleaseEvent(QMouseEvent *event) { - if(getDrawPage()->balloonPlacing) { - QApplication::restoreOverrideCursor(); + if (balloonPlacing) { balloonCursor->hide(); - - std::string FeatName = getDrawPage()->getDocument()->getUniqueObjectName("Balloon"); - std::string PageName = getDrawPage()->getNameInDocument(); - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Balloon")); - TechDraw::DrawViewBalloon *balloon = 0; - - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Balloon")); - Command::doCommand(Command::Doc,"App.activeDocument().addObject('TechDraw::DrawViewBalloon','%s')",FeatName.c_str()); - Command::doCommand(Command::Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); - - balloon = dynamic_cast(getDrawPage()->getDocument()->getObject(FeatName.c_str())); - if (!balloon) { - throw Base::TypeError("CmdTechDrawNewBalloon - balloon not found\n"); - } - - balloon->SourceView.setValue(getDrawPage()->balloonParent); - balloon->origin = mapToScene(event->pos()); - - Gui::Command::commitCommand(); - balloon->recomputeFeature(); - - //Horrible hack to force Tree update - double x = getDrawPage()->balloonParent->X.getValue(); - getDrawPage()->balloonParent->X.setValue(x); + createBalloon(mapToScene(event->pos()), getDrawPage()->balloonParent); } if (event->button()&Qt::MiddleButton) { @@ -1227,7 +1233,7 @@ void QGVPage::mouseReleaseEvent(QMouseEvent *event) } QGraphicsView::mouseReleaseEvent(event); - viewport()->setCursor(Qt::ArrowCursor); + resetCursor(); } TechDraw::DrawPage* QGVPage::getDrawPage() @@ -1244,4 +1250,54 @@ QColor QGVPage::getBackgroundColor() return fcColor.asValue(); } +double QGVPage::getDevicePixelRatio() const { + for (Gui::MDIView *view : m_vpPage->getDocument()->getMDIViews()) { + if (view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + return static_cast(view)->getViewer()->devicePixelRatio(); + } + } + + return 1.0; +} + +QPixmap QGVPage::prepareCursorPixmap(const char *iconName, QPoint &hotspot) { + + QPointF floatHotspot(hotspot); + double pixelRatio = getDevicePixelRatio(); + + // Due to impossibility to query cursor size via Qt API, we stick to (32x32)*device_pixel_ratio + // as FreeCAD Wiki suggests - see https://wiki.freecadweb.org/HiDPI_support#Custom_cursor_size + double cursorSize = 32.0*pixelRatio; + + QPixmap pixmap = Gui::BitmapFactory().pixmapFromSvg(iconName, QSizeF(cursorSize, cursorSize)); + pixmap.setDevicePixelRatio(pixelRatio); + + // The default (and here expected) SVG cursor graphics size is 64x64 pixels, thus we must adjust + // the 64x64 based hotspot position for our 32x32 based cursor pixmaps accordingly + floatHotspot *= 0.5; + +#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) + // On XCB platform, the pixmap device pixel ratio is not taken into account for cursor hot spot, + // therefore we must take care of the transformation ourselves... + // Refer to QTBUG-68571 - https://bugreports.qt.io/browse/QTBUG-68571 + if (qGuiApp->platformName() == QLatin1String("xcb")) { + floatHotspot *= pixelRatio; + } +#endif + + hotspot = floatHotspot.toPoint(); + return pixmap; +} + +void QGVPage::activateCursor(QCursor cursor) { + this->setCursor(cursor); + viewport()->setCursor(cursor); +} + +void QGVPage::resetCursor() { + this->setCursor(Qt::ArrowCursor); + viewport()->setCursor(Qt::ArrowCursor); +} + + #include diff --git a/src/Mod/TechDraw/Gui/QGVPage.h b/src/Mod/TechDraw/Gui/QGVPage.h index 52bbde1583..427d87a4f6 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.h +++ b/src/Mod/TechDraw/Gui/QGVPage.h @@ -93,6 +93,10 @@ public: QGIView* findParent(QGIView *) const; void addBalloonToParent(QGIViewBalloon* balloon, QGIView* parent); + void createBalloon(QPointF origin, TechDraw::DrawViewPart *parent); + void startBalloonPlacing(void); + void cancelBalloonPlacing(void); + void addDimToParent(QGIViewDimension* dim, QGIView* parent); void addLeaderToParent(QGILeaderLine* lead, QGIView* parent); @@ -118,6 +122,7 @@ public: void saveSvg(QString filename); void postProcessXml(QTemporaryFile& tempFile, QString filename, QString pagename); + public Q_SLOTS: void setHighQualityAntialiasing(bool highQualityAntialiasing); @@ -140,6 +145,12 @@ protected: QGITemplate *pageTemplate; + double getDevicePixelRatio() const; + QPixmap prepareCursorPixmap(const char *iconName, QPoint &hotspot); + + void activateCursor(QCursor cursor); + void resetCursor(); + private: RendererType m_renderer; @@ -153,9 +164,11 @@ private: double m_zoomIncrement; int m_reversePan; int m_reverseScroll; + + bool balloonPlacing; QLabel *balloonCursor; QPoint balloonCursorPos; - void cancelBalloonPlacing(void); + QPoint balloonHotspot; QPoint panOrigin; bool panningActive; diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 45b09b6e62..887953a5dd 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -109,6 +109,7 @@ icons/rectangle.svg icons/triangle.svg icons/square.svg + icons/bottomline.svg icons/MRTE/menu.svg diff --git a/src/Mod/TechDraw/Gui/Resources/icons/bottomline.svg b/src/Mod/TechDraw/Gui/Resources/icons/bottomline.svg new file mode 100644 index 0000000000..f97073b88b --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/bottomline.svg @@ -0,0 +1,35 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/TaskBalloon.ui b/src/Mod/TechDraw/Gui/TaskBalloon.ui index b4c1911af1..fd58abd15e 100644 --- a/src/Mod/TechDraw/Gui/TaskBalloon.ui +++ b/src/Mod/TechDraw/Gui/TaskBalloon.ui @@ -164,6 +164,15 @@ :/icons/rectangle.svg:/icons/rectangle.svg + + + Line + + + + :/icons/bottomline.svg:/icons/bottomline.svg + + diff --git a/src/Mod/TechDraw/Gui/ViewProviderPage.h b/src/Mod/TechDraw/Gui/ViewProviderPage.h index 443feb3047..895f92f740 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderPage.h +++ b/src/Mod/TechDraw/Gui/ViewProviderPage.h @@ -91,6 +91,7 @@ public: void setFrameState(bool state); void toggleFrameState(void); void setTemplateMarkers(bool state); + QGVPage *getGraphicsView() { return m_graphicsView; } void setGraphicsView(QGVPage* gv); virtual bool canDelete(App::DocumentObject* obj) const override; diff --git a/src/Mod/Test/Gui/UnitTestImp.cpp b/src/Mod/Test/Gui/UnitTestImp.cpp index 5b34ce1988..a70f8602d7 100644 --- a/src/Mod/Test/Gui/UnitTestImp.cpp +++ b/src/Mod/Test/Gui/UnitTestImp.cpp @@ -192,6 +192,12 @@ void UnitTestDialog::on_startButton_clicked() catch (const Base::Exception& e) { showErrorDialog("Exception", e.what()); } + catch (const std::exception& e) { + showErrorDialog("C++ standard exception", e.what()); + } + catch (...) { + showErrorDialog("Unknown exception", "Unknown exception raised"); + } ui->startButton->setEnabled(true); } diff --git a/src/Mod/Web/Gui/BrowserView.cpp b/src/Mod/Web/Gui/BrowserView.cpp index 0c776f066b..3914e06ffd 100644 --- a/src/Mod/Web/Gui/BrowserView.cpp +++ b/src/Mod/Web/Gui/BrowserView.cpp @@ -693,12 +693,12 @@ void BrowserView::onLoadProgress(int step) void BrowserView::onLoadFinished(bool ok) { - if (ok) { - QProgressBar* bar = SequencerBar::instance()->getProgressBar(); - bar->setValue(100); - bar->hide(); - getMainWindow()->showMessage(QString()); - } + Q_UNUSED(ok) + + QProgressBar* bar = SequencerBar::instance()->getProgressBar(); + bar->setValue(100); + bar->hide(); + getMainWindow()->showMessage(QString()); isLoading = false; } diff --git a/src/Tools/updatecrowdin.py b/src/Tools/updatecrowdin.py index 30d69deaaf..5a06c0d725 100755 --- a/src/Tools/updatecrowdin.py +++ b/src/Tools/updatecrowdin.py @@ -115,7 +115,7 @@ locations = [["AddonManager","../Mod/AddonManager/Resources/translations","../Mo ["TechDraw","../Mod/TechDraw/Gui/Resources/translations","../Mod/TechDraw/Gui/Resources/TechDraw.qrc"], ] -TRESHOLD = 25 # how many % must be translated for the translation to be included in FreeCAD +THRESHOLD = 25 # how many % must be translated for the translation to be included in FreeCAD class CrowdinUpdater: @@ -406,7 +406,7 @@ if __name__ == "__main__": if command == "status": status = updater.status() status = sorted(status,key=lambda item: item['translationProgress'],reverse=True) - print(len([item for item in status if item['translationProgress'] > TRESHOLD])," languages with status > "+str(TRESHOLD)+"%:") + print(len([item for item in status if item['translationProgress'] > THRESHOLD])," languages with status > "+str(THRESHOLD)+"%:") print(" ") sep = False prefix = "" @@ -416,7 +416,7 @@ if __name__ == "__main__": suffix = "\033[0m" for item in status: if item['translationProgress'] > 0: - if (item['translationProgress'] < TRESHOLD) and (not sep): + if (item['translationProgress'] < THRESHOLD) and (not sep): print(" ") print("Other languages:") print(" ") @@ -464,7 +464,7 @@ if __name__ == "__main__": print("retrieving list of languages...") status = updater.status() status = sorted(status,key=lambda item: item['translationProgress'],reverse=True) - languages = [item['languageId'] for item in status if item['translationProgress'] > TRESHOLD] + languages = [item['languageId'] for item in status if item['translationProgress'] > THRESHOLD] applyTranslations(languages) print("Updating Translator.cpp...") for ln in languages: @@ -474,7 +474,7 @@ if __name__ == "__main__": print("retrieving list of languages...") status = updater.status() status = sorted(status,key=lambda item: item['translationProgress'],reverse=True) - languages = [item['languageId'] for item in status if item['translationProgress'] > TRESHOLD] + languages = [item['languageId'] for item in status if item['translationProgress'] > THRESHOLD] print("Updating Translator.cpp...") for ln in languages: updateTranslatorCpp(ln) diff --git a/src/Tools/updatets.py b/src/Tools/updatets.py index 8cd1e14d22..0c344e6f1f 100755 --- a/src/Tools/updatets.py +++ b/src/Tools/updatets.py @@ -146,37 +146,32 @@ def update_translation(entry): print (f"EXTRACTING STRINGS FOR {entry['tsname']}") print ("=============================================") cur = os.getcwd() + log_redirect = f" 2>> {cur}/tsupdate_stderr.log 1>> {cur}/tsupdate_stdout.log" os.chdir(entry["workingdir"]) existingjsons = [f for f in os.listdir(".") if f.endswith(".json")] - filename = entry["tsname"] + ".pro" - print("Running qmake -project") - os.system(f"{QMAKE} -project -o {filename}") - #only update the master ts file + project_filename = entry["tsname"] + ".pro" tsBasename = os.path.join(entry["tsdir"],entry["tsname"]) - mainTranslation = f"{LUPDATE} {filename} -ts {tsBasename}.ts" - print(mainTranslation) - os.system(mainTranslation) - os.remove(filename) + + execline = [] + execline.append (f"{QMAKE} -project -o {project_filename}") + execline.append (f"sed 's/.*<\/translation>/<\/translation>/g' {tsBasename}.ts > {tsBasename}.ts.temp") + execline.append (f"touch {tsBasename}.ts") # In case it didn't get created above + execline.append (f"{LUPDATE} {project_filename} -ts {tsBasename}.ts {log_redirect}") + execline.append (f"mv {tsBasename}.ts.temp {tsBasename}.ts") + execline.append (f"{PYLUPDATE} `find ./ -name \"*.py\"` -ts {tsBasename}py.ts {log_redirect}") + execline.append (f"{LCONVERT} -i {tsBasename}py.ts {tsBasename}.ts -o {tsBasename}.ts {log_redirect}") + execline.append (f"rm {tsBasename}py.ts") + print(f"Executing special commands in {entry['workingdir']}:") + for line in execline: + print (line) + os.system(line) + print() + + os.remove(project_filename) # lupdate creates json files since Qt5.something. Remove them here too for jsonfile in [f for f in os.listdir(".") if f.endswith(".json")]: if not jsonfile in existingjsons: os.remove(jsonfile) - - # Also try to do a python lupdate - execline0 = f"touch {tsBasename}.ts" # In case it didn't get created above - execline1 = f"{PYLUPDATE} `find ./ -name \"*.py\"` -ts {tsBasename}py.ts" - execline2 = f"{LCONVERT} -i {tsBasename}py.ts {tsBasename}.ts -o {tsBasename}.ts" - execline3 = f"rm {tsBasename}py.ts" - print(f"Executing special commands in {entry['workingdir']}:") - print(execline0) - os.system(execline0) - print(execline1) - os.system(execline1) - print(execline2) - os.system(execline2) - print(execline3) - os.system(execline3) - print() os.chdir(cur) @@ -192,6 +187,8 @@ def main(): for i in directories: update_translation(i) print("\nIf updatets.py was run successfully, the next step is to run ./src/Tools/updatecrowdin.py") + print("stderr output from lupdate can be found in tsupdate_stderr.log") + print("stdout output from lupdate can be found in tsupdate_stdout.log") if __name__ == "__main__": main()