From 0e5c07464e58e6c3116a9da7d90475fcd9699034 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me?= Date: Tue, 1 Dec 2020 14:52:28 +0100 Subject: [PATCH] Add documentation, unit test and example --- .../FeaturesAPI_DuplicatedFaces.cpp | 20 ++-- src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.h | 6 +- src/FeaturesPlugin/CMakeLists.txt | 1 + .../FeaturesPlugin_DuplicatedFaces.cpp | 54 +++++----- .../FeaturesPlugin_DuplicatedFaces.h | 3 +- .../Test/TestCheckDuplictedFaces.py | 92 ++++++++++++++++++ src/FeaturesPlugin/doc/FeaturesPlugin.rst | 1 + .../doc/TUI_DuplicatedFacesFeature.rst | 11 +++ .../doc/checkDuplicatedFaceFeature.rst | 53 ++++++++++ .../doc/examples/checkDuplicatedFaces.py | 29 ++++++ .../checkduplicatedFacesPropertyPanel.png | Bin 0 -> 25209 bytes .../doc/images/duplicatedFacesResult.png | Bin 0 -> 8086 bytes .../doc/images/duplicated_shapes.png | Bin 0 -> 947 bytes src/FeaturesPlugin/plugin-Features.xml | 2 +- .../GeomAlgoAPI_DuplicatedFaces.cpp | 25 ++--- src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.h | 16 +-- 16 files changed, 252 insertions(+), 61 deletions(-) create mode 100644 src/FeaturesPlugin/Test/TestCheckDuplictedFaces.py create mode 100644 src/FeaturesPlugin/doc/TUI_DuplicatedFacesFeature.rst create mode 100644 src/FeaturesPlugin/doc/checkDuplicatedFaceFeature.rst create mode 100644 src/FeaturesPlugin/doc/examples/checkDuplicatedFaces.py create mode 100644 src/FeaturesPlugin/doc/images/checkduplicatedFacesPropertyPanel.png create mode 100644 src/FeaturesPlugin/doc/images/duplicatedFacesResult.png create mode 100644 src/FeaturesPlugin/doc/images/duplicated_shapes.png diff --git a/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.cpp b/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.cpp index 9dcdded51..5b86cb56e 100644 --- a/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.cpp +++ b/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.cpp @@ -28,7 +28,7 @@ #include #include - +//================================================================================================= FeaturesAPI_DuplicatedFaces:: FeaturesAPI_DuplicatedFaces(const std::shared_ptr& theFeature) : ModelHighAPI_Interface(theFeature) @@ -36,30 +36,31 @@ FeaturesAPI_DuplicatedFaces:: initialize(); } +//================================================================================================= FeaturesAPI_DuplicatedFaces::~FeaturesAPI_DuplicatedFaces() { } +//================================================================================================= FeaturesAPI_DuplicatedFaces::FeaturesAPI_DuplicatedFaces( - const std::shared_ptr& theFeature, - const ModelHighAPI_Selection& theObject, - const double theTransparency, - const std::string & theNameGroup) + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theObject, + const double theTransparency, + const std::string & theNameGroup) :ModelHighAPI_Interface(theFeature) { if (initialize()) { fillAttribute(theObject, myobjectselected); fillAttribute(theTransparency, mytransparency); - if( theNameGroup != "" ) - { - fillAttribute(true, - feature()->boolean(FeaturesPlugin_DuplicatedFaces::CREATE_GROUP_ID())); + if (theNameGroup != "") { + fillAttribute(true,feature()->boolean(FeaturesPlugin_DuplicatedFaces::CREATE_GROUP_ID())); fillAttribute(theNameGroup, mygroupname); } execute(); } } +//================================================================================================= void FeaturesAPI_DuplicatedFaces::dump(ModelHighAPI_Dumper& theDumper) const { FeaturePtr aBase = feature(); @@ -77,6 +78,7 @@ void FeaturesAPI_DuplicatedFaces::dump(ModelHighAPI_Dumper& theDumper) const theDumper << ")" << std::endl; } +//================================================================================================= DuplicatedFacesPtr getDuplicatedFaces(const std::shared_ptr& thePart, const ModelHighAPI_Selection& theObject, const double theTransparency, diff --git a/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.h b/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.h index 1a4b9bd46..4924a0597 100644 --- a/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.h +++ b/src/FeaturesAPI/FeaturesAPI_DuplicatedFaces.h @@ -78,8 +78,8 @@ typedef std::shared_ptr DuplicatedFacesPtr; /// \param theobject the object selected FEATURESAPI_EXPORT DuplicatedFacesPtr getDuplicatedFaces(const std::shared_ptr& thePart, - const ModelHighAPI_Selection& theObject, - const double theTransparency = 0.0, - const std::string & theNameGroup = ""); + const ModelHighAPI_Selection& theObject, + const double theTransparency = 0.0, + const std::string & theNameGroup = ""); #endif // FeaturesAPI_DuplicatedFaces_H_ diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 12745b129..39470e1f5 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -708,4 +708,5 @@ ADD_UNIT_TESTS(TestExtrusion.py TestFillet1D_Wire_3.py TestFillet1D_Wire_4.py TestFillet1D_Wire_5.py + TestCheckDuplictedFaces.py ) diff --git a/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.cpp b/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.cpp index 088213d3a..9442b5553 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.cpp @@ -45,7 +45,7 @@ #include #include - +//================================================================================================= FeaturesPlugin_DuplicatedFaces::FeaturesPlugin_DuplicatedFaces() { } @@ -66,9 +66,10 @@ void FeaturesPlugin_DuplicatedFaces::initAttributes() boolean(CREATE_GROUP_ID())->setValue(false); } +//================================================================================================= void explode(const GeomShapePtr& theCompound, ListOfShape& theSubs) { - if (theCompound->isCompound() || theCompound->isCompSolid() ) { + if (theCompound->isCompound() || theCompound->isCompSolid()) { GeomAPI_ShapeIterator anIt(theCompound); for (; anIt.more(); anIt.next()) explode(anIt.current(), theSubs); @@ -77,23 +78,30 @@ void explode(const GeomShapePtr& theCompound, ListOfShape& theSubs) theSubs.push_back(theCompound); } +//================================================================================================= void FeaturesPlugin_DuplicatedFaces::execute() { if(boolean(CREATE_GROUP_ID())->value() && selectionList(LIST_FACES_ID())->isInitialized() - && string(GROUP_NAME_ID())->value() != "" ) - { - AttributeStringPtr aNameAtt = string( GROUP_NAME_ID() ) ; + && string(GROUP_NAME_ID())->value() != "" ){ + + AttributeStringPtr aNameAtt = string(GROUP_NAME_ID()); std::wstring aNameFace = aNameAtt->isUValue() ? Locale::Convert::toWString(aNameAtt->valueU()) : Locale::Convert::toWString(aNameAtt->value()); - + if (myGroup.get()) + eraseResults(); setFacesGroup(aNameFace); - } - if( selection(OBJECT_ID())->isInitialized() ) - { + } else { + if (myGroup.get()) { + eraseResults(); + myGroup.reset(); + } + + } + if (selection(OBJECT_ID())->isInitialized()) { AttributeSelectionPtr ancompSolidAttr = selection(OBJECT_ID()); ResultPtr aResult = ancompSolidAttr->context(); @@ -104,12 +112,13 @@ void FeaturesPlugin_DuplicatedFaces::execute() std::list allRes; ModelAPI_Tools::allSubs(aResultBody, allRes); std::list::iterator aRes; - for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + for (aRes = allRes.begin(); aRes != allRes.end(); aRes++) { ModelAPI_Tools::setTransparency(*aRes, aTranparency); } } } +//================================================================================================= void FeaturesPlugin_DuplicatedFaces::attributeChanged(const std::string& theID) { if (theID == OBJECT_ID()) { @@ -119,13 +128,13 @@ void FeaturesPlugin_DuplicatedFaces::attributeChanged(const std::string& theID) if (aShape.get() && ancompSolidAttr->context().get()) { aShape = ancompSolidAttr->context()->shape(); - if(aShape){ + if (aShape) { std::string anError; ListOfShape aFaces; ListOfShape theSubs; explode(aShape, theSubs); - if( !GetDuplicatedFaces( theSubs, + if (!GetDuplicatedFaces(theSubs, 0.001, aFaces, anError)) @@ -136,8 +145,8 @@ void FeaturesPlugin_DuplicatedFaces::attributeChanged(const std::string& theID) std::dynamic_pointer_cast (attribute(LIST_FACES_ID())); - if ( aFacesListAttr->isInitialized()) - aFacesListAttr->clear(); + if (aFacesListAttr->isInitialized()) + aFacesListAttr->clear(); aFacesListAttr->setSelectionType("face"); @@ -154,19 +163,19 @@ void FeaturesPlugin_DuplicatedFaces::attributeChanged(const std::string& theID) std::stringstream alabel; alabel << "Number of duplicated faces : " << aFacesListAttr->size(); string(NUMBER_FACES_ID() )->setValue( alabel.str() ); - } } } } +//================================================================================================= void FeaturesPlugin_DuplicatedFaces::setFacesGroup(const std::wstring& theName ) { std::vector aColor; - ResultGroupPtr aGroup = document()->createGroup(data()); + myGroup = document()->createGroup(data()); // clean the result of the operation - aGroup->data()->setName(theName); - aGroup->store(GeomShapePtr()); + myGroup->data()->setName(theName); + myGroup->store(GeomShapePtr()); // shapes containing in each group ListOfShape aFaces; @@ -174,16 +183,15 @@ void FeaturesPlugin_DuplicatedFaces::setFacesGroup(const std::wstring& theName ) std::dynamic_pointer_cast (attribute(LIST_FACES_ID())); - for(int anI =0; anI< aFacesListAttr->size(); anI++ ) - { + for (int anI =0; anI< aFacesListAttr->size(); anI++) { AttributeSelectionPtr aAtt = aFacesListAttr->value(anI); aFaces.push_back( aAtt->value() ); } + GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aFaces); - aGroup->store(aCompound); + myGroup->store(aCompound); aColor = {255,0,0}; - setResult(aGroup); + setResult(myGroup); ModelAPI_Tools::setColor( lastResult(),aColor); - } diff --git a/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.h b/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.h index 2d847875a..490208992 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.h +++ b/src/FeaturesPlugin/FeaturesPlugin_DuplicatedFaces.h @@ -22,6 +22,7 @@ #include "FeaturesPlugin.h" #include +#include #include #include @@ -102,10 +103,10 @@ public: FeaturesPlugin_DuplicatedFaces(); private: - //Set group of faces void setFacesGroup(const std::wstring& theName ); + ResultGroupPtr myGroup; }; #endif diff --git a/src/FeaturesPlugin/Test/TestCheckDuplictedFaces.py b/src/FeaturesPlugin/Test/TestCheckDuplictedFaces.py new file mode 100644 index 000000000..50b8e44f4 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestCheckDuplictedFaces.py @@ -0,0 +1,92 @@ +# Copyright (C) 2014-2020 CEA/DEN, EDF R&D +# +# 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 +# + +""" + Unit test of Check Duplicated faces +""" +#========================================================================= +# Initialization of the test +#========================================================================= + + +import os +import math + +from ModelAPI import * +from GeomAPI import * +from salome.shaper import model + + +__updated__ = "2020-11-12" + + +if __name__ == '__main__': + + model.begin() + partSet = model.moduleDocument() + Part_1 = model.addPart(partSet) + Part_1_doc = Part_1.document() + ### Create Box + Box_1 = model.addBox(Part_1_doc, 100, 50, 100) + ### Create Point + Point_1 = model.addPoint(Part_1_doc, 100, 0, 0) + ### Create Point + Point_2 = model.addPoint(Part_1_doc, 250, 50, 100) + ### Create Box + Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "all-in-Point_1"), model.selection("VERTEX", "all-in-Point_2")) + ### Create Point + Point_3 = model.addPoint(Part_1_doc, 100, 50, 250) + ### Create Box + Box_3 = model.addBox(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Back][Box_1_1/Left][Box_1_1/Top]"), model.selection("VERTEX", "Point_3")) + ### Create Compound + Compound_1_objects = [model.selection("SOLID", "Box_1_1"), + model.selection("SOLID", "Box_2_1"), + model.selection("SOLID", "Box_3_1")] + Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects) + ### Create Duplicated_faces + Duplicated_faces_1 = model.getDuplicatedFaces(Part_1_doc, model.selection("COMPOUND", "Compound_1_1"), 50, "mygroup") + + model.do() + # Check results + Duplicated_faces_1_Feature = Duplicated_faces_1.feature() + assert Duplicated_faces_1_Feature.error() == '' + assert Duplicated_faces_1_Feature.name() == "Duplicated_faces_1" + + aSelectionList = Duplicated_faces_1_Feature.selectionList("faces") + assert aSelectionList.size() == 2 + + assert(Part_1_doc.size("Groups") == 1) + + #assert Part_1_doc.object("Groups", 0).name() == "mygroup" + resShape = modelAPI_Result(Part_1_doc.object("Groups", 0)).shape() + assert(not resShape.isNull()) + + # the group result is a face, check that this is one face + aShapeExplorer = GeomAPI_ShapeExplorer(resShape, GeomAPI_Shape.FACE) + assert(aShapeExplorer.more()) + assert(aShapeExplorer.current().isFace()) + aShapeExplorer.next() + aShapeExplorer.next() + assert(not aShapeExplorer.more()) + + model.end() + + #========================================================================= + # End of test + #========================================================================= diff --git a/src/FeaturesPlugin/doc/FeaturesPlugin.rst b/src/FeaturesPlugin/doc/FeaturesPlugin.rst index fb8e2a344..538a0dbef 100644 --- a/src/FeaturesPlugin/doc/FeaturesPlugin.rst +++ b/src/FeaturesPlugin/doc/FeaturesPlugin.rst @@ -24,6 +24,7 @@ Features plug-in provides a set of common topological operations. It implements importResultFeature.rst linearCopyFeature.rst measurementFeature.rst + checkDuplicatedFaceFeature.rst pipeFeature.rst placementFeature.rst recoverFeature.rst diff --git a/src/FeaturesPlugin/doc/TUI_DuplicatedFacesFeature.rst b/src/FeaturesPlugin/doc/TUI_DuplicatedFacesFeature.rst new file mode 100644 index 000000000..369057369 --- /dev/null +++ b/src/FeaturesPlugin/doc/TUI_DuplicatedFacesFeature.rst @@ -0,0 +1,11 @@ + + .. _tui_duplicated_faces: + +Check duplicated faces +====================== + +.. literalinclude:: examples/checkDuplicatedFaces.py + :linenos: + :language: python + +:download:`Download this script ` diff --git a/src/FeaturesPlugin/doc/checkDuplicatedFaceFeature.rst b/src/FeaturesPlugin/doc/checkDuplicatedFaceFeature.rst new file mode 100644 index 000000000..aba107ea5 --- /dev/null +++ b/src/FeaturesPlugin/doc/checkDuplicatedFaceFeature.rst @@ -0,0 +1,53 @@ +.. |duplicated_shapes.icon| image:: images/duplicated_shapes.png + +Check duplicated faces +====================== + +The **Check duplicated faces** feature find the duplicated faces of a composolid or compound. + +The result is a list of faces and a group can be created with name specified. + +To check duplicated faces in the active part: + +#. select in the Main Menu *Inspection - > Check duplicated faces* item or +#. click |duplicated_shapes.icon| **Check duplicated faces** button in the toolbar + +The property panel is shown below. + +.. figure:: images/checkduplicatedFacesPropertyPanel.png + :align: center + + Check duplicated faces + + +Input fields: + +- **Object** contains composolid or compound selected in 3D OCC viewer or object browser. +- **Number of duplicated faces** indicate the number of found faces. +- **List of faces** the list of found faces. +- **Transparency** set the transparency of selected object. +- **Create group** check-box allow the creation of the group of found faces. +- **Group name** specified the name of the group created. + + +**TUI Command**: + +.. py:function:: model.getDuplicatedFaces(Part_doc, shape, transparency, nameGroup) + + :param part: The current part object. + :param object: A composolid or compound in format *model.selection("Type", shape)*. + :param number: value for the transparency. + :param string: name of group created. + :return: Created group. + +Result +"""""" + +Result of **Check duplicated faces** where **Create group** is checked. + +.. figure:: images/duplicatedFacesResult.png + :align: center + + Duplicated faces + +**See Also** a sample TUI Script of :ref:`tui_duplicated_faces` operation. \ No newline at end of file diff --git a/src/FeaturesPlugin/doc/examples/checkDuplicatedFaces.py b/src/FeaturesPlugin/doc/examples/checkDuplicatedFaces.py new file mode 100644 index 000000000..1ccb4cb88 --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/checkDuplicatedFaces.py @@ -0,0 +1,29 @@ +from salome.shaper import model +import os + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +### Create Box +Box_1 = model.addBox(Part_1_doc, 100, 50, 100) +### Create Point +Point_1 = model.addPoint(Part_1_doc, 100, 0, 0) +### Create Point +Point_2 = model.addPoint(Part_1_doc, 250, 50, 100) +### Create Box +Box_2 = model.addBox(Part_1_doc, model.selection("VERTEX", "all-in-Point_1"), model.selection("VERTEX", "all-in-Point_2")) +### Create Point +Point_3 = model.addPoint(Part_1_doc, 100, 50, 250) +### Create Box +Box_3 = model.addBox(Part_1_doc, model.selection("VERTEX", "[Box_1_1/Back][Box_1_1/Left][Box_1_1/Top]"), model.selection("VERTEX", "Point_3")) +### Create Compound +Compound_1_objects = [model.selection("SOLID", "Box_1_1"), + model.selection("SOLID", "Box_2_1"), + model.selection("SOLID", "Box_3_1")] +Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects) +### Create Duplicated_faces +Duplicated_faces_1 = model.getDuplicatedFaces(Part_1_doc, model.selection("COMPOUND", "Compound_1_1"), 50, "mygroup") + +model.do() +model.end() diff --git a/src/FeaturesPlugin/doc/images/checkduplicatedFacesPropertyPanel.png b/src/FeaturesPlugin/doc/images/checkduplicatedFacesPropertyPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..48700f68abf4a83800a308532faafd938527a39f GIT binary patch literal 25209 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 T7yvsv;*Fe?l4Pa0aqxcw-#8>2 literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/duplicatedFacesResult.png b/src/FeaturesPlugin/doc/images/duplicatedFacesResult.png new file mode 100644 index 0000000000000000000000000000000000000000..56e1869e9448b677f4674bf3c199f8994a2a9d68 GIT binary patch literal 8086 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 N#uRgMfq`TAe*vifBAWmJ literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/duplicated_shapes.png b/src/FeaturesPlugin/doc/images/duplicated_shapes.png new file mode 100644 index 0000000000000000000000000000000000000000..0d66a119b07a8dab28ea41d5bf263d8b4bd272e8 GIT binary patch literal 947 zcmV;k15EshP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ^@RCwBA{Qv(y12q9a05LI882|(j)eQs)AQl*d zk&zKaA|)jS92S57{)OXz|Nb%j`SXY2`}gk*-@big`1I)$!-o$a7~Z^j1ERqO00a;V zHd{c3$(e^Ru<=VU{QmnNXxKl7zyJQj@sD4B8NUDe!|?UTABL@MfnY;{KpBW%00a<* zmlG2c|Es#^GW`1e2cq#OP$Lk30c!pRV*mIJWdCOP{Ovc`Fr$nmFs&XyECCQeC@zeO ziu$kOp2zU(&p(E5Kuyf-e;9rO4gC#rA<(7&fGOe+kOsMKTU!8wY4&o4-`~H$w5tFy z4?qAh!jeruK)`=yW@d0W{rdF_97dl%e`fgl^(&YU3OktGmoHx!)@f)kd&a07n;4GB3mi{TGY!%V|uhOZBAFm#*bG5q}V7wk=# zPyYS=&A@OvfT7PakD=rAG_b+Q03d*vkX`r>h-Vq5F#P=e4~YMO!w%Un5Dj)I$bV;N zF#H0tYt(~L3B22E-um|NakgA;@DO7kzX#||DXo`1%}<7 z{qtakfl~Ji5DgGOa05Zkes}*I1E+u#!>_L(!@dLYPZSq|*dT9$0GeSJfcOZ=P=Ek} z=M-RRLuyHjY}gJc{S_d9kn^$u5GO!sVgQC=AVGitVnI`IhXfbCfO->d7zh9a7y!=r V1ZfMRt}p-q002ovPDHLkV1iQBlSu#o literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 749b09279..9a39b109f 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -180,7 +180,7 @@ + icon="icons/Features/duplicatedFaces.png" helpfile="checkDuplicatedFaceFeature.html"> diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.cpp index b4c8b0639..4fbe81775 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -31,14 +30,12 @@ #include #include - //================================================================================================= -bool GetDuplicatedFaces( const ListOfShape& theShapes, +bool GetDuplicatedFaces(const ListOfShape& theShapes, const Standard_Real& theTolerance, ListOfShape & theFaces, std::string& theError) { - #ifdef _DEBUG std::cout << "GetDuplicatedFaces " << std::endl; #endif @@ -48,7 +45,7 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, ListOfShape::const_iterator anIt = theShapes.cbegin(); - for(; anIt != theShapes.cend(); ++anIt) { + for (; anIt != theShapes.cend(); ++anIt) { GeomShapePtr aShapePtr = *anIt; @@ -60,8 +57,7 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, aShapesSeq.Append( aShape ); } - if ( aShapesSeq.Length() > 1 ) - { + if (aShapesSeq.Length() > 1){ TopoDS_Compound aCompound; BRep_Builder aBuilder; aBuilder.MakeCompound( aCompound ); @@ -80,7 +76,7 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, std::vector< TopTools_IndexedMapOfShape* > anIndices( aShapesSeq.Length(), NULL ); Handle(TColStd_HArray1OfInteger) anArray; - GeomShapePtr anObj;//Handle(GEOM_Object) anObj; + GeomShapePtr anObj; ListOfShape listOnePerSet; @@ -88,7 +84,6 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItDMSLS (aImages); for (int index = 1; aItDMSLS.More(); aItDMSLS.Next(), ++index) { // some key shape - //const TopoDS_Shape& aSkey = aItDMSLS.Key(); // list of shapes of the argument that can be glued const TopTools_ListOfShape& aLSD = aItDMSLS.Value(); @@ -108,18 +103,16 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, //TopTools_ListIteratorOfListOfShape aListIt (listOnePerSet); ListOfShape::const_iterator aListIt = listOnePerSet.cbegin(); - for (; aListIt != listOnePerSet.cend(); ++aListIt) - { + for (; aListIt != listOnePerSet.cend(); ++aListIt) { TopoDS_Shape aValue = (*aListIt)->impl(); // find a shape to add aValue as a sub-shape anObj.reset(); anIt = theShapes.cbegin(); GeomShapePtr aShapePtr; - for ( int i = 0; i < theShapes.size(); ++i, ++anIt ) - { + for (int i = 0; i < theShapes.size(); ++i, ++anIt) { aShapePtr = *anIt; - if ( !anIndices[i] ) { + if (!anIndices[i]) { anIndices[i] = new TopTools_IndexedMapOfShape; aShape = aShapePtr->impl(); TopExp::MapShapes( aShape, *anIndices[i]); @@ -130,13 +123,13 @@ bool GetDuplicatedFaces( const ListOfShape& theShapes, GeomShapePtr aS(new GeomAPI_Shape); aS->setImpl(new TopoDS_Shape(aSelShape)); // GeomAlgoAPI_ShapeBuilder::add(aShapePtr,aS); - if ( aS.get()) + if (aS.get()) theFaces.push_back(aS); break; } } } - for ( size_t i = 0 ; i < anIndices.size(); ++i ) + for (size_t i = 0 ; i < anIndices.size(); ++i) delete anIndices[i]; return true; diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.h b/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.h index b0e5c7294..e95fa06c9 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_DuplicatedFaces.h @@ -25,14 +25,14 @@ #include /// get the boundin box of theshape. - /// \param theShape the shape - /// \param theTolerance precise TRUE for precise computation; FALSE for fast one. - /// \param theFaces the duplicated faces - /// \param theError error +/// \param theShape the shape +/// \param theTolerance precise TRUE for precise computation; FALSE for fast one. +/// \param theFaces the duplicated faces +/// \param theError error GEOMALGOAPI_EXPORT -bool GetDuplicatedFaces( const ListOfShape& theShapes, - const Standard_Real& theTolerance, - ListOfShape & theFaces, - std::string& theError); +bool GetDuplicatedFaces(const ListOfShape& theShapes, + const Standard_Real& theTolerance, + ListOfShape & theFaces, + std::string& theError); #endif //GEOMALGOAPI_DUPLICATEDFACES_H_ -- 2.39.2