From a575e6c7cbc08f6f235345c62458e8ff19949b16 Mon Sep 17 00:00:00 2001 From: Syres916 <46537884+Syres916@users.noreply.github.com> Date: Mon, 15 Jan 2024 13:43:58 +0000 Subject: [PATCH 01/36] [Gui] [Tux] Fix Nav Style Icons and theme recognition --- src/Mod/Tux/NavigationIndicatorGui.py | 37 ++++++++++---- src/Mod/Tux/Resources/Tux.qrc | 6 ++- .../icons/NavigationOpenSCAD_dark.svg | 50 +++++++++++++++++++ .../icons/NavigationOpenSCAD_light.svg | 50 +++++++++++++++++++ .../icons/NavigationTinkerCAD_dark.svg | 50 +++++++++++++++++++ .../icons/NavigationTinkerCAD_light.svg | 50 +++++++++++++++++++ 6 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg create mode 100644 src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg create mode 100644 src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg create mode 100644 src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg diff --git a/src/Mod/Tux/NavigationIndicatorGui.py b/src/Mod/Tux/NavigationIndicatorGui.py index e20c0be897..c05feb1ba2 100644 --- a/src/Mod/Tux/NavigationIndicatorGui.py +++ b/src/Mod/Tux/NavigationIndicatorGui.py @@ -28,7 +28,7 @@ mw = Gui.getMainWindow() statusBar = mw.statusBar() p = App.ParamGet("User parameter:Tux/NavigationIndicator") pView = App.ParamGet("User parameter:BaseApp/Preferences/View") - +pMWin = App.ParamGet("User parameter:BaseApp/Preferences/MainWindow") try: _encoding = QtGui.QApplication.UnicodeUTF8 @@ -62,6 +62,29 @@ class IndicatorButton(QtGui.QPushButton): if param == "NavigationStyle": setCurrent() + def mousePressEvent(self, event): + RePopulateIcons() + return super(IndicatorButton, self).mousePressEvent(event) + + +def RePopulateIcons(): + curStyleSheet = pMWin.GetString("StyleSheet") + if "dark" in curStyleSheet.lower(): + StyleSheetType = "light" + else: + StyleSheetType = "dark" + + a1.setIcon(QtGui.QIcon(":/icons/NavigationBlender_" + StyleSheetType + ".svg")) + a2.setIcon(QtGui.QIcon(":/icons/NavigationCAD_" + StyleSheetType + ".svg")) + a3.setIcon(QtGui.QIcon(":/icons/NavigationGesture_" + StyleSheetType + ".svg")) + a4.setIcon(QtGui.QIcon(":/icons/NavigationMayaGesture_" + StyleSheetType + ".svg")) + a5.setIcon(QtGui.QIcon(":/icons/NavigationOpenCascade_" + StyleSheetType + ".svg")) + a6.setIcon(QtGui.QIcon(":/icons/NavigationOpenInventor_" + StyleSheetType + ".svg")) + a7.setIcon(QtGui.QIcon(":/icons/NavigationOpenSCAD_" + StyleSheetType + ".svg")) + a8.setIcon(QtGui.QIcon(":/icons/NavigationRevit_" + StyleSheetType + ".svg")) + a9.setIcon(QtGui.QIcon(":/icons/NavigationTinkerCAD_" + StyleSheetType + ".svg")) + a10.setIcon(QtGui.QIcon(":/icons/NavigationTouchpad_" + StyleSheetType + ".svg")) + def retranslateUi(): """Retranslate navigation indicator on language change""" @@ -602,65 +625,57 @@ a0.setData("Undefined ") a0.setObjectName("Indicator_NavigationUndefined") a1 = QtGui.QAction(gStyle) -a1.setIcon(QtGui.QIcon(":/icons/NavigationBlender_dark.svg")) a1.setText("Blender ") a1.setData("Gui::BlenderNavigationStyle") a1.setObjectName("Indicator_NavigationBlender") a2 = QtGui.QAction(gStyle) -a2.setIcon(QtGui.QIcon(":/icons/NavigationCAD_dark.svg")) a2.setText("CAD ") a2.setData("Gui::CADNavigationStyle") a2.setObjectName("Indicator_NavigationCAD") a3 = QtGui.QAction(gStyle) -a3.setIcon(QtGui.QIcon(":/icons/NavigationGesture_dark.svg")) a3.setText("Gesture ") a3.setData("Gui::GestureNavigationStyle") a3.setObjectName("Indicator_NavigationGesture") a4 = QtGui.QAction(gStyle) -a4.setIcon(QtGui.QIcon(":/icons/NavigationMayaGesture_dark.svg")) a4.setText("MayaGesture ") a4.setData("Gui::MayaGestureNavigationStyle") a4.setObjectName("Indicator_NavigationMayaGesture") a5 = QtGui.QAction(gStyle) -a5.setIcon(QtGui.QIcon(":/icons/NavigationOpenCascade_dark.svg")) a5.setText("OpenCascade ") a5.setData("Gui::OpenCascadeNavigationStyle") a5.setObjectName("Indicator_NavigationOpenCascade") a6 = QtGui.QAction(gStyle) -a6.setIcon(QtGui.QIcon(":/icons/NavigationOpenInventor_dark.svg")) a6.setText("OpenInventor ") a6.setData("Gui::InventorNavigationStyle") a6.setObjectName("Indicator_NavigationOpenInventor") a7 = QtGui.QAction(gStyle) -a7.setIcon(QtGui.QIcon(":/icons/NavigationOpenSCAD_dark.svg")) a7.setText("OpenSCAD ") a7.setData("Gui::OpenSCADNavigationStyle") a7.setObjectName("Indicator_NavigationOpenSCAD") a8 = QtGui.QAction(gStyle) -a8.setIcon(QtGui.QIcon(":/icons/NavigationRevit_dark.svg")) a8.setText("Revit ") a8.setData("Gui::RevitNavigationStyle") a8.setObjectName("Indicator_NavigationRevit") a9 = QtGui.QAction(gStyle) -a9.setIcon(QtGui.QIcon(":/icons/NavigationTinkerCAD_dark.svg")) a9.setText("TinkerCAD ") a9.setData("Gui::TinkerCADNavigationStyle") a9.setObjectName("Indicator_NavigationTinkerCAD") a10 = QtGui.QAction(gStyle) -a10.setIcon(QtGui.QIcon(":/icons/NavigationTouchpad_dark.svg")) a10.setText("Touchpad ") a10.setData("Gui::TouchpadNavigationStyle") a10.setObjectName("Indicator_NavigationTouchpad") +RePopulateIcons() + menu.addMenu(menuSettings) menu.addSeparator() menu.addAction(a0) diff --git a/src/Mod/Tux/Resources/Tux.qrc b/src/Mod/Tux/Resources/Tux.qrc index 69dfb4ee3a..483eedd537 100644 --- a/src/Mod/Tux/Resources/Tux.qrc +++ b/src/Mod/Tux/Resources/Tux.qrc @@ -58,13 +58,15 @@ icons/NavigationOpenInventor_dark.svg icons/NavigationOpenInventor_ZoomAlt.svg icons/NavigationOpenInventor_Zoom.svg - icons/NavigationCAD_dark.svg + icons/NavigationOpenSCAD_light.svg + icons/NavigationOpenSCAD_dark.svg icons/NavigationOpenCascade_Select.svg icons/NavigationOpenCascade_PanAlt.svg icons/NavigationOpenCascade_PanAlt.svg icons/NavigationOpenCascade_Select.svg icons/NavigationGesture_Pan.svg - icons/NavigationCAD_dark.svg + icons/NavigationTinkerCAD_light.svg + icons/NavigationTinkerCAD_dark.svg icons/NavigationOpenCascade_Select.svg icons/NavigationOpenCascade_Zoom.svg icons/NavigationGesture_Pan.svg diff --git a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg new file mode 100644 index 0000000000..1ec124fba1 --- /dev/null +++ b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg @@ -0,0 +1,50 @@ + + + + + + + + + image/svg+xml + + + + + + + + + OS + diff --git a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg new file mode 100644 index 0000000000..c3829d9c93 --- /dev/null +++ b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg @@ -0,0 +1,50 @@ + + + + + + + + + image/svg+xml + + + + + + + + + OS + diff --git a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg new file mode 100644 index 0000000000..b21d4bacdf --- /dev/null +++ b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg @@ -0,0 +1,50 @@ + + + + + + + + + image/svg+xml + + + + + + + + + T + diff --git a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg new file mode 100644 index 0000000000..5d011b3d0d --- /dev/null +++ b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg @@ -0,0 +1,50 @@ + + + + + + + + + image/svg+xml + + + + + + + + + T + From e95c553391f1ef01ea5156f59253ce20ab6c30ba Mon Sep 17 00:00:00 2001 From: Syres916 <46537884+Syres916@users.noreply.github.com> Date: Mon, 15 Jan 2024 13:58:27 +0000 Subject: [PATCH 02/36] [Gui] [Tux] Correct text location in icons --- .../Tux/Resources/icons/NavigationOpenSCAD_dark.svg | 4 ++-- .../Tux/Resources/icons/NavigationOpenSCAD_light.svg | 4 ++-- .../Tux/Resources/icons/NavigationTinkerCAD_dark.svg | 10 +++++----- .../Tux/Resources/icons/NavigationTinkerCAD_light.svg | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg index 1ec124fba1..a2eba9ffcc 100644 --- a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg +++ b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_dark.svg @@ -41,10 +41,10 @@ OS diff --git a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg index c3829d9c93..d6900e002c 100644 --- a/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg +++ b/src/Mod/Tux/Resources/icons/NavigationOpenSCAD_light.svg @@ -41,10 +41,10 @@ OS diff --git a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg index b21d4bacdf..aaa6e7faab 100644 --- a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg +++ b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_dark.svg @@ -40,11 +40,11 @@ T + x="27.425451" + y="45.400135">T diff --git a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg index 5d011b3d0d..6b4101c00f 100644 --- a/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg +++ b/src/Mod/Tux/Resources/icons/NavigationTinkerCAD_light.svg @@ -40,11 +40,11 @@ T + x="27.425451" + y="45.400135">T From c1b296dab807153af653f63d22272cdd805d909a Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 15 Jan 2024 22:41:24 -0500 Subject: [PATCH 03/36] ShapeMapper code from RT branch to new TopoShapeMapper files --- src/Mod/Part/App/CMakeLists.txt | 2 + src/Mod/Part/App/TopoShape.h | 56 ++++++ src/Mod/Part/App/TopoShapeMapper.cpp | 75 ++++++++ src/Mod/Part/App/TopoShapeMapper.h | 255 +++++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 src/Mod/Part/App/TopoShapeMapper.cpp create mode 100644 src/Mod/Part/App/TopoShapeMapper.h diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index bf0ce716eb..1a85f3b620 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -533,6 +533,8 @@ SET(Part_SRCS TopoShapeCache.cpp TopoShapeCache.h TopoShapeExpansion.cpp + TopoShapeMapper.h + TopoShapeMapper.cpp TopoShapeOpCode.h edgecluster.cpp edgecluster.h diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index ad4ef2a780..a80ce07946 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -613,6 +613,27 @@ public: bool hasPendingElementMap() const; + /** Helper class to return the generated and modified shape given an input shape + * + * Shape history information is extracted using OCCT APIs + * BRepBuilderAPI_MakeShape::Generated/Modified(). However, there is often + * some glitches in various derived class. So we use this class as an + * abstraction, and create various derived classes to deal with the glitches. + */ + struct PartExport Mapper { + /// Helper vector for temporary storage of both generated and modified shapes + mutable std::vector _res; + virtual ~Mapper() {} + /// Return a list of shape generated from the given input shape + virtual const std::vector &generated(const TopoDS_Shape &) const { + return _res; + } + /// Return a list of shape modified from the given input shape + virtual const std::vector &modified(const TopoDS_Shape &) const { + return _res; + } + }; + /** Make a compound shape * * @param shapes: input shapes @@ -629,6 +650,41 @@ public: */ TopoShape &makeElementCompound(const std::vector &shapes, const char *op=nullptr, bool force=true); + struct BRepFillingParams; + + /** Provides information about the continuity of a curve. + * Corresponds to OCCT type GeomAbs_Shape + */ + enum class Continuity { + /// Only geometric continuity + C0, + /** for each point on the curve, the tangent vectors 'on the right' and 'on + * the left' are collinear with the same orientation. + */ + G1, + /** Continuity of the first derivative. The 'C1' curve is also 'G1' but, in + * addition, the tangent vectors 'on the right' and 'on the left' are equal. + */ + C1, + + /** For each point on the curve, the normalized normal vectors 'on the + * right' and 'on the left' are equal. + */ + G2, + + /// Continuity of the second derivative. + C2, + + /// Continuity of the third derivative. + C3, + + /** Continuity of the N-th derivative, whatever is the value given for N + * (infinite order of continuity). Also provides information about the + * continuity of a surface. + */ + CN, + }; + friend class TopoShapeCache; private: diff --git a/src/Mod/Part/App/TopoShapeMapper.cpp b/src/Mod/Part/App/TopoShapeMapper.cpp new file mode 100644 index 0000000000..89ea456a40 --- /dev/null +++ b/src/Mod/Part/App/TopoShapeMapper.cpp @@ -0,0 +1,75 @@ +#include "TopoShapeMapper.h" + +namespace Part +{ + +void ShapeMapper::expand(const TopoDS_Shape &d, std::vector &shapes) +{ + if (d.IsNull()) return; + for(TopExp_Explorer xp(d, TopAbs_FACE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); + for(TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); + for(TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); +} + +void ShapeMapper::populate(bool generated, + const TopTools_ListOfShape &src, + const TopTools_ListOfShape &dst) +{ + for(TopTools_ListIteratorOfListOfShape it(src);it.More();it.Next()) + populate(generated, it.Value(), dst); +} + +void ShapeMapper::populate(bool generated, + const TopoShape &src, + const TopTools_ListOfShape &dst) +{ + if(src.isNull()) + return; + std::vector dstShapes; + for(TopTools_ListIteratorOfListOfShape it(dst);it.More();it.Next()) + expand(it.Value(), dstShapes); + insert(generated, src.getShape(), dstShapes); +} + +void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d) +{ + if (s.IsNull() || d.IsNull()) return; + // Prevent an element shape from being both generated and modified + if (generated) { + if (_modifiedShapes.count(d)) + return; + _generatedShapes.insert(d); + } else { + if( _generatedShapes.count(d)) + return; + _modifiedShapes.insert(d); + } + auto &entry = generated?_generated[s]:_modified[s]; + if(entry.shapeSet.insert(d).second) + entry.shapes.push_back(d); +}; + +void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const std::vector &d) +{ + if (s.IsNull() || d.empty()) return; + auto &entry = generated?_generated[s]:_modified[s]; + for(auto &shape : d) { + // Prevent an element shape from being both generated and modified + if (generated) { + if (_modifiedShapes.count(shape)) + continue; + _generatedShapes.insert(shape); + } else { + if( _generatedShapes.count(shape)) + continue; + _modifiedShapes.insert(shape); + } + if(entry.shapeSet.insert(shape).second) + entry.shapes.push_back(shape); + } +}; + +} diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h new file mode 100644 index 0000000000..736aebc21c --- /dev/null +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -0,0 +1,255 @@ +#include +#include +#include + +#include +#include +#include "TopoShape.h" + +class BRepBuilderAPI_MakeShape; +class BRepTools_History; +class BRepTools_ReShape; +class ShapeFix_Root; + +namespace Part +{ + +/// Shape hasher that ignore orientation +struct ShapeHasher { + inline size_t operator()(const TopoShape &s) const { + return std::hash {}(s.getShape()); + // return TopTools_ShapeMapHasher{}(s.getShape()); + } + inline size_t operator()(const TopoDS_Shape &s) const { + return std::hash {}(s); + } + inline bool operator()(const TopoShape &a, const TopoShape &b) const { + return a.getShape().IsSame(b.getShape()); + } + inline bool operator()(const TopoDS_Shape &a, const TopoDS_Shape &b) const { + return a.IsSame(b); + } + template + static inline void hash_combine(std::size_t& seed, const T& v) + { + // copied from boost::hash_combine + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + } + inline size_t operator()(const std::pair &s) const { + size_t res = std::hash {}(s.first.getShape()); + hash_combine(res, std::hash {}(s.second.getShape())); + return res; + } + inline size_t operator()(const std::pair &s) const { + size_t res = std::hash {}(s.first); + hash_combine(res, std::hash {}(s.second)); + return res; + } + inline bool operator()(const std::pair &a, + const std::pair &b) const { + return a.first.getShape().IsSame(b.first.getShape()) + && a.second.getShape().IsSame(b.second.getShape()); + } + inline bool operator()(const std::pair &a, + const std::pair &b) const { + return a.first.IsSame(b.first) + && a.second.IsSame(b.second); + } +}; + +/** Shape mapper for generic BRepBuilderAPI_MakeShape derived class + * + * Uses BRepBuilderAPI_MakeShape::Modified/Generated() function to extract + * shape history for generating mapped element names + */ +struct PartExport MapperMaker: TopoShape::Mapper { + BRepBuilderAPI_MakeShape &maker; + MapperMaker(BRepBuilderAPI_MakeShape &maker) + :maker(maker) + {} + virtual const std::vector &modified(const TopoDS_Shape &s) const override; + virtual const std::vector &generated(const TopoDS_Shape &s) const override; +}; + +/** Shape mapper for BRepTools_History + * + * Uses BRepTools_History::Modified/Generated() function to extract + * shape history for generating mapped element names + */ +struct PartExport MapperHistory: TopoShape::Mapper { + Handle(BRepTools_History) history; + MapperHistory(const Handle(BRepTools_History) &history); + MapperHistory(const Handle(BRepTools_ReShape) &reshape); + MapperHistory(ShapeFix_Root &fix); + virtual const std::vector &modified(const TopoDS_Shape &s) const override; + virtual const std::vector &generated(const TopoDS_Shape &s) const override; +}; + +/** Shape mapper for user defined shape mapping + */ +struct PartExport ShapeMapper: TopoShape::Mapper { + virtual ~ShapeMapper() noexcept = default; + + /** Populate mapping from a source shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopoShape &src, const TopTools_ListOfShape &dst); + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a list of sub shapes in the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopTools_ListOfShape &src, const TopTools_ListOfShape &dst); + + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a list of sub shapes in the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const std::vector &src, const std::vector &dst) + { + for(auto &s : src) + populate(generated,s,dst); + } + + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a sub shape of the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopoShape &src, const std::vector &dst) + { + if(src.isNull()) + return; + std::vector dstShapes; + for(auto &d : dst) + expand(d.getShape(), dstShapes); + insert(generated, src.getShape(), dstShapes); + } + + /** Expand a shape into faces, edges and vertices + * @params d: shape to expand + * @param shapes: output sub shapes of faces, edges and vertices + */ + void expand(const TopoDS_Shape &d, std::vector &shapes); + + /** Insert a map entry from a sub shape in the source to a list of sub shapes in the new shape + * + * @params generated: whether the sub shapes are generated or modified + * @param s: a sub shape in the source + * @param d: a list of sub shapes in the new shape + */ + void insert(bool generated, const TopoDS_Shape &s, const std::vector &d); + + /** Insert a map entry from a sub shape in the source to a sub shape in the new shape + * + * @params generated: whether the sub shapes are generated or modified + * @param s: a sub shape in the source + * @param d: a list of sub shapes in the new shape + */ + void insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d); + + virtual const std::vector &generated(const TopoDS_Shape &s) const override { + auto iter = _generated.find(s); + if(iter != _generated.end()) + return iter->second.shapes; + return _res; + } + + virtual const std::vector &modified(const TopoDS_Shape &s) const override { + auto iter = _modified.find(s); + if(iter != _modified.end()) + return iter->second.shapes; + return _res; + } + + std::vector shapes; + std::unordered_set shapeSet; + + struct ShapeValue { + std::vector shapes; + std::unordered_set shapeSet; + }; + typedef std::unordered_map ShapeMap; + ShapeMap _generated; + std::unordered_set _generatedShapes; + ShapeMap _modified; + std::unordered_set _modifiedShapes; +}; + +/// Parameters for TopoShape::makEFilledFace() +struct PartExport TopoShape::BRepFillingParams { + /** Optional initial surface to begin the construction of the surface for the filled face. + * + * It is useful if the surface resulting from construction for the + * algorithm is likely to be complex. The support surface of the face + * under construction is computed by a deformation of Surf which satisfies + * the given constraints. The set of bounding edges defines the wire of + * the face. If no initial surface is given, the algorithm computes it + * automatically. If the set of edges is not connected (Free constraint), + * missing edges are automatically computed. Important: the initial + * surface must have orthogonal local coordinates, i.e. partial + * derivatives dS/du and dS/dv must be orthogonal at each point of + * surface. If this condition breaks, distortions of resulting surface are + * possible + */ + TopoShape surface; + /** Optional map from input edge to continutity order. The default + * continuity order is TopoShape::Continuity::C0. + */ + std::unordered_map orders; + /// Optional map from input shape to face used as support + std::unordered_map supports; + /// Optional begin index to the input shapes to be used as the boundary of the filled face. + int boundary_begin = -1; + /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the filled face. + int boundary_end = -1; + /// The energe minimizing criterion degree; + unsigned int degree = 3; + /// The number of points on the curve NbPntsOnCur + unsigned int ptsoncurve = 15; + /// The number of iterations NbIter + unsigned int numiter = 2; + /// The Boolean Anisotropie + bool anisotropy = false; + /// The 2D tolerance Tol2d + double tol2d = 1e-5; + /// The 3D tolerance Tol3d + double tol3d = 1e-4; + /// The angular tolerance TolAng + double tolG1 = 0.01; + /// The tolerance for curvature TolCur + double tolG2 = 0.1; + /// The highest polynomial degree MaxDeg + unsigned int maxdeg = 8; + /** The greatest number of segments MaxSeg. + * + * If the Boolean Anistropie is true, the algorithm's performance is better + * in cases where the ratio of the length U and the length V indicate a + * great difference between the two. In other words, when the surface is, + * for example, extremely long. + */ + unsigned int maxseg = 9; +}; + + +} From f9a4f25048e591c855e612345d5844d3d48e1713 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 16 Jan 2024 19:13:29 -0500 Subject: [PATCH 04/36] Tests for transferred TopoShapeMapper objects --- tests/src/Mod/Part/App/CMakeLists.txt | 1 + tests/src/Mod/Part/App/TopoShapeMapper.cpp | 121 +++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/src/Mod/Part/App/TopoShapeMapper.cpp diff --git a/tests/src/Mod/Part/App/CMakeLists.txt b/tests/src/Mod/Part/App/CMakeLists.txt index f2467f3b12..9c642e65e2 100644 --- a/tests/src/Mod/Part/App/CMakeLists.txt +++ b/tests/src/Mod/Part/App/CMakeLists.txt @@ -15,4 +15,5 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeExpansion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMapper.cpp ) diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp new file mode 100644 index 0000000000..047dd1c3a9 --- /dev/null +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "gtest/gtest.h" +#include "src/App/InitApplication.h" +#include +#include "Mod/Part/App/TopoShapeMapper.h" + +#include +#include +#include +#include +#include +#include +#include + +// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) + +class TopoShapeMapperTest: public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + } + + void SetUp() override + { + _docName = App::GetApplication().getUniqueDocumentName("test"); + App::GetApplication().newDocument(_docName.c_str(), "testUser"); + } + + void TearDown() override + { + App::GetApplication().closeDocument(_docName.c_str()); + } + +private: + std::string _docName; +}; + +TEST_F(TopoShapeMapperTest, shapeHasherTests) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + std::pair pair1(topoShape, topoShape2); + std::pair pair2(topoShape, topoShape); + std::pair pair3(edge, edge2); + std::pair pair4(edge, edge); + struct Part::ShapeHasher hasher; + + // Act + size_t hash1 = hasher(topoShape); + size_t hash2 = hasher(topoShape2); + size_t hash3 = hasher(edge); + size_t hash4 = hasher(edge2); + size_t hash5 = hasher(topoShape, topoShape); + size_t hash6 = hasher(topoShape, topoShape2); + size_t hash7 = hasher(edge, edge); + size_t hash8 = hasher(edge, edge2); + size_t hash9 = hasher(pair1); + size_t hash10 = hasher(pair2); + size_t hash11 = hasher(pair3); + size_t hash12 = hasher(pair4); + size_t hash13 = hasher(pair1, pair1); + size_t hash14 = hasher(pair1, pair2); + size_t hash15 = hasher(pair3, pair3); + size_t hash16 = hasher(pair3, pair4); + + // Assert + EXPECT_EQ(hash1, hash3); + EXPECT_EQ(hash2, hash4); + EXPECT_NE(hash1, hash2); + EXPECT_TRUE(hash5); + EXPECT_FALSE(hash6); + EXPECT_TRUE(hash7); + EXPECT_FALSE(hash8); + EXPECT_EQ(hash9, hash11); + EXPECT_EQ(hash10, hash12); + EXPECT_NE(hash9, hash10); + EXPECT_TRUE(hash13); + EXPECT_FALSE(hash14); + EXPECT_TRUE(hash15); + EXPECT_FALSE(hash16); +} + +TEST_F(TopoShapeMapperTest, mapperMakerTests) +{ + // How can this be tested? +} + +TEST_F(TopoShapeMapperTest, mapperHistoryTests) +{ + // How can this be tested? +} + +TEST_F(TopoShapeMapperTest, shapeMapperTests) +{ + // Arrange + auto mapper = Part::ShapeMapper(); + auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0); + boxMaker1.Build(); + auto box1 = boxMaker1.Shape(); + Part::TopoShape topoShape1 {box1}; + + // Act + auto e = topoShape1.getSubTopoShapes(TopAbs_EDGE); + mapper.populate(false, box1, {e[0], e[1], e[2], e[3]}); + mapper.populate(true, box1, {e[4], e[5], e[6]}); + std::vector vec1 = mapper.modified(box1); + std::vector vec2 = mapper.generated(box1); + + // Assert + EXPECT_EQ(vec1.size(), 4); + EXPECT_EQ(vec2.size(), 3); +} + + +// // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) From 7d67c319eca93e16ec5544dcdcdebec6d19a0c04 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Tue, 16 Jan 2024 22:43:39 -0500 Subject: [PATCH 05/36] Restore RT hash code for OCC < 7.8.0 --- src/Mod/Part/App/TopoShapeMapper.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index 736aebc21c..f7f4a8e92a 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include "TopoShape.h" @@ -17,11 +18,18 @@ namespace Part /// Shape hasher that ignore orientation struct ShapeHasher { inline size_t operator()(const TopoShape &s) const { +#if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s.getShape()); - // return TopTools_ShapeMapHasher{}(s.getShape()); +#else + return s.getShape().HashCode(INT_MAX); +#endif } inline size_t operator()(const TopoDS_Shape &s) const { +#if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s); +#else + return s.HashCode(INT_MAX); +#endif } inline bool operator()(const TopoShape &a, const TopoShape &b) const { return a.getShape().IsSame(b.getShape()); @@ -37,13 +45,23 @@ struct ShapeHasher { seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } inline size_t operator()(const std::pair &s) const { +#if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first.getShape()); hash_combine(res, std::hash {}(s.second.getShape())); +#else + size_t res = s.first.getShape().HashCode(INT_MAX); + hash_combine(res, s.second.getShape().HashCode(INT_MAX)); +#endif return res; } inline size_t operator()(const std::pair &s) const { +#if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first); hash_combine(res, std::hash {}(s.second)); +#else + size_t res = s.first.HashCode(INT_MAX); + hash_combine(res, s.second.HashCode(INT_MAX)); +#endif return res; } inline bool operator()(const std::pair &a, From 969090b844226c6c21f8ad8e30bb251353fd12bd Mon Sep 17 00:00:00 2001 From: bgbsww Date: Wed, 17 Jan 2024 08:55:16 -0500 Subject: [PATCH 06/36] Move MapperMaker and MapperHistory out to future PR --- src/Mod/Part/App/TopoShapeMapper.h | 28 ---------------------- tests/src/Mod/Part/App/TopoShapeMapper.cpp | 12 +--------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index f7f4a8e92a..89080ae46e 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -76,34 +76,6 @@ struct ShapeHasher { } }; -/** Shape mapper for generic BRepBuilderAPI_MakeShape derived class - * - * Uses BRepBuilderAPI_MakeShape::Modified/Generated() function to extract - * shape history for generating mapped element names - */ -struct PartExport MapperMaker: TopoShape::Mapper { - BRepBuilderAPI_MakeShape &maker; - MapperMaker(BRepBuilderAPI_MakeShape &maker) - :maker(maker) - {} - virtual const std::vector &modified(const TopoDS_Shape &s) const override; - virtual const std::vector &generated(const TopoDS_Shape &s) const override; -}; - -/** Shape mapper for BRepTools_History - * - * Uses BRepTools_History::Modified/Generated() function to extract - * shape history for generating mapped element names - */ -struct PartExport MapperHistory: TopoShape::Mapper { - Handle(BRepTools_History) history; - MapperHistory(const Handle(BRepTools_History) &history); - MapperHistory(const Handle(BRepTools_ReShape) &reshape); - MapperHistory(ShapeFix_Root &fix); - virtual const std::vector &modified(const TopoDS_Shape &s) const override; - virtual const std::vector &generated(const TopoDS_Shape &s) const override; -}; - /** Shape mapper for user defined shape mapping */ struct PartExport ShapeMapper: TopoShape::Mapper { diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp index 047dd1c3a9..6f23f19b8d 100644 --- a/tests/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -86,16 +86,6 @@ TEST_F(TopoShapeMapperTest, shapeHasherTests) EXPECT_FALSE(hash16); } -TEST_F(TopoShapeMapperTest, mapperMakerTests) -{ - // How can this be tested? -} - -TEST_F(TopoShapeMapperTest, mapperHistoryTests) -{ - // How can this be tested? -} - TEST_F(TopoShapeMapperTest, shapeMapperTests) { // Arrange @@ -118,4 +108,4 @@ TEST_F(TopoShapeMapperTest, shapeMapperTests) } -// // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) +// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) From 21b7da61b3f27c8041a5df3d4121165566676922 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Thu, 18 Jan 2024 11:46:15 -0500 Subject: [PATCH 07/36] Lint and other cleanups --- src/Mod/Part/App/TopoShapeMapper.cpp | 132 ++++++++++++--------- src/Mod/Part/App/TopoShapeMapper.h | 126 ++++++++++++-------- tests/src/Mod/Part/App/TopoShapeMapper.cpp | 89 ++++++++++---- 3 files changed, 222 insertions(+), 125 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.cpp b/src/Mod/Part/App/TopoShapeMapper.cpp index 89ea456a40..69f9653d18 100644 --- a/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/src/Mod/Part/App/TopoShapeMapper.cpp @@ -3,73 +3,95 @@ namespace Part { -void ShapeMapper::expand(const TopoDS_Shape &d, std::vector &shapes) +void ShapeMapper::expand(const TopoDS_Shape& d, std::vector& shapes) { - if (d.IsNull()) return; - for(TopExp_Explorer xp(d, TopAbs_FACE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); - for(TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); - for(TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); -} - -void ShapeMapper::populate(bool generated, - const TopTools_ListOfShape &src, - const TopTools_ListOfShape &dst) -{ - for(TopTools_ListIteratorOfListOfShape it(src);it.More();it.Next()) - populate(generated, it.Value(), dst); -} - -void ShapeMapper::populate(bool generated, - const TopoShape &src, - const TopTools_ListOfShape &dst) -{ - if(src.isNull()) + if (d.IsNull()) { return; - std::vector dstShapes; - for(TopTools_ListIteratorOfListOfShape it(dst);it.More();it.Next()) - expand(it.Value(), dstShapes); - insert(generated, src.getShape(), dstShapes); + } + for (TopExp_Explorer xp(d, TopAbs_FACE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } + for (TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } + for (TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } } -void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d) +void ShapeMapper::populate(MappingStatus status, + const TopTools_ListOfShape& src, + const TopTools_ListOfShape& dst) { - if (s.IsNull() || d.IsNull()) return; + for (TopTools_ListIteratorOfListOfShape it(src); it.More(); it.Next()) { + populate(status, it.Value(), dst); + } +} + +void ShapeMapper::populate(MappingStatus status, + const TopoShape& src, + const TopTools_ListOfShape& dst) +{ + if (src.isNull()) { + return; + } + std::vector dstShapes; + for (TopTools_ListIteratorOfListOfShape it(dst); it.More(); it.Next()) { + expand(it.Value(), dstShapes); + } + insert(status, src.getShape(), dstShapes); +} + +void ShapeMapper::insert(MappingStatus status, const TopoDS_Shape& s, const TopoDS_Shape& d) +{ + if (s.IsNull() || d.IsNull()) { + return; + } // Prevent an element shape from being both generated and modified - if (generated) { - if (_modifiedShapes.count(d)) + if (status == MappingStatus::Generated) { + if (_modifiedShapes.count(d)) { return; + } _generatedShapes.insert(d); - } else { - if( _generatedShapes.count(d)) + } + else { + if (_generatedShapes.count(d)) { return; + } _modifiedShapes.insert(d); } - auto &entry = generated?_generated[s]:_modified[s]; - if(entry.shapeSet.insert(d).second) + auto& entry = (status == MappingStatus::Generated) ? _generated[s] : _modified[s]; + if (entry.shapeSet.insert(d).second) { entry.shapes.push_back(d); -}; - -void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const std::vector &d) -{ - if (s.IsNull() || d.empty()) return; - auto &entry = generated?_generated[s]:_modified[s]; - for(auto &shape : d) { - // Prevent an element shape from being both generated and modified - if (generated) { - if (_modifiedShapes.count(shape)) - continue; - _generatedShapes.insert(shape); - } else { - if( _generatedShapes.count(shape)) - continue; - _modifiedShapes.insert(shape); - } - if(entry.shapeSet.insert(shape).second) - entry.shapes.push_back(shape); } }; -} +void ShapeMapper::insert(MappingStatus status, + const TopoDS_Shape& s, + const std::vector& d) +{ + if (s.IsNull() || d.empty()) { + return; + } + auto& entry = (status == MappingStatus::Generated) ? _generated[s] : _modified[s]; + for (auto& shape : d) { + // Prevent an element shape from being both generated and modified + if (status == MappingStatus::Generated) { + if (_modifiedShapes.count(shape)) { + continue; + } + _generatedShapes.insert(shape); + } + else { + if (_generatedShapes.count(shape)) { + continue; + } + _modifiedShapes.insert(shape); + } + if (entry.shapeSet.insert(shape).second) { + entry.shapes.push_back(shape); + } + } +}; + +} // namespace Part diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index 89080ae46e..5b67c4deb2 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -12,39 +12,45 @@ class BRepTools_History; class BRepTools_ReShape; class ShapeFix_Root; -namespace Part +namespace Part { /// Shape hasher that ignore orientation -struct ShapeHasher { - inline size_t operator()(const TopoShape &s) const { +struct ShapeHasher +{ + inline size_t operator()(const TopoShape& s) const + { #if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s.getShape()); #else return s.getShape().HashCode(INT_MAX); #endif } - inline size_t operator()(const TopoDS_Shape &s) const { + inline size_t operator()(const TopoDS_Shape& s) const + { #if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s); #else return s.HashCode(INT_MAX); #endif } - inline bool operator()(const TopoShape &a, const TopoShape &b) const { + inline bool operator()(const TopoShape& a, const TopoShape& b) const + { return a.getShape().IsSame(b.getShape()); } - inline bool operator()(const TopoDS_Shape &a, const TopoDS_Shape &b) const { + inline bool operator()(const TopoDS_Shape& a, const TopoDS_Shape& b) const + { return a.IsSame(b); } - template + template static inline void hash_combine(std::size_t& seed, const T& v) { // copied from boost::hash_combine std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } - inline size_t operator()(const std::pair &s) const { + inline size_t operator()(const std::pair& s) const + { #if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first.getShape()); hash_combine(res, std::hash {}(s.second.getShape())); @@ -54,7 +60,8 @@ struct ShapeHasher { #endif return res; } - inline size_t operator()(const std::pair &s) const { + inline size_t operator()(const std::pair& s) const + { #if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first); hash_combine(res, std::hash {}(s.second)); @@ -64,130 +71,150 @@ struct ShapeHasher { #endif return res; } - inline bool operator()(const std::pair &a, - const std::pair &b) const { + inline bool operator()(const std::pair& a, + const std::pair& b) const + { return a.first.getShape().IsSame(b.first.getShape()) && a.second.getShape().IsSame(b.second.getShape()); } - inline bool operator()(const std::pair &a, - const std::pair &b) const { - return a.first.IsSame(b.first) - && a.second.IsSame(b.second); + inline bool operator()(const std::pair& a, + const std::pair& b) const + { + return a.first.IsSame(b.first) && a.second.IsSame(b.second); } }; +enum class MappingStatus +{ + Generated, + Modified +}; /** Shape mapper for user defined shape mapping */ -struct PartExport ShapeMapper: TopoShape::Mapper { +struct PartExport ShapeMapper: TopoShape::Mapper +{ virtual ~ShapeMapper() noexcept = default; /** Populate mapping from a source shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopoShape &src, const TopTools_ListOfShape &dst); + void populate(MappingStatus status, const TopoShape& src, const TopTools_ListOfShape& dst); /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a list of sub shapes in the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopTools_ListOfShape &src, const TopTools_ListOfShape &dst); + void populate(MappingStatus status, + const TopTools_ListOfShape& src, + const TopTools_ListOfShape& dst); /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a list of sub shapes in the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const std::vector &src, const std::vector &dst) + void populate(MappingStatus status, + const std::vector& src, + const std::vector& dst) { - for(auto &s : src) - populate(generated,s,dst); + for (auto& s : src) { + populate(status, s, dst); + } } /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a sub shape of the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopoShape &src, const std::vector &dst) + void populate(MappingStatus status, const TopoShape& src, const std::vector& dst) { - if(src.isNull()) + if (src.isNull()) { return; + } std::vector dstShapes; - for(auto &d : dst) + for (auto& d : dst) { expand(d.getShape(), dstShapes); - insert(generated, src.getShape(), dstShapes); + } + insert(status, src.getShape(), dstShapes); } /** Expand a shape into faces, edges and vertices * @params d: shape to expand * @param shapes: output sub shapes of faces, edges and vertices */ - void expand(const TopoDS_Shape &d, std::vector &shapes); + void expand(const TopoDS_Shape& d, std::vector& shapes); /** Insert a map entry from a sub shape in the source to a list of sub shapes in the new shape * - * @params generated: whether the sub shapes are generated or modified + * @params status: whether the sub shapes are generated or modified * @param s: a sub shape in the source * @param d: a list of sub shapes in the new shape */ - void insert(bool generated, const TopoDS_Shape &s, const std::vector &d); + void insert(MappingStatus status, const TopoDS_Shape& s, const std::vector& d); /** Insert a map entry from a sub shape in the source to a sub shape in the new shape * - * @params generated: whether the sub shapes are generated or modified + * @params status: whether the sub shapes are generated or modified * @param s: a sub shape in the source * @param d: a list of sub shapes in the new shape */ - void insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d); + void insert(MappingStatus status, const TopoDS_Shape& s, const TopoDS_Shape& d); - virtual const std::vector &generated(const TopoDS_Shape &s) const override { + const std::vector& generated(const TopoDS_Shape& s) const override + { auto iter = _generated.find(s); - if(iter != _generated.end()) + if (iter != _generated.end()) { return iter->second.shapes; + } return _res; } - virtual const std::vector &modified(const TopoDS_Shape &s) const override { + const std::vector& modified(const TopoDS_Shape& s) const override + { auto iter = _modified.find(s); - if(iter != _modified.end()) + if (iter != _modified.end()) { return iter->second.shapes; + } return _res; } std::vector shapes; - std::unordered_set shapeSet; + std::unordered_set shapeSet; - struct ShapeValue { + struct ShapeValue + { std::vector shapes; - std::unordered_set shapeSet; + std::unordered_set shapeSet; }; - typedef std::unordered_map ShapeMap; + typedef std::unordered_map ShapeMap; ShapeMap _generated; - std::unordered_set _generatedShapes; + std::unordered_set _generatedShapes; ShapeMap _modified; - std::unordered_set _modifiedShapes; + std::unordered_set _modifiedShapes; }; -/// Parameters for TopoShape::makEFilledFace() -struct PartExport TopoShape::BRepFillingParams { +/// Parameters for TopoShape::makeElementFilledFace() +struct PartExport TopoShape::BRepFillingParams +{ /** Optional initial surface to begin the construction of the surface for the filled face. * * It is useful if the surface resulting from construction for the @@ -211,7 +238,8 @@ struct PartExport TopoShape::BRepFillingParams { std::unordered_map supports; /// Optional begin index to the input shapes to be used as the boundary of the filled face. int boundary_begin = -1; - /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the filled face. + /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the + /// filled face. int boundary_end = -1; /// The energe minimizing criterion degree; unsigned int degree = 3; @@ -242,4 +270,4 @@ struct PartExport TopoShape::BRepFillingParams { }; -} +} // namespace Part diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp index 6f23f19b8d..88c8fa18f6 100644 --- a/tests/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -38,7 +38,50 @@ private: std::string _docName; }; -TEST_F(TopoShapeMapperTest, shapeHasherTests) +TEST_F(TopoShapeMapperTest, shapeHasherSingle) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + struct Part::ShapeHasher hasher; + + // Act + size_t hash1 = hasher(topoShape); + size_t hash2 = hasher(topoShape2); + size_t hash3 = hasher(edge); + size_t hash4 = hasher(edge2); + + // Assert + EXPECT_EQ(hash1, hash3); + EXPECT_EQ(hash2, hash4); + EXPECT_NE(hash1, hash2); +} + +TEST_F(TopoShapeMapperTest, shapeHasherDual) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + struct Part::ShapeHasher hasher; + + // Act + size_t hash5 = hasher(topoShape, topoShape); + size_t hash6 = hasher(topoShape, topoShape2); + size_t hash7 = hasher(edge, edge); + size_t hash8 = hasher(edge, edge2); + + // Assert + EXPECT_TRUE(hash5); + EXPECT_FALSE(hash6); + EXPECT_TRUE(hash7); + EXPECT_FALSE(hash8); +} + +TEST_F(TopoShapeMapperTest, shapeHasherPair) { // Arrange auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); @@ -52,40 +95,44 @@ TEST_F(TopoShapeMapperTest, shapeHasherTests) struct Part::ShapeHasher hasher; // Act - size_t hash1 = hasher(topoShape); - size_t hash2 = hasher(topoShape2); - size_t hash3 = hasher(edge); - size_t hash4 = hasher(edge2); - size_t hash5 = hasher(topoShape, topoShape); - size_t hash6 = hasher(topoShape, topoShape2); - size_t hash7 = hasher(edge, edge); - size_t hash8 = hasher(edge, edge2); size_t hash9 = hasher(pair1); size_t hash10 = hasher(pair2); size_t hash11 = hasher(pair3); size_t hash12 = hasher(pair4); + + // Assert + EXPECT_EQ(hash9, hash11); + EXPECT_EQ(hash10, hash12); + EXPECT_NE(hash9, hash10); +} + +TEST_F(TopoShapeMapperTest, shapeHasherPairs) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + std::pair pair1(topoShape, topoShape2); + std::pair pair2(topoShape, topoShape); + std::pair pair3(edge, edge2); + std::pair pair4(edge, edge); + struct Part::ShapeHasher hasher; + + // Act size_t hash13 = hasher(pair1, pair1); size_t hash14 = hasher(pair1, pair2); size_t hash15 = hasher(pair3, pair3); size_t hash16 = hasher(pair3, pair4); // Assert - EXPECT_EQ(hash1, hash3); - EXPECT_EQ(hash2, hash4); - EXPECT_NE(hash1, hash2); - EXPECT_TRUE(hash5); - EXPECT_FALSE(hash6); - EXPECT_TRUE(hash7); - EXPECT_FALSE(hash8); - EXPECT_EQ(hash9, hash11); - EXPECT_EQ(hash10, hash12); - EXPECT_NE(hash9, hash10); EXPECT_TRUE(hash13); EXPECT_FALSE(hash14); EXPECT_TRUE(hash15); EXPECT_FALSE(hash16); } + TEST_F(TopoShapeMapperTest, shapeMapperTests) { // Arrange @@ -97,8 +144,8 @@ TEST_F(TopoShapeMapperTest, shapeMapperTests) // Act auto e = topoShape1.getSubTopoShapes(TopAbs_EDGE); - mapper.populate(false, box1, {e[0], e[1], e[2], e[3]}); - mapper.populate(true, box1, {e[4], e[5], e[6]}); + mapper.populate(Part::MappingStatus::Modified, box1, {e[0], e[1], e[2], e[3]}); + mapper.populate(Part::MappingStatus::Generated, box1, {e[4], e[5], e[6]}); std::vector vec1 = mapper.modified(box1); std::vector vec2 = mapper.generated(box1); From 64c867eb0e212ce8fd3bf5d52b039b1dd69ba741 Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 16 Jan 2024 15:30:59 +0100 Subject: [PATCH 08/36] Sketcher Fix radius arc helpers. --- .../Gui/EditModeConstraintCoinManager.cpp | 183 ++++++++++-------- .../Gui/EditModeConstraintCoinManager.h | 7 + 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 5dc22f984a..3aa0bedcc4 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -1333,51 +1333,43 @@ Restart: double helperStartAngle = 0.; double helperRange = 0.; - if (Constr->First != GeoEnum::GeoUndef) { - const Part::Geometry* geo = - geolistfacade.getGeometryFromGeoId(Constr->First); + if (Constr->First == GeoEnum::GeoUndef) { + break; + } - if (geo->is()) { - auto* arc = static_cast(geo); - double radius = arc->getRadius(); - double angle = (double)Constr->LabelPosition; - double startAngle, endAngle; - arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); - if (angle == 10) { - angle = (startAngle + endAngle) / 2; - } - if (!(angle > startAngle && angle < endAngle)) { - if (angle < startAngle - && startAngle - angle < angle + 2 * M_PI - endAngle) { - helperStartAngle = angle; - helperRange = startAngle - angle; - } - else { - if (angle < endAngle) { - angle += 2 * M_PI; - } - helperStartAngle = endAngle; - helperRange = angle - endAngle; - } - } - Base::Vector3d center = arc->getCenter(); - pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); - pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); + + if (geo->is()) { + auto* arc = static_cast(geo); + double radius = arc->getRadius(); + double angle = (double)Constr->LabelPosition; // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + if (angle == 10) { + angle = (startAngle + endAngle) / 2; } - else if (geo->is()) { - auto* circle = static_cast(geo); - double radius = circle->getRadius(); - double angle = (double)Constr->LabelPosition; - if (angle == 10) { - angle = 0; - } - Base::Vector3d center = circle->getCenter(); - pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); - pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); - } - else { - break; + + findHelperAngles(helperStartAngle, + helperRange, + angle, + startAngle, + endAngle); + + Base::Vector3d center = arc->getCenter(); + pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); + pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + } + else if (geo->is()) { + auto* circle = static_cast(geo); + double radius = circle->getRadius(); + double angle = (double)Constr->LabelPosition; + if (angle == 10) { + angle = 0; } + Base::Vector3d center = circle->getCenter(); + pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); + pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); } else { break; @@ -1415,54 +1407,45 @@ Restart: double helperStartAngle = 0.; double helperRange = 0.; - if (Constr->First != GeoEnum::GeoUndef) { - const Part::Geometry* geo = - geolistfacade.getGeometryFromGeoId(Constr->First); + if (Constr->First == GeoEnum::GeoUndef) { + break; + } + const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); - if (geo->is()) { - auto* arc = static_cast(geo); - double radius = arc->getRadius(); - double angle = (double)Constr->LabelPosition; - double startAngle, endAngle; - arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); - if (angle == 10) { - angle = (startAngle + endAngle) / 2; - } - if (!(angle > startAngle && angle < endAngle)) { - if (angle < startAngle - && startAngle - angle < angle + 2 * M_PI - endAngle) { - helperStartAngle = angle; - helperRange = startAngle - angle; - } - else { - if (angle < endAngle) { - angle += 2 * M_PI; - } - helperStartAngle = endAngle; - helperRange = angle - endAngle; - } - } - pnt1 = arc->getCenter(); - pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + if (geo->is()) { + auto* arc = static_cast(geo); + double radius = arc->getRadius(); + double angle = (double)Constr->LabelPosition; // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + if (angle == 10) { + angle = (startAngle + endAngle) / 2; } - else if (geo->is()) { - auto* circle = static_cast(geo); - auto gf = GeometryFacade::getFacade(geo); - double radius; + findHelperAngles(helperStartAngle, + helperRange, + angle, + startAngle, + endAngle); - radius = circle->getRadius(); + pnt1 = arc->getCenter(); + pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + } + else if (geo->is()) { + auto* circle = static_cast(geo); + auto gf = GeometryFacade::getFacade(geo); - double angle = (double)Constr->LabelPosition; - if (angle == 10) { - angle = 0; - } - pnt1 = circle->getCenter(); - pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); - } - else { - break; + double radius; + + radius = circle->getRadius(); + + double angle = (double)Constr->LabelPosition; + if (angle == 10) { + angle = 0; } + pnt1 = circle->getCenter(); + pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); } else { break; @@ -1518,6 +1501,38 @@ Restart: } } +void EditModeConstraintCoinManager::findHelperAngles(double& helperStartAngle, + double& helperRange, + double angle, + double startAngle, + double endAngle) +{ + if (angle < 0) { + angle = angle + 2 * M_PI; + } + // endAngle can be more than 2*pi as its startAngle + arcAngle + if (endAngle > 2 * M_PI && angle < endAngle - 2 * M_PI) { + angle = angle + 2 * M_PI; + } + if (!(angle > startAngle && angle < endAngle)) { + if ((angle < startAngle && startAngle - angle < angle + 2 * M_PI - endAngle) + || (angle > endAngle && startAngle + 2 * M_PI - angle < angle - endAngle)) { + if (angle > startAngle) { + angle -= 2 * M_PI; + } + helperStartAngle = angle; + helperRange = startAngle - angle; + } + else { + if (angle < endAngle) { + angle += 2 * M_PI; + } + helperStartAngle = endAngle; + helperRange = angle - endAngle; + } + } +} + Base::Vector3d EditModeConstraintCoinManager::seekConstraintPosition(const Base::Vector3d& origPos, const Base::Vector3d& norm, const Base::Vector3d& dir, diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h index 657bd6adbb..8db7b6d798 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h @@ -250,6 +250,13 @@ private: /// Essentially a version of sendConstraintIconToCoin, with a blank icon void clearCoinImage(SoImage* soImagePtr); + + /// Find helper angle for radius/diameter constraint + void findHelperAngles(double& helperStartAngle, + double& helperAngle, + double angle, + double startAngle, + double endAngle); //@} private: From dca00ec80eff5002995ed03cf19d6ba715346e04 Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 16 Jan 2024 15:58:08 +0100 Subject: [PATCH 09/36] Sketcher : improve single line angle rendering. --- src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 3aa0bedcc4..2e7d05e6a4 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -1281,18 +1281,20 @@ Restart: const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); if (geo->is()) { - const Part::GeomLineSegment* lineSeg = - static_cast(geo); + auto* lineSeg = static_cast(geo); p0 = Base::convertTo( (lineSeg->getEndPoint() + lineSeg->getStartPoint()) / 2); + double l1 = 2 * distance + - (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length() / 2; + endLineLength1 = 2 * distance; + endLineLength2 = l1 > 0. ? l1 : 0.; Base::Vector3d dir = lineSeg->getEndPoint() - lineSeg->getStartPoint(); startangle = 0.; range = atan2(dir.y, dir.x); } else if (geo->is()) { - const Part::GeomArcOfCircle* arc = - static_cast(geo); + auto* arc = static_cast(geo); p0 = Base::convertTo(arc->getCenter()); double endangle; From df867a25b29158261149097c5681eed199b17d9c Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 16 Jan 2024 16:09:13 +0100 Subject: [PATCH 10/36] Sketcher : arc angle render improvement. --- src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 2e7d05e6a4..8c32200450 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -1297,6 +1297,9 @@ Restart: auto* arc = static_cast(geo); p0 = Base::convertTo(arc->getCenter()); + endLineLength1 = 2 * distance - arc->getRadius(); + endLineLength2 = endLineLength1; + double endangle; arc->getRange(startangle, endangle, /*emulateCCWXY=*/true); range = endangle - startangle; From b818be7d5dd426bb6d846ae2c46bc57abc82634e Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 16 Jan 2024 17:59:38 +0100 Subject: [PATCH 11/36] SoDatumLabel : introduce distance arc helpers. --- src/Gui/SoDatumLabel.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/Gui/SoDatumLabel.h | 3 +++ 2 files changed, 43 insertions(+) diff --git a/src/Gui/SoDatumLabel.cpp b/src/Gui/SoDatumLabel.cpp index 2e2b44b3c4..52f1823317 100644 --- a/src/Gui/SoDatumLabel.cpp +++ b/src/Gui/SoDatumLabel.cpp @@ -93,6 +93,9 @@ SoDatumLabel::SoDatumLabel() SO_NODE_ADD_FIELD(param2, (0.f)); SO_NODE_ADD_FIELD(param4, (0.f)); SO_NODE_ADD_FIELD(param5, (0.f)); + SO_NODE_ADD_FIELD(param6, (0.f)); + SO_NODE_ADD_FIELD(param7, (0.f)); + SO_NODE_ADD_FIELD(param8, (0.f)); useAntialiasing = true; @@ -989,6 +992,43 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) glVertex2f(ar3[0], ar3[1]); glVertex2f(ar4[0], ar4[1]); glEnd(); + + + if (this->datumtype.getValue() == DISTANCE) { + // Draw arc helpers if needed + float range1 = this->param4.getValue(); + if (range1 != 0.0) { + float startangle1 = this->param3.getValue(); + float radius1 = this->param5.getValue(); + SbVec3f center = points[2]; + int countSegments = std::max(6, abs(int(50.0 * range1 / (2 * M_PI)))); + double segment = range1 / (countSegments - 1); + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < countSegments; i++) { + double theta = startangle1 + segment * i; + SbVec3f v1 = center + SbVec3f(radius1 * cos(theta), radius1 * sin(theta), 0); + glVertex2f(v1[0], v1[1]); + } + glEnd(); + } + float range2 = this->param7.getValue(); + if (range2 != 0.0) { + float startangle2 = this->param6.getValue(); + float radius2 = this->param8.getValue(); + SbVec3f center = points[3]; + int countSegments = std::max(6, abs(int(50.0 * range2 / (2 * M_PI)))); + double segment = range2 / (countSegments - 1); + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < countSegments; i++) { + double theta = startangle2 + segment * i; + SbVec3f v1 = center + SbVec3f(radius2 * cos(theta), radius2 * sin(theta), 0); + glVertex2f(v1[0], v1[1]); + } + glEnd(); + } + } } else if (this->datumtype.getValue() == RADIUS || this->datumtype.getValue() == DIAMETER) { // Get the Points diff --git a/src/Gui/SoDatumLabel.h b/src/Gui/SoDatumLabel.h index 077069236a..2e55ffeb8e 100644 --- a/src/Gui/SoDatumLabel.h +++ b/src/Gui/SoDatumLabel.h @@ -77,6 +77,9 @@ public: SoSFFloat param3; SoSFFloat param4; SoSFFloat param5; + SoSFFloat param6; + SoSFFloat param7; + SoSFFloat param8; SoMFVec3f pnts; SoSFVec3f norm; SoSFImage image; From fd2e35b7eb74c2dfde77dafaafbde24dbe7ebe90 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sun, 26 Nov 2023 07:50:02 +0100 Subject: [PATCH 12/36] Sketcher: Add copy/cut/paste sketcher commands --- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 260 ++++++++++++++++++ src/Mod/Sketcher/Gui/ShortcutListener.cpp | 8 +- src/Mod/Sketcher/Gui/ShortcutListener.h | 9 - src/Mod/Sketcher/Gui/ViewProviderSketch.h | 5 +- src/Mod/Sketcher/Gui/Workbench.cpp | 6 +- 5 files changed, 267 insertions(+), 21 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index c08e135aa2..2fc791558f 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -33,6 +34,8 @@ #include #include +#include +#include #include #include #include @@ -140,6 +143,260 @@ Sketcher::SketchObject* getSketchObject() // ================================================================================ +// Copy + +bool copySelectionToClipboard() { + + std::vector selection = Gui::Command::getSelection().getSelectionEx(); + Sketcher::SketchObject* obj = static_cast(selection[0].getObject()); + // only one sketch with its subelements are allowed to be selected + if (selection.size() != 1) { return false; } + std::vector SubNames = selection[0].getSubNames(); + if (SubNames.empty()) { return false; } + + //First we need listOfGeoId and sort them. + std::vector listOfGeoId; + for (std::vector::const_iterator it = SubNames.begin(); it != SubNames.end(); ++it) { + int GeoId = -1; + // only handle non-external edges + if (it->size() > 4 && it->substr(0, 4) == "Edge") { + GeoId = std::atoi(it->substr(4, 4000).c_str()) - 1; + if (GeoId >= 0) { + listOfGeoId.push_back(GeoId); + } + } + else if (it->size() > 6 && it->substr(0, 6) == "Vertex") { + // only if it is a GeomPoint + int VtId = std::atoi(it->substr(6, 4000).c_str()) - 1; + Sketcher::PointPos PosId; + obj->getGeoVertexIndex(VtId, GeoId, PosId); + if (obj->getGeometry(GeoId)->getTypeId() == Part::GeomPoint::getClassTypeId()) { + if (GeoId >= 0) { + listOfGeoId.push_back(GeoId); + } + } + } + } + if (listOfGeoId.empty()) { return false; } + sort(listOfGeoId.begin(), listOfGeoId.end()); + + Base::StringWriter writer; + + //Export selected geometries as a formated string. + std::vector< Part::Geometry* > newVals; + for (auto geoId : listOfGeoId) { + Part::Geometry* geoNew = obj->getGeometry(geoId)->copy(); + newVals.push_back(geoNew); + } + Part::PropertyGeometryList geoToCopy; + geoToCopy.setValues(std::move(newVals)); + geoToCopy.Save(writer); + + //add constraints to the stream string. + std::vector< Sketcher::Constraint* > newConstrVals; + for (auto constr : obj->Constraints.getValues()) { + + auto isSelectedGeoOrAxis = [](const std::vector& vec, int value) { + return (std::find(vec.begin(), vec.end(), value) != vec.end()) + || value == GeoEnum::GeoUndef || value == GeoEnum::RtPnt + || value == GeoEnum::VAxis || value == GeoEnum::HAxis; + }; + + if (!isSelectedGeoOrAxis(listOfGeoId, constr->First) + || !isSelectedGeoOrAxis(listOfGeoId, constr->Second) + || !isSelectedGeoOrAxis(listOfGeoId, constr->Third)) { + continue; + } + + Constraint* temp = constr->copy(); + for (size_t j = 0; j < listOfGeoId.size(); j++) { + if (temp->First == listOfGeoId[j]) { + temp->First = j; + } + if (temp->Second == listOfGeoId[j]) { + temp->Second = j; + } + if (temp->Third == listOfGeoId[j]) { + temp->Third = j; + } + } + newConstrVals.push_back(temp); + } + Sketcher::PropertyConstraintList constToCopy; + constToCopy.setValues(std::move(newConstrVals)); + constToCopy.Save(writer); + + std::string exportedData = writer.getString(); + + if (!exportedData.empty()) { + QClipboard* clipboard = QGuiApplication::clipboard(); + clipboard->setText(QString::fromStdString(exportedData)); + return true; + } + return false; +} + +DEF_STD_CMD_A(CmdSketcherCopyClipboard) + +CmdSketcherCopyClipboard::CmdSketcherCopyClipboard() + : Command("Sketcher_CopyClipboard") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("C&opy in sketcher"); + sToolTipText = QT_TR_NOOP("Copy selected geometries and constraints to the clipboard"); + sWhatsThis = "Sketcher_CopyClipboard"; + sStatusTip = sToolTipText; + sPixmap = "edit-copy"; + sAccel = keySequenceToAccel(QKeySequence::Copy); + eType = ForEdit; +} + +void CmdSketcherCopyClipboard::activated(int iMsg) +{ + Q_UNUSED(iMsg); + copySelectionToClipboard(); +} + +bool CmdSketcherCopyClipboard::isActive() +{ + return isCommandActive(getActiveGuiDocument(), true); +} + +// ================================================================================ + +// Cut + +DEF_STD_CMD_A(CmdSketcherCut) + +CmdSketcherCut::CmdSketcherCut() + : Command("Sketcher_Cut") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("C&ut in sketcher"); + sToolTipText = QT_TR_NOOP("Cut selected geometries and constraints to the clipboard"); + sWhatsThis = "Sketcher_Cut"; + sStatusTip = sToolTipText; + sPixmap = "edit-cut"; + sAccel = keySequenceToAccel(QKeySequence::Cut); + eType = ForEdit; +} + +void CmdSketcherCut::activated(int iMsg) +{ + Q_UNUSED(iMsg); + if (copySelectionToClipboard()) { + + Gui::Document* doc = getActiveGuiDocument(); + ReleaseHandler(doc); + auto* vp = static_cast(doc->getInEdit()); + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Cut in Sketcher")); + vp->deleteSelected(); + Gui::Command::commitCommand(); + } +} + +bool CmdSketcherCut::isActive() +{ + return isCommandActive(getActiveGuiDocument(), true); +} + +// ================================================================================ + +// Paste + +DEF_STD_CMD_A(CmdSketcherPaste) + +CmdSketcherPaste::CmdSketcherPaste() + : Command("Sketcher_Paste") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("P&aste in sketcher"); + sToolTipText = QT_TR_NOOP("Paste selected geometries and constraints from the clipboard"); + sWhatsThis = "Sketcher_Paste"; + sStatusTip = sToolTipText; + sPixmap = "edit-paste"; + sAccel = keySequenceToAccel(QKeySequence::Paste); + eType = ForEdit; +} + +void CmdSketcherPaste::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::Document* doc = getActiveGuiDocument(); + ReleaseHandler(doc); + auto* vp = static_cast(doc->getInEdit()); + Sketcher::SketchObject* Obj = vp->getSketchObject(); + + std::string data = QGuiApplication::clipboard()->text().toStdString(); + int importedFirstGeoId = Obj->getHighestCurveIndex() + 1; + + std::string geoString; + if (data.find("", 0) != std::string::npos) { + geoString = data.substr(0, data.find("", 0) + 16); + } + else { return ; } + + std::istringstream istream(geoString); + Base::XMLReader reader("importingGeo", istream); + Part::PropertyGeometryList geoToCopy; + geoToCopy.Restore(reader); + + const std::vector& geos = geoToCopy.getValues(); + if (geos.empty()) { return; } + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Paste in Sketcher")); + + for (auto geo : geos) { + Part::Geometry* geocopy = geo->copy(); + Obj->addGeometry(geocopy); + } + + if (data.find("copy(); + //update the geoIds of the constraints + if (!isAxisOrRoot(constraintToAdd->First)) { + constraintToAdd->First += importedFirstGeoId; + } + if (!isAxisOrRoot(constraintToAdd->Second)) { + constraintToAdd->Second += importedFirstGeoId; + } + if (!isAxisOrRoot(constraintToAdd->Third)) { + constraintToAdd->Third += importedFirstGeoId; + } + Obj->addConstraint(constraintToAdd); + } + } + + Obj->solve(true); + vp->draw(false, false); // Redraw + + Gui::Command::commitCommand(); +} + +bool CmdSketcherPaste::isActive() +{ + return isCommandActive(getActiveGuiDocument(), false); +} + +// ================================================================================ + // Select Constraints of selected elements DEF_STD_CMD_A(CmdSketcherSelectConstraints) @@ -2432,5 +2689,8 @@ void CreateSketcherCommandsConstraintAccel() rcCmdMgr.addCommand(new CmdSketcherDeleteAllGeometry()); rcCmdMgr.addCommand(new CmdSketcherDeleteAllConstraints()); rcCmdMgr.addCommand(new CmdSketcherRemoveAxesAlignment()); + rcCmdMgr.addCommand(new CmdSketcherCopyClipboard()); + rcCmdMgr.addCommand(new CmdSketcherCut()); + rcCmdMgr.addCommand(new CmdSketcherPaste()); } // clang-format on diff --git a/src/Mod/Sketcher/Gui/ShortcutListener.cpp b/src/Mod/Sketcher/Gui/ShortcutListener.cpp index 805e54f1f4..b161cb4194 100644 --- a/src/Mod/Sketcher/Gui/ShortcutListener.cpp +++ b/src/Mod/Sketcher/Gui/ShortcutListener.cpp @@ -31,12 +31,6 @@ using namespace SketcherGui; -// ******************** ViewProvider attorney *********************************************// -inline void ViewProviderSketchShortcutListenerAttorney::deleteSelected(ViewProviderSketch& vp) -{ - vp.deleteSelected(); -}; - // ******************** ShortcutListener *********************************************// ShortcutListener::ShortcutListener(ViewProviderSketch* vp) { @@ -55,7 +49,7 @@ bool ShortcutListener::eventFilter(QObject* obj, QEvent* event) switch (kevent->key()) { case Qt::Key_Delete: kevent->accept(); - ViewProviderSketchShortcutListenerAttorney::deleteSelected(*pViewProvider); + pViewProvider->deleteSelected(); return true; default: break; diff --git a/src/Mod/Sketcher/Gui/ShortcutListener.h b/src/Mod/Sketcher/Gui/ShortcutListener.h index 414da71fa3..70366adc83 100644 --- a/src/Mod/Sketcher/Gui/ShortcutListener.h +++ b/src/Mod/Sketcher/Gui/ShortcutListener.h @@ -31,15 +31,6 @@ namespace SketcherGui class ViewProviderSketch; -class ViewProviderSketchShortcutListenerAttorney -{ -private: - static inline void deleteSelected(ViewProviderSketch& vp); - - - friend class ShortcutListener; -}; - class ShortcutListener: public QObject { // Q_OBJECT diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index e8e16c5c08..bcadc5bed6 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -672,6 +672,7 @@ public: const Gui::View3DInventorViewer* viewer) override; //@} + void deleteSelected(); /// Control the overlays appearing on the Tree and reflecting different sketcher states QIcon mergeColorfulOverlayIcons(const QIcon& orig) const override; @@ -702,7 +703,6 @@ public: friend class ViewProviderSketchDrawSketchHandlerAttorney; friend class ViewProviderSketchCoinAttorney; friend class ViewProviderSketchSnapAttorney; - friend class ViewProviderSketchShortcutListenerAttorney; //@} protected: /** @name enter/exit edit mode */ @@ -867,9 +867,6 @@ private: bool isConstraintSelected(int constraintId) const; - //********* ViewProviderSketchShortcutListenerAttorney ***********// - void deleteSelected(); - //********* ViewProviderSketchDrawSketchHandlerAttorney **********// void setConstraintSelectability(bool enabled = true); void setPositionText(const Base::Vector2d& Pos, const SbString& txt); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 5c2d74ed2e..c1be2c1ac5 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -543,7 +543,11 @@ inline void SketcherAddWorkbenchTools(Gui::MenuItem& consaccel) << "Sketcher_RemoveAxesAlignment" << "Separator" << "Sketcher_DeleteAllGeometry" - << "Sketcher_DeleteAllConstraints"; + << "Sketcher_DeleteAllConstraints" + << "Separator" + << "Sketcher_CopyClipboard" + << "Sketcher_Cut" + << "Sketcher_Paste"; } template<> From a8b6e1e9c334b394c4205f89d2a9d72bc8962003 Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 11 Jan 2024 18:31:25 +0100 Subject: [PATCH 13/36] Sketcher: python converter : add possibility to add lastGeoId to the constraint process. --- src/Mod/Sketcher/App/PythonConverter.cpp | 318 ++++++++++++++--------- src/Mod/Sketcher/App/PythonConverter.h | 14 +- 2 files changed, 203 insertions(+), 129 deletions(-) diff --git a/src/Mod/Sketcher/App/PythonConverter.cpp b/src/Mod/Sketcher/App/PythonConverter.cpp index d063378161..fe5def95dd 100644 --- a/src/Mod/Sketcher/App/PythonConverter.cpp +++ b/src/Mod/Sketcher/App/PythonConverter.cpp @@ -59,11 +59,11 @@ std::string PythonConverter::convert(const Part::Geometry* geo, Mode mode) return command; } -std::string PythonConverter::convert(const Sketcher::Constraint* constraint) +std::string PythonConverter::convert(const Sketcher::Constraint* constraint, bool useLastGeoIdVar) { // addConstraint(Sketcher.Constraint('Distance',%d,%f)) std::string command; - auto cg = process(constraint); + auto cg = process(constraint, useLastGeoIdVar); command = boost::str(boost::format("addConstraint(%s)\n") % cg); @@ -85,13 +85,13 @@ std::string PythonConverter::convert(const std::string& doc, if (ngeos > 0) { if (construction) { command = boost::str( - boost::format("constrGeoList = []\n%s\n%s.addGeometry(constrGeoList,%s)\ndel " - "constrGeoList") + boost::format("constrGeoList = []\n%s%s.addGeometry(constrGeoList,%s)\n" + "del constrGeoList\n") % geolist % doc % "True"); } else { command = boost::str( - boost::format("geoList = []\n%s\n%s.addGeometry(geoList,%s)\ndel geoList") + boost::format("geoList = []\n%s%s.addGeometry(geoList,%s)\ndel geoList\n") % geolist % doc % "False"); } } @@ -134,10 +134,10 @@ std::string PythonConverter::convert(const std::string& doc, if (sg.construction) { geolist = - boost::str(boost::format("%s\nconstrGeoList.append(%s)\n") % geolist % sg.creation); + boost::str(boost::format("%sconstrGeoList.append(%s)\n") % geolist % sg.creation); } else { - geolist = boost::str(boost::format("%s\ngeoList.append(%s)\n") % geolist % sg.creation); + geolist = boost::str(boost::format("%sgeoList.append(%s)\n") % geolist % sg.creation); } ngeos++; @@ -165,7 +165,8 @@ std::string PythonConverter::convert(const std::string& doc, } std::string PythonConverter::convert(const std::string& doc, - const std::vector& constraints) + const std::vector& constraints, + bool useLastGeoIdVar) { if (constraints.size() == 1) { auto cg = convert(constraints[0]); @@ -176,7 +177,7 @@ std::string PythonConverter::convert(const std::string& doc, std::string constraintlist = "constraintList = []"; for (auto constraint : constraints) { - auto cg = process(constraint); + auto cg = process(constraint, useLastGeoIdVar); constraintlist = boost::str(boost::format("%s\nconstraintList.append(%s)") % constraintlist % cg); @@ -200,7 +201,8 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g auto sgeo = static_cast(geo); SingleGeometry sg; sg.creation = boost::str( - boost::format("Part.LineSegment(App.Vector(%f,%f,%f),App.Vector(%f,%f,%f))") + boost::format( + "Part.LineSegment(App.Vector(%f, %f, %f),App.Vector(%f, %f, %f))") % sgeo->getStartPoint().x % sgeo->getStartPoint().y % sgeo->getStartPoint().z % sgeo->getEndPoint().x % sgeo->getEndPoint().y % sgeo->getEndPoint().z); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); @@ -225,7 +227,7 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g auto sgeo = static_cast(geo); SingleGeometry sg; sg.creation = - boost::str(boost::format("Part.Point(App.Vector(%f,%f,%f))") + boost::str(boost::format("Part.Point(App.Vector(%f, %f, %f))") % sgeo->getPoint().x % sgeo->getPoint().y % sgeo->getPoint().z); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; @@ -309,10 +311,10 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g controlpoints.append(1, ']'); SingleGeometry sg; - sg.creation = - boost::str(boost::format("Part.BSplineCurve (%s,None,None,%s,%d,None,False)") - % controlpoints.c_str() % (bSpline->isPeriodic() ? "True" : "False") - % bSpline->getDegree()); + sg.creation = boost::str( + boost::format("Part.BSplineCurve (%s, None, None, %s, %d, None, False)") + % controlpoints.c_str() % (bSpline->isPeriodic() ? "True" : "False") + % bSpline->getDegree()); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, @@ -342,128 +344,158 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g return creator(geo); } -std::string PythonConverter::process(const Sketcher::Constraint* constraint) +std::string PythonConverter::process(const Sketcher::Constraint* constraint, bool useLastIdVar) { - static std::map> + std::string geoId1 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->First); + std::string geoId2 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Second); + std::string geoId3 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Third); + + static std::map< + const Sketcher::ConstraintType, + std::function< + std::string(const Sketcher::Constraint*, std::string&, std::string&, std::string&)>> converterMap = { {Sketcher::Coincident, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { return boost::str( - boost::format("Sketcher.Constraint('Coincident', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Coincident', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); }}, {Sketcher::Horizontal, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('Horizontal', %i)") - % constr->First); + return boost::str(boost::format("Sketcher.Constraint('Horizontal', %s)") + % geoId1); } else { return boost::str( - boost::format("Sketcher.Constraint('Horizontal', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Horizontal', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Vertical, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('Vertical', %i)") - % constr->First); + return boost::str(boost::format("Sketcher.Constraint('Vertical', %s)") + % geoId1); } else { return boost::str( - boost::format("Sketcher.Constraint('Vertical', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Vertical', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Block, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Block', %i)") - % constr->First); + []([[maybe_unused]] const Sketcher::Constraint* constr, + std::string& geoId1, + [[maybe_unused]] std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Block', %s)") % geoId1); }}, {Sketcher::Tangent, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Tangent', %i, %i)") - % constr->First % constr->Second); + return boost::str(boost::format("Sketcher.Constraint('Tangent', %s, %s)") + % geoId1 % geoId2); } else if (constr->SecondPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Tangent', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) - % constr->Second); + return boost::str(boost::format("Sketcher.Constraint('Tangent', %s, %i, %s)") + % geoId1 % static_cast(constr->FirstPos) % geoId2); } else { return boost::str( - boost::format("Sketcher.Constraint('Tangent', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Tangent', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Parallel, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Parallel', %i, %i)") - % constr->First % constr->Second); + []([[maybe_unused]] const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Parallel', %s, %s)") % geoId1 + % geoId2); }}, {Sketcher::Perpendicular, - [](const Sketcher::Constraint* constr) { + []([[maybe_unused]] const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Perpendicular', %i, %i)") - % constr->First % constr->Second); + return boost::str(boost::format("Sketcher.Constraint('Perpendicular', %s, %s)") + % geoId1 % geoId2); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( - boost::format("Sketcher.Constraint('Perpendicular', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second); + boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s)") % geoId1 + % static_cast(constr->FirstPos) % geoId2); } else { return boost::str( - boost::format("Sketcher.Constraint('Perpendicular', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s, %i)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Equal, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Equal', %i, %i)") - % constr->First % constr->Second); + []([[maybe_unused]] const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Equal', %s, %s)") % geoId1 + % geoId2); }}, {Sketcher::InternalAlignment, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->AlignmentType == EllipseMajorDiameter || constr->AlignmentType == EllipseMinorDiameter || constr->AlignmentType == HyperbolaMajor || constr->AlignmentType == HyperbolaMinor || constr->AlignmentType == ParabolaFocalAxis) { return boost::str( - boost::format("Sketcher.Constraint('InternalAlignment:%s', %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % constr->Second); + boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, %s)") + % constr->internalAlignmentTypeToString() % geoId1 % geoId2); } else if (constr->AlignmentType == EllipseFocus1 || constr->AlignmentType == EllipseFocus2 || constr->AlignmentType == HyperbolaFocus || constr->AlignmentType == ParabolaFocus) { return boost::str( - boost::format("Sketcher.Constraint('InternalAlignment:%s', %i, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % static_cast(constr->FirstPos) % constr->Second); + boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, %i, %s)") + % constr->internalAlignmentTypeToString() % geoId1 + % static_cast(constr->FirstPos) % geoId2); } else if (constr->AlignmentType == BSplineControlPoint) { return boost::str( boost::format( - "Sketcher.Constraint('InternalAlignment:%s', %i, %i, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % static_cast(constr->FirstPos) % constr->Second + "Sketcher.Constraint('InternalAlignment:%s', %s, %i, %s, %i)") + % constr->internalAlignmentTypeToString() % geoId1 + % static_cast(constr->FirstPos) % geoId2 % constr->InternalAlignmentIndex); } else if (constr->AlignmentType == BSplineKnotPoint) { return boost::str( - boost::format("Sketcher.Constraint('InternalAlignment:%s', %i, 1, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First % constr->Second + boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, 1, %s, %i)") + % constr->internalAlignmentTypeToString() % geoId1 % geoId2 % constr->InternalAlignmentIndex); } @@ -471,124 +503,160 @@ std::string PythonConverter::process(const Sketcher::Constraint* constraint) "PythonConverter: Constraint Alignment Type not supported") }}, {Sketcher::Distance, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('Distance', %i, %f)") - % constr->First % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('Distance', %s, %f)") + % geoId1 % constr->getValue()); } else if (constr->FirstPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Distance', %i, %i, %f)") - % constr->First % constr->Second % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('Distance', %s, %s, %f)") + % geoId1 % geoId2 % constr->getValue()); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( - boost::format("Sketcher.Constraint('Distance', %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % constr->getValue()); + boost::format("Sketcher.Constraint('Distance', %s, %i, %s, %f)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % constr->getValue()); } else { return boost::str( - boost::format("Sketcher.Constraint('Distance', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Distance', %s, %i, %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue()); } }}, {Sketcher::Angle, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('Angle', %i, %f)") - % constr->First % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('Angle', %s, %f)") + % geoId1 % constr->getValue()); } - else if (constr->SecondPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Angle', %i, %i, %f)") - % constr->First % constr->Second % constr->getValue()); + else if (constr->Third == GeoEnum::GeoUndef) { + if (constr->SecondPos == Sketcher::PointPos::none) { + return boost::str(boost::format("Sketcher.Constraint('Angle', %s, %s, %f)") + % geoId1 % geoId2 % constr->getValue()); + } + else { + return boost::str( + boost::format("Sketcher.Constraint('Angle', %s, %i, %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 + % static_cast(constr->SecondPos) % constr->getValue()); + } } else { return boost::str( - boost::format("Sketcher.Constraint('Angle', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->getValue()); + boost::format("Sketcher.Constraint('AngleViaPoint', %s, %s, %s, %i, %f)") + % geoId1 % geoId2 % geoId3 % static_cast(constr->ThirdPos) + % constr->getValue()); } }}, {Sketcher::DistanceX, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('DistanceX', %i, %f)") - % constr->First % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('DistanceX', %s, %f)") + % geoId1 % constr->getValue()); } else if (constr->SecondPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('DistanceX', %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) + return boost::str(boost::format("Sketcher.Constraint('DistanceX', %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % constr->getValue()); } else { return boost::str( - boost::format("Sketcher.Constraint('DistanceX', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('DistanceX', %s, %i, %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue()); } }}, {Sketcher::DistanceY, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { - return boost::str(boost::format("Sketcher.Constraint('DistanceY', %i, %f)") - % constr->First % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('DistanceY', %s, %f)") + % geoId1 % constr->getValue()); } else if (constr->SecondPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('DistanceY', %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) + return boost::str(boost::format("Sketcher.Constraint('DistanceY', %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % constr->getValue()); } else { return boost::str( - boost::format("Sketcher.Constraint('DistanceY', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('DistanceY', %s, %i, %s, %i, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue()); } }}, {Sketcher::Radius, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Radius', %i, %f)") - % constr->First % constr->getValue()); + [](const Sketcher::Constraint* constr, + std::string& geoId1, + [[maybe_unused]] std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Radius', %s, %f)") % geoId1 + % constr->getValue()); }}, {Sketcher::Diameter, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Diameter', %i, %f)") - % constr->First % constr->getValue()); + [](const Sketcher::Constraint* constr, + std::string& geoId1, + [[maybe_unused]] std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Diameter', %s, %f)") % geoId1 + % constr->getValue()); }}, {Sketcher::Weight, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Weight', %i, %f)") - % constr->First % constr->getValue()); + [](const Sketcher::Constraint* constr, + std::string& geoId1, + [[maybe_unused]] std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('Weight', %s, %f)") % geoId1 + % constr->getValue()); }}, {Sketcher::PointOnObject, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('PointOnObject', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) - % constr->Second); + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { + return boost::str(boost::format("Sketcher.Constraint('PointOnObject', %s, %i, %s)") + % geoId1 % static_cast(constr->FirstPos) % geoId2); }}, {Sketcher::Symmetric, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + std::string& geoId3) { if (constr->ThirdPos == Sketcher::PointPos::none) { return boost::str( - boost::format("Sketcher.Constraint('Symmetric', %i, %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third); + boost::format("Sketcher.Constraint('Symmetric', %s, %i, %s, %i, %s)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 + % static_cast(constr->SecondPos) % geoId3); } else { return boost::str( - boost::format("Sketcher.Constraint('Symmetric', %i, %i, %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third + boost::format("Sketcher.Constraint('Symmetric', %s, %i, %s, %i, %s, %i)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 + % static_cast(constr->SecondPos) % geoId3 % static_cast(constr->ThirdPos)); } }}, {Sketcher::SnellsLaw, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + std::string& geoId3) { return boost::str( - boost::format("Sketcher.Constraint('SnellsLaw', %i, %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third % constr->getValue()); + boost::format("Sketcher.Constraint('SnellsLaw', %s, %i, %s, %i, %s, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 + % static_cast(constr->SecondPos) % geoId3 % constr->getValue()); }}, }; @@ -600,7 +668,7 @@ std::string PythonConverter::process(const Sketcher::Constraint* constraint) auto creator = result->second; - return creator(constraint); + return creator(constraint, geoId1, geoId2, geoId3); } std::vector PythonConverter::multiLine(std::string&& singlestring) diff --git a/src/Mod/Sketcher/App/PythonConverter.h b/src/Mod/Sketcher/App/PythonConverter.h index 98535583b1..050d09dada 100644 --- a/src/Mod/Sketcher/App/PythonConverter.h +++ b/src/Mod/Sketcher/App/PythonConverter.h @@ -24,6 +24,9 @@ #ifndef SKETCHER_PythonConverter_H #define SKETCHER_PythonConverter_H +#include +#include + #include namespace Part @@ -57,7 +60,7 @@ public: OmitInternalGeometry }; - explicit PythonConverter() = delete; + PythonConverter() = delete; ~PythonConverter() = delete; /// Convert a geometry into the string representing the command creating it @@ -68,17 +71,20 @@ public: const std::vector& geos, Mode mode = Mode::CreateInternalGeometry); - static std::string convert(const Sketcher::Constraint* constraint); + static std::string convert(const Sketcher::Constraint* constraint, + bool useLastGeoIdVar = false); static std::string convert(const std::string& doc, - const std::vector& constraints); + const std::vector& constraints, + bool useLastGeoIdVar = false); static std::vector multiLine(std::string&& singlestring); private: static SingleGeometry process(const Part::Geometry* geo); - static std::string process(const Sketcher::Constraint* constraint); + static std::string process(const Sketcher::Constraint* constraint, + bool useLastGeoIdVar = false); }; } // namespace Sketcher From 8ed22b0fd887e33b3619c319cf7499aef3398901 Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 11 Jan 2024 18:31:57 +0100 Subject: [PATCH 14/36] Sketcher: copy paste : move from XML to python. --- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 124 ++++-------------- 1 file changed, 25 insertions(+), 99 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 2fc791558f..a16c6db99f 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -145,55 +146,24 @@ Sketcher::SketchObject* getSketchObject() // Copy -bool copySelectionToClipboard() { - - std::vector selection = Gui::Command::getSelection().getSelectionEx(); - Sketcher::SketchObject* obj = static_cast(selection[0].getObject()); - // only one sketch with its subelements are allowed to be selected - if (selection.size() != 1) { return false; } - std::vector SubNames = selection[0].getSubNames(); - if (SubNames.empty()) { return false; } - - //First we need listOfGeoId and sort them. - std::vector listOfGeoId; - for (std::vector::const_iterator it = SubNames.begin(); it != SubNames.end(); ++it) { - int GeoId = -1; - // only handle non-external edges - if (it->size() > 4 && it->substr(0, 4) == "Edge") { - GeoId = std::atoi(it->substr(4, 4000).c_str()) - 1; - if (GeoId >= 0) { - listOfGeoId.push_back(GeoId); - } - } - else if (it->size() > 6 && it->substr(0, 6) == "Vertex") { - // only if it is a GeomPoint - int VtId = std::atoi(it->substr(6, 4000).c_str()) - 1; - Sketcher::PointPos PosId; - obj->getGeoVertexIndex(VtId, GeoId, PosId); - if (obj->getGeometry(GeoId)->getTypeId() == Part::GeomPoint::getClassTypeId()) { - if (GeoId >= 0) { - listOfGeoId.push_back(GeoId); - } - } - } - } +bool copySelectionToClipboard(Sketcher::SketchObject* obj) { + std::vector listOfGeoId = getListOfSelectedGeoIds(true); if (listOfGeoId.empty()) { return false; } sort(listOfGeoId.begin(), listOfGeoId.end()); - Base::StringWriter writer; - - //Export selected geometries as a formated string. - std::vector< Part::Geometry* > newVals; + //Export selected geometries as a formatted string. + std::vector shapeGeometry; for (auto geoId : listOfGeoId) { Part::Geometry* geoNew = obj->getGeometry(geoId)->copy(); - newVals.push_back(geoNew); + shapeGeometry.push_back(geoNew); } - Part::PropertyGeometryList geoToCopy; - geoToCopy.setValues(std::move(newVals)); - geoToCopy.Save(writer); + std::string geosAsStr = Sketcher::PythonConverter::convert( + "objectStr", + shapeGeometry, + Sketcher::PythonConverter::Mode::OmitInternalGeometry); - //add constraints to the stream string. - std::vector< Sketcher::Constraint* > newConstrVals; + // Export constraints of selected geos. + std::vector shapeConstraints; for (auto constr : obj->Constraints.getValues()) { auto isSelectedGeoOrAxis = [](const std::vector& vec, int value) { @@ -220,13 +190,12 @@ bool copySelectionToClipboard() { temp->Third = j; } } - newConstrVals.push_back(temp); + shapeConstraints.push_back(temp); } - Sketcher::PropertyConstraintList constToCopy; - constToCopy.setValues(std::move(newConstrVals)); - constToCopy.Save(writer); + std::string cstrAsStr = Sketcher::PythonConverter::convert("objectStr", shapeConstraints, true); - std::string exportedData = writer.getString(); + std::string exportedData = "# Copied from sketcher. From:\n#objectStr = " + Gui::Command::getObjectCmd(obj) + "\n" + + geosAsStr + "\n" + cstrAsStr; if (!exportedData.empty()) { QClipboard* clipboard = QGuiApplication::clipboard(); @@ -255,7 +224,7 @@ CmdSketcherCopyClipboard::CmdSketcherCopyClipboard() void CmdSketcherCopyClipboard::activated(int iMsg) { Q_UNUSED(iMsg); - copySelectionToClipboard(); + copySelectionToClipboard(getSketchObject()); } bool CmdSketcherCopyClipboard::isActive() @@ -286,7 +255,7 @@ CmdSketcherCut::CmdSketcherCut() void CmdSketcherCut::activated(int iMsg) { Q_UNUSED(iMsg); - if (copySelectionToClipboard()) { + if (copySelectionToClipboard(getSketchObject())) { Gui::Document* doc = getActiveGuiDocument(); ReleaseHandler(doc); @@ -329,63 +298,20 @@ void CmdSketcherPaste::activated(int iMsg) Gui::Document* doc = getActiveGuiDocument(); ReleaseHandler(doc); auto* vp = static_cast(doc->getInEdit()); - Sketcher::SketchObject* Obj = vp->getSketchObject(); + Sketcher::SketchObject* obj = vp->getSketchObject(); std::string data = QGuiApplication::clipboard()->text().toStdString(); - int importedFirstGeoId = Obj->getHighestCurveIndex() + 1; - - std::string geoString; - if (data.find("", 0) != std::string::npos) { - geoString = data.substr(0, data.find("", 0) + 16); + if (data.find("# Copied from sketcher.", 0) == std::string::npos) { + return; } - else { return ; } - - std::istringstream istream(geoString); - Base::XMLReader reader("importingGeo", istream); - Part::PropertyGeometryList geoToCopy; - geoToCopy.Restore(reader); - - const std::vector& geos = geoToCopy.getValues(); - if (geos.empty()) { return; } + data = "objectStr = " + Gui::Command::getObjectCmd(obj) +"\n" + data; Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Paste in Sketcher")); - for (auto geo : geos) { - Part::Geometry* geocopy = geo->copy(); - Obj->addGeometry(geocopy); - } + Gui::Command::doCommand(Gui::Command::Doc, data.c_str()); - if (data.find("copy(); - //update the geoIds of the constraints - if (!isAxisOrRoot(constraintToAdd->First)) { - constraintToAdd->First += importedFirstGeoId; - } - if (!isAxisOrRoot(constraintToAdd->Second)) { - constraintToAdd->Second += importedFirstGeoId; - } - if (!isAxisOrRoot(constraintToAdd->Third)) { - constraintToAdd->Third += importedFirstGeoId; - } - Obj->addConstraint(constraintToAdd); - } - } - - Obj->solve(true); - vp->draw(false, false); // Redraw + obj->solve(true); + vp->draw(false, false); Gui::Command::commitCommand(); } From eb91978459b3c96ad57d4510816cdb556b869926 Mon Sep 17 00:00:00 2001 From: Paddle Date: Tue, 16 Jan 2024 18:00:27 +0100 Subject: [PATCH 15/36] Sketcher : Distance constraint : introduce arc helpers for conic distances. --- .../Gui/EditModeConstraintCoinManager.cpp | 135 +++++++++++++++--- 1 file changed, 116 insertions(+), 19 deletions(-) diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 8c32200450..401766eea1 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -814,6 +814,17 @@ Restart: case DistanceY: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); + double helperStartAngle1 = 0.; // for arc helpers + double helperStartAngle2 = 0.; + double helperRange1 = 0.; + double helperRange2 = 0.; + double radius1 = 0.; + double radius2 = 0.; + Base::Vector3d center1(0., 0., 0.); + Base::Vector3d center2(0., 0., 0.); + + int numPoints = 2; + // pnt1 will be initialized to (0,0,0) if only one point is given auto pnt1 = geolistfacade.getPoint(Constr->First, Constr->FirstPos); @@ -838,17 +849,15 @@ Restart: pnt2.ProjectToLine(pnt1 - l2p1, l2p2 - l2p1); pnt2 += pnt1; } - else { - if (isCircleOrArc(*geo1)) { - // circular to line distance - auto [radius, ct] = getRadiusCenterCircleArc(geo1); - // project the center on the line (translated to origin) - pnt1.ProjectToLine(ct - l2p1, l2p2 - l2p1); - Base::Vector3d dir = pnt1; - dir.Normalize(); - pnt1 += ct; - pnt2 = ct + dir * radius; - } + else if (isCircleOrArc(*geo1)) { + // circular to line distance + auto [radius, ct] = getRadiusCenterCircleArc(geo1); + // project the center on the line (translated to origin) + pnt1.ProjectToLine(ct - l2p1, l2p2 - l2p1); + Base::Vector3d dir = pnt1; + dir.Normalize(); + pnt1 += ct; + pnt2 = ct + dir * radius; } } else if (isCircleOrArc(*geo2)) { @@ -890,10 +899,8 @@ Restart: break; } - // NOLINTBEGIN - SoDatumLabel* asciiText = static_cast( - sep->getChild(static_cast(ConstraintNodePosition::DatumLabelIndex))); - // NOLINTEND + int index = static_cast(ConstraintNodePosition::DatumLabelIndex); + auto* asciiText = static_cast(sep->getChild(index)); // NOLINT // Get presentation string (w/o units if option is set) asciiText->string = @@ -909,13 +916,102 @@ Restart: asciiText->datumtype = SoDatumLabel::DISTANCEY; } + // Check if arc helpers are needed + if (Constr->Second != GeoEnum::GeoUndef + && Constr->SecondPos == Sketcher::PointPos::none) { + auto geo1 = geolistfacade.getGeometryFromGeoId(Constr->First); + auto geo2 = geolistfacade.getGeometryFromGeoId(Constr->Second); + + if (isArcOfCircle(*geo1)) { + auto arc = static_cast(geo1); // NOLINT + radius1 = arc->getRadius(); + center1 = arc->getCenter(); + + double angle = + toVector2d(isLineSegment(*geo2) ? pnt2 - center1 : pnt1 - center1) + .Angle(); + double startAngle, endAngle; + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + findHelperAngles(helperStartAngle1, + helperRange1, + angle, + startAngle, + endAngle); + + if (helperRange1 != 0.) { + // We override to draw the full helper as it does not look good + // otherwise We still use findHelperAngles before to find if helper + // is needed. + helperStartAngle1 = endAngle; + helperRange1 = 2 * M_PI - (endAngle - startAngle); + + numPoints++; + } + } + if (isArcOfCircle(*geo2)) { + auto arc = static_cast(geo2); // NOLINT + radius2 = arc->getRadius(); + center2 = arc->getCenter(); + + double angle = + toVector2d(pnt2 - center2).Angle(); // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + findHelperAngles(helperStartAngle2, + helperRange2, + angle, + startAngle, + endAngle); + + if (helperRange2 != 0.) { + helperStartAngle2 = endAngle; + helperRange2 = 2 * M_PI - (endAngle - startAngle); + + numPoints++; + } + } + } + // Assign the Datum Points - asciiText->pnts.setNum(2); + asciiText->pnts.setNum(numPoints); SbVec3f* verts = asciiText->pnts.startEditing(); verts[0] = SbVec3f(pnt1.x, pnt1.y, zConstrH); verts[1] = SbVec3f(pnt2.x, pnt2.y, zConstrH); + if (numPoints > 2) { + if (helperRange1 != 0.) { + verts[2] = SbVec3f(center1.x, center1.y, zConstrH); + asciiText->param3 = helperStartAngle1; + asciiText->param4 = helperRange1; + asciiText->param5 = radius1; + } + else { + verts[2] = SbVec3f(center2.x, center2.y, zConstrH); + asciiText->param3 = helperStartAngle2; + asciiText->param4 = helperRange2; + asciiText->param5 = radius2; + } + if (numPoints > 3) { + verts[3] = SbVec3f(center2.x, center2.y, zConstrH); + asciiText->param6 = helperStartAngle2; + asciiText->param7 = helperRange2; + asciiText->param8 = radius2; + } + else { + asciiText->param6 = 0.; + asciiText->param7 = 0.; + asciiText->param8 = 0.; + } + } + else { + asciiText->param3 = 0.; + asciiText->param4 = 0.; + asciiText->param5 = 0.; + } + asciiText->pnts.finishEditing(); // Assign the Label Distance @@ -1512,6 +1608,7 @@ void EditModeConstraintCoinManager::findHelperAngles(double& helperStartAngle, double startAngle, double endAngle) { + double margin = 0.2; // about 10deg if (angle < 0) { angle = angle + 2 * M_PI; } @@ -1525,15 +1622,15 @@ void EditModeConstraintCoinManager::findHelperAngles(double& helperStartAngle, if (angle > startAngle) { angle -= 2 * M_PI; } - helperStartAngle = angle; - helperRange = startAngle - angle; + helperStartAngle = angle - margin; + helperRange = startAngle - angle + margin; } else { if (angle < endAngle) { angle += 2 * M_PI; } helperStartAngle = endAngle; - helperRange = angle - endAngle; + helperRange = angle - endAngle + margin; } } } From 17893d39caa98aa5d32c4d28b03d7628324f4796 Mon Sep 17 00:00:00 2001 From: Paddle Date: Sat, 20 Jan 2024 06:49:32 +0100 Subject: [PATCH 16/36] Sketcher: PythonConverter: Replace useLastGeoIdVar bool by enum class --- src/Mod/Sketcher/App/PythonConverter.cpp | 17 +++++++++-------- src/Mod/Sketcher/App/PythonConverter.h | 12 +++++++++--- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Mod/Sketcher/App/PythonConverter.cpp b/src/Mod/Sketcher/App/PythonConverter.cpp index fe5def95dd..506463ae62 100644 --- a/src/Mod/Sketcher/App/PythonConverter.cpp +++ b/src/Mod/Sketcher/App/PythonConverter.cpp @@ -59,11 +59,11 @@ std::string PythonConverter::convert(const Part::Geometry* geo, Mode mode) return command; } -std::string PythonConverter::convert(const Sketcher::Constraint* constraint, bool useLastGeoIdVar) +std::string PythonConverter::convert(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { // addConstraint(Sketcher.Constraint('Distance',%d,%f)) std::string command; - auto cg = process(constraint, useLastGeoIdVar); + auto cg = process(constraint, geoIdMode); command = boost::str(boost::format("addConstraint(%s)\n") % cg); @@ -166,7 +166,7 @@ std::string PythonConverter::convert(const std::string& doc, std::string PythonConverter::convert(const std::string& doc, const std::vector& constraints, - bool useLastGeoIdVar) + GeoIdMode geoIdMode) { if (constraints.size() == 1) { auto cg = convert(constraints[0]); @@ -177,7 +177,7 @@ std::string PythonConverter::convert(const std::string& doc, std::string constraintlist = "constraintList = []"; for (auto constraint : constraints) { - auto cg = process(constraint, useLastGeoIdVar); + auto cg = process(constraint, geoIdMode); constraintlist = boost::str(boost::format("%s\nconstraintList.append(%s)") % constraintlist % cg); @@ -344,11 +344,12 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g return creator(geo); } -std::string PythonConverter::process(const Sketcher::Constraint* constraint, bool useLastIdVar) +std::string PythonConverter::process(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { - std::string geoId1 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->First); - std::string geoId2 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Second); - std::string geoId3 = (useLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Third); + bool addLastIdVar = geoIdMode == GeoIdMode::AddLastGeoIdToGeoIds; + std::string geoId1 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->First); + std::string geoId2 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Second); + std::string geoId3 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Third); static std::map< const Sketcher::ConstraintType, diff --git a/src/Mod/Sketcher/App/PythonConverter.h b/src/Mod/Sketcher/App/PythonConverter.h index 050d09dada..8062064589 100644 --- a/src/Mod/Sketcher/App/PythonConverter.h +++ b/src/Mod/Sketcher/App/PythonConverter.h @@ -60,6 +60,12 @@ public: OmitInternalGeometry }; + enum class GeoIdMode + { + DoNotChangeGeoIds, + AddLastGeoIdToGeoIds, + }; + PythonConverter() = delete; ~PythonConverter() = delete; @@ -72,11 +78,11 @@ public: Mode mode = Mode::CreateInternalGeometry); static std::string convert(const Sketcher::Constraint* constraint, - bool useLastGeoIdVar = false); + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); static std::string convert(const std::string& doc, const std::vector& constraints, - bool useLastGeoIdVar = false); + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); static std::vector multiLine(std::string&& singlestring); @@ -84,7 +90,7 @@ private: static SingleGeometry process(const Part::Geometry* geo); static std::string process(const Sketcher::Constraint* constraint, - bool useLastGeoIdVar = false); + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); }; } // namespace Sketcher diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index a16c6db99f..3905fdcaaa 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -192,7 +192,7 @@ bool copySelectionToClipboard(Sketcher::SketchObject* obj) { } shapeConstraints.push_back(temp); } - std::string cstrAsStr = Sketcher::PythonConverter::convert("objectStr", shapeConstraints, true); + std::string cstrAsStr = Sketcher::PythonConverter::convert("objectStr", shapeConstraints, Sketcher::PythonConverter::GeoIdMode::AddLastGeoIdToGeoIds); std::string exportedData = "# Copied from sketcher. From:\n#objectStr = " + Gui::Command::getObjectCmd(obj) + "\n" + geosAsStr + "\n" + cstrAsStr; From 915bfd3dde7e1ef1b7b0b5a714c610a71a5e0758 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 29 Mar 2023 15:49:45 +0200 Subject: [PATCH 17/36] Base: Use std::recursive_mutex --- src/Base/CMakeLists.txt | 2 -- src/Base/Mutex.cpp | 36 ------------------------------------ src/Base/Mutex.h | 39 --------------------------------------- src/Base/PreCompiled.h | 3 +-- src/Base/Sequencer.cpp | 31 ++++++++++++++----------------- 5 files changed, 15 insertions(+), 96 deletions(-) delete mode 100644 src/Base/Mutex.cpp delete mode 100644 src/Base/Mutex.h diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 478bb59a8b..f2528e7155 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -243,7 +243,6 @@ SET(FreeCADBase_CPP_SRCS Matrix.cpp MatrixPyImp.cpp MemDebug.cpp - Mutex.cpp Observer.cpp Parameter.xsd Parameter.cpp @@ -314,7 +313,6 @@ SET(FreeCADBase_HPP_SRCS Interpreter.h Matrix.h MemDebug.h - Mutex.h Observer.h Parameter.h Persistence.h diff --git a/src/Base/Mutex.cpp b/src/Base/Mutex.cpp deleted file mode 100644 index e3d07c4a4e..0000000000 --- a/src/Base/Mutex.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2022 Werner Mayer * - * * - * 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" - -#include "Mutex.h" - - -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) -QRecursiveMutex::QRecursiveMutex() - : QMutex(QMutex::Recursive) -{} - -QRecursiveMutex::~QRecursiveMutex() -{} -#endif diff --git a/src/Base/Mutex.h b/src/Base/Mutex.h deleted file mode 100644 index e65db63092..0000000000 --- a/src/Base/Mutex.h +++ /dev/null @@ -1,39 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2022 Werner Mayer * - * * - * 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 BASE_MUTEX_H -#define BASE_MUTEX_H - -#include -#include - -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) -class BaseExport QRecursiveMutex: public QMutex -{ -public: - QRecursiveMutex(); - ~QRecursiveMutex(); -}; -#endif - -#endif // BASE_MUTEX_H diff --git a/src/Base/PreCompiled.h b/src/Base/PreCompiled.h index f81b2e771b..b38b44a68d 100644 --- a/src/Base/PreCompiled.h +++ b/src/Base/PreCompiled.h @@ -73,6 +73,7 @@ #include #include #include +#include #include // streams @@ -130,8 +131,6 @@ #include #include #include -#include -#include #include #include diff --git a/src/Base/Sequencer.cpp b/src/Base/Sequencer.cpp index 4d41dc0009..3ab27b74be 100644 --- a/src/Base/Sequencer.cpp +++ b/src/Base/Sequencer.cpp @@ -24,12 +24,11 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#include +#include +#include #endif #include "Sequencer.h" -#include "Mutex.h" - using namespace Base; @@ -40,7 +39,7 @@ struct SequencerP // members static std::vector _instances; /**< A vector of all created instances */ static SequencerLauncher* _topLauncher; /**< The outermost launcher */ - static QRecursiveMutex mutex; /**< A mutex-locker for the launcher */ + static std::recursive_mutex mutex; /**< A mutex-locker for the launcher */ /** Sets a global sequencer object. * Access to the last registered object is performed by @see Sequencer(). */ @@ -66,7 +65,7 @@ struct SequencerP */ std::vector SequencerP::_instances; SequencerLauncher* SequencerP::_topLauncher = nullptr; -QRecursiveMutex SequencerP::mutex; +std::recursive_mutex SequencerP::mutex; } // namespace Base SequencerBase& SequencerBase::Instance() @@ -160,7 +159,7 @@ bool SequencerBase::isBlocking() const bool SequencerBase::setLocked(bool bLocked) { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); bool old = this->_bLocked; this->_bLocked = bLocked; return old; @@ -168,19 +167,19 @@ bool SequencerBase::setLocked(bool bLocked) bool SequencerBase::isLocked() const { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); return this->_bLocked; } bool SequencerBase::isRunning() const { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); return (SequencerP::_topLauncher != nullptr); } bool SequencerBase::wasCanceled() const { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); return this->_bCanceled; } @@ -236,7 +235,7 @@ void ConsoleSequencer::resetData() SequencerLauncher::SequencerLauncher(const char* pszStr, size_t steps) { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); // Have we already an instance of SequencerLauncher created? if (!SequencerP::_topLauncher) { SequencerBase::Instance().start(pszStr, steps); @@ -246,24 +245,22 @@ SequencerLauncher::SequencerLauncher(const char* pszStr, size_t steps) SequencerLauncher::~SequencerLauncher() { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); if (SequencerP::_topLauncher == this) { SequencerBase::Instance().stop(); - } - if (SequencerP::_topLauncher == this) { SequencerP::_topLauncher = nullptr; } } void SequencerLauncher::setText(const char* pszTxt) { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); SequencerBase::Instance().setText(pszTxt); } bool SequencerLauncher::next(bool canAbort) { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); if (SequencerP::_topLauncher != this) { return true; // ignore } @@ -272,13 +269,13 @@ bool SequencerLauncher::next(bool canAbort) void SequencerLauncher::setProgress(size_t pos) { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); SequencerBase::Instance().setProgress(pos); } size_t SequencerLauncher::numberOfSteps() const { - QMutexLocker locker(&SequencerP::mutex); + std::lock_guard locker(SequencerP::mutex); return SequencerBase::Instance().numberOfSteps(); } From 95b37fa80641fe3b9d9aba09082c3740532eeb22 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 15 Nov 2023 10:12:42 +0100 Subject: [PATCH 18/36] Base: Do not use else before return --- src/Base/Interpreter.cpp | 5 +--- src/Base/MatrixPyImp.cpp | 8 ++--- src/Base/Parameter.cpp | 6 +--- src/Base/PlacementPyImp.cpp | 18 +++++------- src/Base/PyObjectBase.cpp | 43 ++++++++++++--------------- src/Base/PyTools.c | 58 +++++++++++++++++-------------------- src/Base/QuantityPyImp.cpp | 10 +++---- src/Base/Reader.cpp | 44 ++++++++++++---------------- src/Base/RotationPyImp.cpp | 18 +++++------- src/Base/StackWalker.cpp | 5 +--- src/Base/UnitPyImp.cpp | 24 ++++++--------- src/Base/UnitsApi.cpp | 1 + src/Base/VectorPyImp.cpp | 51 ++++++++++++-------------------- 13 files changed, 115 insertions(+), 176 deletions(-) diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index 9c5b7be311..b1e9870f27 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -475,14 +475,11 @@ void InterpreterSingleton::runFile(const char* pxFileName, bool local) if (PyErr_ExceptionMatches(PyExc_SystemExit)) { throw SystemExitException(); } - throw PyException(); } Py_DECREF(result); } - else { - throw FileException("Unknown file", pxFileName); - } + throw FileException("Unknown file", pxFileName); } bool InterpreterSingleton::loadModule(const char* psModName) diff --git a/src/Base/MatrixPyImp.cpp b/src/Base/MatrixPyImp.cpp index 8d0229b0ec..0fdf71b054 100644 --- a/src/Base/MatrixPyImp.cpp +++ b/src/Base/MatrixPyImp.cpp @@ -256,11 +256,9 @@ PyObject* MatrixPy::richCompare(PyObject* v, PyObject* w, int op) Py_INCREF(res); return res; } - else { - // This always returns False - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } PyObject* MatrixPy::move(PyObject* args) diff --git a/src/Base/Parameter.cpp b/src/Base/Parameter.cpp index 47163d7259..54a33bf907 100644 --- a/src/Base/Parameter.cpp +++ b/src/Base/Parameter.cpp @@ -501,11 +501,7 @@ std::vector> ParameterGrp::GetGroups() /// test if this group is empty bool ParameterGrp::IsEmpty() const { - if (_pGroupNode && _pGroupNode->getFirstChild()) { - return false; - } - - return true; + return !(_pGroupNode && _pGroupNode->getFirstChild()); } /// test if a special sub group is in this group diff --git a/src/Base/PlacementPyImp.cpp b/src/Base/PlacementPyImp.cpp index fb5367b591..d57791d69f 100644 --- a/src/Base/PlacementPyImp.cpp +++ b/src/Base/PlacementPyImp.cpp @@ -148,22 +148,18 @@ PyObject* PlacementPy::richCompare(PyObject* v, PyObject* w, int op) PyErr_SetString(PyExc_TypeError, "no ordering relation is defined for Placement"); return nullptr; } - else if (op == Py_EQ) { + if (op == Py_EQ) { res = (p1 == p2) ? Py_True : Py_False; Py_INCREF(res); return res; } - else { - res = (p1 != p2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - } - else { - // This always returns False - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + res = (p1 != p2) ? Py_True : Py_False; + Py_INCREF(res); + return res; } + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } PyObject* PlacementPy::move(PyObject* args) diff --git a/src/Base/PyObjectBase.cpp b/src/Base/PyObjectBase.cpp index 4f00c0b4ae..0c4000ddfa 100644 --- a/src/Base/PyObjectBase.cpp +++ b/src/Base/PyObjectBase.cpp @@ -365,7 +365,7 @@ int PyObjectBase::__setattro(PyObject *obj, PyObject *attro, PyObject *value) PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr); return -1; } - else if (!static_cast(obj)->isValid()){ + if (!static_cast(obj)->isValid()){ PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr); return -1; } @@ -404,36 +404,32 @@ PyObject *PyObjectBase::_getattr(const char *attr) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast(Py_TYPE(this)); } - else if (streq(attr, "__members__")) { + if (streq(attr, "__members__")) { // Use __dict__ instead as __members__ is deprecated return nullptr; } - else if (streq(attr,"__dict__")) { + if (streq(attr,"__dict__")) { // Return the default dict PyTypeObject *tp = Py_TYPE(this); Py_XINCREF(tp->tp_dict); return tp->tp_dict; } - else if (streq(attr,"softspace")) { + if (streq(attr,"softspace")) { // Internal Python stuff return nullptr; } - else { - // As fallback solution use Python's default method to get generic attributes - PyObject *w{}; - PyObject *res{}; - w = PyUnicode_InternFromString(attr); - if (w) { - res = PyObject_GenericGetAttr(this, w); - Py_XDECREF(w); - return res; - } else { - // Throw an exception for unknown attributes - PyTypeObject *tp = Py_TYPE(this); - PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); - return nullptr; - } + // As fallback solution use Python's default method to get generic attributes + PyObject *w{}, *res{}; + w = PyUnicode_InternFromString(attr); + if (w) { + res = PyObject_GenericGetAttr(this, w); + Py_XDECREF(w); + return res; } + // Throw an exception for unknown attributes + PyTypeObject *tp = Py_TYPE(this); + PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); + return nullptr; } int PyObjectBase::_setattr(const char *attr, PyObject *value) @@ -449,12 +445,11 @@ int PyObjectBase::_setattr(const char *attr, PyObject *value) int res = PyObject_GenericSetAttr(this, w, value); Py_DECREF(w); return res; - } else { - // Throw an exception for unknown attributes - PyTypeObject *tp = Py_TYPE(this); - PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); - return -1; } + // Throw an exception for unknown attributes + PyTypeObject *tp = Py_TYPE(this); + PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); + return -1; } /*------------------------------ diff --git a/src/Base/PyTools.c b/src/Base/PyTools.c index 4a90a3becd..e71216a224 100644 --- a/src/Base/PyTools.c +++ b/src/Base/PyTools.c @@ -359,27 +359,25 @@ PP_Convert_Result(PyObject *presult, const char *resFormat, void *resTarget) Py_DECREF(presult); /* procedures and stmts return None */ return 0; } - else if (! PyArg_Parse(presult, resFormat, resTarget)) { /* convert Python->C */ Py_DECREF(presult); /* need not be tuple */ return -1; /* error in convert */ } - else { - if (strcmp(resFormat, "O") != 0) { /* free object unless exported */ - if (strcmp(resFormat, "s") == 0) { /* copy string: caller owns it */ - char **target = (char**) resTarget; + if (strcmp(resFormat, "O") != 0) { /* free object unless exported */ + if (strcmp(resFormat, "s") == 0) { /* copy string: caller owns it */ + char **target = (char**) resTarget; #if defined (__GNUC__) - *target = strdup(*target); + *target = strdup(*target); #else - *target = _strdup(*target); + *target = _strdup(*target); #endif - } - Py_DECREF(presult); } - return 0; /* returns 0=success, -1=failure */ - } /* if 0: C result in *resTarget */ -} /* caller must decref if fmt="O" */ - /* caller must free() if fmt="s" */ + Py_DECREF(presult); + } + return 0; /* returns 0=success, -1=failure */ + /* if 0: C result in *resTarget */ +} /* caller must decref if fmt="O" */ + /* caller must free() if fmt="s" */ int PP_Get_Global(const char *modname, const char *varname, const char *resfmt, void *cresult) @@ -430,27 +428,26 @@ int PP_DEBUG = 0; /* debug embedded code with pdb? */ const char *PP_Init(const char *modname) { Py_Initialize(); /* init python if needed */ - if (modname!=NULL) return modname; - { /* we assume here that the caller frees allocated memory */ - return "__main__"; - } + if (modname) + return modname; + /* we assume here that the caller frees allocated memory */ + return "__main__"; } int -PP_Make_Dummy_Module(const char *modname) /* namespace for strings, if no file */ -{ /* instead of sharing __main__ for all */ - PyObject *module = NULL, *dict = NULL; /* note: __main__ is created in py_init */ +PP_Make_Dummy_Module(const char *modname) /* namespace for strings, if no file */ +{ /* instead of sharing __main__ for all */ + PyObject *module = NULL, *dict = NULL; /* note: __main__ is created in py_init */ Py_Initialize(); module = PyImport_AddModule(modname); /* fetch or make, no load */ if (module == NULL) /* module not incref'd */ return -1; - else { /* module.__dict__ */ - dict = PyModule_GetDict(module); /* ['__dummy__'] = None */ - PyDict_SetItemString(dict, "__dummy__", Py_None); - PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()); - return 0; - } + /* module.__dict__ */ + dict = PyModule_GetDict(module); /* ['__dummy__'] = None */ + PyDict_SetItemString(dict, "__dummy__", Py_None); + PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()); + return 0; } @@ -479,17 +476,14 @@ PP_Load_Module(const char *modname) /* modname can be "package.module" for PyDict_GetItemString(PyModule_GetDict(module), "__dummy__")) { return module; /* not increfd */ } - else if (PP_RELOAD && module != NULL && PyModule_Check(module)) { module = PyImport_ReloadModule(module); /* reload file,run code */ Py_XDECREF(module); /* still on sys.modules */ return module; /* not increfd */ } - else { - module = PyImport_ImportModule(modname); /* fetch or load module */ - Py_XDECREF(module); /* still on sys.modules */ - return module; /* not increfd */ - } + module = PyImport_ImportModule(modname); /* fetch or load module */ + Py_XDECREF(module); /* still on sys.modules */ + return module; /* not increfd */ } diff --git a/src/Base/QuantityPyImp.cpp b/src/Base/QuantityPyImp.cpp index 6069342ebf..527c01e2d4 100644 --- a/src/Base/QuantityPyImp.cpp +++ b/src/Base/QuantityPyImp.cpp @@ -508,20 +508,18 @@ PyObject* QuantityPy::number_power_handler(PyObject* self, PyObject* other, PyOb return new QuantityPy(new Quantity(q)); } - else if (PyFloat_Check(other)) { + if (PyFloat_Check(other)) { Base::Quantity* a = static_cast(self)->getQuantityPtr(); double b = PyFloat_AsDouble(other); return new QuantityPy(new Quantity(a->pow(b))); } - else if (PyLong_Check(other)) { + if (PyLong_Check(other)) { Base::Quantity* a = static_cast(self)->getQuantityPtr(); double b = (double)PyLong_AsLong(other); return new QuantityPy(new Quantity(a->pow(b))); } - else { - PyErr_SetString(PyExc_TypeError, "Expected quantity or number"); - return nullptr; - } + PyErr_SetString(PyExc_TypeError, "Expected quantity or number"); + return nullptr; } PY_CATCH } diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index 6b6068bf12..3fb14a803c 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -116,12 +116,10 @@ long Base::XMLReader::getAttributeAsInteger(const char* AttrName) const if (pos != AttrMap.end()) { return atol(pos->second.c_str()); } - else { - // wrong name, use hasAttribute if not sure! - std::ostringstream msg; - msg << "XML Attribute: \"" << AttrName << "\" not found"; - throw Base::XMLAttributeError(msg.str()); - } + // wrong name, use hasAttribute if not sure! + std::ostringstream msg; + msg << "XML Attribute: \"" << AttrName << "\" not found"; + throw Base::XMLAttributeError(msg.str()); } unsigned long Base::XMLReader::getAttributeAsUnsigned(const char* AttrName) const @@ -131,12 +129,10 @@ unsigned long Base::XMLReader::getAttributeAsUnsigned(const char* AttrName) cons if (pos != AttrMap.end()) { return strtoul(pos->second.c_str(), nullptr, 10); } - else { - // wrong name, use hasAttribute if not sure! - std::ostringstream msg; - msg << "XML Attribute: \"" << AttrName << "\" not found"; - throw Base::XMLAttributeError(msg.str()); - } + // wrong name, use hasAttribute if not sure! + std::ostringstream msg; + msg << "XML Attribute: \"" << AttrName << "\" not found"; + throw Base::XMLAttributeError(msg.str()); } double Base::XMLReader::getAttributeAsFloat(const char* AttrName) const @@ -146,12 +142,10 @@ double Base::XMLReader::getAttributeAsFloat(const char* AttrName) const if (pos != AttrMap.end()) { return atof(pos->second.c_str()); } - else { - // wrong name, use hasAttribute if not sure! - std::ostringstream msg; - msg << "XML Attribute: \"" << AttrName << "\" not found"; - throw Base::XMLAttributeError(msg.str()); - } + // wrong name, use hasAttribute if not sure! + std::ostringstream msg; + msg << "XML Attribute: \"" << AttrName << "\" not found"; + throw Base::XMLAttributeError(msg.str()); } const char* Base::XMLReader::getAttribute(const char* AttrName) const @@ -161,12 +155,10 @@ const char* Base::XMLReader::getAttribute(const char* AttrName) const if (pos != AttrMap.end()) { return pos->second.c_str(); } - else { - // wrong name, use hasAttribute if not sure! - std::ostringstream msg; - msg << "XML Attribute: \"" << AttrName << "\" not found"; - throw Base::XMLAttributeError(msg.str()); - } + // wrong name, use hasAttribute if not sure! + std::ostringstream msg; + msg << "XML Attribute: \"" << AttrName << "\" not found"; + throw Base::XMLAttributeError(msg.str()); } bool Base::XMLReader::hasAttribute(const char* AttrName) const @@ -216,7 +208,7 @@ void Base::XMLReader::readElement(const char* ElementName) // thus we must stop reading on. break; } - else if (ReadType == EndDocument) { + if (ReadType == EndDocument) { // the end of the document has been reached but we still try to continue on reading throw Base::XMLParseException("End of document reached"); } @@ -276,7 +268,7 @@ void Base::XMLReader::readEndElement(const char* ElementName, int level) && (level < 0 || level == Level)) { return; } - else if (ReadType == EndDocument) { + if (ReadType == EndDocument) { // the end of the document has been reached but we still try to continue on reading throw Base::XMLParseException("End of document reached"); } diff --git a/src/Base/RotationPyImp.cpp b/src/Base/RotationPyImp.cpp index 8d0b019a1c..a4747ac6f1 100644 --- a/src/Base/RotationPyImp.cpp +++ b/src/Base/RotationPyImp.cpp @@ -271,22 +271,18 @@ PyObject* RotationPy::richCompare(PyObject* v, PyObject* w, int op) PyErr_SetString(PyExc_TypeError, "no ordering relation is defined for Rotation"); return nullptr; } - else if (op == Py_EQ) { + if (op == Py_EQ) { res = (r1 == r2) ? Py_True : Py_False; Py_INCREF(res); return res; } - else { - res = (r1 != r2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - } - else { - // This always returns False - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + res = (r1 != r2) ? Py_True : Py_False; + Py_INCREF(res); + return res; } + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } PyObject* RotationPy::invert(PyObject* args) diff --git a/src/Base/StackWalker.cpp b/src/Base/StackWalker.cpp index c3c4a7159c..fcc7fa4dc7 100644 --- a/src/Base/StackWalker.cpp +++ b/src/Base/StackWalker.cpp @@ -1118,10 +1118,7 @@ BOOL __stdcall StackWalker::myReadProcMem( //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); return bRet; } - else - { - return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); - } + return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); } void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) diff --git a/src/Base/UnitPyImp.cpp b/src/Base/UnitPyImp.cpp index e8db65865a..364ffb6641 100644 --- a/src/Base/UnitPyImp.cpp +++ b/src/Base/UnitPyImp.cpp @@ -175,10 +175,8 @@ PyObject* UnitPy::number_multiply_handler(PyObject* self, PyObject* other) return new UnitPy(new Unit((*a) * (*b))); } - else { - PyErr_SetString(PyExc_TypeError, "A Unit can only be multiplied by a Unit"); - return nullptr; - } + PyErr_SetString(PyExc_TypeError, "A Unit can only be multiplied by a Unit"); + return nullptr; } PyObject* UnitPy::richCompare(PyObject* v, PyObject* w, int op) @@ -192,22 +190,18 @@ PyObject* UnitPy::richCompare(PyObject* v, PyObject* w, int op) PyErr_SetString(PyExc_TypeError, "no ordering relation is defined for Units"); return nullptr; } - else if (op == Py_EQ) { + if (op == Py_EQ) { res = (*u1 == *u2) ? Py_True : Py_False; // NOLINT Py_INCREF(res); return res; } - else { - res = (*u1 != *u2) ? Py_True : Py_False; // NOLINT - Py_INCREF(res); - return res; - } - } - else { - // This always returns False - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + res = (*u1 != *u2) ? Py_True : Py_False; // NOLINT + Py_INCREF(res); + return res; } + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } Py::String UnitPy::getType() const diff --git a/src/Base/UnitsApi.cpp b/src/Base/UnitsApi.cpp index f0c118bd20..9984a4dee8 100644 --- a/src/Base/UnitsApi.cpp +++ b/src/Base/UnitsApi.cpp @@ -193,6 +193,7 @@ double UnitsApi::toDouble(PyObject* args, const Base::Unit& u) } throw Base::UnitsMismatchError("Wrong unit type!"); } + if (PyFloat_Check(args)) { return PyFloat_AsDouble(args); } diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index 8e0ea738e9..bf2b66181b 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -150,30 +150,24 @@ PyObject* VectorPy::number_multiply_handler(PyObject* self, PyObject* other) Py::Float mult(a * b); return Py::new_reference_to(mult); } - else if (PyNumber_Check(other)) { + if (PyNumber_Check(other)) { double b = PyFloat_AsDouble(other); return new VectorPy(a * b); } - else { - PyErr_SetString(PyExc_TypeError, "A Vector can only be multiplied by Vector or number"); - return nullptr; - } + PyErr_SetString(PyExc_TypeError, "A Vector can only be multiplied by Vector or number"); + return nullptr; } - else if (PyObject_TypeCheck(other, &(VectorPy::Type))) { + if (PyObject_TypeCheck(other, &(VectorPy::Type))) { Base::Vector3d a = static_cast(other)->value(); if (PyNumber_Check(self)) { double b = PyFloat_AsDouble(self); return new VectorPy(a * b); } - else { - PyErr_SetString(PyExc_TypeError, "A Vector can only be multiplied by Vector or number"); - return nullptr; - } - } - else { - PyErr_SetString(PyExc_TypeError, "First or second arg must be Vector"); + PyErr_SetString(PyExc_TypeError, "A Vector can only be multiplied by Vector or number"); return nullptr; } + PyErr_SetString(PyExc_TypeError, "First or second arg must be Vector"); + return nullptr; } Py_ssize_t VectorPy::sequence_length(PyObject* /*unused*/) @@ -243,13 +237,8 @@ PyObject* VectorPy::mapping_subscript(PyObject* self, PyObject* item) } return sequence_item(self, i); } - else if (PySlice_Check(item)) { - Py_ssize_t start = 0; - Py_ssize_t stop = 0; - Py_ssize_t step = 0; - Py_ssize_t slicelength = 0; - Py_ssize_t cur = 0; - Py_ssize_t i = 0; + if (PySlice_Check(item)) { + Py_ssize_t start = 0, stop = 0, step = 0, slicelength = 0, cur = 0, i = 0; PyObject* slice = item; if (PySlice_GetIndicesEx(slice, sequence_length(self), &start, &stop, &step, &slicelength) @@ -260,7 +249,7 @@ PyObject* VectorPy::mapping_subscript(PyObject* self, PyObject* item) if (slicelength <= 0) { return PyTuple_New(0); } - else if (start == 0 && step == 1 && slicelength == sequence_length(self) + if (start == 0 && step == 1 && slicelength == sequence_length(self) && PyObject_TypeCheck(self, &(VectorPy::Type))) { Base::Vector3d v = static_cast(self)->value(); Py::Tuple xyz(3); @@ -269,7 +258,7 @@ PyObject* VectorPy::mapping_subscript(PyObject* self, PyObject* item) xyz.setItem(2, Py::Float(v.z)); return Py::new_reference_to(xyz); } - else if (PyObject_TypeCheck(self, &(VectorPy::Type))) { + if (PyObject_TypeCheck(self, &(VectorPy::Type))) { Base::Vector3d v = static_cast(self)->value(); Py::Tuple xyz(static_cast(slicelength)); @@ -342,22 +331,18 @@ PyObject* VectorPy::richCompare(PyObject* v, PyObject* w, int op) PyErr_SetString(PyExc_TypeError, "no ordering relation is defined for Vector"); return nullptr; } - else if (op == Py_EQ) { + if (op == Py_EQ) { res = (v1 == v2) ? Py_True : Py_False; // NOLINT Py_INCREF(res); return res; } - else { - res = (v1 != v2) ? Py_True : Py_False; // NOLINT - Py_INCREF(res); - return res; - } - } - else { - // This always returns False - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + res = (v1 != v2) ? Py_True : Py_False; // NOLINT + Py_INCREF(res); + return res; } + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } PyObject* VectorPy::isEqual(PyObject* args) From f1fdd2e2a94c29609f534ece21503ea6f114e7d1 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sat, 20 Jan 2024 18:18:09 +0100 Subject: [PATCH 19/36] Base: Replace if else with switch statement --- src/Base/Console.h | 30 +++++------ src/Base/Persistence.cpp | 54 ++++++++++--------- src/Base/QuantityPyImp.cpp | 108 +++++++++++++++++-------------------- src/Base/Tools.cpp | 42 ++++++++------- src/Base/VectorPyImp.cpp | 2 +- 5 files changed, 115 insertions(+), 121 deletions(-) diff --git a/src/Base/Console.h b/src/Base/Console.h index ab2a2b3616..ed350bd5ca 100644 --- a/src/Base/Console.h +++ b/src/Base/Console.h @@ -579,23 +579,19 @@ public: */ bool isActive(Base::LogStyle category) const { - if (category == Base::LogStyle::Log) { - return bLog; - } - if (category == Base::LogStyle::Warning) { - return bWrn; - } - if (category == Base::LogStyle::Error) { - return bErr; - } - if (category == Base::LogStyle::Message) { - return bMsg; - } - if (category == Base::LogStyle::Critical) { - return bCritical; - } - if (category == Base::LogStyle::Notification) { - return bNotification; + switch (category) { + case Base::LogStyle::Log: + return bLog; + case Base::LogStyle::Warning: + return bWrn; + case Base::LogStyle::Error: + return bErr; + case Base::LogStyle::Message: + return bMsg; + case Base::LogStyle::Critical: + return bCritical; + case Base::LogStyle::Notification: + return bNotification; } return false; diff --git a/src/Base/Persistence.cpp b/src/Base/Persistence.cpp index 094b85767f..7dc3f7d42e 100644 --- a/src/Base/Persistence.cpp +++ b/src/Base/Persistence.cpp @@ -76,32 +76,34 @@ std::string Persistence::encodeAttribute(const std::string& str) { std::string tmp; for (char it : str) { - if (it == '<') { - tmp += "<"; - } - else if (it == '\"') { - tmp += """; - } - else if (it == '\'') { - tmp += "'"; - } - else if (it == '&') { - tmp += "&"; - } - else if (it == '>') { - tmp += ">"; - } - else if (it == '\r') { - tmp += " "; - } - else if (it == '\n') { - tmp += " "; - } - else if (it == '\t') { - tmp += " "; - } - else { - tmp += it; + switch (it) { + case '<': + tmp += "<"; + break; + case '\"': + tmp += """; + break; + case '\'': + tmp += "'"; + break; + case '&': + tmp += "&"; + break; + case '>': + tmp += ">"; + break; + case '\r': + tmp += " "; + break; + case '\n': + tmp += " "; + break; + case '\t': + tmp += " "; + break; + default: + tmp += it; + break; } } diff --git a/src/Base/QuantityPyImp.cpp b/src/Base/QuantityPyImp.cpp index 527c01e2d4..4a59496f42 100644 --- a/src/Base/QuantityPyImp.cpp +++ b/src/Base/QuantityPyImp.cpp @@ -541,35 +541,31 @@ PyObject* QuantityPy::richCompare(PyObject* v, PyObject* w, int op) const Quantity* u2 = static_cast(w)->getQuantityPtr(); PyObject* res = nullptr; - if (op == Py_NE) { - res = (!(*u1 == *u2)) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_LT) { - res = (*u1 < *u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_LE) { - res = (*u1 < *u2) || (*u1 == *u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_GT) { - res = (!(*u1 < *u2)) && (!(*u1 == *u2)) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_GE) { - res = (!(*u1 < *u2)) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_EQ) { - res = (*u1 == *u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; + switch (op) { + case Py_NE: + res = (!(*u1 == *u2)) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_LT: + res = (*u1 < *u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_LE: + res = (*u1 < *u2) || (*u1 == *u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_GT: + res = (!(*u1 < *u2)) && (!(*u1 == *u2)) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_GE: + res = (!(*u1 < *u2)) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_EQ: + res = (*u1 == *u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; } } else if (PyNumber_Check(v) && PyNumber_Check(w)) { @@ -577,35 +573,31 @@ PyObject* QuantityPy::richCompare(PyObject* v, PyObject* w, int op) double u1 = PyFloat_AsDouble(v); double u2 = PyFloat_AsDouble(w); PyObject* res = nullptr; - if (op == Py_NE) { - res = (u1 != u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_LT) { - res = (u1 < u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_LE) { - res = (u1 <= u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_GT) { - res = (u1 > u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_GE) { - res = (u1 >= u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; - } - else if (op == Py_EQ) { - res = (u1 == u2) ? Py_True : Py_False; - Py_INCREF(res); - return res; + switch (op) { + case Py_NE: + res = (u1 != u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_LT: + res = (u1 < u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_LE: + res = (u1 <= u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_GT: + res = (u1 > u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_GE: + res = (u1 >= u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; + case Py_EQ: + res = (u1 == u2) ? Py_True : Py_False; + Py_INCREF(res); + return res; } } diff --git a/src/Base/Tools.cpp b/src/Base/Tools.cpp index 1f315ce721..9e313be85e 100644 --- a/src/Base/Tools.cpp +++ b/src/Base/Tools.cpp @@ -264,17 +264,19 @@ std::string Base::Tools::escapeEncodeString(const std::string& s) std::string result; size_t len = s.size(); for (size_t i = 0; i < len; ++i) { - if (s.at(i) == '\\') { - result += "\\\\"; - } - else if (s.at(i) == '\"') { - result += "\\\""; - } - else if (s.at(i) == '\'') { - result += "\\\'"; - } - else { - result += s.at(i); + switch (s.at(i)) { + case '\\': + result += "\\\\"; + break; + case '\"': + result += "\\\""; + break; + case '\'': + result += "\\\'"; + break; + default: + result += s.at(i); + break; } } return result; @@ -305,14 +307,16 @@ std::string Base::Tools::escapeEncodeFilename(const std::string& s) std::string result; size_t len = s.size(); for (size_t i = 0; i < len; ++i) { - if (s.at(i) == '\"') { - result += "\\\""; - } - else if (s.at(i) == '\'') { - result += "\\\'"; - } - else { - result += s.at(i); + switch (s.at(i)) { + case '\"': + result += "\\\""; + break; + case '\'': + result += "\\\'"; + break; + default: + result += s.at(i); + break; } } return result; diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index bf2b66181b..80d730c39d 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -250,7 +250,7 @@ PyObject* VectorPy::mapping_subscript(PyObject* self, PyObject* item) return PyTuple_New(0); } if (start == 0 && step == 1 && slicelength == sequence_length(self) - && PyObject_TypeCheck(self, &(VectorPy::Type))) { + && PyObject_TypeCheck(self, &(VectorPy::Type))) { Base::Vector3d v = static_cast(self)->value(); Py::Tuple xyz(3); xyz.setItem(0, Py::Float(v.x)); From 629f585a1582eeb859b73323f45442047b985342 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Sun, 21 Jan 2024 15:22:21 -0300 Subject: [PATCH 20/36] Fem: Set PotentialEnabled to False in capacitance_two_balls example - fixes #9707 --- .../equation_electrostatics_capacitance_two_balls.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py index 94ae02167f..ed4624da90 100644 --- a/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py +++ b/src/Mod/Fem/femexamples/equation_electrostatics_capacitance_two_balls.py @@ -138,6 +138,7 @@ def setup(doc=None, solvertype="elmer"): con_elect_pot1 = ObjectsFem.makeConstraintElectrostaticPotential(doc, name_pot1) con_elect_pot1.References = [(geom_obj, "Face1")] con_elect_pot1.ElectricInfinity = True + con_elect_pot1.PotentialEnabled = False analysis.addObject(con_elect_pot1) # constraint potential 2nd @@ -146,6 +147,7 @@ def setup(doc=None, solvertype="elmer"): con_elect_pot2.References = [(geom_obj, "Face2")] con_elect_pot2.CapacitanceBody = 1 con_elect_pot2.CapacitanceBodyEnabled = True + con_elect_pot2.PotentialEnabled = False analysis.addObject(con_elect_pot2) # constraint potential 3rd @@ -154,6 +156,7 @@ def setup(doc=None, solvertype="elmer"): con_elect_pot3.References = [(geom_obj, "Face3")] con_elect_pot3.CapacitanceBody = 2 con_elect_pot3.CapacitanceBodyEnabled = True + con_elect_pot3.PotentialEnabled = False analysis.addObject(con_elect_pot3) # mesh From fa0702956c416d312b616c94d422e26e99077444 Mon Sep 17 00:00:00 2001 From: Ulices Date: Sun, 21 Jan 2024 18:52:34 -0600 Subject: [PATCH 21/36] PartDesign: Update Length/Offset when Occurrences changes (#12069) * Add 'HACK:'/`NOTE:` tags to get special highlightning * [PD] Bugfix: Update Length/Offset when Occurrences changes Fix #12068 --- src/Mod/PartDesign/App/FeatureLinearPattern.cpp | 10 ++++++---- src/Mod/PartDesign/WizardShaft/WizardShaft.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp index 256ea7d29b..2b95e1aca1 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp @@ -221,7 +221,7 @@ const std::list LinearPattern::getTransformations(const std::vector Date: Fri, 19 Jan 2024 19:00:58 +0100 Subject: [PATCH 22/36] CMake: Fix searching for pip installed PySide --- .../SetupShibokenAndPyside.cmake | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake b/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake index 7556a25a89..aca36bc439 100644 --- a/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake +++ b/cMake/FreeCAD_Helpers/SetupShibokenAndPyside.cmake @@ -45,9 +45,9 @@ macro(SetupShibokenAndPyside) if(NOT SHIBOKEN_INCLUDE_DIR) find_pip_package(Shiboken${SHIBOKEN_MAJOR_VERSION}) if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND) - set(Shiboken_INCLUDE_DIR ${Shiboken${SHIBOKEN_MAJOR_VERSION}_INCLUDE_DIRS}) - set(Shiboken_LIBRARY ${Shiboken${SHIBOKEN_MAJOR_VERSION}_LIBRARIES}) - set(Shiboken_FOUND TRUE) + set(SHIBOKEN_INCLUDE_DIR ${Shiboken${SHIBOKEN_MAJOR_VERSION}_INCLUDE_DIRS}) + set(SHIBOKEN_LIBRARY ${Shiboken${SHIBOKEN_MAJOR_VERSION}_LIBRARIES}) + set(SHIBOKEN_FOUND TRUE) endif() endif() @@ -60,9 +60,9 @@ macro(SetupShibokenAndPyside) if(NOT PYSIDE_INCLUDE_DIR) find_pip_package(PySide${PYSIDE_MAJOR_VERSION}) if (PySide${PYSIDE_MAJOR_VERSION}_FOUND) - set(PySide_INCLUDE_DIR ${PySide${PYSIDE_MAJOR_VERSION}_INCLUDE_DIRS}) - set(PySide_LIBRARY ${PySide${PYSIDE_MAJOR_VERSION}_LIBRARIES}) - set(PySide_FOUND TRUE) + set(PYSIDE_INCLUDE_DIR ${PySide${PYSIDE_MAJOR_VERSION}_INCLUDE_DIRS}) + set(PYSIDE_LIBRARY ${PySide${PYSIDE_MAJOR_VERSION}_LIBRARIES}) + set(PYSIDE_FOUND TRUE) endif() endif() @@ -192,9 +192,9 @@ macro(find_pip_package PACKAGE) endforeach() file(TO_NATIVE_PATH "${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}/include" INCLUDE_DIR) file(TO_NATIVE_PATH "${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}/lib" LIBRARY) - set(${PACKAGE}_INCLUDE_DIRS ${INCLUDE_DIR} PARENT_SCOPE) - set(${PACKAGE}_LIBRARIES ${LIBRARY} PARENT_SCOPE) - set(${PACKAGE}_FOUND ${LIBRARY} TRUE) + set(${PACKAGE}_INCLUDE_DIRS ${INCLUDE_DIR}) + set(${PACKAGE}_LIBRARIES ${LIBRARY}) + set(${PACKAGE}_FOUND TRUE) message(STATUS "Found pip-installed ${PACKAGE} in ${PIP_PACKAGE_LOCATION}/${PIP_PACKAGE_NAME}") endif() endmacro() From 9f5f00db692d271f4392f04d28d73534339e59e9 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 19 Jan 2024 19:02:58 +0100 Subject: [PATCH 23/36] Gui: Consolidate module error message in PythonWrapper --- src/Gui/PythonWrapper.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Gui/PythonWrapper.cpp b/src/Gui/PythonWrapper.cpp index 412b56c47f..c56def3526 100644 --- a/src/Gui/PythonWrapper.cpp +++ b/src/Gui/PythonWrapper.cpp @@ -354,6 +354,13 @@ private: ~WrapperManager() override = default; }; +static std::string formatModuleError(std::string name) +{ + std::string error = "Cannot load " + name + " module"; + PyErr_Print(); + return error; +} + template Py::Object qt_wrapInstance(qttype object, const std::string& className, @@ -363,10 +370,7 @@ Py::Object qt_wrapInstance(qttype object, { PyObject* module = PyImport_ImportModule(shiboken.c_str()); if (!module) { - std::string error = "Cannot load "; - error += shiboken; - error += " module"; - throw Py::Exception(PyExc_ImportError, error); + throw Py::Exception(PyExc_ImportError, formatModuleError(shiboken)); } Py::Module mainmod(module, true); @@ -377,10 +381,7 @@ Py::Object qt_wrapInstance(qttype object, module = PyImport_ImportModule(pyside.c_str()); if (!module) { - std::string error = "Cannot load "; - error += pyside; - error += " module"; - throw Py::Exception(PyExc_ImportError, error); + throw Py::Exception(PyExc_ImportError, formatModuleError(pyside)); } Py::Module qtmod(module); @@ -392,10 +393,7 @@ const char* qt_identifyType(QObject* ptr, const std::string& pyside) { PyObject* module = PyImport_ImportModule(pyside.c_str()); if (!module) { - std::string error = "Cannot load "; - error += pyside; - error += " module"; - throw Py::Exception(PyExc_ImportError, error); + throw Py::Exception(PyExc_ImportError, formatModuleError(pyside)); } Py::Module qtmod(module); @@ -415,10 +413,7 @@ void* qt_getCppPointer(const Py::Object& pyobject, const std::string& shiboken, // https://github.com/PySide/Shiboken/blob/master/shibokenmodule/typesystem_shiboken.xml PyObject* module = PyImport_ImportModule(shiboken.c_str()); if (!module) { - std::string error = "Cannot load "; - error += shiboken; - error += " module"; - throw Py::Exception(PyExc_ImportError, error); + throw Py::Exception(PyExc_ImportError, formatModuleError(shiboken)); } Py::Module mainmod(module, true); From ac6f991baff6a536c2768f9d8b9468e028c91575 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sat, 20 Jan 2024 11:58:26 +0100 Subject: [PATCH 24/36] Gui: Consolidate Python -> Qt class conversion --- src/Gui/PythonWrapper.cpp | 60 +++++++-------------------------------- 1 file changed, 11 insertions(+), 49 deletions(-) diff --git a/src/Gui/PythonWrapper.cpp b/src/Gui/PythonWrapper.cpp index c56def3526..490932505a 100644 --- a/src/Gui/PythonWrapper.cpp +++ b/src/Gui/PythonWrapper.cpp @@ -447,9 +447,10 @@ PyTypeObject *getPyTypeObjectForTypeName() } template -qttype* qt_getCppType(PyObject* pyobj) +qttype* qt_getCppType(PyObject* pyobj, const std::string& shiboken) { #if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) + Q_UNUSED(shiboken) PyTypeObject * type = getPyTypeObjectForTypeName(); if (type) { if (Shiboken::Object::checkType(pyobj)) { @@ -459,7 +460,9 @@ qttype* qt_getCppType(PyObject* pyobj) } } #else - Q_UNUSED(pyobj) + void* ptr = qt_getCppPointer(Py::asObject(pyobj), shiboken, "getCppPointer"); + if (ptr) + return reinterpret_cast(ptr); #endif return nullptr; @@ -531,30 +534,12 @@ bool PythonWrapper::toCString(const Py::Object& pyobject, std::string& str) QObject* PythonWrapper::toQObject(const Py::Object& pyobject) { - // http://pastebin.com/JByDAF5Z -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyobject.ptr()); -#else - // Access shiboken/PySide via Python - // - void* ptr = qt_getCppPointer(pyobject, shiboken, "getCppPointer"); - return static_cast(ptr); -#endif - - return nullptr; + return qt_getCppType(pyobject.ptr(), shiboken); } QGraphicsItem* PythonWrapper::toQGraphicsItem(PyObject* pyPtr) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyPtr); -#else - // Access shiboken/PySide via Python - // - void* ptr = qt_getCppPointer(Py::asObject(pyPtr), shiboken, "getCppPointer"); - return static_cast(ptr); -#endif - return nullptr; + return qt_getCppType(pyPtr, shiboken); } QGraphicsItem* PythonWrapper::toQGraphicsItem(const Py::Object& pyobject) @@ -564,15 +549,7 @@ QGraphicsItem* PythonWrapper::toQGraphicsItem(const Py::Object& pyobject) QGraphicsObject* PythonWrapper::toQGraphicsObject(PyObject* pyPtr) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyPtr); -#else - // Access shiboken/PySide via Python - // - void* ptr = qt_getCppPointer(Py::asObject(pyPtr), shiboken, "getCppPointer"); - return reinterpret_cast(ptr); -#endif - return nullptr; + return qt_getCppType(pyPtr, shiboken); } QGraphicsObject* PythonWrapper::toQGraphicsObject(const Py::Object& pyobject) @@ -603,12 +580,7 @@ Py::Object PythonWrapper::fromQImage(const QImage& img) QImage *PythonWrapper::toQImage(PyObject *pyobj) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyobj); -#else - Q_UNUSED(pyobj); -#endif - return nullptr; + return qt_getCppType(pyobj, shiboken); } Py::Object PythonWrapper::fromQIcon(const QIcon* icon) @@ -634,12 +606,7 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon) QIcon *PythonWrapper::toQIcon(PyObject *pyobj) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyobj); -#else - Q_UNUSED(pyobj); -#endif - return nullptr; + return qt_getCppType(pyobj, shiboken); } Py::Object PythonWrapper::fromQDir(const QDir& dir) @@ -663,12 +630,7 @@ Py::Object PythonWrapper::fromQDir(const QDir& dir) QDir* PythonWrapper::toQDir(PyObject* pyobj) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - return qt_getCppType(pyobj); -#else - Q_UNUSED(pyobj); -#endif - return nullptr; + return qt_getCppType(pyobj, shiboken); } Py::Object PythonWrapper::fromQPrinter(QPrinter* printer) From c6911695e76148418b672dcf4a4661682b1acfea Mon Sep 17 00:00:00 2001 From: marioalexis Date: Mon, 22 Jan 2024 00:52:10 -0300 Subject: [PATCH 25/36] Material: Initialize types --- src/Mod/Material/App/AppMaterial.cpp | 24 ++++++++++++++++++++++++ src/Mod/Material/App/MaterialLibrary.cpp | 4 ++-- src/Mod/Material/App/ModelLibrary.cpp | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Mod/Material/App/AppMaterial.cpp b/src/Mod/Material/App/AppMaterial.cpp index 9d2471c657..b63547925d 100644 --- a/src/Mod/Material/App/AppMaterial.cpp +++ b/src/Mod/Material/App/AppMaterial.cpp @@ -28,6 +28,8 @@ #include // #include "Model.h" +#include "MaterialFilter.h" + #include "MaterialManagerPy.h" #include "MaterialPy.h" #include "ModelManagerPy.h" @@ -71,5 +73,27 @@ PyMOD_INIT_FUNC(Material) Base::Interpreter().addType(&Materials::ModelPy ::Type, module, "Model"); Base::Interpreter().addType(&Materials::UUIDsPy ::Type, module, "UUIDs"); + + // Initialize types + + Materials::Material ::init(); + Materials::MaterialFilter ::init(); + Materials::MaterialManager ::init(); + Materials::Model ::init(); + Materials::ModelManager ::init(); + Materials::ModelUUIDs ::init(); + + Materials::LibraryBase ::init(); + Materials::MaterialLibrary ::init(); + Materials::ModelLibrary ::init(); + Materials::MaterialExternalLibrary ::init(); + + Materials::ModelProperty ::init(); + Materials::MaterialProperty ::init(); + + Materials::MaterialValue ::init(); + Materials::Material2DArray ::init(); + Materials::Material3DArray ::init(); + PyMOD_Return(module); } diff --git a/src/Mod/Material/App/MaterialLibrary.cpp b/src/Mod/Material/App/MaterialLibrary.cpp index 1a1573e388..87de1c2104 100644 --- a/src/Mod/Material/App/MaterialLibrary.cpp +++ b/src/Mod/Material/App/MaterialLibrary.cpp @@ -41,7 +41,7 @@ using namespace Materials; /* TRANSLATOR Material::Materials */ -TYPESYSTEM_SOURCE(Materials::MaterialLibrary, LibraryBase) +TYPESYSTEM_SOURCE(Materials::MaterialLibrary, Materials::LibraryBase) MaterialLibrary::MaterialLibrary(const QString& libraryName, const QString& dir, @@ -352,7 +352,7 @@ MaterialLibrary::getMaterialTree(const MaterialFilter* filter) const return materialTree; } -TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, MaterialLibrary::MaterialLibrary) +TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, Materials::MaterialLibrary) MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName, const QString& dir, diff --git a/src/Mod/Material/App/ModelLibrary.cpp b/src/Mod/Material/App/ModelLibrary.cpp index 87a4387263..40df9b3366 100644 --- a/src/Mod/Material/App/ModelLibrary.cpp +++ b/src/Mod/Material/App/ModelLibrary.cpp @@ -99,7 +99,7 @@ QString LibraryBase::getRelativePath(const QString& path) const return filePath; } -TYPESYSTEM_SOURCE(Materials::ModelLibrary, LibraryBase) +TYPESYSTEM_SOURCE(Materials::ModelLibrary, Materials::LibraryBase) ModelLibrary::ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon) : LibraryBase(libraryName, dir, icon) From 0cbc9cd66efedb36266f513793bdcc40ded3b46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Caldas?= Date: Sat, 21 Oct 2023 22:37:58 -0300 Subject: [PATCH 26/36] Does not rely on the pointervalue returned by getNameInDocument() to use as a DAG key. In order to make getNameInDocument() always return a valid string, we implement a getDagKey() method that shall be used instead of getNameInDocument() when we want to use the pointer value as a "key" to identify the DocumentObject. --- src/App/DocumentObject.cpp | 11 ++++++++++- src/App/DocumentObject.h | 2 ++ src/App/Link.cpp | 2 +- src/Gui/ViewProviderLink.cpp | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index 2950697434..708b6ea3b9 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -292,6 +292,15 @@ std::string DocumentObject::getFullLabel() const { return name; } +const char* DocumentObject::getDagKey() const +{ + if(!pcNameInDocument) + { + return nullptr; + } + return pcNameInDocument->c_str(); +} + const char *DocumentObject::getNameInDocument() const { // Note: It can happen that we query the internal name of an object even if it is not @@ -808,7 +817,7 @@ DocumentObject *DocumentObject::getSubObject(const char *subname, if(outList.size()!=_outListMap.size()) { _outListMap.clear(); for(auto obj : outList) - _outListMap[obj->getNameInDocument()] = obj; + _outListMap[obj->getDagKey()] = obj; } auto it = _outListMap.find(name.c_str()); if(it != _outListMap.end()) diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index a274a60c0c..b9b745ad54 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -132,6 +132,8 @@ public: DocumentObject(); ~DocumentObject() override; + /// returns a value that uniquely identifies this DocumentObject. + const char* getDagKey() const; /// returns the name which is set in the document for this object (not the name property!) const char *getNameInDocument() const; /// Return the object ID that is unique within its owner document diff --git a/src/App/Link.cpp b/src/App/Link.cpp index a63cd4bf8f..4328a2ebe1 100644 --- a/src/App/Link.cpp +++ b/src/App/Link.cpp @@ -468,7 +468,7 @@ void LinkBaseExtension::setOnChangeCopyObject( } } - const char *key = flags.testFlag(OnChangeCopyOptions::ApplyAll) ? "*" : parent->getNameInDocument(); + const char *key = flags.testFlag(OnChangeCopyOptions::ApplyAll) ? "*" : parent->getDagKey(); if (external) prop->setValue(key, exclude ? "" : "+"); else diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp index c121fe91b2..61a68d6465 100644 --- a/src/Gui/ViewProviderLink.cpp +++ b/src/Gui/ViewProviderLink.cpp @@ -225,7 +225,7 @@ public: } const char *getLinkedName() const { - return pcLinked->getObject()->getNameInDocument(); + return pcLinked->getObject()->getDagKey(); } const char *getLinkedLabel() const { From 51ccf610c0f681bd397911178ee0b9b7dc77f787 Mon Sep 17 00:00:00 2001 From: xtemp09 Date: Tue, 19 Dec 2023 18:42:24 +0700 Subject: [PATCH 27/36] Fix occasional segmentation fault when exiting Fixes #11521. --- src/Gui/PythonWrapper.cpp | 68 +++++++++++++++------------------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/src/Gui/PythonWrapper.cpp b/src/Gui/PythonWrapper.cpp index 490932505a..5608a606e2 100644 --- a/src/Gui/PythonWrapper.cpp +++ b/src/Gui/PythonWrapper.cpp @@ -263,7 +263,7 @@ PyTypeObject *getPyTypeObjectForTypeName(); */ class WrapperManager : public QObject { - std::unordered_map> wrappers; + public: static WrapperManager& instance() @@ -275,52 +275,38 @@ public: * \brief addQObject * \param obj * \param pyobj - * Add the QObject and its Python wrapper to the list. + * Connects destruction event of a QObject with invalidation of its PythonWrapper via a helper QObject. */ void addQObject(QObject* obj, PyObject* pyobj) { - if (wrappers.find(obj) == wrappers.end()) { - QObject::connect(obj, &QObject::destroyed, this, &WrapperManager::destroyed); - } + const auto PyW_unique_name = QString::number(reinterpret_cast (pyobj)); + auto PyW_invalidator = findChild (PyW_unique_name, Qt::FindDirectChildrenOnly); - auto& pylist = wrappers[obj]; - if (std::find_if(pylist.cbegin(), pylist.cend(), - [pyobj](const Py::Object& py) { - return py.ptr() == pyobj; - }) == pylist.end()) { + if (PyW_invalidator == nullptr) { + PyW_invalidator = new QObject(this); + PyW_invalidator->setObjectName(PyW_unique_name); - pylist.emplace_back(pyobj); - } - } + Py_INCREF (pyobj); + } else + PyW_invalidator->disconnect(); + + auto destroyedFun = [pyobj](){ +#if defined (HAVE_SHIBOKEN) + auto sbk_ptr = reinterpret_cast (pyobj); + if (sbk_ptr != nullptr) { + Base::PyGILStateLocker lock; + Shiboken::Object::setValidCpp(sbk_ptr, false); + } else + Base::Console().DeveloperError("WrapperManager", "A QObject has just been destroyed after its Pythonic wrapper.\n"); +#endif + Py_DECREF (pyobj); + }; + + QObject::connect(PyW_invalidator, &QObject::destroyed, this, destroyedFun); + QObject::connect(obj, &QObject::destroyed, PyW_invalidator, &QObject::deleteLater); +} private: - /*! - * \brief destroyed - * \param obj - * The listed QObject is about to be destroyed. Invalidate its Python wrappers now. - */ - void destroyed(QObject* obj = nullptr) - { - if (obj) { -#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - auto key = wrappers.find(obj); - if (key != wrappers.end()) { - Base::PyGILStateLocker lock; - for (const auto& it : key->second) { - auto value = it.ptr(); - Shiboken::Object::setValidCpp(reinterpret_cast(value), false); - } - - wrappers.erase(key); - } -#endif - } - } - void clear() - { - Base::PyGILStateLocker lock; - wrappers.clear(); - } void wrapQApplication() { // We have to explicitly hold a reference to the wrapper of the QApplication @@ -347,8 +333,6 @@ private: WrapperManager() { - connect(QApplication::instance(), &QCoreApplication::aboutToQuit, - this, &WrapperManager::clear); wrapQApplication(); } ~WrapperManager() override = default; From cce2c2426266bceb0756a5182402e69a5b995b2f Mon Sep 17 00:00:00 2001 From: Paddle Date: Mon, 8 Jan 2024 10:51:50 +0100 Subject: [PATCH 28/36] Core: tree: prevent object replacement when dragging --- src/Gui/Tree.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index fe830d468f..30148e512b 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -1747,7 +1747,8 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent* event) // let the view provider decide to accept the object or ignore it if (da != Qt::LinkAction && !vp->canDropObjectEx(obj, owner, subname.c_str(), item->mySubs)) { - if (event->possibleActions() & Qt::LinkAction) { + // Cause unexpected bugs : https://github.com/FreeCAD/FreeCAD/issues/11676 + /*if (event->possibleActions() & Qt::LinkAction) { if (items.size() > 1) { TREE_TRACE("Cannot replace with more than one object"); event->ignore(); @@ -1760,7 +1761,7 @@ void TreeWidget::dragMoveEvent(QDragMoveEvent* event) } event->setDropAction(Qt::LinkAction); return; - } + }*/ TREE_TRACE("cannot drop " << obj->getFullName() << ' ' << (owner ? owner->getFullName() : "") << '.' << subname); From b140feabaf78e6f384df182bcf87c109eb749cef Mon Sep 17 00:00:00 2001 From: Paddle Date: Mon, 15 Jan 2024 18:38:59 +0100 Subject: [PATCH 29/36] Sketcher: Edges pattern and width by type. --- src/Mod/Sketcher/Gui/AppSketcherGui.cpp | 2 +- src/Mod/Sketcher/Gui/CMakeLists.txt | 2 +- src/Mod/Sketcher/Gui/EditModeCoinManager.cpp | 100 +- src/Mod/Sketcher/Gui/EditModeCoinManager.h | 6 + .../Gui/EditModeCoinManagerParameters.h | 98 +- .../Gui/EditModeConstraintCoinManager.cpp | 26 +- .../Gui/EditModeGeometryCoinConverter.cpp | 149 +-- .../Gui/EditModeGeometryCoinConverter.h | 9 +- .../Gui/EditModeGeometryCoinManager.cpp | 301 +++--- src/Mod/Sketcher/Gui/SketcherSettings.cpp | 162 ++- src/Mod/Sketcher/Gui/SketcherSettings.h | 10 +- .../Gui/SketcherSettingsAppearance.ui | 967 ++++++++++++++++++ .../Sketcher/Gui/SketcherSettingsColors.ui | 835 --------------- 13 files changed, 1565 insertions(+), 1102 deletions(-) create mode 100644 src/Mod/Sketcher/Gui/SketcherSettingsAppearance.ui delete mode 100644 src/Mod/Sketcher/Gui/SketcherSettingsColors.ui diff --git a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp index 2d416d37dc..c45f9b91d9 100644 --- a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp +++ b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp @@ -143,7 +143,7 @@ PyMOD_INIT_FUNC(SketcherGui) QT_TRANSLATE_NOOP("QObject", "Sketcher")); (void)new Gui::PrefPageProducer( QT_TRANSLATE_NOOP("QObject", "Sketcher")); - (void)new Gui::PrefPageProducer( + (void)new Gui::PrefPageProducer( QT_TRANSLATE_NOOP("QObject", "Sketcher")); // add resources and reloads the translators diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index 1e1011d8e2..2b8aa6e7f7 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -39,7 +39,7 @@ set(SketcherGui_UIC_SRCS SketchMirrorDialog.ui SketcherSettings.ui SketcherSettingsGrid.ui - SketcherSettingsColors.ui + SketcherSettingsAppearance.ui SketcherSettingsDisplay.ui SketchRectangularArrayDialog.ui SketcherRegularPolygonDialog.ui diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp index 2dbdff3588..b88aaad185 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp @@ -145,6 +145,38 @@ void EditModeCoinManager::ParameterObserver::initParameters() [this](const std::string& param) { updateElementSizeParameters(param); }}, + {"EdgeWidth", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updateWidth(drawingParameters.CurveWidth, param, 2); + }}, + {"ConstructionWidth", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updateWidth(drawingParameters.ConstructionWidth, param, 1); + }}, + {"InternalWidth", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updateWidth(drawingParameters.InternalWidth, param, 1); + }}, + {"ExternalWidth", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updateWidth(drawingParameters.ExternalWidth, param, 1); + }}, + {"EdgePattern", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updatePattern(drawingParameters.CurvePattern, param, 0b1111111111111111); + }}, + {"ConstructionPattern", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updatePattern(drawingParameters.ConstructionPattern, param, 0b1111110011111100); + }}, + {"InternalPattern", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updatePattern(drawingParameters.InternalPattern, param, 0b1111110011111100); + }}, + {"ExternalPattern", + [this, &drawingParameters = Client.drawingParameters](const std::string& param) { + updatePattern(drawingParameters.ExternalPattern, param, 0b1110010011100100); + }}, {"CreateLineColor", [this, drawingParameters = Client.drawingParameters](const std::string& param) { updateColor(drawingParameters.CreateCurveColor, param); @@ -384,6 +416,30 @@ void EditModeCoinManager::ParameterObserver::updateElementSizeParameters( Client.updateInventorNodeSizes(); } +void EditModeCoinManager::ParameterObserver::updateWidth(int& width, + const std::string& parametername, + int def) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/View"); + + width = hGrp->GetInt(parametername.c_str(), def); + + Client.updateInventorWidths(); +} + +void EditModeCoinManager::ParameterObserver::updatePattern(unsigned int& pattern, + const std::string& parametername, + unsigned int def) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/View"); + + pattern = hGrp->GetInt(parametername.c_str(), def); + + Client.updateInventorPatterns(); +} + void EditModeCoinManager::ParameterObserver::updateColor(SbColor& sbcolor, const std::string& parametername) { @@ -691,14 +747,17 @@ EditModeCoinManager::detectPreselection(SoPickedPoint* Point, const SbVec2s& cur } // checking for a hit in the curves - if (tail == editModeScenegraphNodes.CurveSet[l]) { - const SoDetail* curve_detail = Point->getDetail(editModeScenegraphNodes.CurveSet[l]); - if (curve_detail && curve_detail->getTypeId() == SoLineDetail::getClassTypeId()) { - // get the index - int curveIndex = static_cast(curve_detail)->getLineIndex(); - result.GeoIndex = coinMapping.getCurveGeoId(curveIndex, l); + for (int t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + if (tail == editModeScenegraphNodes.CurveSet[l][t]) { + const SoDetail* curve_detail = + Point->getDetail(editModeScenegraphNodes.CurveSet[l][t]); + if (curve_detail && curve_detail->getTypeId() == SoLineDetail::getClassTypeId()) { + // get the index + int curveIndex = static_cast(curve_detail)->getLineIndex(); + result.GeoIndex = coinMapping.getCurveGeoId(curveIndex, l, t); - return result; + return result; + } } } } @@ -1036,14 +1095,14 @@ void EditModeCoinManager::updateInventorNodeSizes() { auto layersconfiguration = viewProvider.VisualLayerList.getValues(); + updateInventorWidths(); + for (int l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { editModeScenegraphNodes.PointsDrawStyle[l]->pointSize = 8 * drawingParameters.pixelScalingFactor; editModeScenegraphNodes.PointSet[l]->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_FILLED", drawingParameters.markerSize); - editModeScenegraphNodes.CurvesDrawStyle[l]->lineWidth = - layersconfiguration[l].getLineWidth() * drawingParameters.pixelScalingFactor; } editModeScenegraphNodes.RootCrossDrawStyle->lineWidth = @@ -1064,6 +1123,29 @@ void EditModeCoinManager::updateInventorNodeSizes() pEditModeConstraintCoinManager->rebuildConstraintNodes(); } +void EditModeCoinManager::updateInventorWidths() +{ + editModeScenegraphNodes.CurvesDrawStyle->lineWidth = + drawingParameters.CurveWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesConstructionDrawStyle->lineWidth = + drawingParameters.ConstructionWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesInternalDrawStyle->lineWidth = + drawingParameters.InternalWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesExternalDrawStyle->lineWidth = + drawingParameters.ExternalWidth * drawingParameters.pixelScalingFactor; +} + +void EditModeCoinManager::updateInventorPatterns() +{ + editModeScenegraphNodes.CurvesDrawStyle->linePattern = drawingParameters.CurvePattern; + editModeScenegraphNodes.CurvesConstructionDrawStyle->linePattern = + drawingParameters.ConstructionPattern; + editModeScenegraphNodes.CurvesInternalDrawStyle->linePattern = + drawingParameters.InternalPattern; + editModeScenegraphNodes.CurvesExternalDrawStyle->linePattern = + drawingParameters.ExternalPattern; +} + void EditModeCoinManager::updateInventorColors() { editModeScenegraphNodes.RootCrossMaterials->diffuseColor.set1Value( diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManager.h b/src/Mod/Sketcher/Gui/EditModeCoinManager.h index aaf2a9b14e..338d983452 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManager.h +++ b/src/Mod/Sketcher/Gui/EditModeCoinManager.h @@ -141,6 +141,8 @@ class SketcherGuiExport EditModeCoinManager void updateLineRenderingOrderParameters(const std::string& parametername); void updateConstraintPresentationParameters(const std::string& parametername); void updateElementSizeParameters(const std::string& parametername); + void updateWidth(int& width, const std::string& parametername, int def); + void updatePattern(unsigned int& pattern, const std::string& pname, unsigned int def); void updateColor(SbColor& sbcolor, const std::string& parametername); void updateUnit(const std::string& parametername); @@ -282,6 +284,10 @@ private: void updateInventorColors(); + void updateInventorPatterns(); + + void updateInventorWidths(); + /** @name coin nodes creation*/ void createEditModeInventorNodes(); //@} diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h b/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h index a59f7766a6..19a77466e6 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h +++ b/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h @@ -40,7 +40,6 @@ #include #include - #include #include @@ -140,6 +139,16 @@ struct DrawingParameters 17; // Font size to be used by SoDatumLabel, which uses a QPainter and a QFont internally int constraintIconSize = 15; // Size of constraint icons int markerSize = 7; // Size used for markers + + int CurveWidth = 2; // width of normal edges + int ConstructionWidth = 1; // width of construction edges + int InternalWidth = 1; // width of internal edges + int ExternalWidth = 1; // width of external edges + + unsigned int CurvePattern = 0b1111111111111111; // pattern of normal edges + unsigned int ConstructionPattern = 0b1111110011111100; // pattern of construction edges + unsigned int InternalPattern = 0b1111110011111100; // pattern of internal edges + unsigned int ExternalPattern = 0b1110010011100100; // pattern of external edges //@} }; @@ -155,9 +164,9 @@ struct GeometryLayerNodes /** @name Curve nodes*/ //@{ - std::vector& CurvesMaterials; // The materials for the curves - std::vector& CurvesCoordinate; // The coordinates of the segments of the curves - std::vector& CurveSet; // The set of curves + std::vector>& CurvesMaterials; + std::vector>& CurvesCoordinate; + std::vector>& CurveSet; //@} }; @@ -176,9 +185,10 @@ struct GeometryLayerNodes class MultiFieldId { public: - explicit constexpr MultiFieldId(int fieldindex = -1, int layerid = 0) + explicit constexpr MultiFieldId(int fieldindex = -1, int layerid = 0, int geotypeid = 0) : fieldIndex(fieldindex) , layerId(layerid) + , geoTypeId(geotypeid) {} MultiFieldId(const MultiFieldId&) = default; @@ -189,16 +199,19 @@ public: inline bool operator==(const MultiFieldId& obj) const { - return this->fieldIndex == obj.fieldIndex && this->layerId == obj.layerId; + return this->fieldIndex == obj.fieldIndex && this->layerId == obj.layerId + && this->geoTypeId == obj.geoTypeId; } inline bool operator!=(const MultiFieldId& obj) const { - return this->fieldIndex != obj.fieldIndex || this->layerId != obj.layerId; + return this->fieldIndex != obj.fieldIndex || this->layerId != obj.layerId + || this->geoTypeId != obj.geoTypeId; } int fieldIndex = -1; int layerId = 0; + int geoTypeId = 0; static const MultiFieldId Invalid; }; @@ -255,7 +268,16 @@ private: Default = 0 }; + public: + enum class SubLayer + { + Normal = 0, + Construction = 1, + Internal = 2, + External = 3, + }; + void reset() { CoinLayers = 1; @@ -280,8 +302,46 @@ public: CoinLayers = layernumber; } + int inline getSubLayerCount() const + { + return SubLayers; + } + + int inline getSubLayerIndex(const int geoId, const Sketcher::GeometryFacade* geom) const + { + bool isConstruction = geom->getConstruction(); + bool isInternal = geom->isInternalAligned(); + bool isExternal = geoId <= Sketcher::GeoEnum::RefExt; + + return static_cast(isExternal ? SubLayer::External + : isInternal ? SubLayer::Internal + : isConstruction ? SubLayer::Construction + : SubLayer::Normal); + } + + bool isNormalSubLayer(int t) const + { + return t == static_cast(SubLayer::Normal); + } + + bool isConstructionSubLayer(int t) const + { + return t == static_cast(SubLayer::Construction); + } + + bool isInternalSubLayer(int t) const + { + return t == static_cast(SubLayer::Internal); + } + + bool isExternalSubLayer(int t) const + { + return t == static_cast(SubLayer::External); + } + private: int CoinLayers = 1; // defaults to a single Coin Geometry Layer. + int SubLayers = 4; // Normal, Construction, Internal, External. }; /** @brief Struct to hold the results of analysis performed on geometry @@ -340,10 +400,14 @@ struct EditModeScenegraphNodes /** @name Curve nodes*/ //@{ SmSwitchboard* CurvesGroup; - std::vector CurvesMaterials; - std::vector CurvesCoordinate; - std::vector CurvesDrawStyle; - std::vector CurveSet; + std::vector> CurvesMaterials; + std::vector> CurvesCoordinate; + std::vector> CurveSet; + SoDrawStyle* CurvesDrawStyle; + SoDrawStyle* CurvesConstructionDrawStyle; + SoDrawStyle* CurvesInternalDrawStyle; + SoDrawStyle* CurvesExternalDrawStyle; + SoDrawStyle* HiddenCurvesDrawStyle; //@} /** @name Axes nodes*/ @@ -395,7 +459,7 @@ struct EditModeScenegraphNodes }; /** @brief Helper struct containing index conversions (mappings) between - * {GeoId, PointPos} and MF indices per layer, and VertexId and MF indices per layer. + * {GeoId, PointPos} and MF indices per layer, sublayers, and VertexId and MF indices per layer. * * These are updated with every draw of the scenegraph. */ @@ -404,6 +468,9 @@ struct CoinMapping void clear() { + for (size_t l = 0; l < CurvIdToGeoId.size(); ++l) { + CurvIdToGeoId[l].clear(); + } CurvIdToGeoId.clear(); PointIdToGeoId.clear(); GeoElementId2SetId.clear(); @@ -412,9 +479,9 @@ struct CoinMapping /// given the MF index of a curve and the coin layer in which it is drawn returns the GeoId of /// the curve - int getCurveGeoId(int curveindex, int layerindex) + int getCurveGeoId(int curveindex, int layerindex, int sublayerindex = 0) { - return CurvIdToGeoId[layerindex][curveindex]; + return CurvIdToGeoId[layerindex][sublayerindex][curveindex]; } /// given the MF index of a point and the coin layer in which it is drawn returns the GeoId of /// the point @@ -461,7 +528,8 @@ struct CoinMapping //* These map a MF index (second index) within a coin layer (first index) for points or curves // to a GeoId */ - std::vector> CurvIdToGeoId; // conversion of SoLineSet index to GeoId + std::vector>> + CurvIdToGeoId; // conversion of SoLineSet index to GeoId std::vector> PointIdToGeoId; // conversion of SoCoordinate3 index to GeoId //* This maps an MF index (second index) of a point within a coin layer (first index) to a diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 5dc22f984a..c8a38dd933 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -1587,14 +1587,20 @@ void EditModeConstraintCoinManager::updateConstraintColor( std::vector PtNum; std::vector pcolor; // point color - std::vector CurvNum; - std::vector color; // curve color + std::vector> CurvNum; + std::vector> color; // curve color for (int l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { PtNum.push_back(editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.getNum()); pcolor.push_back(editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.startEditing()); - CurvNum.push_back(editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.getNum()); - color.push_back(editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.startEditing()); + CurvNum.emplace_back(); + color.emplace_back(); + for (int t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + CurvNum[l].push_back( + editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.getNum()); + color[l].push_back( + editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.startEditing()); + } } int maxNumberOfConstraints = std::min(editModeScenegraphNodes.constrGroup->getNumChildren(), @@ -1653,9 +1659,11 @@ void EditModeConstraintCoinManager::updateConstraintColor( if (multifieldIndex != MultiFieldId::Invalid) { int index = multifieldIndex.fieldIndex; int layer = multifieldIndex.layerId; - if (layer < static_cast(CurvNum.size()) && index >= 0 - && index < CurvNum[layer]) { - color[layer][index] = drawingParameters.SelectColor; + int sublayer = multifieldIndex.geoTypeId; + if (layer < static_cast(CurvNum.size()) + && sublayer < static_cast(CurvNum[layer].size()) && index >= 0 + && index < CurvNum[layer][sublayer]) { + color[layer][sublayer][index] = drawingParameters.SelectColor; } } } @@ -1730,7 +1738,9 @@ void EditModeConstraintCoinManager::updateConstraintColor( for (int l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.finishEditing(); - editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.finishEditing(); + for (int t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.finishEditing(); + } } } diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp index d1b0679788..5235a0224c 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp @@ -55,27 +55,30 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli arcGeoIds.clear(); // end information layer - Coords.clear(); Points.clear(); + Coords.clear(); Index.clear(); coinMapping.clear(); pointCounter.clear(); - curveCounter.clear(); for (auto l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { - Coords.emplace_back(); Points.emplace_back(); + Coords.emplace_back(); Index.emplace_back(); coinMapping.CurvIdToGeoId.emplace_back(); + for (int t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + Coords[l].emplace_back(); + Index[l].emplace_back(); + coinMapping.CurvIdToGeoId[l].emplace_back(); + } coinMapping.PointIdToGeoId.emplace_back(); coinMapping.PointIdToVertexId.emplace_back(); } pointCounter.resize(geometryLayerParameters.getCoinLayerCount(), 0); - curveCounter.resize(geometryLayerParameters.getCoinLayerCount(), 0); // RootPoint // TODO: RootPoint is here added in layer0. However, this layer may be hidden. The point should, @@ -83,8 +86,8 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli // empty layer. Points[0].emplace_back(0., 0., 0.); coinMapping.PointIdToGeoId[0].push_back(-1); // root point - coinMapping.PointIdToVertexId[0].push_back( - -1); // VertexId is the reference used for point selection/preselection + coinMapping.PointIdToVertexId[0].push_back(-1); + // VertexId is the reference used for point selection/preselection coinMapping.GeoElementId2SetId.emplace(std::piecewise_construct, std::forward_as_tuple(Sketcher::GeoElementId::RtPnt), @@ -93,7 +96,8 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli auto setTracking = [this](int geoId, int coinLayer, EditModeGeometryCoinConverter::PointsMode pointmode, - int numberCurves) { + int numberCurves, + int sublayer) { int numberPoints = 0; if (pointmode == PointsMode::InsertSingle) { @@ -153,12 +157,14 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli coinMapping.GeoElementId2SetId.emplace( std::piecewise_construct, std::forward_as_tuple(geoId, Sketcher::PointPos::none), - std::forward_as_tuple(static_cast(coinMapping.CurvIdToGeoId[coinLayer].size()), - coinLayer)); + std::forward_as_tuple( + static_cast(coinMapping.CurvIdToGeoId[coinLayer][sublayer].size()), + coinLayer, + sublayer)); } for (int i = 0; i < numberCurves; i++) { - coinMapping.CurvIdToGeoId[coinLayer].push_back(geoId); + coinMapping.CurvIdToGeoId[coinLayer][sublayer].push_back(geoId); } }; @@ -168,7 +174,8 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli const auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId); const auto type = geom->getGeometry()->getTypeId(); - auto layerId = getSafeGeomLayerId(geom); + int layerId = getSafeGeomLayerId(geom); + int subLayerId = geometryLayerParameters.getSubLayerIndex(GeoId, geom); auto coinLayer = geometryLayerParameters.getSafeCoinLayer(layerId); @@ -176,43 +183,55 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli convert(geom, GeoId); + EditModeGeometryCoinConverter::AnalyseMode::BoundingBoxMagnitude>(geom, + GeoId, + subLayerId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertSingle, - 0); + 0, + subLayerId); } else if (type == Part::GeomLineSegment::getClassTypeId()) { // add a line convert(geom, GeoId); + EditModeGeometryCoinConverter::AnalyseMode::BoundingBoxMagnitude>(geom, + GeoId, + subLayerId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertStartEnd, - 1); + 1, + subLayerId); } else if (type.isDerivedFrom( Part::GeomConic::getClassTypeId())) { // add a closed curve conic convert(geom, GeoId); + EditModeGeometryCoinConverter::AnalyseMode::BoundingBoxMagnitude>(geom, + GeoId, + subLayerId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertMidOnly, - 1); + 1, + subLayerId); } else if (type.isDerivedFrom( Part::GeomArcOfConic::getClassTypeId())) { // add an arc of conic convert(geom, GeoId); + EditModeGeometryCoinConverter::AnalyseMode::BoundingBoxMagnitude>(geom, + GeoId, + subLayerId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertStartEndMid, - 1); + 1, + subLayerId); arcGeoIds.push_back(GeoId); } else if (type == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline (a bounded @@ -221,58 +240,53 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade& geoli EditModeGeometryCoinConverter::PointsMode::InsertStartEnd, EditModeGeometryCoinConverter::CurveMode::OpenCurve, EditModeGeometryCoinConverter::AnalyseMode:: - BoundingBoxMagnitudeAndBSplineCurvature>(geom, GeoId); + BoundingBoxMagnitudeAndBSplineCurvature>(geom, GeoId, subLayerId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertStartEnd, - 1); + 1, + subLayerId); bsplineGeoIds.push_back(GeoId); } } - for (auto l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { + // Coin Nodes Editing + int vOrFactor = ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider); + double linez = vOrFactor * drawingParameters.zLowLines; // NOLINT + double pointz = vOrFactor * drawingParameters.zLowPoints; - // Coin Nodes Editing - geometryLayerNodes.CurvesCoordinate[l]->point.setNum(Coords[l].size()); - geometryLayerNodes.CurveSet[l]->numVertices.setNum(Index[l].size()); - geometryLayerNodes.CurvesMaterials[l]->diffuseColor.setNum(Index[l].size()); + for (auto l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { geometryLayerNodes.PointsCoordinate[l]->point.setNum(Points[l].size()); geometryLayerNodes.PointsMaterials[l]->diffuseColor.setNum(Points[l].size()); - - SbVec3f* verts = geometryLayerNodes.CurvesCoordinate[l]->point.startEditing(); - int32_t* index = geometryLayerNodes.CurveSet[l]->numVertices.startEditing(); SbVec3f* pverts = geometryLayerNodes.PointsCoordinate[l]->point.startEditing(); - int i = 0; // setting up the line set - for (std::vector::const_iterator it = Coords[l].begin(); - it != Coords[l].end(); - ++it, i++) { - verts[i].setValue(it->x, - it->y, - ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider) - * drawingParameters.zLowLines); + int i = 0; // setting up the point set + for (auto& point : Points[l]) { + pverts[i++].setValue(point.x, point.y, pointz); } - - i = 0; // setting up the indexes of the line set - for (std::vector::const_iterator it = Index[l].begin(); it != Index[l].end(); - ++it, i++) { - index[i] = *it; - } - - i = 0; // setting up the point set - for (std::vector::const_iterator it = Points[l].begin(); - it != Points[l].end(); - ++it, i++) { - pverts[i].setValue( - it->x, - it->y, - ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider) - * drawingParameters.zLowPoints); - } - - geometryLayerNodes.CurvesCoordinate[l]->point.finishEditing(); - geometryLayerNodes.CurveSet[l]->numVertices.finishEditing(); geometryLayerNodes.PointsCoordinate[l]->point.finishEditing(); + + for (auto t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + geometryLayerNodes.CurvesCoordinate[l][t]->point.setNum(Coords[l][t].size()); + geometryLayerNodes.CurveSet[l][t]->numVertices.setNum(Index[l][t].size()); + geometryLayerNodes.CurvesMaterials[l][t]->diffuseColor.setNum(Index[l][t].size()); + + SbVec3f* verts = geometryLayerNodes.CurvesCoordinate[l][t]->point.startEditing(); + int32_t* index = geometryLayerNodes.CurveSet[l][t]->numVertices.startEditing(); + + i = 0; // setting up the line set + for (auto& coord : Coords[l][t]) { + verts[i++].setValue(coord.x, coord.y, linez); // NOLINT + } + + i = 0; // setting up the indexes of the line set + for (auto it : Index[l][t]) { + index[i++] = it; + } + + geometryLayerNodes.CurvesCoordinate[l][t]->point.finishEditing(); + geometryLayerNodes.CurveSet[l][t]->numVertices.finishEditing(); + } } } @@ -281,7 +295,8 @@ template void EditModeGeometryCoinConverter::convert(const Sketcher::GeometryFacade* geometryfacade, - [[maybe_unused]] int geoid) + [[maybe_unused]] int geoid, + int subLayer) { auto geo = static_cast(geometryfacade->getGeometry()); auto layerId = getSafeGeomLayerId(geometryfacade); @@ -317,9 +332,9 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeometryFacade* geom // Curves if constexpr (curvemode == CurveMode::StartEndPointsOnly) { - addPoint(Coords[coinLayer], geo->getStartPoint()); - addPoint(Coords[coinLayer], geo->getEndPoint()); - Index[coinLayer].push_back(2); + addPoint(Coords[coinLayer][subLayer], geo->getStartPoint()); + addPoint(Coords[coinLayer][subLayer], geo->getEndPoint()); + Index[coinLayer][subLayer].push_back(2); } else if constexpr (curvemode == CurveMode::ClosedCurve) { int numSegments = drawingParameters.curvedEdgeCountSegments; @@ -331,13 +346,13 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeometryFacade* geom for (int i = 0; i < numSegments; i++) { Base::Vector3d pnt = geo->value(i * segment); - addPoint(Coords[coinLayer], pnt); + addPoint(Coords[coinLayer][subLayer], pnt); } Base::Vector3d pnt = geo->value(0); - addPoint(Coords[coinLayer], pnt); + addPoint(Coords[coinLayer][subLayer], pnt); - Index[coinLayer].push_back(numSegments + 1); + Index[coinLayer][subLayer].push_back(numSegments + 1); } else if constexpr (curvemode == CurveMode::OpenCurve) { int numSegments = drawingParameters.curvedEdgeCountSegments; @@ -349,13 +364,13 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeometryFacade* geom for (int i = 0; i < numSegments; i++) { Base::Vector3d pnt = geo->value(geo->getFirstParameter() + i * segment); - addPoint(Coords[coinLayer], pnt); + addPoint(Coords[coinLayer][subLayer], pnt); } Base::Vector3d pnt = geo->value(geo->getLastParameter()); - addPoint(Coords[coinLayer], pnt); + addPoint(Coords[coinLayer][subLayer], pnt); - Index[coinLayer].push_back(numSegments + 1); + Index[coinLayer][subLayer].push_back(numSegments + 1); if constexpr (analysemode == AnalyseMode::BoundingBoxMagnitudeAndBSplineCurvature) { //*************************************************************************************************************** diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h index 950635138a..889b5b0a2e 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h @@ -152,7 +152,9 @@ public: private: template - void convert(const Sketcher::GeometryFacade* geometryfacade, [[maybe_unused]] int geoId); + void convert(const Sketcher::GeometryFacade* geometryfacade, + [[maybe_unused]] int geoId, + int subLayerId = 0); private: /// Reference to ViewProviderSketch in order to access the public and the Attorney Interface @@ -160,13 +162,12 @@ private: GeometryLayerNodes& geometryLayerNodes; - std::vector> Coords; std::vector> Points; - std::vector> Index; + std::vector>> Coords; + std::vector>> Index; // temporal counters, one per layer std::vector pointCounter; - std::vector curveCounter; // temporal global vertex counter int vertexCounter = 0; diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp index 120e8dd352..8c6b030a34 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp @@ -73,19 +73,21 @@ void EditModeGeometryCoinManager::processGeometry(const GeoListFacade& geolistfa { // enable all layers editModeScenegraphNodes.PointsGroup->enable.setNum(geometryLayerParameters.getCoinLayerCount()); - editModeScenegraphNodes.CurvesGroup->enable.setNum(geometryLayerParameters.getCoinLayerCount()); + editModeScenegraphNodes.CurvesGroup->enable.setNum( + geometryLayerParameters.getCoinLayerCount() * geometryLayerParameters.getSubLayerCount()); SbBool* swsp = editModeScenegraphNodes.PointsGroup->enable.startEditing(); SbBool* swsc = editModeScenegraphNodes.CurvesGroup->enable.startEditing(); - auto setEnableLayer = [swsp, swsc](int l, bool enabled) { - swsp[l] = enabled; // layer defaults to enabled - swsc[l] = enabled; // layer defaults to enabled - }; - auto layersconfigurations = viewProvider.VisualLayerList.getValues(); for (auto l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { - setEnableLayer(l, layersconfigurations[l].isVisible()); + auto enabled = layersconfigurations[l].isVisible(); + + swsp[l] = enabled; + int slCount = geometryLayerParameters.getSubLayerCount(); + for (int t = 0; t < slCount; t++) { + swsc[l * slCount + t] = enabled; + } } editModeScenegraphNodes.PointsGroup->enable.finishEditing(); @@ -122,14 +124,6 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli bool issketchinvalid) { // Lambdas for convenience retrieval of geometry information - auto isConstructionGeom = [&geolistfacade](int GeoId) { - auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId); - if (geom) { - return geom->getConstruction(); - } - return false; - }; - auto isDefinedGeomPoint = [&geolistfacade](int GeoId) { auto geom = geolistfacade.getGeometryFacadeFromGeoId(GeoId); if (geom) { @@ -162,6 +156,9 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli return false; }; + bool sketchFullyConstrained = + ViewProviderSketchCoinAttorney::isSketchFullyConstrained(viewProvider); + // Update Colors SbColor* crosscolor = editModeScenegraphNodes.RootCrossMaterials->diffuseColor.startEditing(); @@ -169,17 +166,11 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider); for (auto l = 0; l < geometryLayerParameters.getCoinLayerCount(); l++) { - + float x, y, z; int PtNum = editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.getNum(); SbColor* pcolor = editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.startEditing(); - int CurvNum = editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.getNum(); - SbColor* color = editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.startEditing(); - - SbVec3f* verts = editModeScenegraphNodes.CurvesCoordinate[l]->point.startEditing(); SbVec3f* pverts = editModeScenegraphNodes.PointsCoordinate[l]->point.startEditing(); - float x, y, z; - // colors of the point set if (issketchinvalid) { for (int i = 0; i < PtNum; i++) { @@ -189,9 +180,7 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli else { for (int i = 0; i < PtNum; i++) { - if (!(i == 0 && l == 0) - && ViewProviderSketchCoinAttorney::isSketchFullyConstrained( - viewProvider)) { // root point is not coloured + if (!(i == 0 && l == 0) && sketchFullyConstrained) { // root point is not coloured pcolor[i] = drawingParameters.FullyConstrainedColor; } else { @@ -345,98 +334,99 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli drawingParameters.zMidLines, drawingParameters.zLowLines); - int j = 0; // vertexindex + for (auto t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + int CurvNum = editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.getNum(); + SbColor* color = + editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.startEditing(); + SbVec3f* verts = editModeScenegraphNodes.CurvesCoordinate[l][t]->point.startEditing(); - for (int i = 0; i < CurvNum; i++) { - int GeoId = coinMapping.getCurveGeoId(i, l); - // CurvId has several vertices associated to 1 material - // edit->CurveSet->numVertices => [i] indicates number of vertex for line i. - int indexes = (editModeScenegraphNodes.CurveSet[l]->numVertices[i]); + int j = 0; // vertexindex + for (int i = 0; i < CurvNum; i++) { + int GeoId = coinMapping.getCurveGeoId(i, l, t); + // CurvId has several vertices associated to 1 material + // edit->CurveSet->numVertices => [i] indicates number of vertex for line i. + int indexes = (editModeScenegraphNodes.CurveSet[l][t]->numVertices[i]); - bool selected = ViewProviderSketchCoinAttorney::isCurveSelected(viewProvider, GeoId); - bool preselected = (preselectcurve == GeoId); + bool selected = + ViewProviderSketchCoinAttorney::isCurveSelected(viewProvider, GeoId); + bool preselected = (preselectcurve == GeoId); + bool constrainedElement = isFullyConstraintElement(GeoId); - bool constrainedElement = isFullyConstraintElement(GeoId); + if (selected || preselected) { + color[i] = selected ? (preselected ? drawingParameters.PreselectSelectedColor + : drawingParameters.SelectColor) + : drawingParameters.PreselectColor; - if (selected && preselected) { - color[i] = drawingParameters.PreselectSelectedColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * drawingParameters.zHighLine); - } - } - else if (selected) { - color[i] = drawingParameters.SelectColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * drawingParameters.zHighLine); - } - } - else if (preselected) { - color[i] = drawingParameters.PreselectColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * drawingParameters.zHighLine); - } - } - else if (GeoId <= Sketcher::GeoEnum::RefExt) { // external Geometry - color[i] = drawingParameters.CurveExternalColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zExtLine); - } - } - else if (issketchinvalid) { - color[i] = drawingParameters.InvalidSketchColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); - } - } - else if (isConstructionGeom(GeoId)) { - if (isInternalAlignedGeom(GeoId)) { - if (constrainedElement) { - color[i] = drawingParameters.FullyConstraintInternalAlignmentColor; + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = + SbVec3f(x, y, viewOrientationFactor * drawingParameters.zHighLine); } - else { - color[i] = drawingParameters.InternalAlignedGeoColor; + } + else if (geometryLayerParameters.isExternalSubLayer(t)) { + color[i] = drawingParameters.CurveExternalColor; + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = SbVec3f(x, y, viewOrientationFactor * zExtLine); } } else { - if (constrainedElement) { - color[i] = drawingParameters.FullyConstraintConstructionElementColor; + if (issketchinvalid) { + color[i] = drawingParameters.InvalidSketchColor; + + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); + } + } + else if (geometryLayerParameters.isConstructionSubLayer(t)) { + if (constrainedElement) { + color[i] = drawingParameters.FullyConstraintConstructionElementColor; + } + else { + color[i] = drawingParameters.CurveDraftColor; + } + + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = SbVec3f(x, y, viewOrientationFactor * zConstrLine); + } + } + else if (geometryLayerParameters.isInternalSubLayer(t)) { + if (constrainedElement) { + color[i] = drawingParameters.FullyConstraintInternalAlignmentColor; + } + else { + color[i] = drawingParameters.InternalAlignedGeoColor; + } + + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = SbVec3f(x, y, viewOrientationFactor * zConstrLine); + } } else { - color[i] = drawingParameters.CurveDraftColor; + if (sketchFullyConstrained) { + color[i] = drawingParameters.FullyConstrainedColor; + } + else if (constrainedElement) { + color[i] = drawingParameters.FullyConstraintElementColor; + } + else { + color[i] = drawingParameters.CurveColor; + } + + for (int k = j; j < k + indexes; j++) { + verts[j].getValue(x, y, z); + verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); + } } } + } - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zConstrLine); - } - } - else if (ViewProviderSketchCoinAttorney::isSketchFullyConstrained(viewProvider)) { - color[i] = drawingParameters.FullyConstrainedColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); - } - } - else if (isFullyConstraintElement(GeoId)) { - color[i] = drawingParameters.FullyConstraintElementColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); - } - } - else { - color[i] = drawingParameters.CurveColor; - for (int k = j; j < k + indexes; j++) { - verts[j].getValue(x, y, z); - verts[j] = SbVec3f(x, y, viewOrientationFactor * zNormLine); - } - } + editModeScenegraphNodes.CurvesMaterials[l][t]->diffuseColor.finishEditing(); + editModeScenegraphNodes.CurvesCoordinate[l][t]->point.finishEditing(); + editModeScenegraphNodes.CurveSet[l][t]->numVertices.finishEditing(); } // colors of the cross @@ -464,11 +454,7 @@ void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade& geoli } } - // end editing - editModeScenegraphNodes.CurvesMaterials[l]->diffuseColor.finishEditing(); editModeScenegraphNodes.PointsMaterials[l]->diffuseColor.finishEditing(); - editModeScenegraphNodes.CurvesCoordinate[l]->point.finishEditing(); - editModeScenegraphNodes.CurveSet[l]->numVertices.finishEditing(); } editModeScenegraphNodes.RootCrossMaterials->diffuseColor.finishEditing(); @@ -565,45 +551,80 @@ void EditModeGeometryCoinManager::createEditModePointInventorNodes() void EditModeGeometryCoinManager::createEditModeCurveInventorNodes() { - auto layersconfigurations = viewProvider.VisualLayerList.getValue(); + editModeScenegraphNodes.CurvesDrawStyle = new SoDrawStyle; + editModeScenegraphNodes.CurvesDrawStyle->setName("CurvesDrawStyle"); + editModeScenegraphNodes.CurvesDrawStyle->lineWidth = + drawingParameters.CurveWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesDrawStyle->linePattern = drawingParameters.CurvePattern; + editModeScenegraphNodes.CurvesDrawStyle->linePatternScaleFactor = 2; + + editModeScenegraphNodes.CurvesConstructionDrawStyle = new SoDrawStyle; + editModeScenegraphNodes.CurvesConstructionDrawStyle->setName("CurvesConstructionDrawStyle"); + editModeScenegraphNodes.CurvesConstructionDrawStyle->lineWidth = + drawingParameters.ConstructionWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesConstructionDrawStyle->linePattern = + drawingParameters.ConstructionPattern; + editModeScenegraphNodes.CurvesConstructionDrawStyle->linePatternScaleFactor = 2; + + editModeScenegraphNodes.CurvesInternalDrawStyle = new SoDrawStyle; + editModeScenegraphNodes.CurvesInternalDrawStyle->setName("CurvesInternalDrawStyle"); + editModeScenegraphNodes.CurvesInternalDrawStyle->lineWidth = + drawingParameters.InternalWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesInternalDrawStyle->linePattern = + drawingParameters.InternalPattern; + editModeScenegraphNodes.CurvesInternalDrawStyle->linePatternScaleFactor = 2; + + editModeScenegraphNodes.CurvesExternalDrawStyle = new SoDrawStyle; + editModeScenegraphNodes.CurvesExternalDrawStyle->setName("CurvesExternalDrawStyle"); + editModeScenegraphNodes.CurvesExternalDrawStyle->lineWidth = + drawingParameters.ExternalWidth * drawingParameters.pixelScalingFactor; + editModeScenegraphNodes.CurvesExternalDrawStyle->linePattern = + drawingParameters.ExternalPattern; + editModeScenegraphNodes.CurvesExternalDrawStyle->linePatternScaleFactor = 2; for (int i = 0; i < geometryLayerParameters.getCoinLayerCount(); i++) { - SoSeparator* sep = new SoSeparator; - sep->ref(); + editModeScenegraphNodes.CurvesMaterials.emplace_back(); + editModeScenegraphNodes.CurvesCoordinate.emplace_back(); + editModeScenegraphNodes.CurveSet.emplace_back(); + for (int t = 0; t < geometryLayerParameters.getSubLayerCount(); t++) { + SoSeparator* sep = new SoSeparator; + sep->ref(); - auto somaterial = new SoMaterial; - editModeScenegraphNodes.CurvesMaterials.push_back(somaterial); - editModeScenegraphNodes.CurvesMaterials[i]->setName(concat("CurvesMaterials", i).c_str()); - sep->addChild(editModeScenegraphNodes.CurvesMaterials[i]); + auto somaterial = new SoMaterial; + somaterial->setName(concat("CurvesMaterials", i * 10 + t).c_str()); + editModeScenegraphNodes.CurvesMaterials[i].push_back(somaterial); + sep->addChild(editModeScenegraphNodes.CurvesMaterials[i][t]); - auto MtlBind = new SoMaterialBinding; - MtlBind->setName(concat("CurvesMaterialsBinding", i).c_str()); - MtlBind->value = SoMaterialBinding::PER_FACE; - sep->addChild(MtlBind); + auto MtlBind = new SoMaterialBinding; + MtlBind->setName(concat("CurvesMaterialsBinding", i * 10 + t).c_str()); + MtlBind->value = SoMaterialBinding::PER_FACE; + sep->addChild(MtlBind); - auto coords = new SoCoordinate3; - editModeScenegraphNodes.CurvesCoordinate.push_back(coords); - editModeScenegraphNodes.CurvesCoordinate[i]->setName(concat("CurvesCoordinate", i).c_str()); - sep->addChild(editModeScenegraphNodes.CurvesCoordinate[i]); + auto coords = new SoCoordinate3; + coords->setName(concat("CurvesCoordinate", i * 10 + t).c_str()); + editModeScenegraphNodes.CurvesCoordinate[i].push_back(coords); + sep->addChild(editModeScenegraphNodes.CurvesCoordinate[i][t]); - auto drawstyle = new SoDrawStyle; - editModeScenegraphNodes.CurvesDrawStyle.push_back(drawstyle); - editModeScenegraphNodes.CurvesDrawStyle[i]->setName(concat("CurvesDrawStyle", i).c_str()); + if (geometryLayerParameters.isConstructionSubLayer(t)) { + sep->addChild(editModeScenegraphNodes.CurvesConstructionDrawStyle); + } + else if (geometryLayerParameters.isInternalSubLayer(t)) { + sep->addChild(editModeScenegraphNodes.CurvesInternalDrawStyle); + } + else if (geometryLayerParameters.isExternalSubLayer(t)) { + sep->addChild(editModeScenegraphNodes.CurvesExternalDrawStyle); + } + else { + sep->addChild(editModeScenegraphNodes.CurvesDrawStyle); + } - editModeScenegraphNodes.CurvesDrawStyle[i]->lineWidth = - layersconfigurations[i].getLineWidth() * drawingParameters.pixelScalingFactor; - editModeScenegraphNodes.CurvesDrawStyle[i]->linePattern = - layersconfigurations[i].getLinePattern(); - editModeScenegraphNodes.CurvesDrawStyle[i]->linePatternScaleFactor = 5; + auto solineset = new SoLineSet; + solineset->setName(concat("CurvesLineSet", i * 10 + t).c_str()); + editModeScenegraphNodes.CurveSet[i].push_back(solineset); + sep->addChild(editModeScenegraphNodes.CurveSet[i][t]); - sep->addChild(editModeScenegraphNodes.CurvesDrawStyle[i]); - - auto solineset = new SoLineSet; - editModeScenegraphNodes.CurveSet.push_back(solineset); - editModeScenegraphNodes.CurveSet[i]->setName(concat("CurvesLineSet", i).c_str()); - sep->addChild(editModeScenegraphNodes.CurveSet[i]); - - editModeScenegraphNodes.CurvesGroup->addChild(sep); - sep->unref(); + editModeScenegraphNodes.CurvesGroup->addChild(sep); + sep->unref(); + } } } diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.cpp b/src/Mod/Sketcher/Gui/SketcherSettings.cpp index a316235e49..5c30e5fced 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.cpp +++ b/src/Mod/Sketcher/Gui/SketcherSettings.cpp @@ -34,7 +34,7 @@ #include "SketcherSettings.h" #include "ui_SketcherSettings.h" -#include "ui_SketcherSettingsColors.h" +#include "ui_SketcherSettingsAppearance.h" #include "ui_SketcherSettingsDisplay.h" #include "ui_SketcherSettingsGrid.h" @@ -43,6 +43,49 @@ using namespace SketcherGui; /* TRANSLATOR SketcherGui::SketcherSettings */ +QList getPenStyles() +{ + QList styles; + styles << 0b1111111111111111 // solid + << 0b1110111011101110 // dashed 3:1 + << 0b1111110011111100 // dashed 6:2 + << 0b0000111100001111 // dashed 4:4 + << 0b1010101010101010 // point 1:1 + << 0b1110010011100100 // dash point + << 0b1111111100111100; // dash long-dash + return styles; +} + +const QVector binaryPatternToDashPattern(int binaryPattern) +{ + QVector dashPattern; + int count = 0; + bool isDash = (binaryPattern & 0x8000) != 0; // Check the highest bit + + for (int i = 0; i < 16; ++i) { + bool currentBit = (binaryPattern & (0x8000 >> i)) != 0; + if (currentBit == isDash) { + ++count; // Counting dashes or spaces + } + else { + // Adjust count to be odd for dashes and even for spaces (see qt doc) + count = (count % 2 == (isDash ? 0 : 1)) ? count + 1 : count; + dashPattern << count; + count = 1; // Reset count for next dash/space + isDash = !isDash; + } + } + count = (count % 2 == (isDash ? 0 : 1)) ? count + 1 : count; + dashPattern << count; // Add the last count + + if ((dashPattern.size() % 2) == 1) { + // prevent this error : qWarning("QPen::setDashPattern: Pattern not of even length"); + dashPattern << 1; + } + + return dashPattern; +} + SketcherSettings::SketcherSettings(QWidget* parent) : PreferencePage(parent) , ui(new Ui_SketcherSettings) @@ -206,17 +249,17 @@ SketcherSettingsGrid::SketcherSettingsGrid(QWidget* parent) { ui->setupUi(this); - QList> styles; - styles << qMakePair(Qt::SolidLine, 0xffff) << qMakePair(Qt::DashLine, 0x0f0f) - << qMakePair(Qt::DotLine, 0xaaaa); + QList styles = getPenStyles(); ui->gridLinePattern->setIconSize(QSize(80, 12)); ui->gridDivLinePattern->setIconSize(QSize(80, 12)); - for (QList>::iterator it = styles.begin(); it != styles.end(); ++it) { + for (auto& style : styles) { QPixmap px(ui->gridLinePattern->iconSize()); px.fill(Qt::transparent); QBrush brush(Qt::black); - QPen pen(it->first); + + QPen pen; + pen.setDashPattern(binaryPatternToDashPattern(style)); pen.setBrush(brush); pen.setWidth(2); @@ -226,8 +269,8 @@ SketcherSettingsGrid::SketcherSettingsGrid(QWidget* parent) painter.drawLine(0, mid, ui->gridLinePattern->iconSize().width(), mid); painter.end(); - ui->gridLinePattern->addItem(QIcon(px), QString(), QVariant(it->second)); - ui->gridDivLinePattern->addItem(QIcon(px), QString(), QVariant(it->second)); + ui->gridLinePattern->addItem(QIcon(px), QString(), QVariant(style)); + ui->gridDivLinePattern->addItem(QIcon(px), QString(), QVariant(style)); } } @@ -273,13 +316,13 @@ void SketcherSettingsGrid::loadSettings() ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Sketcher/General"); - int pattern = hGrp->GetInt("GridLinePattern", 0x0f0f); + int pattern = hGrp->GetInt("GridLinePattern", 0b0000111100001111); int index = ui->gridLinePattern->findData(QVariant(pattern)); if (index < 0) { index = 1; } ui->gridLinePattern->setCurrentIndex(index); - pattern = hGrp->GetInt("GridDivLinePattern", 0xffff); + pattern = hGrp->GetInt("GridDivLinePattern", 0b1111111111111111); index = ui->gridDivLinePattern->findData(QVariant(pattern)); if (index < 0) { index = 0; @@ -412,24 +455,51 @@ void SketcherSettingsDisplay::onBtnTVApplyClicked(bool) } -/* TRANSLATOR SketcherGui::SketcherSettingsColors */ +/* TRANSLATOR SketcherGui::SketcherSettingsAppearance */ -SketcherSettingsColors::SketcherSettingsColors(QWidget* parent) +SketcherSettingsAppearance::SketcherSettingsAppearance(QWidget* parent) : PreferencePage(parent) - , ui(new Ui_SketcherSettingsColors) + , ui(new Ui_SketcherSettingsAppearance) { ui->setupUi(this); + + QList styles = getPenStyles(); + + ui->EdgePattern->setIconSize(QSize(70, 12)); + ui->ConstructionPattern->setIconSize(QSize(70, 12)); + ui->InternalPattern->setIconSize(QSize(70, 12)); + ui->ExternalPattern->setIconSize(QSize(70, 12)); + for (auto& style : styles) { + QPixmap px(ui->EdgePattern->iconSize()); + px.fill(Qt::transparent); + QBrush brush(Qt::black); + QPen pen; + pen.setDashPattern(binaryPatternToDashPattern(style)); + pen.setBrush(brush); + pen.setWidth(2); + + QPainter painter(&px); + painter.setPen(pen); + double mid = ui->EdgePattern->iconSize().height() / 2.0; + painter.drawLine(0, mid, ui->EdgePattern->iconSize().width(), mid); + painter.end(); + + ui->EdgePattern->addItem(QIcon(px), QString(), QVariant(style)); + ui->ConstructionPattern->addItem(QIcon(px), QString(), QVariant(style)); + ui->InternalPattern->addItem(QIcon(px), QString(), QVariant(style)); + ui->ExternalPattern->addItem(QIcon(px), QString(), QVariant(style)); + } } /** * Destroys the object and frees any allocated resources */ -SketcherSettingsColors::~SketcherSettingsColors() +SketcherSettingsAppearance::~SketcherSettingsAppearance() { // no need to delete child widgets, Qt does it all for us } -void SketcherSettingsColors::saveSettings() +void SketcherSettingsAppearance::saveSettings() { // Sketcher ui->SketchEdgeColor->onSave(); @@ -455,9 +525,32 @@ void SketcherSettingsColors::saveSettings() ui->CursorTextColor->onSave(); ui->CursorCrosshairColor->onSave(); ui->CreateLineColor->onSave(); + + ui->EdgeWidth->onSave(); + ui->ConstructionWidth->onSave(); + ui->InternalWidth->onSave(); + ui->ExternalWidth->onSave(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/View"); + QVariant data = ui->EdgePattern->itemData(ui->EdgePattern->currentIndex()); + int pattern = data.toInt(); + hGrp->SetInt("EdgePattern", pattern); + + data = ui->ConstructionPattern->itemData(ui->ConstructionPattern->currentIndex()); + pattern = data.toInt(); + hGrp->SetInt("ConstructionPattern", pattern); + + data = ui->InternalPattern->itemData(ui->InternalPattern->currentIndex()); + pattern = data.toInt(); + hGrp->SetInt("InternalPattern", pattern); + + data = ui->ExternalPattern->itemData(ui->ExternalPattern->currentIndex()); + pattern = data.toInt(); + hGrp->SetInt("ExternalPattern", pattern); } -void SketcherSettingsColors::loadSettings() +void SketcherSettingsAppearance::loadSettings() { // Sketcher ui->SketchEdgeColor->onRestore(); @@ -483,12 +576,47 @@ void SketcherSettingsColors::loadSettings() ui->CursorTextColor->onRestore(); ui->CursorCrosshairColor->onRestore(); ui->CreateLineColor->onRestore(); + + ui->EdgeWidth->onRestore(); + ui->ConstructionWidth->onRestore(); + ui->InternalWidth->onRestore(); + ui->ExternalWidth->onRestore(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher/View"); + int pattern = hGrp->GetInt("EdgePattern", 0b1111111111111111); + int index = ui->EdgePattern->findData(QVariant(pattern)); + if (index < 0) { + index = 0; + } + ui->EdgePattern->setCurrentIndex(index); + + pattern = hGrp->GetInt("ConstructionPattern", 0b1111110011111100); + index = ui->ConstructionPattern->findData(QVariant(pattern)); + if (index < 0) { + index = 0; + } + ui->ConstructionPattern->setCurrentIndex(index); + + pattern = hGrp->GetInt("InternalPattern", 0b1111110011111100); + index = ui->InternalPattern->findData(QVariant(pattern)); + if (index < 0) { + index = 0; + } + ui->InternalPattern->setCurrentIndex(index); + + pattern = hGrp->GetInt("ExternalPattern", 0b1110010011100100); + index = ui->ExternalPattern->findData(QVariant(pattern)); + if (index < 0) { + index = 0; + } + ui->ExternalPattern->setCurrentIndex(index); } /** * Sets the strings of the subwidgets using the current language. */ -void SketcherSettingsColors::changeEvent(QEvent* e) +void SketcherSettingsAppearance::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); diff --git a/src/Mod/Sketcher/Gui/SketcherSettings.h b/src/Mod/Sketcher/Gui/SketcherSettings.h index 1d3f52effc..ddc8261635 100644 --- a/src/Mod/Sketcher/Gui/SketcherSettings.h +++ b/src/Mod/Sketcher/Gui/SketcherSettings.h @@ -32,7 +32,7 @@ namespace SketcherGui class Ui_SketcherSettings; class Ui_SketcherSettingsGrid; class Ui_SketcherSettingsDisplay; -class Ui_SketcherSettingsColors; +class Ui_SketcherSettingsAppearance; class SketcherGeneralWidget; /** * The SketcherSettings class implements a preference page to change sketcher settings. @@ -107,13 +107,13 @@ private: * The SketcherSettings class implements a preference page to change sketcher settings. * @author Werner Mayer */ -class SketcherSettingsColors: public Gui::Dialog::PreferencePage +class SketcherSettingsAppearance: public Gui::Dialog::PreferencePage { Q_OBJECT public: - explicit SketcherSettingsColors(QWidget* parent = nullptr); - ~SketcherSettingsColors() override; + explicit SketcherSettingsAppearance(QWidget* parent = nullptr); + ~SketcherSettingsAppearance() override; void saveSettings() override; void loadSettings() override; @@ -122,7 +122,7 @@ protected: void changeEvent(QEvent* e) override; private: - std::unique_ptr ui; + std::unique_ptr ui; }; } // namespace SketcherGui diff --git a/src/Mod/Sketcher/Gui/SketcherSettingsAppearance.ui b/src/Mod/Sketcher/Gui/SketcherSettingsAppearance.ui new file mode 100644 index 0000000000..fa9cf59e7b --- /dev/null +++ b/src/Mod/Sketcher/Gui/SketcherSettingsAppearance.ui @@ -0,0 +1,967 @@ + + + SketcherGui::SketcherSettingsAppearance + + + + 0 + 0 + 689 + 863 + + + + Appearance + + + + + + Working colors + + + + + + + + + 200 + 0 + + + + Creating line + + + + + + + Color used while new sketch elements are created + + + + 204 + 204 + 204 + + + + CreateLineColor + + + View + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 0 + + + + Coordinate text + + + + + + + Text color of the coordinates + + + + 0 + 0 + 255 + + + + CursorTextColor + + + View + + + + + + + Cursor crosshair + + + + + + + Color of crosshair cursor. +(The one you get when creating a new sketch element.) + + + + 255 + 255 + 255 + + + + CursorCrosshairColor + + + View + + + + + + + + + + + + Geometric element colors + + + + + + + 95 + 0 + + + + Constrained + + + + + + + + 95 + 0 + + + + Unconstrained + + + + + + + Pattern + + + + + + + Width + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Vertex + + + + + + + + 0 + 0 + + + + Color of fully constrained vertex color in edit mode + + + + 255 + 149 + 128 + + + + FullyConstraintConstructionPointColor + + + View + + + + + + + + 0 + 0 + + + + Color of vertices being edited + + + + 255 + 38 + 0 + + + + EditedVertexColor + + + View + + + + + + + Edge + + + + + + + + 0 + 0 + + + + Color of fully constrained edge color in edit mode + + + + 128 + 208 + 160 + + + + FullyConstraintElementColor + + + View + + + + + + + + 0 + 0 + + + + Color of edges being edited + + + + 255 + 255 + 255 + + + + EditedEdgeColor + + + View + + + + + + + Line pattern of normal edges. + + + -1 + + + + + + + Width of normal edges. + + + mm + + + 1 + + + 99 + + + 2 + + + EdgeWidth + + + Mod/Sketcher/View + + + + + + + Construction geometry + + + + + + + + 0 + 0 + + + + Color of fully constrained construction edge color in edit mode + + + + 143 + 169 + 253 + + + + FullyConstraintConstructionElementColor + + + View + + + + + + + + 0 + 0 + + + + Color of construction geometry in edit mode + + + + 0 + 0 + 220 + + + + ConstructionColor + + + View + + + + + + + Line pattern of construction edges. + + + -1 + + + + + + + Width of construction edges. + + + mm + + + 1 + + + 99 + + + 1 + + + ConstructionWidth + + + Mod/Sketcher/View + + + + + + + Internal alignment edge + + + + + + + + 0 + 0 + + + + Color of fully constrained internal alignment edge color in edit mode + + + + 222 + 222 + 200 + + + + FullyConstraintInternalAlignmentColor + + + View + + + + + + + + 0 + 0 + + + + Color of edges of internal alignment geometry + + + + 178 + 178 + 127 + + + + InternalAlignedGeoColor + + + View + + + + + + + Line pattern of internal aligned edges. + + + -1 + + + + + + + Width of internal aligned edges. + + + mm + + + 1 + + + 99 + + + 1 + + + InternalWidth + + + Mod/Sketcher/View + + + + + + + External geometry + + + + + + + + 0 + 0 + + + + Color of external geometry in edit mode + + + + 204 + 51 + 115 + + + + ExternalColor + + + View + + + + + + + Line pattern of external edges. + + + -1 + + + + + + + Width of external edges. + + + mm + + + 1 + + + 99 + + + 1 + + + ExternalWidth + + + Mod/Sketcher/View + + + + + + + + 200 + 0 + + + + Fully constrained Sketch + + + + + + + + 0 + 0 + + + + Color of fully constrained geometry in edit mode + + + + 0 + 255 + 0 + + + + FullyConstrainedColor + + + View + + + + + + + Invalid Sketch + + + + + + + + 0 + 0 + + + + Color of geometry indicating an invalid sketch + + + + 255 + 109 + 0 + + + + InvalidSketchColor + + + View + + + + + + + + + + Constraint colors + + + + + + + + + 200 + 0 + + + + Constraint symbols + + + + + + + Color of driving constraints in edit mode + + + + 255 + 38 + 0 + + + + ConstrainedIcoColor + + + View + + + + + + + Dimensional constraint + + + + + + + Color of dimensional driving constraints + + + + 255 + 38 + 0 + + + + ConstrainedDimColor + + + View + + + + + + + Reference constraint + + + + + + + Color of reference constraints in edit mode + + + + 0 + 38 + 255 + + + + NonDrivingConstrDimColor + + + View + + + + + + + Expression dependent constraint + + + + + + + Color of expression dependent constraints in edit mode + + + + 255 + 127 + 38 + + + + ExprBasedConstrDimColor + + + View + + + + + + + Deactivated constraint + + + + + + + Color of deactivated constraints in edit mode + + + + 127 + 127 + 127 + + + + DeactivatedConstrDimColor + + + View + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Colors outside Sketcher + + + + + + + + + 200 + 0 + + + + Edge + + + + + + + Color of edges + + + + 255 + 255 + 255 + + + + SketchEdgeColor + + + View + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Vertex + + + + + + + Color of vertices + + + + 255 + 255 + 255 + + + + SketchVertexColor + + + View + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
+ + Gui::ColorButton + QPushButton +
Gui/Widgets.h
+
+ + Gui::PrefColorButton + Gui::ColorButton +
Gui/PrefWidgets.h
+
+
+ + +
diff --git a/src/Mod/Sketcher/Gui/SketcherSettingsColors.ui b/src/Mod/Sketcher/Gui/SketcherSettingsColors.ui deleted file mode 100644 index ddf7005ffc..0000000000 --- a/src/Mod/Sketcher/Gui/SketcherSettingsColors.ui +++ /dev/null @@ -1,835 +0,0 @@ - - - SketcherGui::SketcherSettingsColors - - - - 0 - 0 - 689 - 863 - - - - Colors - - - - - - Working colors - - - - - - - - - 240 - 0 - - - - Creating line - - - - - - - Color used while new sketch elements are created - - - - 204 - 204 - 204 - - - - CreateLineColor - - - View - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 240 - 0 - - - - Coordinate text - - - - - - - Text color of the coordinates - - - - 0 - 0 - 255 - - - - CursorTextColor - - - View - - - - - - - Cursor crosshair - - - - - - - Color of crosshair cursor. -(The one you get when creating a new sketch element.) - - - - 255 - 255 - 255 - - - - CursorCrosshairColor - - - View - - - - - - - - - - - - Geometric element colors - - - - - - - - - 120 - 0 - - - - Constrained - - - - - - - - 120 - 0 - - - - Unconstrained - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Edge - - - - - - - - 0 - 0 - - - - Color of fully constrained edge color in edit mode - - - - 128 - 208 - 160 - - - - FullyConstraintElementColor - - - View - - - - - - - - 0 - 0 - - - - Color of edges being edited - - - - 255 - 255 - 255 - - - - EditedEdgeColor - - - View - - - - - - - Vertex - - - - - - - - 0 - 0 - - - - Color of fully constrained vertex color in edit mode - - - - 255 - 149 - 128 - - - - FullyConstraintConstructionPointColor - - - View - - - - - - - - 0 - 0 - - - - Color of vertices being edited - - - - 255 - 38 - 0 - - - - EditedVertexColor - - - View - - - - - - - Construction geometry - - - - - - - - 0 - 0 - - - - Color of fully constrained construction edge color in edit mode - - - - 143 - 169 - 253 - - - - FullyConstraintConstructionElementColor - - - View - - - - - - - - 0 - 0 - - - - Color of construction geometry in edit mode - - - - 0 - 0 - 220 - - - - ConstructionColor - - - View - - - - - - - - 240 - 0 - - - - Internal alignment edge - - - - - - - - 0 - 0 - - - - Color of fully constrained internal alignment edge color in edit mode - - - - 222 - 222 - 200 - - - - FullyConstraintInternalAlignmentColor - - - View - - - - - - - - 0 - 0 - - - - Color of edges of internal alignment geometry - - - - 178 - 178 - 127 - - - - InternalAlignedGeoColor - - - View - - - - - - - External geometry - - - - - - - - 0 - 0 - - - - Color of external geometry in edit mode - - - - 204 - 51 - 115 - - - - ExternalColor - - - View - - - - - - - - - - - - 240 - 0 - - - - Fully constrained Sketch - - - - - - - - 0 - 0 - - - - Color of fully constrained geometry in edit mode - - - - 0 - 255 - 0 - - - - FullyConstrainedColor - - - View - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Invalid Sketch - - - - - - - - 0 - 0 - - - - Color of geometry indicating an invalid sketch - - - - 255 - 109 - 0 - - - - InvalidSketchColor - - - View - - - - - - - - - - - - Constraint colors - - - - - - - - - 240 - 0 - - - - Constraint symbols - - - - - - - Color of driving constraints in edit mode - - - - 255 - 38 - 0 - - - - ConstrainedIcoColor - - - View - - - - - - - Dimensional constraint - - - - - - - Color of dimensional driving constraints - - - - 255 - 38 - 0 - - - - ConstrainedDimColor - - - View - - - - - - - Reference constraint - - - - - - - Color of reference constraints in edit mode - - - - 0 - 38 - 255 - - - - NonDrivingConstrDimColor - - - View - - - - - - - Expression dependent constraint - - - - - - - Color of expression dependent constraints in edit mode - - - - 255 - 127 - 38 - - - - ExprBasedConstrDimColor - - - View - - - - - - - Deactivated constraint - - - - - - - Color of deactivated constraints in edit mode - - - - 127 - 127 - 127 - - - - DeactivatedConstrDimColor - - - View - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Colors outside Sketcher - - - - - - - - - 240 - 0 - - - - Edge - - - - - - - Color of edges - - - - 255 - 255 - 255 - - - - SketchEdgeColor - - - View - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Vertex - - - - - - - Color of vertices - - - - 255 - 255 - 255 - - - - SketchVertexColor - - - View - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Gui::ColorButton - QPushButton -
Gui/Widgets.h
-
- - Gui::PrefColorButton - Gui::ColorButton -
Gui/PrefWidgets.h
-
-
- - -
From 9cd9d752ef79018c81e3aaad36436c3641f29fec Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 16 Jan 2024 08:50:13 +0100 Subject: [PATCH 30/36] Update action.yml Updated ccache https://ccache.dev/releasenotes.html#_ccache_4_9 --- .github/workflows/actions/windows/getCcache/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/actions/windows/getCcache/action.yml b/.github/workflows/actions/windows/getCcache/action.yml index 7d0ceff711..be56349f46 100644 --- a/.github/workflows/actions/windows/getCcache/action.yml +++ b/.github/workflows/actions/windows/getCcache/action.yml @@ -41,11 +41,11 @@ inputs: ccachedownloadpath: description: "Path where to download ccache" required: false - default: https://github.com/ccache/ccache/releases/download/v4.8.2/ + default: https://github.com/ccache/ccache/releases/download/v4.9/ ccacheversion: description: "Ccache version to be downloaded" required: false - default: ccache-4.8.2-windows-x86_64 + default: ccache-4.9-windows-x86_64 runs: using: "composite" From 1fdffef21d4adaf8ac01e4d96409caf8df42a74d Mon Sep 17 00:00:00 2001 From: Vincenzo Calligaro Date: Mon, 22 Jan 2024 18:19:46 +0100 Subject: [PATCH 31/36] [Core] [Preferences] Modernize for loop in DlgSettingsEditor.cpp (#12011) * Preferences: modernize for loop in DlgSettingsEditor.cpp Signed-off-by: CalligaroV * Preferences: modernize for loop in DlgSettingsEditor.cpp added textType and textColor variables to unpack range-for loops iterators Signed-off-by: CalligaroV * Update src/Gui/PreferencePages/DlgSettingsEditor.cpp Minor linter updates, as suggested Co-authored-by: Chris Hennes * Update src/Gui/PreferencePages/DlgSettingsEditor.cpp Minor linter updates, as suggested Co-authored-by: Chris Hennes --------- Signed-off-by: CalligaroV Co-authored-by: Chris Hennes --- src/Gui/PreferencePages/DlgSettingsEditor.cpp | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/Gui/PreferencePages/DlgSettingsEditor.cpp b/src/Gui/PreferencePages/DlgSettingsEditor.cpp index a8a4bb35a8..65b44ced5f 100644 --- a/src/Gui/PreferencePages/DlgSettingsEditor.cpp +++ b/src/Gui/PreferencePages/DlgSettingsEditor.cpp @@ -163,9 +163,10 @@ DlgSettingsEditor::DlgSettingsEditor( QWidget* parent ) QStringList labels; labels << tr("Items"); ui->displayItems->setHeaderLabels(labels); ui->displayItems->header()->hide(); - for (QVector >::Iterator it = d->colormap.begin(); it != d->colormap.end(); ++it) { + for (const auto &[textType, textColor]: d->colormap) + { auto item = new QTreeWidgetItem(ui->displayItems); - item->setText(0, tr((*it).first.toLatin1())); + item->setText(0, tr(textType.toLatin1())); } pythonSyntax = new PythonSyntaxHighlighter(ui->textEdit1); pythonSyntax->setDocument(ui->textEdit1->document()); @@ -243,11 +244,11 @@ void DlgSettingsEditor::saveSettings() // Saves the color map ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Editor"); - for (QVector >::Iterator it = d->colormap.begin(); it != d->colormap.end(); ++it) { - auto col = static_cast((*it).second); - hGrp->SetUnsigned((*it).first.toLatin1(), col); + for (const auto &[textType, textColor] : d->colormap) + { + auto col = static_cast(textColor); + hGrp->SetUnsigned(textType.toLatin1(), col); } - hGrp->SetInt( "FontSize", ui->fontSize->value() ); hGrp->SetASCII( "Font", ui->fontFamily->currentText().toLatin1() ); @@ -280,13 +281,13 @@ void DlgSettingsEditor::loadSettings() // Restores the color map ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Editor"); - for (QVector>::Iterator it = d->colormap.begin(); - it != d->colormap.end(); ++it) { - auto col = static_cast((*it).second); - col = hGrp->GetUnsigned((*it).first.toLatin1(), col); - (*it).second = static_cast(col); + for (auto &[textType, textColor] : d->colormap) + { + auto col = static_cast(textColor); + col = hGrp->GetUnsigned(textType.toLatin1(), col); + textColor = static_cast(col); QColor color = App::Color::fromPackedRGB(col); - pythonSyntax->setColor((*it).first, color); + pythonSyntax->setColor(textType, color); } // fill up font styles @@ -332,8 +333,9 @@ void DlgSettingsEditor::resetSettingsToDefaults() ParameterGrp::handle hGrp; hGrp = WindowParameter::getDefaultParameter()->GetGroup("Editor"); //reset the parameters in the "Editor" group - for (QVector >::Iterator it = d->colormap.begin(); it != d->colormap.end(); ++it) { - hGrp->RemoveUnsigned((*it).first.toLatin1()); + for (const auto &[textType, textColor] : d->colormap) + { + hGrp->RemoveUnsigned(textType.toLatin1()); } //reset "FontSize" parameter hGrp->RemoveInt("FontSize"); @@ -351,8 +353,8 @@ void DlgSettingsEditor::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { int index = 0; - for (QVector >::Iterator it = d->colormap.begin(); it != d->colormap.end(); ++it) - ui->displayItems->topLevelItem(index++)->setText(0, tr((*it).first.toLatin1())); + for (const auto &[textType, textColor]: d->colormap) + ui->displayItems->topLevelItem(index++)->setText(0, tr(textType.toLatin1())); ui->retranslateUi(this); } else { QWidget::changeEvent(e); From 8c3ff5d3e9b5c453b6128071b37eda09d5144d83 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Fri, 19 Jan 2024 18:21:55 -0700 Subject: [PATCH 32/36] Gui: Add missing override --- src/Gui/propertyeditor/PropertyEditor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/propertyeditor/PropertyEditor.h b/src/Gui/propertyeditor/PropertyEditor.h index bd01c2f99e..c50fedf0d9 100644 --- a/src/Gui/propertyeditor/PropertyEditor.h +++ b/src/Gui/propertyeditor/PropertyEditor.h @@ -100,7 +100,7 @@ protected Q_SLOTS: void onRowsRemoved(const QModelIndex &parent, int start, int end); protected: - bool eventFilter(QObject* object, QEvent* event); + bool eventFilter(QObject* object, QEvent* event) override; void closeEditor (QWidget * editor, QAbstractItemDelegate::EndEditHint hint) override; void commitData (QWidget * editor) override; void editorDestroyed (QObject * editor) override; From 5b98a762d19159d4d6be31cef2f9aab1cae1be6e Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Sat, 20 Jan 2024 11:17:34 +0100 Subject: [PATCH 33/36] Draft: Improve layer functions The current make_layer function has a `None` default for the shape color and the line color. With that value the current preference is used. This, and how the function is called, results in some confusing behaviors: * Newly created layers will only use 2 values from the preferences when they might use 5. The latter makes more sense for the end-user IMO. * Layers created during DXF import (for example) will have a different shape color depending on the current preferences. * The make_layer function may reapply colors that have already been set by the view provider. To solve this all view property related function parameter have been changed to a not None value. If a None value is supplied the view property as set by the view provider is not changed. The Layer Manager has been updated accordingly. I realize that calling a function with 6 None values is not very convenient, but think it is the solution that is least likely to break other exiting code. Additionally: * Removed the makeLayer function. Layers were introduced in V0.19 when the naming scheme was changed to "make_*". Maybe it was created by mistake, or before the actual renaming operation started, but it is safe to remove it now. * Removed overly verbose messages. * gui_layers.py had a missing import (result of a previous V0.22 PR): `from draftutils import utils`. --- src/Mod/Draft/Draft.py | 3 +- src/Mod/Draft/draftguitools/gui_layers.py | 21 ++- src/Mod/Draft/draftmake/make_layer.py | 160 ++++++++---------- .../Draft/drafttests/draft_test_objects.py | 1 + .../Draft/draftviewproviders/view_layer.py | 3 +- 5 files changed, 83 insertions(+), 105 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 50f32c4bc6..d54960f138 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -379,8 +379,7 @@ if App.GuiUp: from draftobjects.layer import (Layer, _VisGroup) -from draftmake.make_layer import (make_layer, - makeLayer) +from draftmake.make_layer import make_layer if App.GuiUp: from draftviewproviders.view_layer import (ViewProviderLayer, diff --git a/src/Mod/Draft/draftguitools/gui_layers.py b/src/Mod/Draft/draftguitools/gui_layers.py index 21b709e33d..800c6c6091 100644 --- a/src/Mod/Draft/draftguitools/gui_layers.py +++ b/src/Mod/Draft/draftguitools/gui_layers.py @@ -37,6 +37,7 @@ import Draft import Draft_rc from draftguitools import gui_base from draftutils import params +from draftutils import utils from draftutils.translate import translate # The module is used to prevent complaints from code checkers (flake8) @@ -76,8 +77,8 @@ class Layer(gui_base.GuiCommandSimplest): self.doc.openTransaction("Create Layer") Gui.addModule("Draft") - Gui.doCommand('_layer_ = Draft.make_layer()') - Gui.doCommand('FreeCAD.ActiveDocument.recompute()') + Gui.doCommand("_layer_ = Draft.make_layer(name=None, line_color=None, shape_color=None, line_width=None, draw_style=None, transparency=None)") + Gui.doCommand("FreeCAD.ActiveDocument.recompute()") self.doc.commitTransaction() @@ -170,7 +171,8 @@ class LayerManager: if not changed: FreeCAD.ActiveDocument.openTransaction("Layers change") changed = True - obj = Draft.make_layer() + obj = Draft.make_layer(name=None, line_color=None, shape_color=None, + line_width=None, draw_style=None, transparency=None) # visibility checked = True if self.model.item(row,0).checkState() == QtCore.Qt.Checked else False @@ -303,7 +305,7 @@ class LayerManager: nameItem = QtGui.QStandardItem(translate("Draft", "New Layer")) widthItem = QtGui.QStandardItem() widthItem.setData(params.get_param_view("DefaultShapeLineWidth"), QtCore.Qt.DisplayRole) - styleItem = QtGui.QStandardItem("Solid") + styleItem = QtGui.QStandardItem(utils.DRAW_STYLES[params.get_param("DefaultDrawStyle")]) lineColorItem = QtGui.QStandardItem() lineColorItem.setData( utils.get_rgba_tuple(params.get_param_view("DefaultShapeLineColor"))[:3], @@ -315,7 +317,10 @@ class LayerManager: QtCore.Qt.UserRole ) transparencyItem = QtGui.QStandardItem() - transparencyItem.setData(0, QtCore.Qt.DisplayRole) + transparencyItem.setData( + params.get_param_view("DefaultShapeTransparency"), + QtCore.Qt.DisplayRole + ) linePrintColorItem = QtGui.QStandardItem() linePrintColorItem.setData( utils.get_rgba_tuple(params.get_param("DefaultPrintColor"))[:3], @@ -428,7 +433,7 @@ if FreeCAD.GuiUp: editor.setMaximum(99) elif index.column() == 3: # Line style editor = QtGui.QComboBox(parent) - editor.addItems(["Solid","Dashed","Dotted","Dashdot"]) + editor.addItems(utils.DRAW_STYLES) elif index.column() == 4: # Line color editor = QtGui.QLineEdit(parent) self.first = True @@ -452,7 +457,7 @@ if FreeCAD.GuiUp: elif index.column() == 2: # Line width editor.setValue(index.data()) elif index.column() == 3: # Line style - editor.setCurrentIndex(["Solid","Dashed","Dotted","Dashdot"].index(index.data())) + editor.setCurrentIndex(utils.DRAW_STYLES.index(index.data())) elif index.column() == 4: # Line color editor.setText(str(index.data(QtCore.Qt.UserRole))) if self.first: @@ -486,7 +491,7 @@ if FreeCAD.GuiUp: elif index.column() == 2: # Line width model.setData(index,editor.value()) elif index.column() == 3: # Line style - model.setData(index,["Solid","Dashed","Dotted","Dashdot"][editor.currentIndex()]) + model.setData(index,utils.DRAW_STYLES[editor.currentIndex()]) elif index.column() == 4: # Line color model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) diff --git a/src/Mod/Draft/draftmake/make_layer.py b/src/Mod/Draft/draftmake/make_layer.py index d1287d11ed..59020fd912 100644 --- a/src/Mod/Draft/draftmake/make_layer.py +++ b/src/Mod/Draft/draftmake/make_layer.py @@ -30,7 +30,6 @@ # @{ import FreeCAD as App from draftobjects.layer import Layer, LayerContainer -from draftutils import params from draftutils import utils from draftutils.messages import _msg, _err from draftutils.translate import translate @@ -79,53 +78,52 @@ def getLayerContainer(): def make_layer(name=None, - line_color=None, shape_color=None, + line_color=(0.0, 0.0, 0.0), # does not match default DefaultShapeLineColor + shape_color=(0.8, 0.8, 0.8), # matches default DefaultShapeColor line_width=2.0, - draw_style="Solid", transparency=0): + draw_style="Solid", + transparency=0): """Create a Layer object in the active document. - If a layer container named `'LayerContainer'` does not exist, - it is created with this name. + If a layer container named `'LayerContainer'` does not exist, it is created. - A layer controls the view properties of the objects inside the layer, - so all parameters except for `name` only apply if the graphical interface + A layer controls the view properties of the objects inside the layer. + All parameters except for `name` only apply if the graphical interface is up. + All parameters that control view properties can be set to `None`. Their + value, as set by the view provider (matching the current preferences), is + then not changed. + Parameters ---------- - name: str, optional - It is used to set the layer's `Label` (user editable). - It defaults to `None`, in which case the `Label` - is set to `'Layer'` or to its translation in the current language. + name: str or `None`, optional + It defaults to `None`. + It is used to set the layer's `Label`. If it is `None` the `Label` is + set to `'Layer'` or to its translation in the current language. - line_color: tuple, optional - It defaults to `None`, in which case it uses the value of the parameter - `User parameter:BaseApp/Preferences/View/DefaultShapeLineColor`. - If it is given, it should be a tuple of three - floating point values from 0.0 to 1.0. + line_color: tuple or `None`, optional + It defaults to `(0.0, 0.0, 0.0)`. + If it is given, it should be a tuple of three floating point values + from 0.0 to 1.0. - shape_color: tuple, optional - It defaults to `None`, in which case it uses the value of the parameter - `User parameter:BaseApp/Preferences/View/DefaultShapeColor`. - If it is given, it should be a tuple of three - floating point values from 0.0 to 1.0. + shape_color: tuple or `None`, optional + It defaults to `(0.8, 0.8, 0.8)`. + If it is given, it should be a tuple of three floating point values + from 0.0 to 1.0. - line_width: float, optional + line_width: float or `None`, optional It defaults to 2.0. - It determines the width of the edges of the objects contained - in the layer. + It determines the width of the edges of the objects contained in the layer. - draw_style: str, optional + draw_style: str or `None`, optional It defaults to `'Solid'`. - It determines the style of the edges of the objects contained - in the layer. - If it is given, it should be 'Solid', 'Dashed', 'Dotted', - or 'Dashdot'. + It determines the style of the edges of the objects contained in the layer. + If it is given, it should be 'Solid', 'Dashed', 'Dotted' or 'Dashdot'. - transparency: int, optional + transparency: int or `None`, optional It defaults to 0. - It should be an integer value from 0 (completely opaque) - to 100 (completely transparent). + It should be an integer from 0 to 100. Return ------ @@ -139,15 +137,13 @@ def make_layer(name=None, If there is a problem it will return `None`. """ _name = "make_layer" - utils.print_header(_name, translate("draft","Layer")) found, doc = utils.find_doc(App.activeDocument()) if not found: _err(translate("draft","No active document. Aborting.")) return None - if name: - _msg("name: {}".format(name)) + if name is not None: try: utils.type_check([(name, str)], name=_name) except TypeError: @@ -156,8 +152,7 @@ def make_layer(name=None, else: name = translate("draft", "Layer") - if line_color: - _msg("line_color: {}".format(line_color)) + if line_color is not None: try: utils.type_check([(line_color, tuple)], name=_name) except TypeError: @@ -167,14 +162,8 @@ def make_layer(name=None, if not all(isinstance(color, (int, float)) for color in line_color): _err(translate("draft","Wrong input: must be a tuple of three floats 0.0 to 1.0.")) return None - else: - c = params.get_param_view("DefaultShapeLineColor") - line_color = (((c >> 24) & 0xFF) / 255, - ((c >> 16) & 0xFF) / 255, - ((c >> 8) & 0xFF) / 255) - if shape_color: - _msg("shape_color: {}".format(shape_color)) + if shape_color is not None: try: utils.type_check([(shape_color, tuple)], name=_name) except TypeError: @@ -184,38 +173,33 @@ def make_layer(name=None, if not all(isinstance(color, (int, float)) for color in shape_color): _err(translate("draft","Wrong input: must be a tuple of three floats 0.0 to 1.0.")) return None - else: - c = params.get_param_view("DefaultShapeColor") - shape_color = (((c >> 24) & 0xFF) / 255, - ((c >> 16) & 0xFF) / 255, - ((c >> 8) & 0xFF) / 255) - _msg("line_width: {}".format(line_width)) - try: - utils.type_check([(line_width, (int, float))], name=_name) - line_width = float(abs(line_width)) - except TypeError: - _err(translate("draft","Wrong input: must be a number.")) - return None + if line_width is not None: + try: + utils.type_check([(line_width, (int, float))], name=_name) + line_width = float(abs(line_width)) + except TypeError: + _err(translate("draft","Wrong input: must be a number.")) + return None - _msg("draw_style: {}".format(draw_style)) - try: - utils.type_check([(draw_style, str)], name=_name) - except TypeError: - _err(translate("draft","Wrong input: must be 'Solid', 'Dashed', 'Dotted', or 'Dashdot'.")) - return None + if draw_style is not None: + try: + utils.type_check([(draw_style, str)], name=_name) + except TypeError: + _err(translate("draft","Wrong input: must be 'Solid', 'Dashed', 'Dotted', or 'Dashdot'.")) + return None - if draw_style not in ('Solid', 'Dashed', 'Dotted', 'Dashdot'): - _err(translate("draft","Wrong input: must be 'Solid', 'Dashed', 'Dotted', or 'Dashdot'.")) - return None + if draw_style not in ('Solid', 'Dashed', 'Dotted', 'Dashdot'): + _err(translate("draft","Wrong input: must be 'Solid', 'Dashed', 'Dotted', or 'Dashdot'.")) + return None - _msg("transparency: {}".format(transparency)) - try: - utils.type_check([(transparency, (int, float))], name=_name) - transparency = int(abs(transparency)) - except TypeError: - _err(translate("draft","Wrong input: must be a number between 0 and 100.")) - return None + if transparency is not None: + try: + utils.type_check([(transparency, (int, float))], name=_name) + transparency = int(abs(transparency)) + except TypeError: + _err(translate("draft","Wrong input: must be a number between 0 and 100.")) + return None new_obj = doc.addObject("App::FeaturePython", "Layer") Layer(new_obj) @@ -224,32 +208,20 @@ def make_layer(name=None, if App.GuiUp: ViewProviderLayer(new_obj.ViewObject) - - new_obj.ViewObject.LineColor = line_color - new_obj.ViewObject.ShapeColor = shape_color - new_obj.ViewObject.LineWidth = line_width - new_obj.ViewObject.DrawStyle = draw_style - new_obj.ViewObject.Transparency = transparency + if line_color is not None: + new_obj.ViewObject.LineColor = line_color + if shape_color is not None: + new_obj.ViewObject.ShapeColor = shape_color + if line_width is not None: + new_obj.ViewObject.LineWidth = line_width + if draw_style is not None: + new_obj.ViewObject.DrawStyle = draw_style + if transparency is not None: + new_obj.ViewObject.Transparency = transparency container = get_layer_container() container.addObject(new_obj) return new_obj - -def makeLayer(name=None, linecolor=None, drawstyle=None, - shapecolor=None, transparency=None): - """Create a Layer. DEPRECATED. Use 'make_layer'.""" - utils.use_instead("make_layer") - - if not drawstyle: - drawstyle = "Solid" - - if not transparency: - transparency = 0 - - return make_layer(name, - line_color=linecolor, shape_color=shapecolor, - draw_style=drawstyle, transparency=transparency) - ## @} diff --git a/src/Mod/Draft/drafttests/draft_test_objects.py b/src/Mod/Draft/drafttests/draft_test_objects.py index 1544b7089a..e81c7730e1 100644 --- a/src/Mod/Draft/drafttests/draft_test_objects.py +++ b/src/Mod/Draft/drafttests/draft_test_objects.py @@ -586,6 +586,7 @@ def _create_objects(doc=None, line_color=(0.33, 0.0, 0.49), shape_color=(0.56, 0.89, 0.56), line_width=4, + draw_style="Solid", transparency=50) box = doc.addObject("Part::Box", "Box") box.Length = 200 diff --git a/src/Mod/Draft/draftviewproviders/view_layer.py b/src/Mod/Draft/draftviewproviders/view_layer.py index 2160d02475..65aa23f661 100644 --- a/src/Mod/Draft/draftviewproviders/view_layer.py +++ b/src/Mod/Draft/draftviewproviders/view_layer.py @@ -557,7 +557,8 @@ class ViewProviderLayerContainer: doc = App.ActiveDocument doc.openTransaction(translate("draft", "Add new layer")) - Draft.make_layer() + Draft.make_layer(name=None, line_color=None, shape_color=None, + line_width=None, draw_style=None, transparency=None) doc.recompute() doc.commitTransaction() From 341f71ec5b04890f112aaac6e06446d1b6a78a5c Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Sun, 21 Jan 2024 12:32:31 +0100 Subject: [PATCH 34/36] Draft: Inform user that objects without a Shape cannot be cloned Fixes #11923. --- src/Mod/Draft/draftguitools/gui_clone.py | 64 ++++++++++++------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_clone.py b/src/Mod/Draft/draftguitools/gui_clone.py index b50262c6f7..262948dfb7 100644 --- a/src/Mod/Draft/draftguitools/gui_clone.py +++ b/src/Mod/Draft/draftguitools/gui_clone.py @@ -1,7 +1,8 @@ # *************************************************************************** -# * (c) 2009, 2010 Yorik van Havre * -# * (c) 2009, 2010 Ken Cline * -# * (c) 2020 Eliud Cabrera Castillo * +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * Copyright (c) 2020 Eliud Cabrera Castillo * +# * Copyright (c) 2023 FreeCAD Project Association * # * * # * This file is part of the FreeCAD CAx development system. * # * * @@ -48,7 +49,7 @@ import Draft_rc import draftguitools.gui_base_original as gui_base_original import draftguitools.gui_tool_utils as gui_tool_utils import draftutils.todo as todo -from draftutils.messages import _msg +from draftutils.messages import _msg, _wrn from draftutils.translate import translate # The module is used to prevent complaints from code checkers (flake8) @@ -65,10 +66,10 @@ class Clone(gui_base_original.Modifier): def GetResources(self): """Set icon, menu and tooltip.""" - return {'Pixmap': 'Draft_Clone', - 'Accel': "C,L", - 'MenuText': QT_TRANSLATE_NOOP("Draft_Clone", "Clone"), - 'ToolTip': QT_TRANSLATE_NOOP("Draft_Clone", "Creates a clone of the selected objects.\nThe resulting clone can be scaled in each of its three directions.")} + return {"Pixmap": "Draft_Clone", + "Accel": "C, L", + "MenuText": QT_TRANSLATE_NOOP("Draft_Clone", "Clone"), + "ToolTip": QT_TRANSLATE_NOOP("Draft_Clone", "Creates a clone of the selected objects.\nThe resulting clone can be scaled in each of its three directions.")} def Activated(self): """Execute when the command is called.""" @@ -84,30 +85,31 @@ class Clone(gui_base_original.Modifier): self.proceed() def proceed(self): - """Proceed with the command if one object was selected.""" - if Gui.Selection.getSelection(): - sels = len(Gui.Selection.getSelection()) - Gui.addModule("Draft") - App.ActiveDocument.openTransaction(translate("Draft", "Clone")) - nonRepeatList = [] - n = 0 - for obj in Gui.Selection.getSelection(): - if obj not in nonRepeatList: - _cmd = "Draft.make_clone" - _cmd += "(" - _cmd += "FreeCAD.ActiveDocument." - _cmd += 'getObject("' + obj.Name + '")' - _cmd += ")" - Gui.doCommand("c" + str(n) + " = " + _cmd) - nonRepeatList.append(obj) - n += 1 - App.ActiveDocument.commitTransaction() - App.ActiveDocument.recompute() - Gui.Selection.clearSelection() + """Proceed with the command if objects were selected.""" + objs = Gui.Selection.getSelection() + if not objs: + self.finish() + return + objs_shape = [obj for obj in objs if hasattr(obj, "Shape")] + if not objs_shape: + _wrn(translate("draft", "Cannot clone object(s) without a Shape, aborting")) + self.finish() + return + elif len(objs_shape) < len(objs): + _wrn(translate("draft", "Cannot clone object(s) without a Shape, skipping them")) - objects = App.ActiveDocument.Objects - for i in range(sels): - Gui.Selection.addSelection(objects[-(1 + i)]) + Gui.addModule("Draft") + App.ActiveDocument.openTransaction(translate("Draft", "Clone")) + for idx, obj in enumerate(objs_shape): + cmd = "Draft.make_clone(FreeCAD.ActiveDocument." + obj.Name + ")" + Gui.doCommand("clone" + str(idx) + " = " + cmd) + App.ActiveDocument.commitTransaction() + App.ActiveDocument.recompute() + + Gui.Selection.clearSelection() + objs = App.ActiveDocument.Objects + for i in range(len(objs_shape)): + Gui.Selection.addSelection(objs[-(1 + i)]) self.finish() def finish(self): From a14e0cbbbb9c5fb2fc958757cf76a98dc75a83b0 Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Sun, 21 Jan 2024 15:11:07 +0100 Subject: [PATCH 35/36] Draft: ShapeString double escape backslash in string Fixes 12058. --- .../Draft/drafttaskpanels/task_shapestring.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Mod/Draft/drafttaskpanels/task_shapestring.py b/src/Mod/Draft/drafttaskpanels/task_shapestring.py index 2a18768b62..b98e3846b3 100644 --- a/src/Mod/Draft/drafttaskpanels/task_shapestring.py +++ b/src/Mod/Draft/drafttaskpanels/task_shapestring.py @@ -149,10 +149,9 @@ class ShapeStringTaskPanelCmd(ShapeStringTaskPanel): def createObject(self): """Create object in the current document.""" - dquote = '"' - String = self.form.leString.text() - String = dquote + String.replace(dquote, '\\"') + dquote - FFile = dquote + str(self.fileSpec) + dquote + String = self.form.leString.text().replace('\\', '\\\\').replace('"', '\\"') + String = '"' + String + '"' + FFile = '"' + str(self.fileSpec) + '"' Size = str(App.Units.Quantity(self.form.sbHeight.text()).Value) Tracking = str(0.0) @@ -163,13 +162,13 @@ class ShapeStringTaskPanelCmd(ShapeStringTaskPanel): try: qr, sup, points, fil = self.sourceCmd.getStrings() Gui.addModule("Draft") - self.sourceCmd.commit(translate("draft", "Create ShapeString"), - ['ss=Draft.make_shapestring(String=' + String + ', FontFile=' + FFile + ', Size=' + Size + ', Tracking=' + Tracking + ')', - 'plm=FreeCAD.Placement()', - 'plm.Base=' + toString(ssBase), - 'plm.Rotation.Q=' + qr, - 'ss.Placement=plm', - 'ss.Support=' + sup, + self.sourceCmd.commit(translate('draft', 'Create ShapeString'), + ['ss = Draft.make_shapestring(String=' + String + ', FontFile=' + FFile + ', Size=' + Size + ', Tracking=' + Tracking + ')', + 'plm = FreeCAD.Placement()', + 'plm.Base = ' + toString(ssBase), + 'plm.Rotation.Q = ' + qr, + 'ss.Placement = plm', + 'ss.Support = ' + sup, 'Draft.autogroup(ss)', 'FreeCAD.ActiveDocument.recompute()']) except Exception: From cc45b58dadae53d7a99be1ed7db25f6c93bb13d5 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Mon, 22 Jan 2024 12:37:33 -0500 Subject: [PATCH 36/36] [Import]fix linkage warning on linux/gcc (#12071) * [Import]fix linkage warning on linux/gcc https://stackoverflow.com/questions/41167119/how-to-fix-a-wsubobject-linkage-warning --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/Mod/Import/App/dxf/dxf.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Mod/Import/App/dxf/dxf.h b/src/Mod/Import/App/dxf/dxf.h index d82119df08..45ac21fdec 100644 --- a/src/Mod/Import/App/dxf/dxf.h +++ b/src/Mod/Import/App/dxf/dxf.h @@ -173,7 +173,12 @@ struct LWPolyDataOut std::vector Bulge; point3D Extr; }; -using eDXFGroupCode_t = enum { + + +// "using" for enums is not supported by all platforms +// https://stackoverflow.com/questions/41167119/how-to-fix-a-wsubobject-linkage-warning +enum eDXFGroupCode_t +{ eObjectType = 0, ePrimaryText = 1, eName = 2, @@ -211,7 +216,8 @@ using eDXFGroupCode_t = enum { eYOffset = 10, eZOffset = 20 }; -using eDXFVersion_t = enum { +enum eDXFVersion_t +{ RUnknown, ROlder, R10, @@ -226,7 +232,8 @@ using eDXFVersion_t = enum { R2018, RNewer, }; -using eDimensionType_t = enum { +enum eDimensionType_t +{ eLinear = 0, // Rotated, Horizontal, or Vertical eAligned = 1, eAngular = 2, @@ -431,6 +438,7 @@ class ImportExport CDxfRead private: // Low-level reader members std::ifstream* m_ifs; // TODO: gsl::owner + // https://stackoverflow.com/questions/41167119/how-to-fix-a-wsubobject-linkage-warning eDXFGroupCode_t m_record_type = eObjectType; std::string m_record_data; bool m_not_eof = true;