4b57f8f300554a4b8d28535f06ee9ab6fadb9d0d
[occt.git] / src / BRepOffset / BRepOffset_Analyse.cxx
1 // Created on: 1995-10-20
2 // Created by: Yves FRICAUD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <BRepOffset_Analyse.ixx>
18 #include <BRepOffset_Interval.hxx>
19 #include <BRepOffset_Tool.hxx>
20 #include <BRepOffset_ListIteratorOfListOfInterval.hxx>
21 #include <BRep_Tool.hxx>
22 #include <BRepTools.hxx>
23 #include <BRep_Builder.hxx>
24
25 #include <BRepAdaptor_Curve.hxx>
26
27 #include <gp.hxx>
28 #include <gp_Vec.hxx>
29 #include <gp_Dir.hxx>
30 #include <gp_Pnt.hxx>
31 #include <gp_Pnt2d.hxx>
32
33 #include <Geom_Surface.hxx>
34 #include <Geom_Curve.hxx>
35 #include <Geom2d_Curve.hxx>
36
37 #include <TopExp.hxx>
38 #include <TopExp_Explorer.hxx>
39
40 #include <TopoDS.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Edge.hxx>
43 #include <TopTools_ListIteratorOfListOfShape.hxx>
44 #include <TopTools_MapOfShape.hxx>
45
46 #include <Precision.hxx>
47 #include <gp.hxx>
48
49
50 //=======================================================================
51 //function : BRepOffset_Analyse
52 //purpose  : 
53 //=======================================================================
54
55 BRepOffset_Analyse::BRepOffset_Analyse()
56 :myDone(Standard_False)
57 {
58 }
59
60
61 //=======================================================================
62 //function : BRepOffset_Analyse
63 //purpose  : 
64 //=======================================================================
65
66 BRepOffset_Analyse::BRepOffset_Analyse(const TopoDS_Shape& S, 
67                                        const Standard_Real Angle)
68 :myDone(Standard_False)
69 {
70   Perform( S, Angle);
71 }
72
73 //=======================================================================
74 //function : EdgeAnlyse
75 //purpose  : 
76 //=======================================================================
77
78 static void EdgeAnalyse(const TopoDS_Edge&         E,
79                         const TopoDS_Face&         F1,
80                         const TopoDS_Face&         F2,
81                         const Standard_Real        SinTol,
82                         BRepOffset_ListOfInterval& LI)
83 {
84
85   
86   TopLoc_Location L;
87   Standard_Real   f,l;
88   
89   Handle (Geom_Surface) S1 = BRep_Tool::Surface(F1);
90   Handle (Geom_Surface) S2 = BRep_Tool::Surface(F2);
91   Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
92   Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E,F2,f,l);
93
94   BRepAdaptor_Curve C(E);
95   f = C.FirstParameter();
96   l = C.LastParameter();
97   
98   // Tangent if the regularity is at least G1.
99   if (BRep_Tool::HasContinuity(E,F1,F2)) {
100     if (BRep_Tool::Continuity(E,F1,F2) > GeomAbs_C0) {
101       BRepOffset_Interval I;
102         I.First(f); I.Last(l);
103       I.Type(BRepOffset_Tangent);
104       LI.Append(I);
105       return;
106     }
107   }
108   // First stage : Type determined by one of ends.
109   // Calculate normals and tangents on the curves and surface.
110   // normals are oriented outwards.
111   
112   Standard_Real ParOnC = 0.5*(f+l);
113   gp_Vec T1 = C.DN(ParOnC,1).Transformed(L.Transformation());
114   if (T1.SquareMagnitude() > gp::Resolution()) {
115     T1.Normalize();
116   }
117   
118   if (BRepOffset_Tool::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
119     T1.Reverse();
120   }
121   if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
122
123   gp_Pnt2d P  = C1->Value(ParOnC);
124   gp_Pnt   P3;
125   gp_Vec   D1U,D1V;
126   
127   S1->D1(P.X(),P.Y(),P3,D1U,D1V);
128   gp_Vec DN1(D1U^D1V);
129   if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
130   
131   P = C2->Value(ParOnC);
132   S2->D1(P.X(),P.Y(),P3,D1U,D1V);
133   gp_Vec DN2(D1U^D1V);
134   if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
135
136   DN1.Normalize();
137   DN2.Normalize();
138
139   gp_Vec        ProVec     = DN1^DN2;
140   Standard_Real NormProVec = ProVec.Magnitude(); 
141
142   BRepOffset_Interval I;
143   I.First(f); I.Last(l);
144
145   if (Abs(NormProVec) < SinTol) {
146     // plane
147     if (DN1.Dot(DN2) > 0) {   
148       //Tangent
149       I.Type(BRepOffset_Tangent);
150     }
151     else  {                   
152       //Mixed not finished!
153 #ifdef DEB
154       cout <<" faces locally mixed"<<endl;
155 #endif
156       I.Type(BRepOffset_Convex);
157     }
158   }
159   else {  
160     if (NormProVec > gp::Resolution())
161       ProVec.Normalize();
162     Standard_Real Prod  = T1.Dot(DN1^DN2);
163     if (Prod > 0.) {       
164       //
165       I.Type(BRepOffset_Convex);
166     }
167     else {                       
168       //reenters
169       I.Type(BRepOffset_Concave);
170     }
171   }
172   LI.Append(I);
173 }
174
175 //=======================================================================
176 //function : BuildAncestors
177 //purpose  : 
178 //=======================================================================
179
180 static void BuildAncestors (const TopoDS_Shape&                        S,
181                             TopTools_IndexedDataMapOfShapeListOfShape& MA)
182 {  
183   MA.Clear();
184   TopExp::MapShapesAndAncestors(S,TopAbs_VERTEX,TopAbs_EDGE,MA);
185   TopExp::MapShapesAndAncestors(S,TopAbs_EDGE  ,TopAbs_FACE,MA);
186
187   // Purge ancestors.
188   TopTools_MapOfShape Map;
189   for (Standard_Integer i = 1; i <= MA.Extent(); i++) {
190     Map.Clear();
191     TopTools_ListOfShape&              L = MA(i);
192     TopTools_ListIteratorOfListOfShape it(L);
193     while (it.More()) {
194       if (!Map.Add(it.Value())) {
195         L.Remove(it);
196       }
197       else {
198         it.Next();
199       }
200     }
201   }
202 }
203
204 //=======================================================================
205 //function : IsDone
206 //purpose  : 
207 //=======================================================================
208
209 Standard_Boolean BRepOffset_Analyse::IsDone() const 
210 {
211   return myDone;
212 }
213
214
215 //=======================================================================
216 //function : Perform
217 //purpose  : 
218 //=======================================================================
219
220 void BRepOffset_Analyse::Perform (const TopoDS_Shape& S, 
221                                   const Standard_Real Angle)
222 {
223   myShape = S;
224
225   angle                = Angle;
226   Standard_Real SinTol = sin(Angle);
227
228   // Build ancestors.
229   BuildAncestors (S,ancestors);
230
231   
232   TopExp_Explorer Exp(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
233   for ( ; Exp.More(); Exp.Next()) {
234     const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
235     if (!mapEdgeType.IsBound(E)) {
236       BRepOffset_ListOfInterval LI;
237       mapEdgeType.Bind(E,LI);
238       
239       const TopTools_ListOfShape& L = Ancestors(E);
240       if ( L.IsEmpty()) 
241         continue;
242
243       if (L.Extent() == 2) {
244         const TopoDS_Face& F1 = TopoDS::Face(L.First());
245         const TopoDS_Face& F2 = TopoDS::Face(L.Last ());
246         EdgeAnalyse(E,F1,F2,SinTol,mapEdgeType(E));
247       }
248       else if (L.Extent() == 1) {
249         Standard_Real U1,U2;
250         const TopoDS_Face& F = TopoDS::Face(L.First());
251         BRep_Tool::Range(E,F,U1,U2);
252         BRepOffset_Interval Inter(U1,U2,BRepOffset_Other);
253         
254         if (! BRepTools::IsReallyClosed(E,F)) {
255           Inter.Type(BRepOffset_FreeBoundary);
256         }
257         mapEdgeType(E).Append(Inter);
258       }
259       else {  
260 #ifdef DEB                   
261         cout <<"edge shared by more than two faces"<<endl;
262 #endif  
263       }
264     }
265   }
266   myDone = Standard_True;
267 }
268
269 //=======================================================================
270 //function : Clear
271 //purpose  : 
272 //=======================================================================
273
274 void BRepOffset_Analyse::Clear()
275 {
276   myDone = Standard_False;
277   myShape     .Nullify();
278   mapEdgeType.Clear();
279   ancestors  .Clear();
280 }
281
282
283
284
285
286 //=======================================================================
287 //function : BRepOffset_ListOfInterval&
288 //purpose  : 
289 //=======================================================================
290
291 const BRepOffset_ListOfInterval& BRepOffset_Analyse::Type(const TopoDS_Edge& E)
292 const 
293 {
294   return mapEdgeType (E);
295 }
296
297
298 //=======================================================================
299 //function : Edges
300 //purpose  : 
301 //=======================================================================
302
303 void BRepOffset_Analyse::Edges(const TopoDS_Vertex&  V, 
304                                const BRepOffset_Type T,
305                                TopTools_ListOfShape& LE) 
306 const 
307 {
308   LE.Clear();
309   const TopTools_ListOfShape& L = Ancestors (V);
310   TopTools_ListIteratorOfListOfShape it(L);
311   
312   for ( ;it.More(); it.Next()) {
313     const TopoDS_Edge& E = TopoDS::Edge(it.Value());
314     TopoDS_Vertex V1,V2;
315     BRepOffset_Tool::EdgeVertices (E,V1,V2);
316     if (V1.IsSame(V)) {
317       if (mapEdgeType(E).Last().Type() == T)
318         LE.Append(E);
319     }
320     if (V2.IsSame(V)) {
321       if (mapEdgeType(E).First().Type() == T)
322         LE.Append(E);
323     }
324   }
325 }
326
327
328 //=======================================================================
329 //function : Edges
330 //purpose  : 
331 //=======================================================================
332
333 void BRepOffset_Analyse::Edges(const TopoDS_Face&    F, 
334                                const BRepOffset_Type T,
335                                TopTools_ListOfShape& LE) 
336 const 
337 {
338   LE.Clear();
339   TopExp_Explorer exp(F, TopAbs_EDGE);
340   
341   for ( ;exp.More(); exp.Next()) {
342     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
343
344     const BRepOffset_ListOfInterval& Lint = Type(E);
345     BRepOffset_ListIteratorOfListOfInterval it(Lint);
346     for ( ;it.More(); it.Next()) {
347       if (it.Value().Type() == T) LE.Append(E);
348     }
349   }
350 }
351
352 //=======================================================================
353 //function : TangentEdges
354 //purpose  : 
355 //=======================================================================
356
357 void BRepOffset_Analyse::TangentEdges(const TopoDS_Edge&    Edge  ,
358                                       const TopoDS_Vertex&  Vertex,
359                                       TopTools_ListOfShape& Edges  ) const 
360 {
361   gp_Vec V,VRef;
362
363
364   Standard_Real U,URef;
365   BRepAdaptor_Curve C3d, C3dRef;
366
367   URef   = BRep_Tool::Parameter(Vertex,Edge);
368   C3dRef = BRepAdaptor_Curve(Edge);
369   VRef   = C3dRef.DN(URef,1);
370   if (VRef.SquareMagnitude() < gp::Resolution()) return;
371
372   Edges.Clear();
373
374   const TopTools_ListOfShape& Anc = Ancestors(Vertex);
375   TopTools_ListIteratorOfListOfShape it(Anc);
376   for ( ; it.More(); it.Next()) {
377     const TopoDS_Edge& CurE = TopoDS::Edge(it.Value());
378     if ( CurE.IsSame(Edge)) continue;
379     U   = BRep_Tool::Parameter(Vertex,CurE);
380     C3d = BRepAdaptor_Curve(CurE);
381     V   = C3d.DN(U,1);
382     if (V.SquareMagnitude() < gp::Resolution()) continue;
383     if (V.IsParallel(VRef,angle)) {
384       Edges.Append(CurE);
385     }
386   }
387 }
388
389
390
391 //=======================================================================
392 //function : HasAncestor
393 //purpose  : 
394 //=======================================================================
395
396 Standard_Boolean  BRepOffset_Analyse::HasAncestor (const TopoDS_Shape& S) const 
397 {
398   return ancestors.Contains(S);
399 }
400
401
402 //=======================================================================
403 //function : Ancestors
404 //purpose  : 
405 //=======================================================================
406
407 const TopTools_ListOfShape& BRepOffset_Analyse::Ancestors 
408 (const TopoDS_Shape& S) const 
409 {
410   return ancestors.FindFromKey(S);
411 }
412
413
414 //=======================================================================
415 //function : Explode
416 //purpose  : 
417 //=======================================================================
418
419 void BRepOffset_Analyse::Explode(      TopTools_ListOfShape& List,
420                                  const BRepOffset_Type       T   ) const 
421 {
422   List.Clear();
423   BRep_Builder B;
424   TopTools_MapOfShape Map;
425   
426   TopExp_Explorer Fexp;
427   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
428     if ( Map.Add(Fexp.Current())) {
429       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
430       TopoDS_Compound Co;
431       B.MakeCompound(Co);
432       B.Add(Co,Face);
433       // add to Co all faces from the cloud of faces
434       // G1 created from <Face>
435       AddFaces(Face,Co,Map,T);
436       List.Append(Co);
437     }
438   }
439 }
440
441 //=======================================================================
442 //function : Explode
443 //purpose  : 
444 //=======================================================================
445
446 void BRepOffset_Analyse::Explode(      TopTools_ListOfShape& List,
447                                  const BRepOffset_Type       T1,
448                                  const BRepOffset_Type       T2) const 
449 {
450   List.Clear();
451   BRep_Builder B;
452   TopTools_MapOfShape Map;
453   
454   TopExp_Explorer Fexp;
455   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
456     if ( Map.Add(Fexp.Current())) {
457       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
458       TopoDS_Compound Co;
459       B.MakeCompound(Co);
460       B.Add(Co,Face);
461       // add to Co all faces from the cloud of faces
462       // G1 created from  <Face>
463       AddFaces(Face,Co,Map,T1,T2);
464       List.Append(Co);
465     }
466   }
467 }
468
469
470 //=======================================================================
471 //function : AddFaces
472 //purpose  : 
473 //=======================================================================
474
475 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
476                                    TopoDS_Compound&      Co,
477                                    TopTools_MapOfShape&  Map,
478                                    const BRepOffset_Type T) const 
479 {
480   BRep_Builder B;
481   TopExp_Explorer exp(Face,TopAbs_EDGE);
482   for ( ; exp.More(); exp.Next()) {
483     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
484     const BRepOffset_ListOfInterval& LI = Type(E);
485     if (!LI.IsEmpty() && LI.First().Type() == T) {
486       // so <NewFace> is attached to G1 by <Face>
487       const TopTools_ListOfShape& L = Ancestors(E);
488       if (L.Extent() == 2) {
489         TopoDS_Face F1 = TopoDS::Face(L.First());
490         if ( F1.IsSame(Face)) 
491           F1 = TopoDS::Face(L.Last ());
492         if ( Map.Add(F1)) {
493           B.Add(Co,F1);
494           AddFaces(F1,Co,Map,T);
495         }
496       }
497     }
498   }
499 }
500 //=======================================================================
501 //function : AddFaces
502 //purpose  : 
503 //=======================================================================
504
505 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
506                                    TopoDS_Compound&      Co,
507                                    TopTools_MapOfShape&  Map,
508                                    const BRepOffset_Type T1,
509                                    const BRepOffset_Type T2) const 
510 {
511   BRep_Builder B;
512   TopExp_Explorer exp(Face,TopAbs_EDGE);
513   for ( ; exp.More(); exp.Next()) {
514     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
515     const BRepOffset_ListOfInterval& LI = Type(E);
516     if (!LI.IsEmpty() && 
517         (LI.First().Type() == T1 || LI.First().Type() == T2)) {
518       // so <NewFace> is attached to G1 by <Face>
519       const TopTools_ListOfShape& L = Ancestors(E);
520       if (L.Extent() == 2) {
521         TopoDS_Face F1 = TopoDS::Face(L.First());
522         if ( F1.IsSame(Face)) 
523           F1 = TopoDS::Face(L.Last ());
524         if ( Map.Add(F1)) {
525           B.Add(Co,F1);
526           AddFaces(F1,Co,Map,T1,T2);
527         }
528       }
529     }
530   }
531 }