Salome HOME
Merge remote-tracking branch 'origin/Toolbars_Management'
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_NExplode.cpp
1 // Copyright (C) 2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "GeomAlgoAPI_NExplode.h"
22
23 #include <TopoDS_Shape.hxx>
24 #include <BRep_Tool.hxx>
25 #include <TopoDS.hxx>
26 #include <GProp_GProps.hxx>
27 #include <BRepGProp.hxx>
28 #include <NCollection_DataMap.hxx>
29 #include <Precision.hxx>
30 #include <Bnd_Box.hxx>
31 #include <BRepBndLib.hxx>
32 #include <TopExp_Explorer.hxx>
33 #include <TopTools_MapOfShape.hxx>
34
35 #include <vector>
36 #include <algorithm>
37
38 static std::pair<double, double> ShapeToDouble (const TopoDS_Shape& S)
39 {
40   // Computing of CentreOfMass
41   gp_Pnt GPoint;
42   double Len;
43
44   if (S.ShapeType() == TopAbs_VERTEX) {
45     GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
46     Len = (double)S.Orientation();
47   }
48   else {
49     GProp_GProps GPr;
50     if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
51       BRepGProp::LinearProperties(S, GPr);
52     }
53     else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
54       BRepGProp::SurfaceProperties(S, GPr);
55     }
56     else {
57       BRepGProp::VolumeProperties(S, GPr);
58     }
59     GPoint = GPr.CentreOfMass();
60     Len = GPr.Mass();
61   }
62
63   double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
64   return std::make_pair(dMidXYZ, Len);
65 }
66
67 /*!
68 * \brief Sort shapes in the list by their coordinates.
69 */
70 struct CompareShapes : public std::binary_function<TopoDS_Shape, TopoDS_Shape, bool>
71 {
72   typedef NCollection_DataMap<TopoDS_Shape, std::pair<double, double> > DataMapOfShapeDouble;
73
74   CompareShapes(DataMapOfShapeDouble* theCashMap) : myMap(theCashMap) {}
75
76   bool operator() (const TopoDS_Shape& lhs, const TopoDS_Shape& rhs);
77
78   DataMapOfShapeDouble* myMap;
79 };
80
81 bool CompareShapes::operator() (const TopoDS_Shape& theShape1,
82   const TopoDS_Shape& theShape2)
83 {
84   if (!myMap->IsBound(theShape1)) {
85     myMap->Bind(theShape1, ShapeToDouble(theShape1));
86   }
87
88   if (!myMap->IsBound(theShape2)) {
89     myMap->Bind(theShape2, ShapeToDouble(theShape2));
90   }
91
92   std::pair<double, double> val1 = myMap->Find(theShape1);
93   std::pair<double, double> val2 = myMap->Find(theShape2);
94
95   double tol = Precision::Confusion();
96   bool exchange = Standard_False;
97
98   double dMidXYZ = val1.first - val2.first;
99   if (dMidXYZ >= tol) {
100     exchange = Standard_True;
101   }
102   else if (Abs(dMidXYZ) < tol) {
103     double dLength = val1.second - val2.second;
104     if (dLength >= tol) {
105       exchange = Standard_True;
106     }
107     else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
108       // equal values possible on shapes such as two halves of a sphere and
109       // a membrane inside the sphere
110       Bnd_Box box1,box2;
111       BRepBndLib::Add(theShape1, box1);
112       if (!box1.IsVoid()) {
113         BRepBndLib::Add(theShape2, box2);
114         Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
115         if (dSquareExtent >= tol) {
116           exchange = Standard_True;
117         }
118         else if (Abs(dSquareExtent) < tol) {
119           Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
120           box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
121           val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
122           box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
123           val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
124           if ((val1 - val2) >= tol) {
125             exchange = Standard_True;
126           }
127           else // compare adresses if shapes are geometrically equal
128             exchange = theShape1.TShape().get() > theShape2.TShape().get();
129         }
130       }
131     } else // compare adresses if shapes are geometrically equal
132       exchange = theShape1.TShape().get() > theShape2.TShape().get();
133   }
134
135   //return val1 < val2;
136   return !exchange;
137 }
138
139 GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode(
140   const GeomShapePtr theContext, const GeomAPI_Shape::ShapeType theShapeType)
141 {
142   std::vector<TopoDS_Shape> aShapesVec;
143
144   const TopoDS_Shape& aContext = theContext->impl<TopoDS_Shape>();
145   TopExp_Explorer anExp(aContext, (TopAbs_ShapeEnum)theShapeType);
146   TopTools_MapOfShape aMapShape;
147   for(; anExp.More(); anExp.Next()) {
148     if (aMapShape.Add(anExp.Current()))
149       aShapesVec.push_back(anExp.Current());
150   }
151
152   CompareShapes::DataMapOfShapeDouble aCash;
153   CompareShapes shComp(&aCash);
154   std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
155
156   std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
157   for (; anIter != aShapesVec.end(); ++anIter) {
158     GeomShapePtr aShapePtr(new GeomAPI_Shape);
159     aShapePtr->setImpl<TopoDS_Shape>(new TopoDS_Shape(*anIter));
160     mySorted.push_back(aShapePtr);
161   }
162 }
163
164 int GeomAlgoAPI_NExplode::index(const GeomShapePtr theSubShape)
165 {
166   ListOfShape::iterator anIter = mySorted.begin();
167   for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) {
168     if ((*anIter)->isSame(theSubShape))
169       return anIndex;
170   }
171   return 0; // not found
172 }
173
174 GeomShapePtr GeomAlgoAPI_NExplode::shape(const int theIndex)
175 {
176   ListOfShape::iterator anIter = mySorted.begin();
177   for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) {
178     if (anIndex == theIndex)
179       return *anIter;
180   }
181   return GeomShapePtr(); // not found
182 }