1 // Copyright (C) 2007-2013 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
23 #include <Standard_Stream.hxx>
25 #include <GEOMUtils.hxx>
27 #include <Basics_OCCTVersion.hxx>
29 #include <utilities.h>
31 #include <Utils_ExceptHandlers.hxx>
34 #include <BRepMesh_IncrementalMesh.hxx>
36 #include <BRepExtrema_DistShapeShape.hxx>
38 #include <BRep_Builder.hxx>
39 #include <BRep_Tool.hxx>
40 #include <BRepBndLib.hxx>
41 #include <BRepGProp.hxx>
42 #include <BRepTools.hxx>
44 #include <Bnd_Box.hxx>
49 #include <TopoDS_Edge.hxx>
50 #include <TopoDS_Face.hxx>
51 #include <TopoDS_Shape.hxx>
52 #include <TopoDS_Vertex.hxx>
53 #include <TopoDS_Compound.hxx>
54 #include <TopoDS_Iterator.hxx>
55 #include <TopExp_Explorer.hxx>
56 #include <TopTools_MapOfShape.hxx>
57 #include <TopTools_ListOfShape.hxx>
58 #include <TopTools_ListIteratorOfListOfShape.hxx>
59 #include <TopTools_Array1OfShape.hxx>
61 #include <Geom_Surface.hxx>
62 #include <Geom_Plane.hxx>
64 #include <GeomLProp_CLProps.hxx>
65 #include <GeomLProp_SLProps.hxx>
67 #include <GProp_GProps.hxx>
68 #include <GProp_PrincipalProps.hxx>
70 #include <TColStd_Array1OfReal.hxx>
77 #include <Standard_Failure.hxx>
78 #include <Standard_NullObject.hxx>
79 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
81 #define STD_SORT_ALGO 1
83 //=======================================================================
84 //function : GetPosition
86 //=======================================================================
87 gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape)
91 if (theShape.IsNull())
95 aResult.Transform(theShape.Location().Transformation());
96 if (theShape.ShapeType() == TopAbs_FACE) {
97 Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape));
98 if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) {
99 Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS);
100 gp_Pln aPln = aGPlane->Pln();
101 aResult = aPln.Position();
102 // In case of reverse orinetation of the face invert the plane normal
103 // (the face's normal does not mathc the plane's normal in this case)
104 if(theShape.Orientation() == TopAbs_REVERSED)
106 gp_Dir Vx = aResult.XDirection();
107 gp_Dir N = aResult.Direction().Mirrored(Vx);
108 gp_Pnt P = aResult.Location();
109 aResult = gp_Ax3(P, N, Vx);
117 TopAbs_ShapeEnum aShType = theShape.ShapeType();
119 if (aShType == TopAbs_VERTEX) {
120 aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
123 if (aShType == TopAbs_COMPOUND) {
124 aShType = GetTypeOfSimplePart(theShape);
127 GProp_GProps aSystem;
128 if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE)
129 BRepGProp::LinearProperties(theShape, aSystem);
130 else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL)
131 BRepGProp::SurfaceProperties(theShape, aSystem);
133 BRepGProp::VolumeProperties(theShape, aSystem);
135 aPnt = aSystem.CentreOfMass();
138 aResult.SetLocation(aPnt);
143 //=======================================================================
144 //function : GetVector
146 //=======================================================================
147 gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape,
148 Standard_Boolean doConsiderOrientation)
150 if (theShape.IsNull())
151 Standard_NullObject::Raise("Null shape is given for a vector");
153 if (theShape.ShapeType() != TopAbs_EDGE)
154 Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge");
156 TopoDS_Edge anE = TopoDS::Edge(theShape);
158 TopoDS_Vertex V1, V2;
159 TopExp::Vertices(anE, V1, V2, doConsiderOrientation);
161 if (V1.IsNull() || V2.IsNull())
162 Standard_NullObject::Raise("Invalid edge is given, it must have two points");
164 gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
165 if (aV.Magnitude() < gp::Resolution()) {
166 Standard_ConstructionError::Raise("Vector of zero length is given");
172 //=======================================================================
173 //function : ShapeToDouble
174 //purpose : used by CompareShapes::operator()
175 //=======================================================================
176 std::pair<double, double> ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting)
178 // Computing of CentreOfMass
182 if (S.ShapeType() == TopAbs_VERTEX) {
183 GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
184 Len = (double)S.Orientation();
188 // BEGIN: fix for Mantis issue 0020842
190 BRepGProp::LinearProperties(S, GPr);
193 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
194 BRepGProp::LinearProperties(S, GPr);
196 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
197 BRepGProp::SurfaceProperties(S, GPr);
200 BRepGProp::VolumeProperties(S, GPr);
203 // END: fix for Mantis issue 0020842
204 GPoint = GPr.CentreOfMass();
208 double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
209 return std::make_pair(dMidXYZ, Len);
212 //=======================================================================
213 //function : CompareShapes::operator()
214 //purpose : used by std::sort(), called from SortShapes()
215 //=======================================================================
216 bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1,
217 const TopoDS_Shape& theShape2)
219 if (!myMap.IsBound(theShape1)) {
220 myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting));
223 if (!myMap.IsBound(theShape2)) {
224 myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting));
227 std::pair<double, double> val1 = myMap.Find(theShape1);
228 std::pair<double, double> val2 = myMap.Find(theShape2);
230 double tol = Precision::Confusion();
231 bool exchange = Standard_False;
233 double dMidXYZ = val1.first - val2.first;
234 if (dMidXYZ >= tol) {
235 exchange = Standard_True;
237 else if (Abs(dMidXYZ) < tol) {
238 double dLength = val1.second - val2.second;
239 if (dLength >= tol) {
240 exchange = Standard_True;
242 else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
244 // equal values possible on shapes such as two halves of a sphere and
245 // a membrane inside the sphere
247 BRepBndLib::Add(theShape1, box1);
248 if (!box1.IsVoid()) {
249 BRepBndLib::Add(theShape2, box2);
250 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
251 if (dSquareExtent >= tol) {
252 exchange = Standard_True;
254 else if (Abs(dSquareExtent) < tol) {
255 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
256 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
257 val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
258 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
259 val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
260 if ((val1 - val2) >= tol) {
261 exchange = Standard_True;
268 //return val1 < val2;
272 //=======================================================================
273 //function : SortShapes
275 //=======================================================================
276 void GEOMUtils::SortShapes (TopTools_ListOfShape& SL,
277 const Standard_Boolean isOldSorting)
280 std::vector<TopoDS_Shape> aShapesVec;
281 aShapesVec.reserve(SL.Extent());
283 TopTools_ListIteratorOfListOfShape it (SL);
284 for (; it.More(); it.Next()) {
285 aShapesVec.push_back(it.Value());
289 CompareShapes shComp (isOldSorting);
290 std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
291 //std::sort(aShapesVec.begin(), aShapesVec.end(), shComp);
293 std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
294 for (; anIter != aShapesVec.end(); ++anIter) {
298 // old implementation
299 Standard_Integer MaxShapes = SL.Extent();
300 TopTools_Array1OfShape aShapes (1,MaxShapes);
301 TColStd_Array1OfInteger OrderInd(1,MaxShapes);
302 TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z;
303 TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z;
305 // Computing of CentreOfMass
306 Standard_Integer Index;
309 TopTools_ListIteratorOfListOfShape it(SL);
310 for (Index=1; it.More(); Index++)
312 TopoDS_Shape S = it.Value();
313 SL.Remove( it ); // == it.Next()
315 OrderInd.SetValue (Index, Index);
316 if (S.ShapeType() == TopAbs_VERTEX) {
317 GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S ));
318 Length.SetValue( Index, (Standard_Real) S.Orientation());
321 // BEGIN: fix for Mantis issue 0020842
323 BRepGProp::LinearProperties (S, GPr);
326 if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
327 BRepGProp::LinearProperties (S, GPr);
329 else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
330 BRepGProp::SurfaceProperties(S, GPr);
333 BRepGProp::VolumeProperties(S, GPr);
336 // END: fix for Mantis issue 0020842
337 GPoint = GPr.CentreOfMass();
338 Length.SetValue(Index, GPr.Mass());
340 MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9);
341 //cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl;
345 Standard_Integer aTemp;
346 Standard_Boolean exchange, Sort = Standard_True;
347 Standard_Real tol = Precision::Confusion();
350 Sort = Standard_False;
351 for (Index=1; Index < MaxShapes; Index++)
353 exchange = Standard_False;
354 Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1));
355 Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1));
356 if ( dMidXYZ >= tol ) {
357 // cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <<MidXYZ(OrderInd(Index+1))
358 // << " d: " << dMidXYZ << endl;
359 exchange = Standard_True;
361 else if ( Abs(dMidXYZ) < tol && dLength >= tol ) {
362 // cout << "Length: " << Length(OrderInd(Index))<< " > " <<Length(OrderInd(Index+1))
363 // << " d: " << dLength << endl;
364 exchange = Standard_True;
366 else if ( Abs(dMidXYZ) < tol && Abs(dLength) < tol &&
367 aShapes(OrderInd(Index)).ShapeType() <= TopAbs_FACE) {
369 // equal values possible on shapes such as two halves of a sphere and
370 // a membrane inside the sphere
372 BRepBndLib::Add( aShapes( OrderInd(Index) ), box1 );
373 if ( box1.IsVoid() ) continue;
374 BRepBndLib::Add( aShapes( OrderInd(Index+1) ), box2 );
375 Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
376 if ( dSquareExtent >= tol ) {
377 // cout << "SquareExtent: " << box1.SquareExtent()<<" > "<<box2.SquareExtent() << endl;
378 exchange = Standard_True;
380 else if ( Abs(dSquareExtent) < tol ) {
381 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
382 box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
383 val1 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
384 box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
385 val2 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
386 //exchange = val1 > val2;
387 if ((val1 - val2) >= tol) {
388 exchange = Standard_True;
390 //cout << "box: " << val1<<" > "<<val2 << endl;
396 // cout << "exchange " << Index << " & " << Index+1 << endl;
397 aTemp = OrderInd(Index);
398 OrderInd(Index) = OrderInd(Index+1);
399 OrderInd(Index+1) = aTemp;
400 Sort = Standard_True;
405 for (Index=1; Index <= MaxShapes; Index++)
406 SL.Append( aShapes( OrderInd(Index) ));
410 //=======================================================================
411 //function : CompsolidToCompound
413 //=======================================================================
414 TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid)
416 if (theCompsolid.ShapeType() != TopAbs_COMPSOLID) {
420 TopoDS_Compound aCompound;
422 B.MakeCompound(aCompound);
424 TopTools_MapOfShape mapShape;
425 TopoDS_Iterator It (theCompsolid, Standard_True, Standard_True);
427 for (; It.More(); It.Next()) {
428 TopoDS_Shape aShape_i = It.Value();
429 if (mapShape.Add(aShape_i)) {
430 B.Add(aCompound, aShape_i);
437 //=======================================================================
438 //function : AddSimpleShapes
440 //=======================================================================
441 void GEOMUtils::AddSimpleShapes (const TopoDS_Shape& theShape, TopTools_ListOfShape& theList)
443 if (theShape.ShapeType() != TopAbs_COMPOUND &&
444 theShape.ShapeType() != TopAbs_COMPSOLID) {
445 theList.Append(theShape);
449 TopTools_MapOfShape mapShape;
450 TopoDS_Iterator It (theShape, Standard_True, Standard_True);
452 for (; It.More(); It.Next()) {
453 TopoDS_Shape aShape_i = It.Value();
454 if (mapShape.Add(aShape_i)) {
455 if (aShape_i.ShapeType() == TopAbs_COMPOUND ||
456 aShape_i.ShapeType() == TopAbs_COMPSOLID) {
457 AddSimpleShapes(aShape_i, theList);
459 theList.Append(aShape_i);
465 //=======================================================================
466 //function : CheckTriangulation
468 //=======================================================================
469 bool GEOMUtils::CheckTriangulation (const TopoDS_Shape& aShape)
471 bool isTriangulation = true;
473 TopExp_Explorer exp (aShape, TopAbs_FACE);
476 TopLoc_Location aTopLoc;
477 Handle(Poly_Triangulation) aTRF;
478 aTRF = BRep_Tool::Triangulation(TopoDS::Face(exp.Current()), aTopLoc);
480 isTriangulation = false;
483 else // no faces, try edges
485 TopExp_Explorer expe (aShape, TopAbs_EDGE);
489 TopLoc_Location aLoc;
490 Handle(Poly_Polygon3D) aPE = BRep_Tool::Polygon3D(TopoDS::Edge(expe.Current()), aLoc);
492 isTriangulation = false;
496 if (!isTriangulation) {
497 // calculate deflection
498 Standard_Real aDeviationCoefficient = 0.001;
501 BRepBndLib::Add(aShape, B);
502 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
503 B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
505 Standard_Real dx = aXmax - aXmin, dy = aYmax - aYmin, dz = aZmax - aZmin;
506 Standard_Real aDeflection = Max(Max(dx, dy), dz) * aDeviationCoefficient * 4;
507 Standard_Real aHLRAngle = 0.349066;
509 BRepMesh_IncrementalMesh Inc (aShape, aDeflection, Standard_False, aHLRAngle);
515 //=======================================================================
516 //function : GetTypeOfSimplePart
518 //=======================================================================
519 TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape)
521 TopAbs_ShapeEnum aType = theShape.ShapeType();
522 if (aType == TopAbs_VERTEX) return TopAbs_VERTEX;
523 else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE;
524 else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE;
525 else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID;
526 else if (aType == TopAbs_COMPOUND) {
527 // Only the iType of the first shape in the compound is taken into account
528 TopoDS_Iterator It (theShape, Standard_False, Standard_False);
530 return GetTypeOfSimplePart(It.Value());
536 //=======================================================================
537 //function : GetEdgeNearPoint
539 //=======================================================================
540 TopoDS_Shape GEOMUtils::GetEdgeNearPoint (const TopoDS_Shape& theShape,
541 const TopoDS_Vertex& thePoint)
543 TopoDS_Shape aResult;
545 // 1. Explode the shape on edges
546 TopTools_MapOfShape mapShape;
547 Standard_Integer nbEdges = 0;
548 TopExp_Explorer exp (theShape, TopAbs_EDGE);
549 for (; exp.More(); exp.Next()) {
550 if (mapShape.Add(exp.Current())) {
556 Standard_NullObject::Raise("Given shape contains no edges");
559 Standard_Integer ind = 1;
560 TopTools_Array1OfShape anEdges (1, nbEdges);
561 TColStd_Array1OfReal aDistances (1, nbEdges);
562 for (exp.Init(theShape, TopAbs_EDGE); exp.More(); exp.Next()) {
563 if (mapShape.Add(exp.Current())) {
564 TopoDS_Shape anEdge = exp.Current();
565 anEdges(ind) = anEdge;
567 // 2. Classify the point relatively each edge
568 BRepExtrema_DistShapeShape aDistTool (thePoint, anEdges(ind));
569 if (!aDistTool.IsDone())
570 Standard_ConstructionError::Raise("Cannot find a distance from the given point to one of edges");
572 aDistances(ind) = aDistTool.Value();
577 // 3. Define edge, having minimum distance to the point
578 Standard_Real nearest = RealLast(), nbFound = 0;
579 Standard_Real prec = Precision::Confusion();
580 for (ind = 1; ind <= nbEdges; ind++) {
581 if (Abs(aDistances(ind) - nearest) < prec) {
584 else if (aDistances(ind) < nearest) {
585 nearest = aDistances(ind);
586 aResult = anEdges(ind);
593 Standard_ConstructionError::Raise("Multiple edges near the given point are found");
595 else if (nbFound == 0) {
596 Standard_ConstructionError::Raise("There are no edges near the given point");