0031460: Modeling Algorithms - Regression: Revolution not done.
[occt.git] / src / BRepPrimAPI / BRepPrimAPI_MakeRevol.cxx
1 // Created on: 1993-10-14
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1993-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 // Modified by skv - Fri Mar  4 15:50:09 2005
18 // Add methods for supporting history.
19
20 #include <BRep_TEdge.hxx>
21 #include <BRepLib.hxx>
22 #include <BRepPrimAPI_MakeRevol.hxx>
23 #include <BRepSweep_Revol.hxx>
24 #include <gp_Ax1.hxx>
25 #include <TopExp_Explorer.hxx>
26 #include <TopoDS_Shape.hxx>
27 #include <TopTools_DataMapOfShapeListOfShape.hxx>
28 #include <BRepTools_ReShape.hxx>
29 #include <Geom_TrimmedCurve.hxx>
30 #include <GeomAdaptor_SurfaceOfRevolution.hxx>
31 #include <GeomAdaptor_HCurve.hxx>
32 #include <Extrema_ExtCC.hxx>
33 #include <Extrema_POnCurv.hxx>
34 #include <Geom_Line.hxx>
35
36 // perform checks on the argument
37 static const TopoDS_Shape& check(const TopoDS_Shape& S)
38 {
39  BRepLib::BuildCurves3d(S);
40    return S;
41 }
42
43 //=======================================================================
44 //function : BRepPrimAPI_MakeRevol
45 //purpose  : 
46 //=======================================================================
47
48 BRepPrimAPI_MakeRevol::BRepPrimAPI_MakeRevol(const TopoDS_Shape& S, 
49                                      const gp_Ax1& A, 
50                                      const Standard_Real D, 
51              const Standard_Boolean Copy) : 
52              myRevol(check(S), A, D, Copy),
53              myIsBuild(Standard_False)
54
55 {
56   if (!CheckValidity(check(S), A))
57   {
58     myShape.Nullify();
59     myIsBuild = Standard_True;
60   }
61   else
62   {
63     Build();
64   }
65 }
66
67
68 //=======================================================================
69 //function : BRepPrimAPI_MakeRevol
70 //purpose  : 
71 //=======================================================================
72
73 BRepPrimAPI_MakeRevol::BRepPrimAPI_MakeRevol(const TopoDS_Shape& S, 
74                                      const gp_Ax1& A, 
75              const Standard_Boolean Copy) :
76              
77              myRevol(check(S), A, 2. * M_PI, Copy),
78               myIsBuild(Standard_False)
79 {
80
81   if (!CheckValidity(check(S), A))
82   {
83     myShape.Nullify();
84     myIsBuild = Standard_True;
85   }
86   else
87   {
88     Build();
89   }
90 }
91
92
93 //=======================================================================
94 //function : Revol
95 //purpose  : 
96 //=======================================================================
97
98 const BRepSweep_Revol&  BRepPrimAPI_MakeRevol::Revol() const 
99 {
100   return myRevol;
101 }
102
103
104 //=======================================================================
105 //function : Build
106 //purpose  : 
107 //=======================================================================
108
109 void  BRepPrimAPI_MakeRevol::Build()
110 {
111   if (myIsBuild)
112   {
113     return;
114   }
115   myShape = myRevol.Shape();
116   BRepLib::UpdateInnerTolerances(myShape);
117   
118   Done();
119   myIsBuild = Standard_True;
120
121   myHist.Nullify();
122   myDegenerated.Clear();
123   TopTools_DataMapOfShapeListOfShape aDegE;
124   BRep_Builder aBB;
125
126   TopExp_Explorer anExp(myShape, TopAbs_EDGE);
127   //Problem is that some degenerated edges can be shared by different faces.
128   //It is not valid for correct shape.
129   //To solve problem it is possible to copy shared degenerated edge for each face, which has it, and 
130   //replace shared edge by its copy
131   for (; anExp.More(); anExp.Next()) {
132     const TopoDS_Shape &anEdge = anExp.Current();
133     Handle(BRep_TEdge)  aTEdge = Handle(BRep_TEdge)::DownCast(anEdge.TShape());
134
135     if (aTEdge->Degenerated())
136     {
137       TopTools_ListOfShape* anL = aDegE.ChangeSeek(anEdge);
138       if (anL)
139       {
140         //Make the copy if degenerated edge occurs more then once
141         TopoDS_Shape aCopyE = anEdge.EmptyCopied();
142         aCopyE.Orientation(TopAbs_FORWARD);
143         TopoDS_Iterator aVIter(anEdge.Oriented(TopAbs_FORWARD), Standard_False);
144         for (; aVIter.More(); aVIter.Next())
145         {
146           aBB.Add(aCopyE, aVIter.Value());
147         }
148         aCopyE.Orientation(anEdge.Orientation());
149         anL->Append(aCopyE);
150         myDegenerated.Append(aCopyE);
151       }
152       else
153       {
154         anL = aDegE.Bound(anEdge, TopTools_ListOfShape());
155         anL->Append(anEdge);
156         myDegenerated.Append(anEdge);
157       }
158     }
159   }
160   if (!myDegenerated.IsEmpty())
161   {
162     BRepTools_ReShape aSubs;
163     TopTools_DataMapOfShapeListOfShape aDegF;
164     Standard_Boolean isReplaced = Standard_False;
165     anExp.Init(myShape, TopAbs_FACE);
166     //Replace degenerated edge by its copies for different faces
167     //First, for each face list of d.e. is created
168     for (; anExp.More(); anExp.Next())
169     {
170       const TopoDS_Shape& aF = anExp.Current();
171       TopExp_Explorer anExpE(aF, TopAbs_EDGE);
172       for (; anExpE.More(); anExpE.Next())
173       {
174         const TopoDS_Shape &anE = anExpE.Current();
175         if (BRep_Tool::Degenerated(TopoDS::Edge(anE)))
176         {
177           TopTools_ListOfShape* anL = aDegF.ChangeSeek(aF);
178           if (!anL)
179           {
180             anL = aDegF.Bound(aF, TopTools_ListOfShape());
181           }
182           anL->Append(anE);
183         }
184       }
185     }
186     //
187     //Second, replace edges by copies using ReShape
188     BRepTools_ReShape aSubsF;
189     TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aFIter(aDegF);
190     for (; aFIter.More(); aFIter.Next())
191     {
192       aSubs.Clear();
193       isReplaced = Standard_False;
194       const TopoDS_Shape& aF = aFIter.Key();
195       const TopTools_ListOfShape& aDEL = aFIter.ChangeValue();
196       TopTools_ListIteratorOfListOfShape anEIter(aDEL);
197       for (; anEIter.More(); anEIter.Next())
198       {
199         const TopoDS_Shape& anE = anEIter.Value();
200         if (aDegE.IsBound(anE))
201         {
202           TopTools_ListOfShape& aCEL = aDegE.ChangeFind(anE);
203           TopTools_ListIteratorOfListOfShape anIt(aCEL);
204           for (; anIt.More(); anIt.Next())
205           {
206             if (anIt.Value().IsEqual(anE))
207             {
208               //First occurence of initial deg. edge is not replaced
209               aCEL.Remove(anIt);
210               break;
211             }
212             if (anIt.Value().Orientation() == anE.Orientation())
213             {
214               //All other occurences of anE are replaced by any copy
215               //with suitable orientation
216               isReplaced = Standard_True;
217               aSubs.Replace(anE, anIt.Value());
218               aCEL.Remove(anIt);
219               break;
220             }
221           }
222         }
223       }
224       if (isReplaced)
225       {
226         TopoDS_Shape aNF = aSubs.Apply(aF);
227         aSubsF.Replace(aF, aNF);
228         if (myHist.IsNull())
229         {
230           myHist = aSubs.History();
231         }
232         else
233         {
234           myHist->Merge(aSubs.History());
235         }
236         myShape = aSubsF.Apply(myShape);
237         myHist->Merge(aSubsF.History());
238         //Pair aF->aNF is in history after first replacing of edge by aNF = aSubs.Apply(aF)
239         //After merging history for replacing faces, modified list for aF contains two exemplar of aNF
240         //So, using ReplaceModified clears modified list for aF and leaves only one exemplar of aNF
241         myHist->ReplaceModified(aF, aNF);
242         aSubsF.Clear();
243       }
244     }
245   }
246 }
247 //=======================================================================
248 //function : IsIntersect
249 //purpose  : used in CheckValidity to find out is there
250 //           intersection between curve and axe of revolution
251 //=======================================================================
252 static Standard_Boolean IsIntersect(const Handle(Adaptor3d_HCurve)& theC, 
253                                     const gp_Ax1& theAxe)
254 {
255   const gp_Lin anAxis(theAxe);
256   //Quick test for circle
257   if (theC->GetType() == GeomAbs_Circle)
258   {
259     gp_Circ aCirc = theC->Circle();
260     const gp_Pnt& aCentr = aCirc.Location();
261     Standard_Real anR2 = aCirc.Radius();
262     anR2 -= Precision::Confusion();
263     anR2 *= anR2;
264     if (anAxis.SquareDistance(aCentr) > anR2)
265     {
266       return Standard_False;
267     }
268   }
269   const Handle(Geom_Line) aL = new Geom_Line(anAxis);
270   const GeomAdaptor_Curve aLin(aL);
271   const Standard_Real aParTol = theC->Resolution(Precision::Confusion());
272   const Standard_Real aParF = theC->FirstParameter() + aParTol,
273                       aParL = theC->LastParameter() - aParTol;
274
275   Extrema_ExtCC anExtr(theC->Curve(), aLin);
276   anExtr.Perform();
277   if (anExtr.IsDone() && anExtr.NbExt() > 0)
278   {
279     Extrema_POnCurv aP1, aP2;
280     for (Standard_Integer i = 1; i <= anExtr.NbExt(); i++)
281     {
282       if (anExtr.SquareDistance(i) > Precision::SquareConfusion())
283       {
284         continue;
285       }
286       anExtr.Points(i, aP1, aP2);
287       if ((aParF < aP1.Parameter()) && (aP1.Parameter() < aParL))
288       {
289         return Standard_True;
290       }
291     }
292   }
293   return Standard_False;
294 }
295
296 //=======================================================================
297 //function : CheckValidity
298 //purpose  : 
299 //=======================================================================
300
301 Standard_Boolean BRepPrimAPI_MakeRevol::CheckValidity(const TopoDS_Shape& theShape,
302                                                       const gp_Ax1& theA)
303 {
304   TopExp_Explorer anExp(theShape, TopAbs_EDGE);
305   Standard_Boolean IsValid = Standard_True;
306   for (; anExp.More(); anExp.Next())
307   {
308     const TopoDS_Edge& anE = TopoDS::Edge(anExp.Current());
309
310     if (BRep_Tool::Degenerated(anE))
311     {
312       continue;
313     }
314
315     TopLoc_Location L;
316     Standard_Real First, Last;
317     Handle(Geom_Curve) C = BRep_Tool::Curve(anE, L, First, Last);
318     gp_Trsf Tr = L.Transformation();
319     C = Handle(Geom_Curve)::DownCast(C->Copy());
320     C = new Geom_TrimmedCurve(C, First, Last);
321     C->Transform(Tr);
322
323     Handle(GeomAdaptor_HCurve) HC = new GeomAdaptor_HCurve();
324     HC->ChangeCurve().Load(C, First, Last);
325     //Checking coinsidence axe of revolution and basis curve
326     //This code is taken directly from GeomAdaptor_SurfaceOfRevolution
327     Standard_Integer Ratio = 1;
328     Standard_Real Dist;
329     gp_Pnt PP;
330     do {
331       PP = HC->Value(First + (Last - First) / Ratio);
332       Dist = gp_Lin(theA).Distance(PP);
333       Ratio++;
334     } while (Dist < Precision::Confusion() && Ratio < 100);
335     //
336     if (Ratio >= 100) // edge coinsides with axes
337     {
338       IsValid = Standard_True; //Such edges are allowed by revol algo and treated
339                                //by special way, so they must be concidered as valid
340     }
341     else
342     {
343       IsValid = !IsIntersect(HC, theA);
344     }
345     if (!IsValid)
346     {
347       break;
348     }
349   }
350   //
351   return IsValid;
352 }
353
354
355 //=======================================================================
356 //function : FirstShape
357 //purpose  : 
358 //=======================================================================
359
360 TopoDS_Shape BRepPrimAPI_MakeRevol::FirstShape()
361 {
362   return myRevol.FirstShape();
363 }
364
365
366 //=======================================================================
367 //function : LastShape
368 //purpose  : 
369 //=======================================================================
370
371 TopoDS_Shape BRepPrimAPI_MakeRevol::LastShape()
372 {
373   return myRevol.LastShape();
374 }
375
376 //=======================================================================
377 //function : Generated
378 //purpose  : 
379 //=======================================================================
380 const TopTools_ListOfShape& BRepPrimAPI_MakeRevol::Generated (const TopoDS_Shape& S)
381 {
382   myGenerated.Clear();
383
384   if (!myRevol.IsUsed(S))
385   {
386     return myGenerated;
387   }
388
389   TopoDS_Shape aGS = myRevol.Shape(S);
390   if (!aGS.IsNull())
391   { 
392     if (BRepTools_History::IsSupportedType(aGS))
393     {
394       if (aGS.ShapeType() == TopAbs_EDGE)
395       {
396         Standard_Boolean isDeg = BRep_Tool::Degenerated(TopoDS::Edge(aGS));
397         if (isDeg)
398         {
399           TopTools_ListIteratorOfListOfShape anIt(myDegenerated);
400           for (; anIt.More(); anIt.Next())
401           {
402             if (aGS.IsSame(anIt.Value()))
403             {
404               myGenerated.Append(aGS);
405               if (!myHist.IsNull())
406               {
407                 TopTools_ListIteratorOfListOfShape anIt1(myHist->Modified(aGS));
408                 for (; anIt1.More(); anIt1.Next())
409                 {
410                   myGenerated.Append(anIt1.Value());
411                 }
412                 return myGenerated;
413               }
414             }
415           }
416           return myGenerated;
417         }
418       }
419       //
420       if (myHist.IsNull())
421       {
422         myGenerated.Append(aGS);
423         return myGenerated;
424       }
425       //
426       if (myHist->Modified(aGS).IsEmpty())
427       {
428         myGenerated.Append(aGS);
429         return myGenerated;
430       }
431       //
432       TopTools_ListIteratorOfListOfShape anIt(myHist->Modified(aGS));
433       for (; anIt.More(); anIt.Next())
434       {
435         myGenerated.Append(anIt.Value());
436       }
437     }
438   }
439   return myGenerated;
440 }
441 //=======================================================================
442 //function : IsDeleted
443 //purpose  : 
444 //=======================================================================
445 Standard_Boolean BRepPrimAPI_MakeRevol::IsDeleted(const TopoDS_Shape& S)
446 {
447   return !myRevol.IsUsed(S);
448 }
449
450
451 //=======================================================================
452 //function : FirstShape
453 //purpose  : This method returns the shape of the beginning of the revolution,
454 //           generated with theShape (subShape of the generating shape).
455 //=======================================================================
456
457 TopoDS_Shape BRepPrimAPI_MakeRevol::FirstShape(const TopoDS_Shape &theShape)
458 {
459   return myRevol.FirstShape(theShape);
460 }
461
462
463 //=======================================================================
464 //function : LastShape
465 //purpose  : This method returns the shape of the end of the revolution,
466 //           generated with theShape (subShape of the generating shape).
467 //=======================================================================
468
469 TopoDS_Shape BRepPrimAPI_MakeRevol::LastShape(const TopoDS_Shape &theShape)
470 {
471   return myRevol.LastShape(theShape);
472 }
473
474 //=======================================================================
475 //function : HasDegenerated
476 //purpose  : 
477 //=======================================================================
478
479 Standard_Boolean BRepPrimAPI_MakeRevol::HasDegenerated () const
480 {
481   return (!myDegenerated.IsEmpty());
482 }
483
484
485 //=======================================================================
486 //function : Degenerated
487 //purpose  : 
488 //=======================================================================
489
490 const TopTools_ListOfShape& BRepPrimAPI_MakeRevol::Degenerated () const
491 {
492   return myDegenerated;
493 }