From 5e34fe0812d73214790a7d3f2e341900c28fafd8 Mon Sep 17 00:00:00 2001 From: jfa Date: Mon, 17 Jul 2023 21:49:52 +0100 Subject: [PATCH] Implement bos #35141 Makewire keeping types of edges --- .../examples/topological_geom_objs_ex02.py | 29 ++ doc/salome/gui/GEOM/input/creating_wire.doc | 4 +- idl/GEOM_Gen.idl | 27 +- src/BuildGUI/BuildGUI_WireDlg.cxx | 4 +- src/GEOMImpl/GEOMImpl_IShapes.hxx | 6 + src/GEOMImpl/GEOMImpl_IShapesOperations.cxx | 24 +- src/GEOMImpl/GEOMImpl_IShapesOperations.hxx | 9 +- src/GEOMImpl/GEOMImpl_ShapeDriver.cxx | 32 +- src/GEOMImpl/GEOMImpl_ShapeDriver.hxx | 5 +- src/GEOM_I/GEOM_IShapesOperations_i.cc | 18 +- src/GEOM_I/GEOM_IShapesOperations_i.hh | 3 +- src/GEOM_I_Superv/GEOM_Superv_i.cc | 2 +- src/GEOM_SWIG/geomBuilder.py | 84 ++++- test/test_wire_modes.py | 310 ++++++++++++++++++ test/tests.set | 6 + 15 files changed, 544 insertions(+), 19 deletions(-) create mode 100644 test/test_wire_modes.py diff --git a/doc/salome/examples/topological_geom_objs_ex02.py b/doc/salome/examples/topological_geom_objs_ex02.py index 5e1c28497..bdc20c364 100644 --- a/doc/salome/examples/topological_geom_objs_ex02.py +++ b/doc/salome/examples/topological_geom_objs_ex02.py @@ -26,3 +26,32 @@ id_wire = geompy.addToStudy(wire,"Wire") # display the wire gg.createAndDisplayGO(id_wire) + +# Create a wire from edges that are not connected to each other. +# Given tolerance should cover the gaps to build connected wire. +# Three different modes to do that are possible. +gap = 1 +tolerance = gap +px_gap = geompy.MakeVertex(100. + gap, 0. , 0. ) +py_gap = geompy.MakeVertex(0. , 100. + gap, 0. ) +vxy_gap = geompy.MakeVector(px_gap, py_gap) + +# 1. Join edges by fixing tolerance +wire_ft = geompy.MakeWire([vxy_gap, arc], tolerance, "wire_fixed_tolerance") +# final wire tolerance will be near the half of the gap (0.5) +print(geompy.Tolerance(wire_ft)[5]) +assert(abs(geompy.Tolerance(wire_ft)[5] - 0.5) < 1e-04) + +# 2. Join edges by changing their underlying curves (but keeping curve types) +# This functionality is available in TUI only. +wire_cc = geompy.MakeWireConstCurveType([vxy_gap, arc], tolerance, "wire_const_curve_type") +# final wire tolerance will stay small +print(geompy.Tolerance(wire_cc)[5]) +assert(geompy.Tolerance(wire_cc)[5] < 1e-04) + +# 3. Join edges by changing their underlying curves (approximating with b-splines) +# This functionality is available in TUI only. +wire_ap = geompy.MakeWireWithMode([vxy_gap, arc], tolerance, GEOM.WBM_Approximation, "wire_approximated_curves") +# final wire tolerance will stay small +print(geompy.Tolerance(wire_ap)[5]) +assert(geompy.Tolerance(wire_ap)[5] < 1e-04) diff --git a/doc/salome/gui/GEOM/input/creating_wire.doc b/doc/salome/gui/GEOM/input/creating_wire.doc index 917332160..858fb29f6 100644 --- a/doc/salome/gui/GEOM/input/creating_wire.doc +++ b/doc/salome/gui/GEOM/input/creating_wire.doc @@ -29,7 +29,7 @@ connect in the middle of the gap. \image html wiresn.png "Wire" -Our TUI Scripts provide you with useful examples of creation of -\ref tui_creation_wire "Advanced Geometric Objects". +Our TUI Scripts provide you with useful examples of +\ref tui_creation_wire "Creation of a Wire". */ diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index 9bf78ddb8..d1428637a 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -220,6 +220,29 @@ module GEOM CC_LE ///< Less then or equal to }; + /*! + * \brief Wire construction mode. Regulates the way gaps are closed. + * + * Is used in function GEOM_IShapesOperations.MakeWire() + */ + enum wire_build_mode + { + /*! Do not change curves, just enlarge wire tolerance to cover the gaps */ + WBM_FixTolerance, + + /*! + * Replace curves, neighbour to the gap, + * with BSplines, connecting in the middle of the gap + */ + WBM_Approximation, + + /*! + * Replace curves, neighbour to the gap, with new curves of the same + * type and close parameters, connecting in the middle of the gap + */ + WBM_KeepCurveType + }; + /*! * \brief Object creation parameters * @@ -2034,10 +2057,12 @@ module GEOM * \param theEdgesAndWires List of edge and/or wires. * \param theTolerance Maximum distance between vertices, that will be merged. * Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()). + * \param theMode Mode of gaps filling. * \return New GEOM_Object, containing the created wire. */ GEOM_Object MakeWire (in ListOfGO theEdgesAndWires, - in double theTolerance); + in double theTolerance, + in wire_build_mode theMode); /*! * \brief Create a face on the given wire. diff --git a/src/BuildGUI/BuildGUI_WireDlg.cxx b/src/BuildGUI/BuildGUI_WireDlg.cxx index 916f99e67..609f5fa8a 100644 --- a/src/BuildGUI/BuildGUI_WireDlg.cxx +++ b/src/BuildGUI/BuildGUI_WireDlg.cxx @@ -288,7 +288,9 @@ bool BuildGUI_WireDlg::execute (ObjectList& objects) for ( int i = 0; i < myEdgesAndWires.count(); i++ ) objlist[i] = myEdgesAndWires[i].copy(); - GEOM::GEOM_Object_var anObj = anOper->MakeWire(objlist.in(), GroupArgs->SpinBox_DX->value()); + GEOM::GEOM_Object_var anObj = anOper->MakeWire(objlist.in(), + GroupArgs->SpinBox_DX->value(), + GEOM::WBM_FixTolerance); if (!anObj->_is_nil()) objects.push_back(anObj._retn()); diff --git a/src/GEOMImpl/GEOMImpl_IShapes.hxx b/src/GEOMImpl/GEOMImpl_IShapes.hxx index d58e82dbf..60d7e8750 100644 --- a/src/GEOMImpl/GEOMImpl_IShapes.hxx +++ b/src/GEOMImpl/GEOMImpl_IShapes.hxx @@ -41,6 +41,7 @@ class GEOMImpl_IShapes SHAPE_ARG_INDICES = 5, // for Sub-shape SHAPE_ARG_TOLERANCE = 6, // linear tolerance (for Wire, Edge) SHAPE_ARG_ANGLE_TOL = 7, // angular tolerance (for Edge) + SHAPE_ARG_WIRE_MODE = 8, // gaps closing mode (for Wire) }; GEOMImpl_IShapes(Handle(GEOM_Function) theFunction): _func(theFunction) {} @@ -77,6 +78,11 @@ class GEOMImpl_IShapes Standard_Real GetTolerance() { return _func->GetReal(SHAPE_ARG_TOLERANCE); } + void SetWireMode(const Standard_Integer theValue) + { _func->SetInteger(SHAPE_ARG_WIRE_MODE, theValue); } + + Standard_Integer GetWireMode() { return _func->GetInteger(SHAPE_ARG_WIRE_MODE); } + void SetAngularTolerance(const Standard_Real theValue) { _func->SetReal(SHAPE_ARG_ANGLE_TOL, theValue); } diff --git a/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx b/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx index c253bba98..edc8d56fd 100644 --- a/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx @@ -379,7 +379,8 @@ Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeEdgeWire //============================================================================= Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeWire (std::list theShapes, - const Standard_Real theTolerance) + const Standard_Real theTolerance, + const GEOMImpl_WireBuildMode theMode) { SetErrorCode(KO); @@ -396,6 +397,7 @@ Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeWire GEOMImpl_IShapes aCI (aFunction); aCI.SetTolerance(theTolerance); + aCI.SetWireMode(theMode); Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient; @@ -426,7 +428,19 @@ Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeWire //Make a Python command GEOM::TPythonDump pd (aFunction); - pd << aWire << " = geompy.MakeWire(["; + pd << aWire; + switch (theMode) { + case GEOMImpl_WBM_FixTolerance: + pd << " = geompy.MakeWire(["; + break; + case GEOMImpl_WBM_Approximation: + pd << " = geompy.MakeWireWithMode(["; + break; + case GEOMImpl_WBM_KeepCurveType: + pd << " = geompy.MakeWireConstCurveType(["; + break; + default: ; + } // Shapes it = theShapes.begin(); @@ -436,7 +450,11 @@ Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeWire pd << ", " << (*it++); } } - pd << "], " << theTolerance << ")"; + pd << "], " << theTolerance; + if (theMode == GEOMImpl_WBM_Approximation) { + pd << ", GEOM.WBM_Approximation"; + } + pd << ")"; SetErrorCode(OK); return aWire; diff --git a/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx b/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx index cd20bea5f..dc352ba58 100644 --- a/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx @@ -48,6 +48,12 @@ class GEOM_Engine; class GEOM_Object; class TopoDS_Shape; +enum GEOMImpl_WireBuildMode { + GEOMImpl_WBM_FixTolerance = 1, + GEOMImpl_WBM_Approximation = 2, + GEOMImpl_WBM_KeepCurveType = 3 +}; + class GEOMImpl_IShapesOperations : public GEOM_IOperations { public: @@ -94,7 +100,8 @@ class GEOMImpl_IShapesOperations : public GEOM_IOperations const Standard_Real theAngularTolerance); Standard_EXPORT Handle(GEOM_Object) MakeWire (std::list theEdgesAndWires, - const Standard_Real theTolerance); + const Standard_Real theTolerance, + const GEOMImpl_WireBuildMode theMode = GEOMImpl_WBM_FixTolerance); Standard_EXPORT Handle(GEOM_Object) MakeFace (Handle(GEOM_Object) theWire, const bool isPlanarWanted); diff --git a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx index 8f1f24850..0923bd112 100644 --- a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx @@ -22,6 +22,8 @@ #include +#include + #include #include #include @@ -436,7 +438,9 @@ Standard_Integer GEOMImpl_ShapeDriver::Execute(Handle(TFunction_Logbook)& log) c if (aTolerance < Precision::Confusion()) aTolerance = Precision::Confusion(); - aShape = MakeWireFromEdges(aShapes, aTolerance); + Standard_Integer aMode = aCI.GetWireMode(); + + aShape = MakeWireFromEdges(aShapes, aTolerance, (GEOMImpl_WireBuildMode)aMode); } else if (aType == FACE_WIRE) { // result may be a face or a compound of faces @@ -1088,7 +1092,8 @@ Standard_Integer GEOMImpl_ShapeDriver::Execute(Handle(TFunction_Logbook)& log) c } TopoDS_Wire GEOMImpl_ShapeDriver::MakeWireFromEdges(const Handle(TColStd_HSequenceOfTransient)& theEdgesFuncs, - const Standard_Real theTolerance) + const Standard_Real theTolerance, + const GEOMImpl_WireBuildMode theMode) { BRep_Builder B; @@ -1136,14 +1141,30 @@ TopoDS_Wire GEOMImpl_ShapeDriver::MakeWireFromEdges(const Handle(TColStd_HSequen } aFW->ClosedWireMode() = isClosed; aFW->FixConnected(theTolerance); + if (aFW->StatusConnected(ShapeExtend_FAIL)) { Standard_ConstructionError::Raise("Wire construction failed: cannot build connected wire"); } // IMP 0019766 - if (aFW->StatusConnected(ShapeExtend_DONE3)) { - // Confused with but not Analyzer.Precision(), set the same - aFW->SetPrecision(theTolerance); // bos #33377, prevent conversion of initial curves to BSplines + if (theMode == GEOMImpl_WBM_KeepCurveType) { +#if OCC_VERSION_LARGE > 0x07050305 + aFW->FixCurves(); + if (aFW->StatusCurves(ShapeExtend_FAIL1)) { + Standard_ConstructionError::Raise("Wire construction failed: cannot update Bezier or B-Spline curve ends, because they don't correspond to the first and last poles"); + } + if (aFW->StatusCurves(ShapeExtend_FAIL)) { + Standard_ConstructionError::Raise("Wire construction failed: cannot rebuild curves through new points"); + } +#else + Standard_NotImplemented::Raise("Wire construction failed: option KeepCurveType is not supported by current OCCT version: please, use OCCT 7.5.3p6 or newer."); +#endif // OCC_VERSION_LARGE > 0x07050305 + } + else if (aFW->StatusConnected(ShapeExtend_DONE3)) { + if (theMode != GEOMImpl_WBM_Approximation) { + // Confused with but not Analyzer.Precision(), set the same + aFW->SetPrecision(theTolerance); + } aFW->FixGapsByRangesMode() = Standard_True; if (aFW->FixGaps3d()) { Handle(ShapeExtend_WireData) sbwd = aFW->WireData(); @@ -1906,6 +1927,7 @@ GetCreationInformation(std::string& theOperationName, theOperationName = "WIRE"; AddParam( theParams, "Wires/edges", aCI.GetShapes() ); AddParam( theParams, "Tolerance", aCI.GetTolerance() ); + AddParam( theParams, "Mode", aCI.GetWireMode() ); break; case FACE_WIRE: theOperationName = "FACE"; diff --git a/src/GEOMImpl/GEOMImpl_ShapeDriver.hxx b/src/GEOMImpl/GEOMImpl_ShapeDriver.hxx index 1e3328781..4336142fa 100644 --- a/src/GEOMImpl/GEOMImpl_ShapeDriver.hxx +++ b/src/GEOMImpl/GEOMImpl_ShapeDriver.hxx @@ -31,6 +31,8 @@ #include #include +#include "GEOMImpl_IShapesOperations.hxx" + #include class TopoDS_Face; @@ -56,7 +58,8 @@ public: Standard_EXPORT static TopoDS_Wire MakeWireFromEdges (const Handle(TColStd_HSequenceOfTransient)& theEdgesFuncs, - const Standard_Real theTolerance); + const Standard_Real theTolerance, + const GEOMImpl_WireBuildMode theMode = GEOMImpl_WBM_FixTolerance); Standard_EXPORT virtual bool GetCreationInformation(std::string& theOperationName, std::vector& params); diff --git a/src/GEOM_I/GEOM_IShapesOperations_i.cc b/src/GEOM_I/GEOM_IShapesOperations_i.cc index 7526c83ed..1e02554d7 100644 --- a/src/GEOM_I/GEOM_IShapesOperations_i.cc +++ b/src/GEOM_I/GEOM_IShapesOperations_i.cc @@ -186,7 +186,8 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeEdgeWire //============================================================================= GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeWire (const GEOM::ListOfGO& theEdgesAndWires, - const CORBA::Double theTolerance) + const CORBA::Double theTolerance, + const GEOM::wire_build_mode theMode) { GEOM::GEOM_Object_var aGEOMObject; @@ -204,9 +205,22 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeWire aShapes.push_back(aSh); } + // Mode of gaps closing + GEOMImpl_WireBuildMode aMode = GEOMImpl_WBM_FixTolerance; + switch (theMode) { + case GEOM::WBM_Approximation: + aMode = GEOMImpl_WBM_Approximation; + break; + case GEOM::WBM_KeepCurveType: + aMode = GEOMImpl_WBM_KeepCurveType; + break; + default: + break; + } + // Make Solid Handle(::GEOM_Object) anObject = - GetOperations()->MakeWire(aShapes, theTolerance); + GetOperations()->MakeWire(aShapes, theTolerance, aMode); if (!GetOperations()->IsDone() || anObject.IsNull()) return aGEOMObject._retn(); diff --git a/src/GEOM_I/GEOM_IShapesOperations_i.hh b/src/GEOM_I/GEOM_IShapesOperations_i.hh index 28c5944f4..2d8cdf36e 100644 --- a/src/GEOM_I/GEOM_IShapesOperations_i.hh +++ b/src/GEOM_I/GEOM_IShapesOperations_i.hh @@ -56,7 +56,8 @@ class GEOM_I_EXPORT GEOM_IShapesOperations_i : const CORBA::Double theAngularTolerance); GEOM::GEOM_Object_ptr MakeWire (const GEOM::ListOfGO& theEdgesAndWires, - const CORBA::Double theTolerance); + const CORBA::Double theTolerance, + const GEOM::wire_build_mode theMode); GEOM::GEOM_Object_ptr MakeFace (GEOM::GEOM_Object_ptr theWire, CORBA::Boolean isPlanarWanted); diff --git a/src/GEOM_I_Superv/GEOM_Superv_i.cc b/src/GEOM_I_Superv/GEOM_Superv_i.cc index ecca07532..c510ec9a3 100644 --- a/src/GEOM_I_Superv/GEOM_Superv_i.cc +++ b/src/GEOM_I_Superv/GEOM_Superv_i.cc @@ -2153,7 +2153,7 @@ GEOM::GEOM_Object_ptr GEOM_Superv_i::MakeWire (GEOM::GEOM_List_ptr theEdgesAndWi if (GEOM_List_i* aListImplEW = dynamic_cast*>(GetServant(theEdgesAndWires, myPOA).in())) { getShapesOp(); - GEOM::GEOM_Object_ptr anObj = myShapesOp->MakeWire(aListImplEW->GetList(), theTolerance); + GEOM::GEOM_Object_ptr anObj = myShapesOp->MakeWire(aListImplEW->GetList(), theTolerance, GEOM::WBM_FixTolerance); endService( " GEOM_Superv_i::MakeWire" ); return anObj; } diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index d62ca1288..7cf3edc64 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -4717,6 +4717,8 @@ class geomBuilder(GEOM._objref_GEOM_Gen): return anObj ## Create a wire from the set of edges and wires. + # To close a gap, enlarges wire tolerance. + # # @param theEdgesAndWires List of edges and/or wires. # @param theTolerance Maximum distance between vertices, that will be merged. # Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()) @@ -4731,6 +4733,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): def MakeWire(self, theEdgesAndWires, theTolerance = 1e-07, theName=None): """ Create a wire from the set of edges and wires. + To close a gap, enlarges wire tolerance. Parameters: theEdgesAndWires List of edges and/or wires. @@ -4744,11 +4747,90 @@ class geomBuilder(GEOM._objref_GEOM_Gen): New GEOM.GEOM_Object, containing the created wire. """ # Example: see GEOM_TestAll.py - anObj = self.ShapesOp.MakeWire(theEdgesAndWires, theTolerance) + anObj = self.ShapesOp.MakeWire(theEdgesAndWires, theTolerance, GEOM.WBM_FixTolerance) RaiseIfFailed("MakeWire", self.ShapesOp) self._autoPublish(anObj, theName, "wire") return anObj + ## Create a wire from the set of edges and wires. + # To close a gap, replaces curves, neighbour to the gap, with new curves + # of the same type and close parameters, connecting in the middle of the gap. + # + # @param theEdgesAndWires List of edges and/or wires. + # @param theTolerance Maximum distance between vertices, that will be merged. + # Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()) + # @param theName Object name; when specified, this parameter is used + # for result publication in the study. Otherwise, if automatic + # publication is switched on, default value is used for result name. + # + # @return New GEOM.GEOM_Object, containing the created wire. + # + # @ref tui_creation_wire "Example" + @ManageTransactions("ShapesOp") + def MakeWireConstCurveType(self, theEdgesAndWires, theTolerance = 1e-07, theName=None): + """ + Create a wire from the set of edges and wires. + To close a gap, replaces curves, neighbour to the gap, with new curves + of the same type and close parameters, connecting in the middle of the gap. + + Parameters: + theEdgesAndWires List of edges and/or wires. + theTolerance Maximum distance between vertices, that will be merged. + Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()). + theName Object name; when specified, this parameter is used + for result publication in the study. Otherwise, if automatic + publication is switched on, default value is used for result name. + + Returns: + New GEOM.GEOM_Object, containing the created wire. + """ + anObj = self.ShapesOp.MakeWire(theEdgesAndWires, theTolerance, GEOM.WBM_KeepCurveType) + RaiseIfFailed("MakeWireConstCurveType", self.ShapesOp) + self._autoPublish(anObj, theName, "wire") + return anObj + + ## Create a wire from the set of edges and wires. + # Possible gaps are closed according to theMode. + # + # @param theEdgesAndWires List of edges and/or wires. + # @param theTolerance Maximum distance between vertices, that will be merged. + # Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()) + # @param theMode GEOM.wire_build_mode Mode of gaps closing. + # Possible values are GEOM.WBM_FixTolerance, GEOM.WBM_KeepCurveType + # and GEOM.WBM_Approximation. + # @param theName Object name; when specified, this parameter is used + # for result publication in the study. Otherwise, if automatic + # publication is switched on, default value is used for result name. + # + # @return New GEOM.GEOM_Object, containing the created wire. + # + # @ref tui_creation_wire "Example" + @ManageTransactions("ShapesOp") + def MakeWireWithMode(self, theEdgesAndWires, theTolerance = 1e-07, + theMode = GEOM.WBM_Approximation, theName=None): + """ + Create a wire from the set of edges and wires. + Possible gaps are closed according to theMode. + + Parameters: + theEdgesAndWires List of edges and/or wires. + theTolerance Maximum distance between vertices, that will be merged. + Values less than 1e-07 are equivalent to 1e-07 (Precision::Confusion()). + theMode GEOM.wire_build_mode Mode of gaps closing. + Possible values are GEOM.WBM_FixTolerance, GEOM.WBM_KeepCurveType + and GEOM.WBM_Approximation. + theName Object name; when specified, this parameter is used + for result publication in the study. Otherwise, if automatic + publication is switched on, default value is used for result name. + + Returns: + New GEOM.GEOM_Object, containing the created wire. + """ + anObj = self.ShapesOp.MakeWire(theEdgesAndWires, theTolerance, theMode) + RaiseIfFailed("MakeWireWithMode", self.ShapesOp) + self._autoPublish(anObj, theName, "wire") + return anObj + ## Create a face on the given wire. # @param theWire closed Wire or Edge to build the face on. # @param isPlanarWanted If TRUE, the algorithm tries to build a planar face. diff --git a/test/test_wire_modes.py b/test/test_wire_modes.py new file mode 100644 index 000000000..31614fa42 --- /dev/null +++ b/test/test_wire_modes.py @@ -0,0 +1,310 @@ +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +import salome +salome.salome_init() + +import GEOM +from salome.geom import geomBuilder +import math +geompy = geomBuilder.New() + +# gaps and tolerances +halfGap = math.sqrt(2.0) / 2.0 # dx = 1 and dy = 1 +tol = 3.0 # max. gap to be closed +prec = 1e-4 # precision of comparison + +# prepare edges +O = geompy.MakeVertex(0, 0, 0) +OX = geompy.MakeVectorDXDYDZ(1, 0, 0) +OY = geompy.MakeVectorDXDYDZ(0, 1, 0) +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + +Vertex_1 = geompy.MakeVertex(30, 70, 0) +Vertex_2 = geompy.MakeVertex(100, 0, 0) +Vertex_3 = geompy.MakeVertex(100, 70, 0) +Vertex_4 = geompy.MakeVertex(0, 70, 0) +Vertex_5 = geompy.MakeVertex(60, 60, 0) +Vertex_6 = geompy.MakeVertex(10, 50, 0) +Vertex_7 = geompy.MakeVertex(20, 0, 0) +Vertex_8 = geompy.MakeVertex(15, 80, 0) +Vertex_9 = geompy.MakeVertex(35, 60, 0) +Vertex_10 = geompy.MakeVertex(-20, 80, 0) +Vertex_11 = geompy.MakeVertex(10, -10, 0) +Vertex_12 = geompy.MakeVertex(10, 20, 0) +Vertex_13 = geompy.MakeVertex(-10, 30, 0) +Vertex_14 = geompy.MakeVertex(-20, 0, 0) +Vertex_15 = geompy.MakeVertex(-10, -10, 0) + +# Linear segments +Curve_1 = geompy.MakePolyline([O, Vertex_2, Vertex_3, Vertex_4], True) + +# Circles +Circle_1 = geompy.MakeCircle(Vertex_3, None, 10) +Circle_2 = geompy.MakeCircle(Vertex_5, None, 15) + +# Ellipses +geomObj_1 = geompy.MakeEllipse(O, None, 30, 10) +geomObj_2 = geompy.MakeRotation(geomObj_1, OZ, 45*math.pi/180.0) +Translation_1 = geompy.MakeTranslation(geomObj_2, 100, 0, 0) +geomObj_3 = geompy.MakeEllipse(None, None, 20, 10) +geomObj_4 = geompy.MakeRotation(geomObj_3, OZ, 90*math.pi/180.0) +Translation_2 = geompy.MakeTranslation(geomObj_4, 50, 10, 0) + +# Closed B-Spline curve +Curve_2 = geompy.MakeInterpol([Vertex_1, Vertex_6, Vertex_10, Vertex_8], True, False) + +# Closed Bezier curve +Curve_4 = geompy.MakeBezier([Vertex_7, Vertex_12, Vertex_13, Vertex_14, Vertex_15, Vertex_11], True) + +# Partition +Partition_1 = geompy.MakePartition([Circle_1, Circle_2, Curve_1, Curve_2, Translation_1, Translation_2, Curve_4], [], [], [], geompy.ShapeType["EDGE"], 0, [], 0) + +[Edge_1,Edge_2,Edge_3,Edge_4,Edge_5,Edge_6,Edge_7,Edge_8,Edge_9,Edge_10,Edge_11,Edge_12,Edge_13,Edge_14,Edge_15,Edge_16,Edge_17,Edge_18,Edge_19,Edge_20,Edge_21,Edge_22,Edge_23,Edge_24,Edge_25,Edge_26,Edge_27,Edge_28,Edge_29,Edge_30,Edge_31,Edge_32] = geompy.ExtractShapes(Partition_1, geompy.ShapeType["FLAT"], True) + +# FuseCollinearEdges +Wire_1 = geompy.MakeWire([Edge_16, Edge_20], 1e-07) +Wire_2 = geompy.MakeWire([Edge_30, Edge_32], 1e-07) +Wire_3 = geompy.MakeWire([Edge_24, Edge_31], 1e-07) +Wire_4 = geompy.MakeWire([Edge_11, Edge_15], 1e-07) + +FuseEdges_1 = geompy.FuseCollinearEdgesWithinWire(Wire_1, []) +[Edge_33] = geompy.ExtractShapes(FuseEdges_1, geompy.ShapeType["EDGE"], True) +FuseEdges_2 = geompy.FuseCollinearEdgesWithinWire(Wire_2, []) +[Edge_34] = geompy.ExtractShapes(FuseEdges_2, geompy.ShapeType["EDGE"], True) +FuseEdges_3 = geompy.FuseCollinearEdgesWithinWire(Wire_3, []) +[Edge_35] = geompy.ExtractShapes(FuseEdges_3, geompy.ShapeType["EDGE"], True) +FuseEdges_4 = geompy.FuseCollinearEdgesWithinWire(Wire_4, []) +[Edge_36] = geompy.ExtractShapes(FuseEdges_4, geompy.ShapeType["EDGE"], True) + +# Make gaps +Translation_3 = geompy.MakeTranslation(Edge_2, -1, -1, 0) # closed bezier outer part +Translation_4 = geompy.MakeTranslation(Edge_5, -1, 1, 0) # closed b-spline outer part +Translation_5 = geompy.MakeTranslation(Edge_18, 0, 1, 0) +Translation_6 = geompy.MakeTranslation(Edge_34, 1, 1, 0) +Translation_7 = geompy.MakeTranslation(Edge_35, 1, -1, 0) +Translation_8 = geompy.MakeTranslation(Edge_13, 0, -1, 0) + +Translation_9 = geompy.MakeTranslation(Edge_7, 1, 1, 0) # closed bezier inner part +Translation_10 = geompy.MakeTranslation(Edge_9, 1, -1, 0) # closed b-spline inner part +Translation_11 = geompy.MakeTranslation(Edge_33, 0, -1, 0) +Translation_12 = geompy.MakeTranslation(Edge_25, -1, -1, 0) +Translation_13 = geompy.MakeTranslation(Edge_23, -1, 1, 0) +Translation_14 = geompy.MakeTranslation(Edge_36, 0, 1, 0) + +# Not closed B-Spline and Bezier curves +translated_vertex_3 = geompy.GetSubShape(Translation_3, [3]) +translated_vertex_2 = geompy.GetSubShape(Translation_3, [2]) +Curve_1 = geompy.MakeBezier([translated_vertex_3, Vertex_11, Vertex_15, Vertex_14, translated_vertex_2], False) + +translated_vertex_2_1 = geompy.GetSubShape(Translation_9, [2]) +translated_vertex_3_1 = geompy.GetSubShape(Translation_9, [3]) +Curve_2 = geompy.MakeBezier([translated_vertex_2_1, Vertex_12, translated_vertex_3_1], False) + +translated_vertex_2_2 = geompy.GetSubShape(Translation_4, [2]) +translated_vertex_3_2 = geompy.GetSubShape(Translation_4, [3]) +Curve_3 = geompy.MakeInterpol([translated_vertex_2_2, Vertex_10, Vertex_8, translated_vertex_3_2], False, False) + +translated_vertex_2_3 = geompy.GetSubShape(Translation_10, [2]) +translated_vertex_3_3 = geompy.GetSubShape(Translation_10, [3]) +Curve_4 = geompy.MakeInterpol([translated_vertex_2_3, Vertex_9, Vertex_6, translated_vertex_3_3], False, False) + +# Make wires with different methods + +########################################################### +### Use case 1. With pieces of closed Beziers and B_Splines +### +### MakeWire() works good +### MakeWireConstCurveType() raises exception, +### as pieces of Beziers and B_Splines are not supported now +### MakeWireWithMode(GEOM.WBM_Approximation) gives wrong result, +### as pieces of closed bezier curve are wrongly treated +########################################################### + +# add to study argument edges +edges_outer_1 = [Translation_3, Translation_4, Translation_5, Translation_6, Translation_7, Translation_8, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28] + +edges_inner_1 = [Translation_9, Translation_10, Translation_11, Translation_12, Translation_13, Translation_14, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28] + +edges_outer_1_folder = geompy.NewFolder('edges_outer_1') +edges_inner_1_folder = geompy.NewFolder('edges_inner_1') + +ii = 1 +for ee in edges_outer_1: + geompy.addToStudy(ee, "edge_outer_1_%d"%ii) + geompy.PutToFolder(ee, edges_outer_1_folder) + ii += 1 + pass +ii = 1 +for ee in edges_inner_1: + geompy.addToStudy(ee, "edge_inner_1_%d"%ii) + geompy.PutToFolder(ee, edges_inner_1_folder) + ii += 1 + pass + +# a. Old implementation (FixTolerance) +Wire_FixTolerance_Outer_1 = geompy.MakeWire(edges_outer_1, tol, 'Wire_FixTolerance_Outer_1') +Wire_FixTolerance_Inner_1 = geompy.MakeWire(edges_inner_1, tol, 'Wire_FixTolerance_Inner_1') + +# b. New implementation (ConstCurveType) + +# b.1. Not supported case: +# Errors because of not supported Bezier and B-Spline +# (Ends of edge do not correspond to first and last poles) +# +#Wire_ConstCurveType_Outer_1 = geompy.MakeWireConstCurveType(edges_outer_1, tol, 'Wire_ConstCurveType_Outer_1') +#Wire_ConstCurveType_Inner_1 = geompy.MakeWireConstCurveType(edges_inner_1, tol, 'Wire_ConstCurveType_Inner_1') +# +try: + Wire_ConstCurveType_BezierOnly = geompy.MakeWireConstCurveType([Edge_1, Edge_6, Translation_4, Translation_5, Translation_6, Translation_7, Translation_8, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28], tol, 'Wire_ConstCurveType_BezierOnly') +except: + print("KNOWN PROBLEM: MakeWireConstCurveType doesn't support pieces of Bezier curves") +else: + assert(False), "MakeWireConstCurveType should fail here" + pass +# +try: + Wire_ConstCurveType_BSplineOnly = geompy.MakeWireConstCurveType([Translation_9, Edge_4, Edge_8, Translation_11, Translation_12, Translation_13, Translation_14, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28], tol, 'Wire_ConstCurveType_BSplineOnly') +except: + print("KNOWN PROBLEM: MakeWireConstCurveType doesn't support pieces of BSpline curves") +else: + assert(False), "MakeWireConstCurveType should fail here" + pass + +# c. Approximation mode (canonical curves are approximated with b-splines) +Wire_Approximation_Outer_1 = geompy.MakeWireWithMode(edges_outer_1, tol, GEOM.WBM_Approximation, 'Wire_Approximation_Outer_1') +Wire_Approximation_Inner_1 = geompy.MakeWireWithMode(edges_inner_1, tol, GEOM.WBM_Approximation, 'Wire_Approximation_Inner_1') + +### check tolerances +# +tol_FO1 = geompy.Tolerance(Wire_FixTolerance_Outer_1)[5] +tol_FI1 = geompy.Tolerance(Wire_FixTolerance_Inner_1)[5] +assert(abs(tol_FO1 - halfGap) < prec) +assert(abs(tol_FI1 - halfGap) < prec) +# +### Not supported case +#tol_CO1 = geompy.Tolerance(Wire_ConstCurveType_Outer_1)[5] +#tol_CI1 = geompy.Tolerance(Wire_ConstCurveType_Inner_1)[5] +#assert(tol_CO1 < prec) +#assert(tol_CI1 < prec) +# +tol_AO1 = geompy.Tolerance(Wire_Approximation_Outer_1)[5] +tol_AI1 = geompy.Tolerance(Wire_Approximation_Inner_1)[5] +assert(tol_AO1 < prec) +assert(tol_AI1 < prec) + +### check wire length +# +Length_FO1 = geompy.BasicProperties( Wire_FixTolerance_Outer_1 )[0] +Length_FI1 = geompy.BasicProperties( Wire_FixTolerance_Inner_1 )[0] +assert(abs(Length_FO1 - 530.13081) < prec) +assert(abs(Length_FI1 - 415.46762) < prec) +# +### Not supported case +#Length_CO1 = geompy.BasicProperties( Wire_ConstCurveType_Outer_1 )[0] +#Length_CI1 = geompy.BasicProperties( Wire_ConstCurveType_Inner_1 )[0] +#assert(abs(Length_CO1 - ) < prec) +#assert(abs(Length_CI1 - ) < prec) +# +# Here we have a problem with Approximation mode: pieces of bezier curve are wrongly treated +Length_AO1 = geompy.BasicProperties( Wire_Approximation_Outer_1 )[0] +Length_AI1 = geompy.BasicProperties( Wire_Approximation_Inner_1 )[0] +#assert(math.abs(Length_AO1 - 514.35263) < prec) +#assert(math.abs(Length_AI1 - 437.69903) < prec) +if Length_AO1 < 520.0 or Length_AI1 > 425.0: + print("KNOWN PROBLEM: MakeWireWithMode(GEOM.WBM_Approximation) error: pieces of closed bezier curve are wrongly treated") + pass + +############################################################## +### Use case 2. With entire Beziers and B_Splines (not closed) +### +### All three methods give good results +############################################################## + +# add to study argument edges +edges_outer_2 = [Curve_1, Curve_3, Translation_5, Translation_6, Translation_7, Translation_8, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28] + +edges_inner_2 = [Curve_2, Curve_4, Translation_11, Translation_12, Translation_13, Translation_14, Edge_3, Edge_10, Edge_12, Edge_19, Edge_21, Edge_28] + +edges_outer_2_folder = geompy.NewFolder('edges_outer_2') +edges_inner_2_folder = geompy.NewFolder('edges_inner_2') + +ii = 1 +for ee in edges_outer_2: + geompy.addToStudy(ee, "edge_outer_2_%d"%ii) + geompy.PutToFolder(ee, edges_outer_2_folder) + ii += 1 + pass +ii = 1 +for ee in edges_inner_2: + geompy.addToStudy(ee, "edge_inner_2_%d"%ii) + geompy.PutToFolder(ee, edges_inner_2_folder) + ii += 1 + pass + +# a. Old implementation (FixTolerance) +Wire_FixTolerance_Outer_2 = geompy.MakeWire(edges_outer_2, tol, 'Wire_FixTolerance_Outer_2') +Wire_FixTolerance_Inner_2 = geompy.MakeWire(edges_inner_2, tol, 'Wire_FixTolerance_Inner_2') + +# b. New implementation (ConstCurveType) +Wire_ConstCurveType_Outer_2 = geompy.MakeWireConstCurveType(edges_outer_2, tol, 'Wire_ConstCurveType_Outer_2') +Wire_ConstCurveType_Inner_2 = geompy.MakeWireConstCurveType(edges_inner_2, tol, 'Wire_ConstCurveType_Inner_2') + +# c. Approximation mode (in case of need canonical curves are approximated with b-splines) +Wire_Approximation_Outer_2 = geompy.MakeWireWithMode(edges_outer_2, tol, GEOM.WBM_Approximation, 'Wire_Approximation_Outer_2') +Wire_Approximation_Inner_2 = geompy.MakeWireWithMode(edges_inner_2, tol, GEOM.WBM_Approximation, 'Wire_Approximation_Inner_2') + +### check tolerances +# +tol_FO2 = geompy.Tolerance(Wire_FixTolerance_Outer_2)[5] +tol_FI2 = geompy.Tolerance(Wire_FixTolerance_Inner_2)[5] +assert(abs(tol_FO2 - halfGap) < prec) +assert(abs(tol_FI2 - halfGap) < prec) +# +tol_CO2 = geompy.Tolerance(Wire_ConstCurveType_Outer_2)[5] +tol_CI2 = geompy.Tolerance(Wire_ConstCurveType_Inner_2)[5] +assert(tol_CO2 < prec) +assert(tol_CI2 < prec) +# +tol_AO2 = geompy.Tolerance(Wire_Approximation_Outer_2)[5] +tol_AI2 = geompy.Tolerance(Wire_Approximation_Inner_2)[5] +assert(tol_AO2 < prec) +assert(tol_AI2 < prec) + +### check wire length +# +Length_FO2 = geompy.BasicProperties( Wire_FixTolerance_Outer_2 )[0] +Length_FI2 = geompy.BasicProperties( Wire_FixTolerance_Inner_2 )[0] +assert(abs(Length_FO2 - 527.57476) < prec) +assert(abs(Length_FI2 - 421.28096) < prec) +# +Length_CO2 = geompy.BasicProperties( Wire_ConstCurveType_Outer_2 )[0] +Length_CI2 = geompy.BasicProperties( Wire_ConstCurveType_Inner_2 )[0] +assert(abs(Length_CO2 - 534.02648) < prec) +assert(abs(Length_CI2 - 418.95420) < prec) +# +Length_AO2 = geompy.BasicProperties( Wire_Approximation_Outer_2 )[0] +Length_AI2 = geompy.BasicProperties( Wire_Approximation_Inner_2 )[0] +assert(abs(Length_AO2 - 537.15192) < prec) +assert(abs(Length_AI2 - 422.09815) < prec) + + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/test/tests.set b/test/tests.set index aa00e8dfe..417fe1771 100644 --- a/test/tests.set +++ b/test/tests.set @@ -34,3 +34,9 @@ IF(${OpenCASCADE_VERSION}.${OpenCASCADE_SP_VERSION} VERSION_GREATER "7.5.3.3") test_WrappedFace.py ) ENDIF() + +IF(${OpenCASCADE_VERSION}.${OpenCASCADE_SP_VERSION} VERSION_GREATER "7.5.3.5") + LIST(APPEND ALL_TESTS + test_wire_modes.py + ) +ENDIF() -- 2.39.2