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