825abd54f3512281ec639273e7548f50eb9b9150
[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
18 #include <Adaptor3d_Surface.hxx>
19 #include <BRep_Builder.hxx>
20 #include <BRep_Tool.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepOffset_Analyse.hxx>
24 #include <BRepOffset_Interval.hxx>
25 #include <BRepOffset_ListIteratorOfListOfInterval.hxx>
26 #include <BRepOffset_Tool.hxx>
27 #include <BRepTools.hxx>
28 #include <Geom2d_Curve.hxx>
29 #include <Geom_Curve.hxx>
30 #include <Geom_Surface.hxx>
31 #include <gp.hxx>
32 #include <gp_Dir.hxx>
33 #include <gp_Pnt.hxx>
34 #include <gp_Pnt2d.hxx>
35 #include <gp_Vec.hxx>
36 #include <Precision.hxx>
37 #include <TopExp.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopoDS.hxx>
40 #include <TopoDS_Compound.hxx>
41 #include <TopoDS_Edge.hxx>
42 #include <TopoDS_Face.hxx>
43 #include <TopoDS_Shape.hxx>
44 #include <TopoDS_Vertex.hxx>
45 #include <TopTools_ListIteratorOfListOfShape.hxx>
46 #include <TopTools_MapOfShape.hxx>
47
48 //
49 static void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d);
50 //
51 static BRepOffset_Type DefineConnectType(const TopoDS_Edge&         E,
52                                                            const TopoDS_Face&         F1,
53                                                            const TopoDS_Face&         F2,
54                                                            const Standard_Real        SinTol,
55                                          const Standard_Boolean     CorrectPoint);
56 //
57 static void CorrectOrientationOfTangent(gp_Vec& TangVec,
58                                         const TopoDS_Vertex& aVertex,
59                                         const TopoDS_Edge& anEdge)
60 {
61   TopoDS_Vertex Vlast = TopExp::LastVertex(anEdge);
62   if (aVertex.IsSame(Vlast))
63     TangVec.Reverse();
64 }
65 //=======================================================================
66 //function : BRepOffset_Analyse
67 //purpose  : 
68 //=======================================================================
69
70 BRepOffset_Analyse::BRepOffset_Analyse()
71 :myDone(Standard_False)
72 {
73 }
74
75
76 //=======================================================================
77 //function : BRepOffset_Analyse
78 //purpose  : 
79 //=======================================================================
80
81 BRepOffset_Analyse::BRepOffset_Analyse(const TopoDS_Shape& S, 
82                                        const Standard_Real Angle)
83 :myDone(Standard_False)
84 {
85   Perform( S, Angle);
86 }
87
88 //=======================================================================
89 //function : EdgeAnlyse
90 //purpose  : 
91 //=======================================================================
92
93 static void EdgeAnalyse(const TopoDS_Edge&         E,
94                                           const TopoDS_Face&         F1,
95                                           const TopoDS_Face&         F2,
96                                           const Standard_Real        SinTol,
97                                                 BRepOffset_ListOfInterval& LI)
98 {
99   
100   Standard_Real   f,l;
101   BRep_Tool::Range(E, F1, f, l);
102   BRepOffset_Interval I;
103   I.First(f); I.Last(l);
104   //
105   // Tangent if the regularity is at least G1.
106   if (BRep_Tool::HasContinuity(E,F1,F2)) {
107     if (BRep_Tool::Continuity(E,F1,F2) > GeomAbs_C0) {
108       I.Type(BRepOffset_Tangent);
109       LI.Append(I);
110       return;
111     }
112   }
113   //
114   BRepOffset_Type aType = DefineConnectType(E, F1, F2, SinTol, Standard_False);
115   if(aType != BRepOffset_Tangent)
116   {
117     aType = DefineConnectType(E, F1, F2, SinTol, Standard_True);
118   }
119   I.Type(aType);
120   LI.Append(I);
121 }
122
123 //=======================================================================
124 //function : BuildAncestors
125 //purpose  : 
126 //=======================================================================
127
128 static void BuildAncestors (const TopoDS_Shape&                        S,
129                             TopTools_IndexedDataMapOfShapeListOfShape& MA)
130 {  
131   MA.Clear();
132   TopExp::MapShapesAndAncestors(S,TopAbs_VERTEX,TopAbs_EDGE,MA);
133   TopExp::MapShapesAndAncestors(S,TopAbs_EDGE  ,TopAbs_FACE,MA);
134
135   // Purge ancestors.
136   TopTools_MapOfShape Map;
137   for (Standard_Integer i = 1; i <= MA.Extent(); i++) {
138     Map.Clear();
139     TopTools_ListOfShape&              L = MA(i);
140     TopTools_ListIteratorOfListOfShape it(L);
141     while (it.More()) {
142       if (!Map.Add(it.Value())) {
143         L.Remove(it);
144       }
145       else {
146         it.Next();
147       }
148     }
149   }
150 }
151
152 //=======================================================================
153 //function : IsDone
154 //purpose  : 
155 //=======================================================================
156
157 Standard_Boolean BRepOffset_Analyse::IsDone() const 
158 {
159   return myDone;
160 }
161
162
163 //=======================================================================
164 //function : Perform
165 //purpose  : 
166 //=======================================================================
167
168 void BRepOffset_Analyse::Perform (const TopoDS_Shape& S, 
169                                   const Standard_Real Angle)
170 {
171   myShape = S;
172
173   angle                = Angle;
174   Standard_Real SinTol = Sin(Angle);
175
176   // Build ancestors.
177   BuildAncestors (S,ancestors);
178
179   
180   TopExp_Explorer Exp(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
181   for ( ; Exp.More(); Exp.Next()) {
182     const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
183     if (!mapEdgeType.IsBound(E)) {
184       BRepOffset_ListOfInterval LI;
185       mapEdgeType.Bind(E,LI);
186       
187       const TopTools_ListOfShape& L = Ancestors(E);
188       if ( L.IsEmpty()) 
189         continue;
190
191       if (L.Extent() == 2) {
192         const TopoDS_Face& F1 = TopoDS::Face(L.First());
193         const TopoDS_Face& F2 = TopoDS::Face(L.Last ());
194         EdgeAnalyse(E,F1,F2,SinTol,mapEdgeType(E));
195       }
196       else if (L.Extent() == 1) {
197         Standard_Real U1,U2;
198         const TopoDS_Face& F = TopoDS::Face(L.First());
199         BRep_Tool::Range(E,F,U1,U2);
200         BRepOffset_Interval Inter(U1,U2,BRepOffset_Other);
201         
202         if (! BRepTools::IsReallyClosed(E,F)) {
203           Inter.Type(BRepOffset_FreeBoundary);
204         }
205         mapEdgeType(E).Append(Inter);
206       }
207       else {  
208 #ifdef OCCT_DEBUG
209         cout <<"edge shared by more than two faces"<<endl;
210 #endif  
211       }
212     }
213   }
214   myDone = Standard_True;
215 }
216
217 //=======================================================================
218 //function : Clear
219 //purpose  : 
220 //=======================================================================
221
222 void BRepOffset_Analyse::Clear()
223 {
224   myDone = Standard_False;
225   myShape     .Nullify();
226   mapEdgeType.Clear();
227   ancestors  .Clear();
228 }
229
230
231
232
233
234 //=======================================================================
235 //function : BRepOffset_ListOfInterval&
236 //purpose  : 
237 //=======================================================================
238
239 const BRepOffset_ListOfInterval& BRepOffset_Analyse::Type(const TopoDS_Edge& E)
240 const 
241 {
242   return mapEdgeType (E);
243 }
244
245
246 //=======================================================================
247 //function : Edges
248 //purpose  : 
249 //=======================================================================
250
251 void BRepOffset_Analyse::Edges(const TopoDS_Vertex&  V, 
252                                const BRepOffset_Type T,
253                                TopTools_ListOfShape& LE) 
254 const 
255 {
256   LE.Clear();
257   const TopTools_ListOfShape& L = Ancestors (V);
258   TopTools_ListIteratorOfListOfShape it(L);
259   
260   for ( ;it.More(); it.Next()) {
261     const TopoDS_Edge& E = TopoDS::Edge(it.Value());
262     TopoDS_Vertex V1,V2;
263     BRepOffset_Tool::EdgeVertices (E,V1,V2);
264     if (V1.IsSame(V)) {
265       if (mapEdgeType(E).Last().Type() == T)
266         LE.Append(E);
267     }
268     if (V2.IsSame(V)) {
269       if (mapEdgeType(E).First().Type() == T)
270         LE.Append(E);
271     }
272   }
273 }
274
275
276 //=======================================================================
277 //function : Edges
278 //purpose  : 
279 //=======================================================================
280
281 void BRepOffset_Analyse::Edges(const TopoDS_Face&    F, 
282                                const BRepOffset_Type T,
283                                TopTools_ListOfShape& LE) 
284 const 
285 {
286   LE.Clear();
287   TopExp_Explorer exp(F, TopAbs_EDGE);
288   
289   for ( ;exp.More(); exp.Next()) {
290     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
291
292     const BRepOffset_ListOfInterval& Lint = Type(E);
293     BRepOffset_ListIteratorOfListOfInterval it(Lint);
294     for ( ;it.More(); it.Next()) {
295       if (it.Value().Type() == T) LE.Append(E);
296     }
297   }
298 }
299
300 //=======================================================================
301 //function : TangentEdges
302 //purpose  : 
303 //=======================================================================
304
305 void BRepOffset_Analyse::TangentEdges(const TopoDS_Edge&    Edge  ,
306                                       const TopoDS_Vertex&  Vertex,
307                                       TopTools_ListOfShape& Edges  ) const 
308 {
309   gp_Vec V,VRef;
310
311
312   Standard_Real U,URef;
313   BRepAdaptor_Curve C3d, C3dRef;
314
315   URef   = BRep_Tool::Parameter(Vertex,Edge);
316   C3dRef = BRepAdaptor_Curve(Edge);
317   VRef   = C3dRef.DN(URef,1);
318   CorrectOrientationOfTangent(VRef, Vertex, Edge);
319   if (VRef.SquareMagnitude() < gp::Resolution()) return;
320
321   Edges.Clear();
322
323   const TopTools_ListOfShape& Anc = Ancestors(Vertex);
324   TopTools_ListIteratorOfListOfShape it(Anc);
325   for ( ; it.More(); it.Next()) {
326     const TopoDS_Edge& CurE = TopoDS::Edge(it.Value());
327     if ( CurE.IsSame(Edge)) continue;
328     U   = BRep_Tool::Parameter(Vertex,CurE);
329     C3d = BRepAdaptor_Curve(CurE);
330     V   = C3d.DN(U,1);
331     CorrectOrientationOfTangent(V, Vertex, CurE);
332     if (V.SquareMagnitude() < gp::Resolution()) continue;
333     if (V.IsOpposite(VRef,angle)) {
334       Edges.Append(CurE);
335     }
336   }
337 }
338
339
340
341 //=======================================================================
342 //function : HasAncestor
343 //purpose  : 
344 //=======================================================================
345
346 Standard_Boolean  BRepOffset_Analyse::HasAncestor (const TopoDS_Shape& S) const 
347 {
348   return ancestors.Contains(S);
349 }
350
351
352 //=======================================================================
353 //function : Ancestors
354 //purpose  : 
355 //=======================================================================
356
357 const TopTools_ListOfShape& BRepOffset_Analyse::Ancestors 
358 (const TopoDS_Shape& S) const 
359 {
360   return ancestors.FindFromKey(S);
361 }
362
363
364 //=======================================================================
365 //function : Explode
366 //purpose  : 
367 //=======================================================================
368
369 void BRepOffset_Analyse::Explode(      TopTools_ListOfShape& List,
370                                  const BRepOffset_Type       T   ) const 
371 {
372   List.Clear();
373   BRep_Builder B;
374   TopTools_MapOfShape Map;
375   
376   TopExp_Explorer Fexp;
377   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
378     if ( Map.Add(Fexp.Current())) {
379       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
380       TopoDS_Compound Co;
381       B.MakeCompound(Co);
382       B.Add(Co,Face);
383       // add to Co all faces from the cloud of faces
384       // G1 created from <Face>
385       AddFaces(Face,Co,Map,T);
386       List.Append(Co);
387     }
388   }
389 }
390
391 //=======================================================================
392 //function : Explode
393 //purpose  : 
394 //=======================================================================
395
396 void BRepOffset_Analyse::Explode(      TopTools_ListOfShape& List,
397                                  const BRepOffset_Type       T1,
398                                  const BRepOffset_Type       T2) const 
399 {
400   List.Clear();
401   BRep_Builder B;
402   TopTools_MapOfShape Map;
403   
404   TopExp_Explorer Fexp;
405   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
406     if ( Map.Add(Fexp.Current())) {
407       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
408       TopoDS_Compound Co;
409       B.MakeCompound(Co);
410       B.Add(Co,Face);
411       // add to Co all faces from the cloud of faces
412       // G1 created from  <Face>
413       AddFaces(Face,Co,Map,T1,T2);
414       List.Append(Co);
415     }
416   }
417 }
418
419
420 //=======================================================================
421 //function : AddFaces
422 //purpose  : 
423 //=======================================================================
424
425 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
426                                    TopoDS_Compound&      Co,
427                                    TopTools_MapOfShape&  Map,
428                                    const BRepOffset_Type T) const 
429 {
430   BRep_Builder B;
431   TopExp_Explorer exp(Face,TopAbs_EDGE);
432   for ( ; exp.More(); exp.Next()) {
433     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
434     const BRepOffset_ListOfInterval& LI = Type(E);
435     if (!LI.IsEmpty() && LI.First().Type() == T) {
436       // so <NewFace> is attached to G1 by <Face>
437       const TopTools_ListOfShape& L = Ancestors(E);
438       if (L.Extent() == 2) {
439         TopoDS_Face F1 = TopoDS::Face(L.First());
440         if ( F1.IsSame(Face)) 
441           F1 = TopoDS::Face(L.Last ());
442         if ( Map.Add(F1)) {
443           B.Add(Co,F1);
444           AddFaces(F1,Co,Map,T);
445         }
446       }
447     }
448   }
449 }
450 //=======================================================================
451 //function : AddFaces
452 //purpose  : 
453 //=======================================================================
454
455 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
456                                    TopoDS_Compound&      Co,
457                                    TopTools_MapOfShape&  Map,
458                                    const BRepOffset_Type T1,
459                                    const BRepOffset_Type T2) const 
460 {
461   BRep_Builder B;
462   TopExp_Explorer exp(Face,TopAbs_EDGE);
463   for ( ; exp.More(); exp.Next()) {
464     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
465     const BRepOffset_ListOfInterval& LI = Type(E);
466     if (!LI.IsEmpty() && 
467         (LI.First().Type() == T1 || LI.First().Type() == T2)) {
468       // so <NewFace> is attached to G1 by <Face>
469       const TopTools_ListOfShape& L = Ancestors(E);
470       if (L.Extent() == 2) {
471         TopoDS_Face F1 = TopoDS::Face(L.First());
472         if ( F1.IsSame(Face)) 
473           F1 = TopoDS::Face(L.Last ());
474         if ( Map.Add(F1)) {
475           B.Add(Co,F1);
476           AddFaces(F1,Co,Map,T1,T2);
477         }
478       }
479     }
480   }
481 }
482
483 //=======================================================================
484 //function : Correct2dPoint
485 //purpose  : 
486 //=======================================================================
487 void Correct2dPoint(const Adaptor3d_Surface& theS, gp_Pnt2d& theP2d)
488 {
489   const Standard_Real coeff = 0.01;
490   Standard_Real eps;
491   Standard_Real u1, u2, v1, v2;
492   if(theS.GetType() >= GeomAbs_BezierSurface)
493   {
494     u1 = theS.FirstUParameter();
495     u2 = theS.LastUParameter();
496     v1 = theS.FirstVParameter();
497     v2 = theS.LastVParameter();
498     if(!(Precision::IsInfinite(u1) || Precision::IsInfinite(u2)))
499     {
500       eps = Max(coeff*(u2-u1), Precision::PConfusion());
501       if(Abs(theP2d.X()-u1) < eps)
502       {
503         theP2d.SetX(u1 + eps);
504       }
505       if(Abs(theP2d.X()-u2) < eps)
506       {
507         theP2d.SetX(u2 - eps);
508       }
509     }
510     if(!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
511     {
512       eps = Max(coeff*(v2-v1), Precision::PConfusion());
513       if(Abs(theP2d.Y()-v1) < eps)
514       {
515         theP2d.SetY(v1 + eps);
516       }
517       if(Abs(theP2d.Y()-v2) < eps)
518       {
519         theP2d.SetY(v2 - eps);
520       }
521     }
522   }
523 }
524
525 //=======================================================================
526 //function : DefineConnectType
527 //purpose  : 
528 //=======================================================================
529 BRepOffset_Type DefineConnectType(const TopoDS_Edge&         E,
530                                                     const TopoDS_Face&         F1,
531                                                     const TopoDS_Face&         F2,
532                                                     const Standard_Real        SinTol,
533                                   const Standard_Boolean     CorrectPoint)
534 {
535   TopLoc_Location L;
536   Standard_Real   f,l;
537   
538   BRepAdaptor_Surface S1(F1), S2(F2);
539   Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
540   Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E,F2,f,l);
541
542   BRepAdaptor_Curve C(E);
543   f = C.FirstParameter();
544   l = C.LastParameter();
545 //
546   Standard_Real ParOnC = 0.5*(f+l);
547   gp_Vec T1 = C.DN(ParOnC,1).Transformed(L.Transformation());
548   if (T1.SquareMagnitude() > gp::Resolution()) {
549     T1.Normalize();
550   }
551   
552   if (BRepOffset_Tool::OriEdgeInFace(E,F1) == TopAbs_REVERSED) {
553     T1.Reverse();
554   }
555   if (F1.Orientation() == TopAbs_REVERSED) T1.Reverse();
556
557   gp_Pnt2d P  = C1->Value(ParOnC);
558   gp_Pnt   P3;
559   gp_Vec   D1U,D1V;
560   
561   if(CorrectPoint) 
562     Correct2dPoint(S1, P);
563   //
564   S1.D1(P.X(),P.Y(),P3,D1U,D1V);
565   gp_Vec DN1(D1U^D1V);
566   if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
567   
568   P = C2->Value(ParOnC);
569   if(CorrectPoint) 
570     Correct2dPoint(S2, P);
571   S2.D1(P.X(),P.Y(),P3,D1U,D1V);
572   gp_Vec DN2(D1U^D1V);
573   if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
574
575   DN1.Normalize();
576   DN2.Normalize();
577
578   gp_Vec        ProVec     = DN1^DN2;
579   Standard_Real NormProVec = ProVec.Magnitude(); 
580
581   if (Abs(NormProVec) < SinTol) {
582     // plane
583     if (DN1.Dot(DN2) > 0) {   
584       //Tangent
585       return BRepOffset_Tangent;
586     }
587     else  {                   
588       //Mixed not finished!
589 #ifdef OCCT_DEBUG
590       cout <<" faces locally mixed"<<endl;
591 #endif
592       return BRepOffset_Convex;
593     }
594   }
595   else {  
596     if (NormProVec > gp::Resolution())
597       ProVec.Normalize();
598     Standard_Real Prod  = T1.Dot(DN1^DN2);
599     if (Prod > 0.) {       
600       //
601       return BRepOffset_Convex;
602     }
603     else {                       
604       //reenters
605       return BRepOffset_Concave;
606     }
607   }
608 }