1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #include <Standard_Stream.hxx>
24 #include <GEOMUtils.hxx>
26 #include <Basics_OCCTVersion.hxx>
28 #include <utilities.h>
30 #include <Utils_ExceptHandlers.hxx>
33 #include <BRepMesh_IncrementalMesh.hxx>
35 #include <BRep_Builder.hxx>
36 #include <BRep_Tool.hxx>
37 #include <BRepBndLib.hxx>
38 #include <BRepGProp.hxx>
39 #include <BRepTools.hxx>
41 #include <Bnd_Box.hxx>
46 #include <TopoDS_Edge.hxx>
47 #include <TopoDS_Face.hxx>
48 #include <TopoDS_Shape.hxx>
49 #include <TopoDS_Vertex.hxx>
50 #include <TopoDS_Compound.hxx>
51 #include <TopoDS_Iterator.hxx>
52 #include <TopExp_Explorer.hxx>
53 #include <TopTools_MapOfShape.hxx>
54 #include <TopTools_ListOfShape.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
57 #include <Geom_Surface.hxx>
58 #include <Geom_Plane.hxx>
60 #include <GeomLProp_CLProps.hxx>
61 #include <GeomLProp_SLProps.hxx>
63 #include <GProp_GProps.hxx>
64 #include <GProp_PrincipalProps.hxx>
71 #include <Standard_Failure.hxx>
72 #include <Standard_NullObject.hxx>
73 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
75 #define STD_SORT_ALGO 1
77 //=======================================================================
78 //function : GetPosition
80 //=======================================================================
81 gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape)
85 if (theShape.IsNull())
89 aResult.Transform(theShape.Location().Transformation());
90 if (theShape.ShapeType() == TopAbs_FACE) {
91 Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape));
92 if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) {
93 Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS);
94 gp_Pln aPln = aGPlane->Pln();
95 aResult = aPln.Position();
96 // In case of reverse orinetation of the face invert the plane normal
97 // (the face's normal does not mathc the plane's normal in this case)
98 if(theShape.Orientation() == TopAbs_REVERSED)
100 gp_Dir Vx = aResult.XDirection();
101 gp_Dir N = aResult.Direction().Mirrored(Vx);
102 gp_Pnt P = aResult.Location();
103 aResult = gp_Ax3(P, N, Vx);
111 TopAbs_ShapeEnum aShType = theShape.ShapeType();
113 if (aShType == TopAbs_VERTEX) {
114 aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
117 if (aShType == TopAbs_COMPOUND) {
118 aShType = GetTypeOfSimplePart(theShape);
121 GProp_GProps aSystem;
122 if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE)
123 BRepGProp::LinearProperties(theShape, aSystem);
124 else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL)
125 BRepGProp::SurfaceProperties(theShape, aSystem);
127 BRepGProp::VolumeProperties(theShape, aSystem);
129 aPnt = aSystem.CentreOfMass();
132 aResult.SetLocation(aPnt);
137 //=======================================================================
138 //function : GetVector
140 //=======================================================================
141 gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape)
143 if (theShape.IsNull())
144 Standard_NullObject::Raise("Null shape is given for a vector");
146 if (theShape.ShapeType() != TopAbs_EDGE)
147 Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge");
149 TopoDS_Edge anE = TopoDS::Edge(theShape);
151 TopoDS_Vertex V1, V2;
152 TopExp::Vertices(anE, V1, V2, Standard_True);
154 if (V1.IsNull() || V2.IsNull())
155 Standard_NullObject::Raise("Invalid edge is given, it must have two points");
157 gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
158 if (aV.Magnitude() < gp::Resolution()) {
159 Standard_ConstructionError::Raise("Vector of zero length is given");
165 //=======================================================================
166 //function : ShapeToDouble
167 //purpose : used by CompareShapes::operator()
168 //=======================================================================
169 std::pair<double, double> ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting)
171 // Computing of CentreOfMass
175 if (S.ShapeType() == TopAbs_VERTEX) {
176 GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
177 Len = (double)S.Orientation();
181 // BEGIN: fix for Mantis issue 0020842
183 BRepGProp::LinearProperties(S, GPr);
186 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
187 BRepGProp::LinearProperties(S, GPr);
189 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
190 BRepGProp::SurfaceProperties(S, GPr);
193 BRepGProp::VolumeProperties(S, GPr);
196 // END: fix for Mantis issue 0020842
197 GPoint = GPr.CentreOfMass();
201 double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
202 return std::make_pair(dMidXYZ, Len);
205 //=======================================================================
206 //function : CompareShapes::operator()
207 //purpose : used by std::sort(), called from SortShapes()
208 //=======================================================================
209 bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1,
210 const TopoDS_Shape& theShape2)
212 if (!myMap.IsBound(theShape1)) {
213 myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting));
216 if (!myMap.IsBound(theShape2)) {
217 myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting));
220 std::pair<double, double> val1 = myMap.Find(theShape1);
221 std::pair<double, double> val2 = myMap.Find(theShape2);
223 double tol = Precision::Confusion();
224 bool exchange = Standard_False;
226 double dMidXYZ = val1.first - val2.first;
227 if (dMidXYZ >= tol) {
228 exchange = Standard_True;
230 else if (Abs(dMidXYZ) < tol) {
231 double dLength = val1.second - val2.second;
232 if (dLength >= tol) {
233 exchange = Standard_True;
235 else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
237 // equal values possible on shapes such as two halves of a sphere and
238 // a membrane inside the sphere
240 BRepBndLib::Add(theShape1, box1);
241 if (!box1.IsVoid()) {
242 BRepBndLib::Add(theShape2, box2);
243 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
244 if (dSquareExtent >= tol) {
245 exchange = Standard_True;
247 else if (Abs(dSquareExtent) < tol) {
248 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
249 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
250 val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
251 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
252 val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
253 if ((val1 - val2) >= tol) {
254 exchange = Standard_True;
261 //return val1 < val2;
265 //=======================================================================
266 //function : SortShapes
268 //=======================================================================
269 void GEOMUtils::SortShapes (TopTools_ListOfShape& SL,
270 const Standard_Boolean isOldSorting)
273 std::vector<TopoDS_Shape> aShapesVec;
274 aShapesVec.reserve(SL.Extent());
276 TopTools_ListIteratorOfListOfShape it (SL);
277 for (; it.More(); it.Next()) {
278 aShapesVec.push_back(it.Value());
282 CompareShapes shComp (isOldSorting);
283 std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
284 //std::sort(aShapesVec.begin(), aShapesVec.end(), shComp);
286 std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
287 for (; anIter != aShapesVec.end(); ++anIter) {
291 // old implementation
292 Standard_Integer MaxShapes = SL.Extent();
293 TopTools_Array1OfShape aShapes (1,MaxShapes);
294 TColStd_Array1OfInteger OrderInd(1,MaxShapes);
295 TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z;
296 TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z;
298 // Computing of CentreOfMass
299 Standard_Integer Index;
302 TopTools_ListIteratorOfListOfShape it(SL);
303 for (Index=1; it.More(); Index++)
305 TopoDS_Shape S = it.Value();
306 SL.Remove( it ); // == it.Next()
308 OrderInd.SetValue (Index, Index);
309 if (S.ShapeType() == TopAbs_VERTEX) {
310 GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S ));
311 Length.SetValue( Index, (Standard_Real) S.Orientation());
314 // BEGIN: fix for Mantis issue 0020842
316 BRepGProp::LinearProperties (S, GPr);
319 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
320 BRepGProp::LinearProperties (S, GPr);
322 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
323 BRepGProp::SurfaceProperties(S, GPr);
326 BRepGProp::VolumeProperties(S, GPr);
329 // END: fix for Mantis issue 0020842
330 GPoint = GPr.CentreOfMass();
331 Length.SetValue(Index, GPr.Mass());
333 MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9);
334 //cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl;
338 Standard_Integer aTemp;
339 Standard_Boolean exchange, Sort = Standard_True;
340 Standard_Real tol = Precision::Confusion();
343 Sort = Standard_False;
344 for (Index=1; Index < MaxShapes; Index++)
346 exchange = Standard_False;
347 Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1));
348 Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1));
349 if ( dMidXYZ >= tol ) {
350 // cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <<MidXYZ(OrderInd(Index+1))
351 // << " d: " << dMidXYZ << endl;
352 exchange = Standard_True;
354 else if ( Abs(dMidXYZ) < tol && dLength >= tol ) {
355 // cout << "Length: " << Length(OrderInd(Index))<< " > " <<Length(OrderInd(Index+1))
356 // << " d: " << dLength << endl;
357 exchange = Standard_True;
359 else if ( Abs(dMidXYZ) < tol && Abs(dLength) < tol &&
360 aShapes(OrderInd(Index)).ShapeType() <= TopAbs_FACE) {
362 // equal values possible on shapes such as two halves of a sphere and
363 // a membrane inside the sphere
365 BRepBndLib::Add( aShapes( OrderInd(Index) ), box1 );
366 if ( box1.IsVoid() ) continue;
367 BRepBndLib::Add( aShapes( OrderInd(Index+1) ), box2 );
368 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
369 if ( dSquareExtent >= tol ) {
370 // cout << "SquareExtent: " << box1.SquareExtent()<<" > "<<box2.SquareExtent() << endl;
371 exchange = Standard_True;
373 else if ( Abs(dSquareExtent) < tol ) {
374 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
375 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
376 val1 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
377 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
378 val2 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
379 //exchange = val1 > val2;
380 if ((val1 - val2) >= tol) {
381 exchange = Standard_True;
383 //cout << "box: " << val1<<" > "<<val2 << endl;
389 // cout << "exchange " << Index << " & " << Index+1 << endl;
390 aTemp = OrderInd(Index);
391 OrderInd(Index) = OrderInd(Index+1);
392 OrderInd(Index+1) = aTemp;
393 Sort = Standard_True;
398 for (Index=1; Index <= MaxShapes; Index++)
399 SL.Append( aShapes( OrderInd(Index) ));
403 //=======================================================================
404 //function : CompsolidToCompound
406 //=======================================================================
407 TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid)
409 if (theCompsolid.ShapeType() != TopAbs_COMPSOLID) {
413 TopoDS_Compound aCompound;
415 B.MakeCompound(aCompound);
417 TopTools_MapOfShape mapShape;
418 TopoDS_Iterator It (theCompsolid, Standard_True, Standard_True);
420 for (; It.More(); It.Next()) {
421 TopoDS_Shape aShape_i = It.Value();
422 if (mapShape.Add(aShape_i)) {
423 B.Add(aCompound, aShape_i);
430 //=======================================================================
431 //function : CheckTriangulation
433 //=======================================================================
434 bool GEOMUtils::CheckTriangulation (const TopoDS_Shape& aShape)
436 bool isTriangulation = true;
438 TopExp_Explorer exp (aShape, TopAbs_FACE);
441 TopLoc_Location aTopLoc;
442 Handle(Poly_Triangulation) aTRF;
443 aTRF = BRep_Tool::Triangulation(TopoDS::Face(exp.Current()), aTopLoc);
445 isTriangulation = false;
448 else // no faces, try edges
450 TopExp_Explorer expe (aShape, TopAbs_EDGE);
454 TopLoc_Location aLoc;
455 Handle(Poly_Polygon3D) aPE = BRep_Tool::Polygon3D(TopoDS::Edge(expe.Current()), aLoc);
457 isTriangulation = false;
461 if (!isTriangulation) {
462 // calculate deflection
463 Standard_Real aDeviationCoefficient = 0.001;
466 BRepBndLib::Add(aShape, B);
467 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
468 B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
470 Standard_Real dx = aXmax - aXmin, dy = aYmax - aYmin, dz = aZmax - aZmin;
471 Standard_Real aDeflection = Max(Max(dx, dy), dz) * aDeviationCoefficient * 4;
472 Standard_Real aHLRAngle = 0.349066;
474 BRepMesh_IncrementalMesh Inc (aShape, aDeflection, Standard_False, aHLRAngle);
480 //=======================================================================
481 //function : GetTypeOfSimplePart
483 //=======================================================================
484 TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape)
486 TopAbs_ShapeEnum aType = theShape.ShapeType();
487 if (aType == TopAbs_VERTEX) return TopAbs_VERTEX;
488 else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE;
489 else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE;
490 else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID;
491 else if (aType == TopAbs_COMPOUND) {
492 // Only the iType of the first shape in the compound is taken into account
493 TopoDS_Iterator It (theShape, Standard_False, Standard_False);
495 return GetTypeOfSimplePart(It.Value());