0025021: New option of BRepOffsetAPI_MakeOffset algorithm: open result for open wire
[occt.git] / src / BRepOffsetAPI / BRepOffsetAPI_MakeOffset.cxx
1 // Created on: 1995-09-18
2 // Created by: Bruno DUMORTIER
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 <BRepOffsetAPI_MakeOffset.ixx>
18 #include <BRepBuilderAPI_MakeFace.hxx>
19 #include <BRep_Builder.hxx>
20 #include <BRep_Tool.hxx>
21 #include <BRepAlgo_FaceRestrictor.hxx>
22 #include <Extrema_ExtPS.hxx>
23 #include <BRepAdaptor_Surface.hxx>
24 #include <BRepFill_OffsetWire.hxx>
25 #include <BRepFill_ListIteratorOfListOfOffsetWire.hxx>
26 #include <BRepTopAdaptor_FClass2d.hxx>
27 #include <gp_Pnt2d.hxx>
28 #include <gp_Pnt.hxx>
29 #include <Precision.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx> 
31 #include <TopExp_Explorer.hxx>
32 #include <TopExp.hxx>
33 #include <TopoDS.hxx>
34 #include <TopoDS_Vertex.hxx>
35 #include <TopoDS_Compound.hxx>
36 #include <TopoDS_Wire.hxx>
37
38 #include <StdFail_NotDone.hxx>
39
40 //=======================================================================
41 //function : BRepOffsetAPI_MakeOffset
42 //purpose  : 
43 //=======================================================================
44
45 BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset()
46 :myIsInitialized( Standard_False)
47 {
48 }
49
50
51 //=======================================================================
52 //function : BRepOffsetAPI_MakeOffset
53 //purpose  : 
54 //=======================================================================
55
56 BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset(const TopoDS_Face& Spine, 
57                                                    const GeomAbs_JoinType Join,
58                                                    const Standard_Boolean IsOpenResult)
59 {
60   Init(Spine, Join, IsOpenResult);
61 }
62
63
64 //=======================================================================
65 //function : Init
66 //purpose  : 
67 //=======================================================================
68
69 void BRepOffsetAPI_MakeOffset::Init(const TopoDS_Face&     Spine,
70                                     const GeomAbs_JoinType Join,
71                                     const Standard_Boolean IsOpenResult)
72 {
73   myFace          = Spine;
74   myIsInitialized = Standard_True;
75   myJoin          = Join;
76   myIsOpenResult  = IsOpenResult;
77   TopExp_Explorer exp;
78   for (exp.Init(myFace,TopAbs_WIRE); exp.More();exp.Next()) {
79     myWires.Append(exp.Current());
80   }
81 }
82
83 //=======================================================================
84 //function : BRepOffsetAPI_MakeOffset
85 //purpose  : 
86 //=======================================================================
87
88 BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset(const TopoDS_Wire& Spine, 
89                                                    const GeomAbs_JoinType Join,
90                                                    const Standard_Boolean IsOpenResult)
91 {
92   myWires.Append(Spine);
93   myIsInitialized = Standard_True;
94   myJoin = Join;
95   myIsOpenResult  = IsOpenResult;
96 }
97
98 //=======================================================================
99 //function : Init
100 //purpose  : 
101 //=======================================================================
102
103 void BRepOffsetAPI_MakeOffset::Init(const GeomAbs_JoinType Join,
104                                     const Standard_Boolean IsOpenResult)
105 {
106   myJoin = Join;
107   myIsOpenResult  = IsOpenResult;
108 }
109
110 //=======================================================================
111 //function : BRepOffsetAPI_MakeOffset
112 //purpose  : 
113 //=======================================================================
114
115 void BRepOffsetAPI_MakeOffset::AddWire(const TopoDS_Wire& Spine)
116
117 {
118   myIsInitialized = Standard_True;
119   myWires.Append(Spine);
120 }
121
122 //=======================================================================
123 //function : BuildDomain
124 //purpose  : 
125 //=======================================================================
126
127 static void BuildDomains(TopoDS_Face&               myFace,
128                          TopTools_ListOfShape&      WorkWires,
129                          BRepFill_ListOfOffsetWire& myAlgos,
130                          GeomAbs_JoinType           myJoin,
131                          Standard_Boolean           myIsOpenResult,
132                          Standard_Boolean           isPositive)
133 {
134   BRepAlgo_FaceRestrictor  FR;
135   TopoDS_Vertex            VF,VL;
136   TopTools_ListOfShape     LOW;
137   BRep_Builder             B;
138
139   if (myFace.IsNull()) {
140     myFace   = BRepBuilderAPI_MakeFace(TopoDS::Wire(WorkWires.First()),Standard_True);
141     if (myFace.IsNull())
142       StdFail_NotDone::Raise ("BRepOffsetAPI_MakeOffset : the wire is not planar");
143   }
144 //  Modified by Sergey KHROMOV - Thu Apr 26 16:04:43 2001 Begin
145   TopExp_Explorer anExp(myFace, TopAbs_WIRE);
146   TopoDS_Shape    aWire1 = WorkWires.First();
147   TopoDS_Shape    aWire2;
148   if (anExp.More()) {
149     aWire2 = anExp.Current();
150     if ((aWire1.Orientation() == aWire2.Orientation() && isPositive) ||
151       (aWire1.Orientation() == TopAbs::Complement(aWire2.Orientation()) && !isPositive)) {
152         TopTools_ListOfShape LWires;
153         TopTools_ListIteratorOfListOfShape itl;
154         for (itl.Initialize(WorkWires); itl.More(); itl.Next()) {
155           const TopoDS_Shape& W = itl.Value();
156           LWires.Append(W.Reversed());
157         }
158         WorkWires = LWires;
159     }
160   }
161 //  Modified by Sergey KHROMOV - Thu Apr 26 16:04:44 2001 End
162   FR.Init(myFace,Standard_True);
163   //====================================================
164   // Construction of faces limited by closed wires.
165   //====================================================
166   TopTools_ListIteratorOfListOfShape itl(WorkWires);
167   for (; itl.More(); itl.Next()) {
168     TopoDS_Wire& W = TopoDS::Wire(itl.Value());
169     if (W.Closed()){
170       FR.Add(W);
171       continue;
172     }
173     TopExp::Vertices (W,VF,VL);
174     if (VF.IsSame(VL)) {
175       FR.Add(W);
176     }
177     else {
178       LOW.Append(W);
179     }
180   }
181   FR.Perform();
182   if (!FR.IsDone()) {
183     StdFail_NotDone::Raise ("BRepOffsetAPI_MakeOffset : Build Domains");
184   }
185   TopTools_ListOfShape Faces;
186   for (; FR.More(); FR.Next()) {
187     Faces.Append(FR.Current());
188   }
189
190   //===========================================
191   // No closed wire => only one domain
192   //===========================================
193   if (Faces.IsEmpty()) {
194     TopoDS_Shape aLocalShape = myFace.EmptyCopied();
195     TopoDS_Face F = TopoDS::Face(aLocalShape);
196 //    TopoDS_Face F = TopoDS::Face(myFace.EmptyCopied());
197     TopTools_ListIteratorOfListOfShape itW(LOW);
198     for ( ; itW.More(); itW.Next()) {
199       B.Add(F,itW.Value());
200     }
201     BRepFill_OffsetWire Algo(F, myJoin, myIsOpenResult);
202     myAlgos.Append(Algo);
203     return;
204   }
205
206   //====================================================
207   // Classification of open wires.
208   //====================================================  
209 //  for (TopTools_ListIteratorOfListOfShape itF(Faces); itF.More(); itF.Next()) {
210   TopTools_ListIteratorOfListOfShape itF;
211   for (itF.Initialize(Faces) ; itF.More(); itF.Next()) {
212     TopoDS_Face&          F = TopoDS::Face(itF.Value());
213     BRepAdaptor_Surface   S(F,0);
214     Standard_Real         Tol = BRep_Tool::Tolerance(F); 
215
216     BRepTopAdaptor_FClass2d CL(F,Precision::Confusion());
217
218     TopTools_ListIteratorOfListOfShape itW(LOW);
219     while (itW.More()) {
220       TopoDS_Wire& W = TopoDS::Wire(itW.Value());
221       //=======================================================
222       // Choice of a point on the wire. + projection on the face.
223       //=======================================================
224       TopExp_Explorer exp(W,TopAbs_VERTEX);
225       TopoDS_Vertex   V  = TopoDS::Vertex(exp.Current());
226       gp_Pnt2d        PV;
227       gp_Pnt          P3d = BRep_Tool::Pnt(V);
228       Extrema_ExtPS ExtPS (P3d,S,Tol,Tol);
229       Standard_Real     Dist2Min = Precision::Infinite();
230       Standard_Real     Found   = Standard_False;
231       for (Standard_Integer ie = 1; ie <= ExtPS.NbExt(); ie++) {
232         Standard_Real X,Y;
233         if (ExtPS.SquareDistance(ie) < Dist2Min) {
234           Dist2Min = ExtPS.SquareDistance(ie);
235           Found   = Standard_True;
236           ExtPS.Point(ie).Parameter(X,Y);
237           PV.SetCoord(X,Y);
238         }
239       }
240       if ( Found && (CL.Perform(PV) == TopAbs_IN)) {
241         // The face that contains a wire is found and it is removed from the list
242         B.Add(F,W);
243         LOW.Remove(itW);
244       }
245       else {
246         itW.Next();
247       }
248     }
249   }
250   //========================================
251   // Creation of algorithms on each domain.
252   //========================================
253   for (itF.Initialize(Faces); itF.More(); itF.Next()) {
254     BRepFill_OffsetWire Algo(TopoDS::Face(itF.Value()), myJoin, myIsOpenResult);
255     myAlgos.Append(Algo);
256   }
257 }
258
259 //=======================================================================
260 //function : Perform
261 //purpose  : 
262 //=======================================================================
263
264 void BRepOffsetAPI_MakeOffset::Perform(const Standard_Real Offset,
265                                        const Standard_Real Alt)
266 {
267   StdFail_NotDone_Raise_if ( !myIsInitialized,
268     "BRepOffsetAPI_MakeOffset : Perform without Init");
269
270   try
271   {
272     Standard_Integer i = 1;
273     BRepFill_ListIteratorOfListOfOffsetWire itOW;
274     TopoDS_Compound Res;
275     BRep_Builder    B;
276     B.MakeCompound (Res);
277     myLastIsLeft = (Offset <= 0);
278
279     if( Offset <= 0. )
280     {
281       if( myLeft.IsEmpty() )
282       {
283         //  Modified by Sergey KHROMOV - Fri Apr 27 14:35:26 2001 Begin
284         BuildDomains(myFace,myWires,myLeft,myJoin,myIsOpenResult, Standard_False);
285         //  Modified by Sergey KHROMOV - Fri Apr 27 14:35:26 2001 End
286       }
287
288       for (itOW.Initialize(myLeft); itOW.More(); itOW.Next())
289       {
290         BRepFill_OffsetWire& Algo = itOW.Value();
291         Algo.Perform(Abs(Offset),Alt);
292         if (Algo.IsDone() && !Algo.Shape().IsNull())
293         {
294           B.Add(Res,Algo.Shape());
295           if (i == 1)
296             myShape = Algo.Shape();
297
298           i++;
299         }
300       }
301     }
302     else
303     {
304       if (myRight.IsEmpty())
305       {
306         //  Modified by Sergey KHROMOV - Fri Apr 27 14:35:28 2001 Begin
307         BuildDomains(myFace,myWires,myRight,myJoin,myIsOpenResult, Standard_True);
308         //  Modified by Sergey KHROMOV - Fri Apr 27 14:35:35 2001 End
309       }
310
311       for(itOW.Initialize(myRight); itOW.More(); itOW.Next())
312       {
313         BRepFill_OffsetWire& Algo = itOW.Value();
314         Algo.Perform(Offset,Alt);
315
316         if (Algo.IsDone() && !Algo.Shape().IsNull())
317         {
318           B.Add(Res,Algo.Shape());
319
320           if (i == 1)
321             myShape = Algo.Shape();
322
323           i++;
324         }
325       }
326     }
327
328     if( i > 2 )
329       myShape = Res;
330
331     if(myShape.IsNull())
332       NotDone();
333     else
334       Done();
335   }
336   catch(...) //Every exception was caught.
337   {
338     cout<<"An exception was caught in BRepOffsetAPI_MakeOffset::Perform : ";
339     Standard_ConstructionError::Caught()->Print(cout); 
340     cout<<endl;
341     NotDone();
342     myShape.Nullify();
343   }
344 }
345
346 //=======================================================================
347 //function : Build
348 //purpose  : 
349 //=======================================================================
350
351 void BRepOffsetAPI_MakeOffset::Build()
352 {
353   Done();
354 }
355
356
357 //=======================================================================
358 //function : ShapesFromShape
359 //purpose  : 
360 //=======================================================================
361
362 const TopTools_ListOfShape& BRepOffsetAPI_MakeOffset::Generated
363   (const TopoDS_Shape& S)
364 {
365   myGenerated.Clear();
366   BRepFill_ListIteratorOfListOfOffsetWire itOW;
367   BRepFill_ListOfOffsetWire* Algos;
368   Algos= &myLeft;
369   if (!myLastIsLeft) {
370     Algos = &myRight;
371   }
372   for (itOW.Initialize(*Algos); itOW.More(); itOW.Next()) {
373     BRepFill_OffsetWire& OW = itOW.Value();
374     TopTools_ListOfShape L;
375     L =  OW.GeneratedShapes(S.Oriented(TopAbs_FORWARD));
376     myGenerated.Append(L);
377     L =  OW.GeneratedShapes(S.Oriented(TopAbs_REVERSED));
378     myGenerated.Append(L);
379   }
380   return myGenerated;
381 }