1 // Copyright (C) 2017-2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "GeomAlgoAPI_NExplode.h"
22 #include <GeomAPI_Pnt.h>
23 #include <GeomAPI_ShapeExplorer.h>
25 #include <Bnd_Box.hxx>
26 #include <BRep_Tool.hxx>
27 #include <BRepBndLib.hxx>
28 #include <BRepGProp.hxx>
29 #include <GProp_GProps.hxx>
30 #include <Precision.hxx>
32 #include <TopoDS_Shape.hxx>
36 #include <unordered_map>
38 namespace NExplodeTools
42 // do nothing (new approach to order shapes)
45 void pointToDouble(gp_Pnt& thePoint)
47 // old approach to order shapes
48 double dMidXYZ = thePoint.X() * 999.0 + thePoint.Y() * 99.0 + thePoint.Z() * 0.9;
49 thePoint.SetCoord(dMidXYZ, 0.0, 0.0);
52 std::pair<GeomPointPtr, double> ShapeToDouble(const GeomShapePtr& theShape,
53 void(*convertPoint)(gp_Pnt&))
55 // Computing of CentreOfMass
59 TopoDS_Shape S = theShape->impl<TopoDS_Shape>();
60 if (S.ShapeType() == TopAbs_VERTEX) {
61 GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
62 Len = (double)S.Orientation();
66 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
67 BRepGProp::LinearProperties(S, GPr);
69 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
70 BRepGProp::SurfaceProperties(S, GPr);
73 BRepGProp::VolumeProperties(S, GPr);
75 GPoint = GPr.CentreOfMass();
79 (*convertPoint)(GPoint);
80 GeomPointPtr aMidPoint(new GeomAPI_Pnt(GPoint.X(), GPoint.Y(), GPoint.Z()));
81 return std::make_pair(aMidPoint, Len);
85 * \brief Sort shapes in the list by their coordinates.
87 struct CompareShapes : public std::binary_function<TopoDS_Shape, TopoDS_Shape, bool>
89 typedef std::unordered_map<GeomShapePtr,
90 std::pair<GeomPointPtr, double>,
92 GeomAPI_Shape::Equal > DataMapOfShapeDouble;
94 CompareShapes(void(*convertPoint)(gp_Pnt&))
95 : myConvertPoint(convertPoint) {}
97 bool operator() (const GeomShapePtr& lhs, const GeomShapePtr& rhs);
99 DataMapOfShapeDouble myMap;
100 void(*myConvertPoint)(gp_Pnt&);
104 bool NExplodeTools::CompareShapes::operator() (const GeomShapePtr& lhs, const GeomShapePtr& rhs)
106 if (myMap.find(lhs) == myMap.end()) {
107 myMap[lhs] = ShapeToDouble(lhs, myConvertPoint);
110 if (myMap.find(rhs) == myMap.end()) {
111 myMap[rhs] = ShapeToDouble(rhs, myConvertPoint);
114 const std::pair<GeomPointPtr, double>& val1 = myMap.at(lhs);
115 const std::pair<GeomPointPtr, double>& val2 = myMap.at(rhs);
117 double tol = 10.0 * Precision::Confusion();
118 bool exchange = Standard_False;
120 // compare coordinates of center points
121 if (val2.first->isLess(val1.first, tol)) {
122 exchange = Standard_True;
124 else if (!val1.first->isLess(val2.first, tol)) {
125 double dLength = val1.second - val2.second;
126 if (dLength >= tol) {
127 exchange = Standard_True;
129 else if (Abs(dLength) < tol && lhs->shapeType() <= GeomAPI_Shape::FACE) {
130 // equal values possible on shapes such as two halves of a sphere and
131 // a membrane inside the sphere
133 BRepBndLib::Add(lhs->impl<TopoDS_Shape>(), box1);
134 if (!box1.IsVoid()) {
135 BRepBndLib::Add(rhs->impl<TopoDS_Shape>(), box2);
136 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
137 if (dSquareExtent >= tol) {
138 exchange = Standard_True;
140 else if (Abs(dSquareExtent) < tol) {
141 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, value1, value2;
142 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
143 value1 = (aXmin + aXmax)*999.0 + (aYmin + aYmax)*99.0 + (aZmin + aZmax)*0.9;
144 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
145 value2 = (aXmin + aXmax)*999.0 + (aYmin + aYmax)*99.0 + (aZmin + aZmax)*0.9;
146 if (value1 - value2 >= tol) {
147 exchange = Standard_True;
149 else { // compare adresses if shapes are geometrically equal
150 exchange = lhs->impl<TopoDS_Shape>().TShape().get() >
151 rhs->impl<TopoDS_Shape>().TShape().get();
156 else { // compare adresses if shapes are geometrically equal
157 exchange = lhs->impl<TopoDS_Shape>().TShape().get() >
158 rhs->impl<TopoDS_Shape>().TShape().get();
162 //return val1 < val2;
166 GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode(const GeomShapePtr theContext,
167 const GeomAPI_Shape::ShapeType theShapeType,
168 const ShapeOrder theOrder)
170 std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aMapShape;
171 GeomAPI_ShapeExplorer anExp(theContext, theShapeType);
172 for (; anExp.more(); anExp.next()) {
173 GeomShapePtr aCurrent = anExp.current();
174 if (aMapShape.find(aCurrent) == aMapShape.end()) {
175 mySorted.push_back(aCurrent);
176 aMapShape.insert(aCurrent);
182 GeomAlgoAPI_NExplode::GeomAlgoAPI_NExplode(const ListOfShape& theShapes,
183 const ShapeOrder theOrder)
184 : mySorted(theShapes.begin(), theShapes.end())
189 int GeomAlgoAPI_NExplode::index(const GeomShapePtr theSubShape)
191 std::vector<GeomShapePtr>::iterator anIter = mySorted.begin();
192 for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) {
193 if ((*anIter)->isSame(theSubShape))
196 return 0; // not found
199 GeomShapePtr GeomAlgoAPI_NExplode::shape(const int theIndex)
201 std::vector<GeomShapePtr>::iterator anIter = mySorted.begin();
202 for(int anIndex = 1; anIter != mySorted.end(); anIter++, anIndex++) {
203 if (anIndex == theIndex)
206 return GeomShapePtr(); // not found
209 void GeomAlgoAPI_NExplode::reorder(const ShapeOrder theNewOrder)
211 NExplodeTools::CompareShapes shComp(
212 theNewOrder == ORDER_BY_HASH_VALUE ? NExplodeTools::pointToDouble : NExplodeTools::dummy);
213 std::stable_sort(mySorted.begin(), mySorted.end(), shComp);