Salome HOME
Merge branch 'hydro/imps_2015'
[modules/geom.git] / src / BlockFix / BlockFix_CheckTool.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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, or (at your option) any later version.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File:      BlockFix_CheckTool.cxx
24 //  Created:   17.12.04 11:15:25
25 //  Author:    Sergey KUUL
26
27 #include <BlockFix_CheckTool.hxx>
28
29 #include <BRep_Tool.hxx>
30
31 #include <Geom_Curve.hxx>
32
33 #include <gp_Pnt.hxx>
34 #include <gp_Vec.hxx>
35
36 #include <TopExp.hxx>
37 #include <TopExp_Explorer.hxx>
38
39 #include <TopoDS.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Solid.hxx>
43 #include <TopoDS_Shape.hxx>
44 #include <TopoDS_Vertex.hxx>
45
46 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
47 #include <TopTools_IndexedMapOfShape.hxx>
48 #include <TopTools_MapOfShape.hxx>
49 #include <TopTools_ListOfShape.hxx>
50 #include <TopTools_ListIteratorOfListOfShape.hxx>
51
52 //=======================================================================
53 //function : BlockFix_CheckTool()
54 //purpose  : Constructor
55 //=======================================================================
56 BlockFix_CheckTool::BlockFix_CheckTool( )
57 {
58   myHasCheck = Standard_False;
59   myAngTolerance = -1.;
60   myPossibleBlocks.Clear();
61 }
62
63 //=======================================================================
64 //function : SetShape
65 //purpose  :
66 //=======================================================================
67 void BlockFix_CheckTool::SetShape(const TopoDS_Shape& aShape)
68 {
69   myHasCheck = Standard_False;
70   myShape = aShape;
71   myPossibleBlocks.Clear();
72 }
73
74 //=======================================================================
75 //function : SetAngTolerance
76 //purpose  :
77 //=======================================================================
78 void BlockFix_CheckTool::SetAngTolerance(const Standard_Real theTolerance)
79 {
80   myHasCheck     = Standard_False;
81   myAngTolerance = theTolerance;
82   myPossibleBlocks.Clear();
83 }
84
85 //=======================================================================
86 //function : Perform
87 //purpose  :
88 //=======================================================================
89 void BlockFix_CheckTool::Perform()
90 {
91   myNbSolids=0;
92   myNbBlocks=0;
93   myNbDegen=0;
94   myNbUF=0;
95   myNbUE=0;
96   myNbUFUE=0;
97
98   TopExp_Explorer exps (myShape, TopAbs_SOLID);
99   TopTools_MapOfShape mapS;
100   for (; exps.More(); exps.Next()) {
101     TopoDS_Solid aSolid = TopoDS::Solid(exps.Current());
102     if (!mapS.Add(aSolid)) continue;
103     myNbSolids++;
104     Standard_Boolean IsBlock=Standard_True;
105     Standard_Boolean MayBeUF=Standard_False;
106     Standard_Boolean MayBeUE=Standard_False;
107     Standard_Integer nf=0;
108     TopExp_Explorer expf (aSolid, TopAbs_FACE);
109     TopTools_MapOfShape mapF;
110     for (; expf.More(); expf.Next()) {
111       if (mapF.Add(expf.Current()))
112         nf++;
113     }
114
115     if (nf < 6) {
116       IsBlock = Standard_False;
117     }
118     else if (nf > 6) {
119       IsBlock = Standard_False;
120       // check faces unification
121       TopTools_SequenceOfShape faces;
122       mapF.Clear();
123       for (expf.Init(aSolid, TopAbs_FACE); expf.More(); expf.Next()) {
124         if (mapF.Add(expf.Current())) {
125           TopoDS_Face aFace = TopoDS::Face(expf.Current());
126           faces.Append(aFace);
127         }
128       }
129       Standard_Boolean HasFacesForUnification = Standard_False;
130       for (Standard_Integer i=1; i<faces.Length() && !HasFacesForUnification; i++) {
131         TopoDS_Face F1 = TopoDS::Face(faces.Value(i));
132         TopTools_MapOfShape Edges;
133         for (TopExp_Explorer expe(F1,TopAbs_EDGE); expe.More(); expe.Next())
134           Edges.Add(expe.Current().Oriented(TopAbs_FORWARD));
135         TopLoc_Location L1;
136         Handle(Geom_Surface) S1 = BRep_Tool::Surface(F1,L1);
137         for(Standard_Integer j=i+1; j<=faces.Length() && !HasFacesForUnification; j++) {
138           TopoDS_Face F2 = TopoDS::Face(faces.Value(j));
139           TopLoc_Location L2;
140           Handle(Geom_Surface) S2 = BRep_Tool::Surface(F2,L2);
141           if( S1==S2 && L1==L2 ) {
142             // faces have equal based surface
143             // now check common edge
144             for(TopExp_Explorer expe2(F2,TopAbs_EDGE); expe2.More(); expe2.Next()) {
145               if(Edges.Contains(expe2.Current().Oriented(TopAbs_FORWARD))) {
146                 HasFacesForUnification = Standard_True;
147                 break;
148               }
149             }
150           }
151         }
152       }
153       if (HasFacesForUnification) {
154         MayBeUF=Standard_True;
155       }
156     }
157
158     Standard_Integer nbe=0;
159     TopTools_MapOfShape DegenEdges;
160     TopExp_Explorer expe (aSolid, TopAbs_EDGE);
161     TopTools_MapOfShape mapE;
162     for (; expe.More(); expe.Next()) {
163       TopoDS_Edge E = TopoDS::Edge(expe.Current());
164       if (!mapE.Add(E)) continue;
165       if (BRep_Tool::Degenerated(E)) {
166         DegenEdges.Add(E);
167       }
168       else {
169         nbe++;
170       }
171     }
172     if (nbe == 12 && DegenEdges.Extent() > 0) {
173       IsBlock = Standard_False;
174       myNbDegen++;
175       myPossibleBlocks.Append(aSolid);
176       continue;
177     }
178     if (nbe < 12)
179       IsBlock = Standard_False;
180     if (nbe > 12) {
181       // check edges unification
182       // creating map of edge faces
183       TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
184       TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
185
186       mapF.Clear();
187       for (expf.Init(aSolid, TopAbs_FACE); expf.More(); expf.Next()) {
188         TopoDS_Face aFace = TopoDS::Face(expf.Current());
189         if (!mapF.Add(aFace)) continue;
190         TopTools_IndexedDataMapOfShapeListOfShape aMapFacesEdges;
191
192         TopTools_MapOfShape mapEe;
193         for (expe.Init(aFace, TopAbs_EDGE); expe.More(); expe.Next()) {
194           TopoDS_Edge edge = TopoDS::Edge(expe.Current());
195           if (!mapEe.Add(edge)) continue;
196           if (!aMapEdgeFaces.Contains(edge)) continue;
197           const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
198           TopTools_ListIteratorOfListOfShape anIter (aList);
199           for (; anIter.More(); anIter.Next()) {
200             TopoDS_Face face = TopoDS::Face(anIter.Value());
201             if (face.IsSame(aFace)) continue;
202             if (aMapFacesEdges.Contains(face)) {
203               aMapFacesEdges.ChangeFromKey(face).Append(edge);
204             }
205             else {
206               TopTools_ListOfShape ListEdges;
207               ListEdges.Append(edge);
208               aMapFacesEdges.Add(face,ListEdges);
209             }
210           }
211         }
212         Standard_Integer i = 1;
213         for (; i <= aMapFacesEdges.Extent(); i++) {
214           const TopTools_ListOfShape& ListEdges = aMapFacesEdges.FindFromIndex(i);
215           if (ListEdges.Extent() > 1) {
216             if (myAngTolerance < 0.) {
217               break;
218             }
219
220             // Check if edges have C1 continuity.
221             if (!isC1(ListEdges)) {
222               break;
223             }
224           }
225         }
226         if (i <= aMapFacesEdges.Extent()) {
227           IsBlock = Standard_False;
228           MayBeUE = Standard_True;
229           break;
230         }
231       }
232     }
233
234     if (IsBlock)
235       myNbBlocks++;
236     else {
237       if (MayBeUF) {
238         myPossibleBlocks.Append(aSolid);
239         if (MayBeUE)
240           myNbUFUE++;
241         else
242           myNbUF++;
243       }
244       else if (MayBeUE) {
245         myNbUE++;
246         myPossibleBlocks.Append(aSolid);
247       }
248     }
249   }
250
251   myHasCheck = Standard_True;
252 }
253
254 //=======================================================================
255 //function : NbPossibleBlocks
256 //purpose  :
257 //=======================================================================
258 Standard_Integer BlockFix_CheckTool::NbPossibleBlocks() const
259 {
260   return myPossibleBlocks.Length();
261 }
262
263 //=======================================================================
264 //function : PossibleBlock
265 //purpose  :
266 //=======================================================================
267 TopoDS_Shape BlockFix_CheckTool::PossibleBlock(const Standard_Integer num) const
268 {
269   TopoDS_Shape res;
270   if( num>0 && num<=myPossibleBlocks.Length() )
271     res = myPossibleBlocks.Value(num);
272   return res;
273 }
274
275 //=======================================================================
276 //function : DumpCheckResult
277 //purpose  :
278 //=======================================================================
279 void BlockFix_CheckTool::DumpCheckResult(Standard_OStream& S) const
280 {
281   if(!myHasCheck)
282     S<<"Check not performed!"<<endl;
283   else {
284     S<<"dump results of check:"<<endl;
285     S<<"  total number of solids = "<<myNbSolids<<endl;
286     S<<"  including: number of good blocks = "<<myNbBlocks<<endl;
287     S<<"             number of possible blocks = "<<NbPossibleBlocks()<<endl;
288     S<<"             including: need remove degenerative = "<<myNbDegen<<endl;
289     S<<"                        need unionfaces = "<<myNbUF<<endl;
290     S<<"                        need unionedges = "<<myNbUE<<endl;
291     S<<"                        need both unionfaces and unionedges = "<<myNbUFUE<<endl;
292     Standard_Integer nbtmp = myNbSolids - myNbBlocks - NbPossibleBlocks();
293     S<<"             number of impossible blocks = "<<nbtmp<<endl;
294   }
295 }
296
297 //=======================================================================
298 //function : isC1
299 //purpose  :
300 //=======================================================================
301 Standard_Boolean BlockFix_CheckTool::isC1
302           (const TopTools_ListOfShape &theEdges) const
303 {
304   // Fill the map vertex - list of ancestor edges
305   TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
306   TopTools_ListIteratorOfListOfShape        anIter(theEdges);
307   TopTools_MapOfShape                       aMapFence;
308   Standard_Integer                          i;
309   Standard_Integer                          aNbVtx;
310
311   for (; anIter.More(); anIter.Next()) {
312     TopTools_IndexedMapOfShape  aMapVtx;
313     const TopoDS_Shape         &anEdge = anIter.Value();
314
315     if (aMapFence.Add(anEdge)) {
316       TopExp::MapShapes(anEdge, TopAbs_VERTEX, aMapVtx);
317       aNbVtx = aMapVtx.Extent();
318
319       for (i = 1; i <= aNbVtx; ++i) {
320         const TopoDS_Shape &aVtx = aMapVtx.FindKey(i);
321
322         if (!aMapVE.Contains(aVtx)) {
323           aMapVE.Add(aVtx, TopTools_ListOfShape());
324         }
325
326         aMapVE.ChangeFromKey(aVtx).Append(anEdge);
327       }
328     }
329   }
330
331   // Check C1 continuity.
332   Standard_Integer aNbEnds = 0;
333
334   for (i = 1, aNbVtx = aMapVE.Extent(); i <= aNbVtx; ++i) {
335     const TopTools_ListOfShape &anEdges  = aMapVE.FindFromIndex(i);
336     Standard_Integer            aNbEdges = anEdges.Extent();
337
338     if (aNbEdges == 1) {
339       ++aNbEnds;
340     } else if (aNbEdges == 2) {
341       TopoDS_Vertex      aCommonVtx = TopoDS::Vertex(aMapVE.FindKey(i));
342       TopoDS_Edge        anEdge1    = TopoDS::Edge(anEdges.First());
343       TopoDS_Edge        anEdge2    = TopoDS::Edge(anEdges.Last());
344       Standard_Real      aParam1    = BRep_Tool::Parameter(aCommonVtx, anEdge1);
345       Standard_Real      aParam2    = BRep_Tool::Parameter(aCommonVtx, anEdge2);
346       Standard_Real      aPar[2];
347       Handle(Geom_Curve) aCurve1    =
348         BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]);
349       Handle(Geom_Curve) aCurve2    =
350         BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]);
351       gp_Pnt             aPnt;
352       gp_Vec             aVec1;
353       gp_Vec             aVec2;
354
355       aCurve1->D1(aParam1, aPnt, aVec1);
356       aCurve2->D1(aParam2, aPnt, aVec2);
357
358       if (anEdge1.Orientation() != anEdge2.Orientation()) {
359         // Orientations are different. One vector should be reversed.
360         aVec1.Reverse();
361       }
362
363       const Standard_Real anAngle = aVec1.Angle(aVec2);
364
365       if (anAngle > myAngTolerance) {
366         // There is no C1 continuity.
367         break;
368       }
369     } else {
370       // Non-manifold case.
371       break;
372     }
373   }
374
375   return (i > aNbVtx && aNbEnds == 2);
376 }