Salome HOME
Update copyrights
[modules/shaper.git] / src / Selector / Selector_NExplode.cpp
1 // Copyright (C) 2017-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "Selector_NExplode.h"
21
22 #include <TopoDS_Shape.hxx>
23 #include <BRep_Tool.hxx>
24 #include <TopoDS.hxx>
25 #include <GProp_GProps.hxx>
26 #include <BRepGProp.hxx>
27 #include <NCollection_DataMap.hxx>
28 #include <Precision.hxx>
29 #include <Bnd_Box.hxx>
30 #include <BRepBndLib.hxx>
31 #include <TopExp_Explorer.hxx>
32 #include <TopTools_MapOfShape.hxx>
33
34 #include <vector>
35 #include <algorithm>
36
37 static std::pair<double, double> ShapeToDouble (const TopoDS_Shape& S)
38 {
39   // Computing of CentreOfMass
40   gp_Pnt GPoint;
41   double Len;
42
43   if (S.ShapeType() == TopAbs_VERTEX) {
44     GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
45     Len = (double)S.Orientation();
46   }
47   else {
48     GProp_GProps GPr;
49     if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
50       BRepGProp::LinearProperties(S, GPr);
51     }
52     else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
53       BRepGProp::SurfaceProperties(S, GPr);
54     }
55     else {
56       BRepGProp::VolumeProperties(S, GPr);
57     }
58     GPoint = GPr.CentreOfMass();
59     Len = GPr.Mass();
60   }
61
62   double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
63   return std::make_pair(dMidXYZ, Len);
64 }
65
66 /*!
67 * \brief Sort shapes in the list by their coordinates.
68 */
69 struct CompareShapes : public std::binary_function<TopoDS_Shape, TopoDS_Shape, bool>
70 {
71   typedef NCollection_DataMap<TopoDS_Shape, std::pair<double, double> > DataMapOfShapeDouble;
72
73   CompareShapes(DataMapOfShapeDouble* theCashMap) : myMap(theCashMap) {}
74
75   bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs);
76
77   DataMapOfShapeDouble* myMap;
78 };
79
80 bool CompareShapes::operator() (const TopoDS_Shape& theShape1,
81   const TopoDS_Shape& theShape2)
82 {
83   if (!myMap->IsBound(theShape1)) {
84     myMap->Bind(theShape1, ShapeToDouble(theShape1));
85   }
86
87   if (!myMap->IsBound(theShape2)) {
88     myMap->Bind(theShape2, ShapeToDouble(theShape2));
89   }
90
91   std::pair<double, double> val1 = myMap->Find(theShape1);
92   std::pair<double, double> val2 = myMap->Find(theShape2);
93
94   double tol = Precision::Confusion();
95   bool exchange = Standard_False;
96
97   double dMidXYZ = val1.first - val2.first;
98   if (dMidXYZ >= tol) {
99     exchange = Standard_True;
100   }
101   else if (Abs(dMidXYZ) < tol) {
102     double dLength = val1.second - val2.second;
103     if (dLength >= tol) {
104       exchange = Standard_True;
105     }
106     else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
107       // equal values possible on shapes such as two halves of a sphere and
108       // a membrane inside the sphere
109 // LCOV_EXCL_START
110       // this part of code is taken from GEOM module, but can not reproduce in SHAPER
111       Bnd_Box box1,box2;
112       BRepBndLib::Add(theShape1, box1);
113       if (!box1.IsVoid()) {
114         BRepBndLib::Add(theShape2, box2);
115         Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
116         if (dSquareExtent >= tol) {
117           exchange = Standard_True;
118         }
119         else if (Abs(dSquareExtent) < tol) {
120           Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
121           box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
122           val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
123           box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
124           val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
125           if ((val1 - val2) >= tol) {
126             exchange = Standard_True;
127           }
128         }
129       }
130 // LCOV_EXCL_STOP
131     } else // compare addresses if shapes are geometrically equal
132       return theShape1.TShape().get() > theShape2.TShape().get();
133   }
134
135   //return val1 < val2;
136   return !exchange;
137 }
138
139 Selector_NExplode::Selector_NExplode(const TopoDS_ListOfShape& theShapes)
140 {
141   std::vector<TopoDS_Shape> aShapesVec;
142
143   for(TopoDS_ListOfShape::Iterator anIter(theShapes); anIter.More(); anIter.Next()) {
144       aShapesVec.push_back(anIter.Value());
145   }
146
147   CompareShapes::DataMapOfShapeDouble aCash;
148   CompareShapes shComp(&aCash);
149   std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
150
151   std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
152   for (; anIter != aShapesVec.end(); ++anIter) {
153     mySorted.Append(*anIter);
154   }
155 }
156
157 Selector_NExplode::Selector_NExplode(const TopoDS_Shape& theShape, const TopAbs_ShapeEnum theType)
158 {
159   std::vector<TopoDS_Shape> aShapesVec;
160   TopTools_MapOfShape anAdded; // to avoid same shapes duplication
161   for(TopExp_Explorer anExp(theShape, theType); anExp.More(); anExp.Next()) {
162     if (anAdded.Add(anExp.Current()))
163      aShapesVec.push_back(anExp.Current());
164   }
165
166   CompareShapes::DataMapOfShapeDouble aCash;
167   CompareShapes shComp(&aCash);
168   std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
169
170   std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
171   for (; anIter != aShapesVec.end(); ++anIter) {
172     mySorted.Append(*anIter);
173   }
174 }
175
176
177 int Selector_NExplode::index(const TopoDS_Shape& theSubShape)
178 {
179   TopoDS_ListOfShape::Iterator anIter(mySorted);
180   for(int anIndex = 1; anIter.More(); anIter.Next(), anIndex++) {
181     if (anIter.Value().IsSame(theSubShape))
182       return anIndex;
183   }
184   return -1; // not found
185 }
186
187 TopoDS_Shape Selector_NExplode::shape(const int theIndex)
188 {
189   TopoDS_ListOfShape::Iterator anIter(mySorted);
190   for(int anIndex = 1; anIter.More(); anIter.Next(), anIndex++) {
191     if (anIndex == theIndex)
192       return anIter.Value();
193   }
194   return TopoDS_Shape(); // not found
195 }