0027991: Modeling Algorithms - BRepGProp_Face crashes on face without geometric surface
[occt.git] / src / BRepBndLib / BRepBndLib.cxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15
16 #include <Bnd_Box.hxx>
17 #include <BndLib_Add3dCurve.hxx>
18 #include <BndLib_AddSurface.hxx>
19 #include <BRep_Polygon3D.hxx>
20 #include <BRep_Tool.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepBndLib.hxx>
24 #include <Geom_Curve.hxx>
25 #include <Geom_Surface.hxx>
26 #include <GeomAdaptor_Curve.hxx>
27 #include <Poly_Polygon3D.hxx>
28 #include <Poly_PolygonOnTriangulation.hxx>
29 #include <Poly_Triangulation.hxx>
30 #include <TColgp_Array1OfPnt.hxx>
31 #include <TColStd_Array1OfInteger.hxx>
32 #include <TColStd_HArray1OfInteger.hxx>
33 #include <TopExp_Explorer.hxx>
34 #include <TopLoc_Location.hxx>
35 #include <TopoDS.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <Adaptor3d_HCurve.hxx>
38 #include <Adaptor3d_HSurface.hxx>
39 #include <BRepTools.hxx>
40 #include <Geom_BSplineSurface.hxx>
41 #include <Geom_BezierSurface.hxx>
42 #include <Bnd_Box2d.hxx>
43 #include <BndLib_Add2dCurve.hxx>
44 #include <BRepTopAdaptor_FClass2d.hxx>
45 #include <ElSLib.hxx>
46 #include <ElCLib.hxx>
47 #include <Geom_Plane.hxx>
48 #include <Extrema_ExtSS.hxx>
49 #include <GeomAdaptor_Surface.hxx>
50 //
51 static Standard_Boolean CanUseEdges(const Adaptor3d_Surface& BS);
52 //
53 static void FindExactUVBounds(const TopoDS_Face F, 
54                               Standard_Real& umin, Standard_Real& umax, 
55                               Standard_Real& vmin, Standard_Real& vmax,
56                               const Standard_Real Tol, 
57                               Standard_Boolean& isNaturalRestriction);
58 //
59 static void AdjustFaceBox(const BRepAdaptor_Surface& BS, 
60                           const Standard_Real umin, const Standard_Real umax, 
61                           const Standard_Real vmin, const Standard_Real vmax,
62                           Bnd_Box& FaceBox,
63                           const Bnd_Box& EdgeBox, const Standard_Real Tol);
64 //
65 static Standard_Boolean IsModifySize(const BRepAdaptor_Surface& theBS, 
66                                      const gp_Pln& thePln, const gp_Pnt& theP,
67                                      const Standard_Real umin, const Standard_Real umax,
68                                      const Standard_Real vmin, const Standard_Real vmax,
69                                      const BRepTopAdaptor_FClass2d& theFClass,
70                                      const Standard_Real theTolU, const Standard_Real theTolV);
71
72 //
73 //=======================================================================
74 //function : Add
75 //purpose  : Add a shape bounding to a box
76 //=======================================================================
77 void BRepBndLib::Add(const TopoDS_Shape& S, Bnd_Box& B, Standard_Boolean useTriangulation)
78 {
79   TopExp_Explorer ex;
80
81   // Add the faces
82   BRepAdaptor_Surface BS;
83   TopLoc_Location l, aDummyLoc;
84   Standard_Integer i, nbNodes;
85   BRepAdaptor_Curve BC;
86
87   for (ex.Init(S,TopAbs_FACE); ex.More(); ex.Next()) {
88     const TopoDS_Face& F = TopoDS::Face(ex.Current());
89     const Handle(Poly_Triangulation)& T = BRep_Tool::Triangulation(F, l);
90     const Handle(Geom_Surface)& GS = BRep_Tool::Surface (F, aDummyLoc);
91     if ((useTriangulation || GS.IsNull()) && !T.IsNull())
92     {
93       nbNodes = T->NbNodes();
94       const TColgp_Array1OfPnt& Nodes = T->Nodes();
95       for (i = 1; i <= nbNodes; i++) {
96         if (l.IsIdentity()) B.Add(Nodes(i));
97         else B.Add(Nodes(i).Transformed(l));
98       }
99       //       B.Enlarge(T->Deflection());
100       B.Enlarge(T->Deflection() + BRep_Tool::Tolerance(F));
101     } else
102     {
103       if (!GS.IsNull()) {
104         BS.Initialize(F, Standard_False);
105         if (BS.GetType() != GeomAbs_Plane) {
106           BS.Initialize(F);
107           BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
108         }
109         else {
110           // on travaille directement sur les courbes 3d.
111           TopExp_Explorer ex2(F, TopAbs_EDGE);
112           if (!ex2.More()) {
113             BS.Initialize(F);
114             BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
115           }
116           else {
117             for (;ex2.More();ex2.Next()) {
118               BC.Initialize(TopoDS::Edge(ex2.Current()));
119               BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(F), B);
120             }
121             B.Enlarge(BRep_Tool::Tolerance(F));
122           }
123         }
124       }
125     }
126   }
127
128   // Add the edges not in faces
129   Handle(TColStd_HArray1OfInteger) HIndices;
130   Handle(Poly_PolygonOnTriangulation) Poly;
131   Handle(Poly_Triangulation) T;
132   for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE); ex.More(); ex.Next())
133   {
134     const TopoDS_Edge& E = TopoDS::Edge(ex.Current());
135     Handle(Poly_Polygon3D) P3d = BRep_Tool::Polygon3D(E, l);
136     if (!P3d.IsNull())
137     {
138       const TColgp_Array1OfPnt& Nodes = P3d->Nodes();
139       nbNodes = P3d->NbNodes();
140       for (i = 1; i <= nbNodes; i++)
141       {
142         if (l.IsIdentity()) B.Add(Nodes(i));
143         else B.Add(Nodes(i).Transformed(l));
144       }
145       //       B.Enlarge(P3d->Deflection());
146       B.Enlarge(P3d->Deflection() + BRep_Tool::Tolerance(E));
147     }
148     else
149     {
150       BRep_Tool::PolygonOnTriangulation(E, Poly, T, l);
151       if (useTriangulation && !Poly.IsNull())
152       {
153         const TColStd_Array1OfInteger& Indices = Poly->Nodes();
154         const TColgp_Array1OfPnt& Nodes = T->Nodes();
155         nbNodes = Indices.Length();
156         for (i = 1; i <= nbNodes; i++)
157         {
158           if (l.IsIdentity()) B.Add(Nodes(Indices(i)));
159           else B.Add(Nodes(Indices(i)).Transformed(l));
160         }
161         //      B.Enlarge(T->Deflection());
162         B.Enlarge(Poly->Deflection() + BRep_Tool::Tolerance(E));
163       }
164       else {
165         if (BRep_Tool::IsGeometric(E))
166         {
167           BC.Initialize(E);
168           BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(E), B);
169         }
170       }
171     }
172   }
173
174   // Add the vertices not in edges
175
176   for (ex.Init(S,TopAbs_VERTEX,TopAbs_EDGE); ex.More(); ex.Next()) {
177     B.Add(BRep_Tool::Pnt(TopoDS::Vertex(ex.Current())));
178     B.Enlarge(BRep_Tool::Tolerance(TopoDS::Vertex(ex.Current())));
179   }
180 }
181
182
183
184 //=======================================================================
185 //function : AddClose
186 //purpose  : Add a precise shape bounding to a box
187 //=======================================================================
188
189 void BRepBndLib::AddClose(const TopoDS_Shape& S, Bnd_Box& B)
190 {
191   TopExp_Explorer ex;
192
193   // No faces
194
195   // Add the edges
196
197   BRepAdaptor_Curve BC;
198
199   for (ex.Init(S,TopAbs_EDGE); ex.More(); ex.Next()) {
200     BC.Initialize(TopoDS::Edge(ex.Current()));
201     BndLib_Add3dCurve::Add(BC,0.,B);
202   }
203
204   // Add the vertices not in edges
205
206   for (ex.Init(S,TopAbs_VERTEX,TopAbs_EDGE); ex.More(); ex.Next()) {
207     B.Add(BRep_Tool::Pnt(TopoDS::Vertex(ex.Current())));
208   }
209 }
210
211 //=======================================================================
212 //function : AddOptimal
213 //purpose  : Add a shape bounding to a box
214 //=======================================================================
215 void BRepBndLib::AddOptimal(const TopoDS_Shape& S, Bnd_Box& B, 
216                             const Standard_Boolean useTriangulation, 
217                             const Standard_Boolean useShapeTolerance)
218 {
219   TopExp_Explorer ex;
220
221   // Add the faces
222   BRepAdaptor_Surface BS;
223   Handle(Poly_Triangulation) T;
224   TopLoc_Location l;
225   Standard_Integer i, nbNodes;
226   BRepAdaptor_Curve BC;
227
228   for (ex.Init(S,TopAbs_FACE); ex.More(); ex.Next()) {
229     const TopoDS_Face& F = TopoDS::Face(ex.Current());
230     T = BRep_Tool::Triangulation(F, l);
231     Bnd_Box aLocBox;
232     if (useTriangulation && !T.IsNull())
233     {
234       nbNodes = T->NbNodes();
235       const TColgp_Array1OfPnt& Nodes = T->Nodes();
236       for (i = 1; i <= nbNodes; i++) {
237         if (l.IsIdentity()) aLocBox.Add(Nodes(i));
238         else aLocBox.Add(Nodes(i).Transformed(l));
239       }
240       //       B.Enlarge(T->Deflection());
241       aLocBox.Enlarge(T->Deflection() + BRep_Tool::Tolerance(F));
242       Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
243       aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
244       B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
245     } 
246     else
247     {
248       const Handle(Geom_Surface)& GS = BRep_Tool::Surface(F, l);
249       if (!GS.IsNull()) {
250         BS.Initialize(F, Standard_False);
251         if (CanUseEdges(BS)) {
252           TopExp_Explorer ex2(F, TopAbs_EDGE);
253           if (!ex2.More()) {
254             BS.Initialize(F);
255             Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
256             BndLib_AddSurface::AddOptimal(BS, Tol, aLocBox);
257           }
258           else
259           {
260             Standard_Real Tol;
261             for (;ex2.More();ex2.Next()) {
262               Bnd_Box anEBox;
263               const TopoDS_Edge& anE = TopoDS::Edge(ex2.Current());
264               if(BRep_Tool::Degenerated(anE))
265               {
266                 continue;
267               }
268               BC.Initialize(anE);
269               Tol = useShapeTolerance?  BRep_Tool::Tolerance(anE) : 0.;
270               BndLib_Add3dCurve::AddOptimal(BC, Tol, anEBox);
271               aLocBox.Add(anEBox);
272             }
273           }
274         }
275         else
276         {
277           Standard_Real umin, umax, vmin, vmax;
278           Standard_Boolean isNaturalRestriction = Standard_False;
279           Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
280           FindExactUVBounds(F, umin, umax, vmin, vmax, Tol, isNaturalRestriction);
281           BndLib_AddSurface::AddOptimal(BS, umin, umax, vmin, vmax, 
282                                         Tol, aLocBox);
283           //
284           if(!isNaturalRestriction)
285           {
286             TopExp_Explorer ex2(F, TopAbs_EDGE);
287             Bnd_Box EBox;
288             for (;ex2.More();ex2.Next()) {
289               Bnd_Box anEBox;
290               const TopoDS_Edge& anE = TopoDS::Edge(ex2.Current());
291               if(BRep_Tool::Degenerated(anE))
292               {
293                 continue;
294               }
295               BC.Initialize(anE);
296               Tol = useShapeTolerance?  BRep_Tool::Tolerance(anE) : 0.;
297               BndLib_Add3dCurve::AddOptimal(BC, Tol, anEBox);
298               EBox.Add(anEBox);
299             }
300             Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
301             AdjustFaceBox(BS, umin, umax, vmin, vmax, aLocBox, EBox, 
302                           Tol);
303           }
304         }
305         Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
306         aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
307         B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
308       }
309     }
310   }
311
312   // Add the edges not in faces
313   Handle(TColStd_HArray1OfInteger) HIndices;
314   Handle(Poly_PolygonOnTriangulation) Poly;
315
316   for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE); ex.More(); ex.Next())
317   {
318     const TopoDS_Edge& E = TopoDS::Edge(ex.Current());
319     Bnd_Box aLocBox;
320     Handle(Poly_Polygon3D) P3d = BRep_Tool::Polygon3D(E, l);
321     if (useTriangulation && (!P3d.IsNull()))
322     {
323       const TColgp_Array1OfPnt& Nodes = P3d->Nodes();
324       nbNodes = P3d->NbNodes();
325       for (i = 1; i <= nbNodes; i++)
326       {
327         if (l.IsIdentity()) aLocBox.Add(Nodes(i));
328         else aLocBox.Add(Nodes(i).Transformed(l));
329       }
330       Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
331       aLocBox.Enlarge(P3d->Deflection() + Tol);
332     }
333     else
334     {
335       BRep_Tool::PolygonOnTriangulation(E, Poly, T, l);
336       if (useTriangulation && !Poly.IsNull())
337       {
338         const TColStd_Array1OfInteger& Indices = Poly->Nodes();
339         const TColgp_Array1OfPnt& Nodes = T->Nodes();
340         nbNodes = Indices.Length();
341         for (i = 1; i <= nbNodes; i++)
342         {
343           if (l.IsIdentity()) aLocBox.Add(Nodes(Indices(i)));
344           else aLocBox.Add(Nodes(Indices(i)).Transformed(l));
345         }
346         Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
347         aLocBox.Enlarge(Poly->Deflection() + Tol);
348       }
349       else {
350         if (BRep_Tool::IsGeometric(E))
351         {
352           BC.Initialize(E);
353           Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
354           BndLib_Add3dCurve::AddOptimal(BC, Tol, aLocBox);
355         }
356       }
357     }
358     if (!aLocBox.IsVoid())
359     {
360       Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
361       aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
362       B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
363     }
364   }
365
366   // Add the vertices not in edges
367
368   for (ex.Init(S,TopAbs_VERTEX,TopAbs_EDGE); ex.More(); ex.Next()) {
369     Bnd_Box aLocBox;
370     const TopoDS_Vertex& aV = TopoDS::Vertex(ex.Current());
371     aLocBox.Add(BRep_Tool::Pnt(aV));
372     Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(aV) : 0.;
373     aLocBox.Enlarge(Tol);
374     Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
375     aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
376     B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
377   }
378 }
379
380 //=======================================================================
381 //function : CanUseEdges
382 //purpose  : Define is it possible using only edges bnd boxes 
383 //           to get face bnd box
384 //=======================================================================
385 Standard_Boolean CanUseEdges(const Adaptor3d_Surface& BS)
386 {
387   GeomAbs_SurfaceType aST = BS.GetType();
388   if(aST == GeomAbs_Plane ||
389      aST == GeomAbs_Cylinder ||
390      aST == GeomAbs_Cone ||
391      aST == GeomAbs_SurfaceOfExtrusion)
392   {
393     return Standard_True;
394   }
395   else if(aST == GeomAbs_SurfaceOfRevolution)
396   {
397     const Handle(Adaptor3d_HCurve)& aBC = BS.BasisCurve();
398     if(aBC->GetType() == GeomAbs_Line)
399     {
400       return Standard_True;
401     }
402     else
403     {
404       return Standard_False;
405     }
406   }
407   else if(aST == GeomAbs_OffsetSurface)
408   {
409     const Handle(Adaptor3d_HSurface)& aS = BS.BasisSurface();
410     return CanUseEdges(aS->Surface());
411   }
412   else if(aST == GeomAbs_BSplineSurface)
413   {
414     Handle(Geom_BSplineSurface) aBSpl = BS.BSpline();
415     if((aBSpl->UDegree() == 1 && aBSpl->NbUKnots() == 2) ||
416        (aBSpl->VDegree() == 1 && aBSpl->NbVKnots() == 2))
417     {
418       return Standard_True;
419     }
420     else
421     {
422       return Standard_False;
423     }
424   }
425   else if(aST == GeomAbs_BezierSurface)
426   {
427     Handle(Geom_BezierSurface) aBz = BS.Bezier();
428     if((aBz->UDegree() == 1 ) ||
429        (aBz->VDegree() == 1 ))
430     {
431       return Standard_True;
432     }
433     else
434     {
435       return Standard_False;
436     }
437   }
438   return Standard_False;
439 }
440
441 //=======================================================================
442 //function : FindExactUVBounds
443 //purpose  : 
444 //=======================================================================
445 void FindExactUVBounds(const TopoDS_Face FF, 
446                        Standard_Real& umin, Standard_Real& umax, 
447                        Standard_Real& vmin, Standard_Real& vmax,
448                        const Standard_Real Tol, 
449                        Standard_Boolean& isNaturalRestriction)
450 {
451   TopoDS_Face F = FF;
452   F.Orientation(TopAbs_FORWARD);
453   TopExp_Explorer ex(F,TopAbs_EDGE);
454   //
455   //Check Natural restriction
456   isNaturalRestriction = BRep_Tool::NaturalRestriction(F); //Can we trust this flag?
457   BRepAdaptor_Surface aBAS(F, Standard_False);
458   if(!isNaturalRestriction)
459   {
460     //Check by comparing pcurves and surface boundaries
461     umin = aBAS.FirstUParameter();
462     umax = aBAS.LastUParameter();
463     vmin = aBAS.FirstVParameter();
464     vmax = aBAS.LastVParameter();
465     Standard_Boolean isUperiodic = aBAS.IsUPeriodic(), isVperiodic = aBAS.IsVPeriodic();
466     Standard_Real aT1, aT2;
467     Standard_Real TolU = Max(aBAS.UResolution(Tol), Precision::PConfusion());
468     Standard_Real TolV = Max(aBAS.VResolution(Tol), Precision::PConfusion());
469     Standard_Integer Nu = 0, Nv = 0, NbEdges = 0;
470     gp_Vec2d Du(1, 0), Dv(0, 1);
471     gp_Pnt2d aP;
472     gp_Vec2d aV;
473     for (;ex.More();ex.Next()) {
474       NbEdges++;
475       if(NbEdges > 4)
476       {
477         break;
478       }
479       const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
480       const Handle(Geom2d_Curve) aC2D = BRep_Tool::CurveOnSurface(aE, F, aT1, aT2);
481       if (aC2D.IsNull()) 
482       {
483         break;
484       }
485       //
486       aC2D->D1((aT1 + aT2)/2., aP, aV);
487       Standard_Real magn = aV.SquareMagnitude();
488       if(magn < gp::Resolution())
489       {
490         break;
491       }
492       else
493       {
494         aV /= Sqrt(magn);
495       }
496       Standard_Real u = aP.X(), v = aP.Y();
497       if(isUperiodic)
498       {
499         ElCLib::InPeriod(u, umin, umax);
500       }
501       if(isVperiodic)
502       {
503         ElCLib::InPeriod(v, vmin, vmax);
504       }
505       //
506       if(Abs(u - umin) <= TolU || Abs(u - umax) <= TolU)
507       {
508         Standard_Real d = Dv * aV;
509         if(1. - Abs(d) <= Precision::PConfusion())
510         {
511           Nu++;
512           if(Nu > 2)
513           {
514             break;
515           }
516         }
517         else
518         {
519           break;
520         }
521       }
522       else if(Abs(v - vmin) <= TolV || Abs(v - vmax) <= TolV)
523       {
524         Standard_Real d = Du * aV;
525         if(1. - Abs(d) <= Precision::PConfusion())
526         {
527           Nv++;
528           if(Nv > 2)
529           {
530             break;
531           }
532         }
533         else
534         {
535           break;
536         }
537       }
538       else
539       {
540         break;
541       }
542     }
543     if(Nu == 2 && Nv == 2)
544     {
545       isNaturalRestriction = Standard_True;
546     }
547   }
548   //
549   if(isNaturalRestriction)
550   {
551     umin = aBAS.FirstUParameter();
552     umax = aBAS.LastUParameter();
553     vmin = aBAS.FirstVParameter();
554     vmax = aBAS.LastVParameter();
555     return;
556   }
557
558   // fill box for the given face
559   Standard_Real aT1, aT2;
560   Standard_Real TolU = Max(aBAS.UResolution(Tol), Precision::PConfusion());
561   Standard_Real TolV = Max(aBAS.VResolution(Tol), Precision::PConfusion());
562   Standard_Real TolUV = Max(TolU, TolV);
563   Bnd_Box2d aBox;
564   ex.Init(F,TopAbs_EDGE);
565   for (;ex.More();ex.Next()) {
566     const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
567     const Handle(Geom2d_Curve) aC2D = BRep_Tool::CurveOnSurface(aE, F, aT1, aT2);
568     if (aC2D.IsNull()) 
569     {
570       continue;
571     }
572     //
573     BndLib_Add2dCurve::AddOptimal(aC2D, aT1, aT2, TolUV, aBox);
574     //
575   }
576   //
577   aBox.Get(umin, vmin, umax, vmax);
578   //
579   TopLoc_Location aLoc;
580   Handle(Geom_Surface) aS = BRep_Tool::Surface(FF, aLoc);
581   Standard_Real aUmin, aUmax, aVmin, aVmax;
582   aS->Bounds(aUmin, aUmax, aVmin, aVmax);
583   if(!aS->IsUPeriodic())
584   {
585     umin = Max(aUmin, umin);
586     umax = Min(aUmax, umax);
587   }
588   else
589   {
590     if(umax - umin > aS->UPeriod())
591     {
592       Standard_Real delta = umax - umin - aS->UPeriod();
593       umin += delta/2.;
594       umax -= delta/2;
595     }
596   }
597   //
598   if(!aS->IsVPeriodic())
599   {
600     vmin = Max(aVmin, vmin);
601     vmax = Min(aVmax, vmax);
602   }
603   else
604   {
605     if(vmax - vmin > aS->VPeriod())
606     {
607       Standard_Real delta = vmax - vmin - aS->VPeriod();
608       vmin += delta/2.;
609       vmax -= delta/2;
610     }
611   }
612 }
613 //=======================================================================
614 //function : Reorder
615 //purpose  : 
616 //=======================================================================
617 inline void Reorder(Standard_Real& a, Standard_Real& b)
618 {
619   if(a > b)
620   {
621     Standard_Real t = a;
622     a = b;
623     b = t;
624   }
625 }
626 //=======================================================================
627 //function : IsModifySize
628 //purpose  : 
629 //=======================================================================
630 Standard_Boolean IsModifySize(const BRepAdaptor_Surface& theBS, 
631                               const gp_Pln& thePln, const gp_Pnt& theP,
632                               const Standard_Real umin, const Standard_Real umax,
633                               const Standard_Real vmin, const Standard_Real vmax,
634                               const BRepTopAdaptor_FClass2d& theFClass,
635                               const Standard_Real theTolU, const Standard_Real theTolV)
636 {
637   Standard_Real pu1 = 0, pu2, pv1 = 0, pv2;
638   ElSLib::PlaneParameters(thePln.Position(), theP, pu2, pv2);
639   Reorder(pu1, pu2);
640   Reorder(pv1, pv2);
641   Handle(Geom_Plane) aPlane = new Geom_Plane(thePln);
642   GeomAdaptor_Surface aGAPln(aPlane, pu1, pu2, pv1, pv2);
643   Extrema_ExtSS anExtr(aGAPln, theBS, pu1, pu2, pv1, pv2, umin, umax, vmin, vmax, theTolU, theTolV);
644   if(anExtr.IsDone())
645   {
646     if(anExtr.NbExt() > 0)
647     {
648       Standard_Integer i, imin = 0;;
649       Standard_Real dmin = RealLast();
650       Standard_Real uextr = 0., vextr = 0.;
651       Extrema_POnSurf P1, P2;
652       for(i = 1; i <= anExtr.NbExt(); ++i)
653       {
654         Standard_Real d = anExtr.SquareDistance(i);
655         if(d < dmin)
656         {
657           imin = i;
658           dmin = d;
659         }
660       }
661       if(imin > 0)
662       {
663         anExtr.Points(imin, P1, P2);
664         P2.Parameter(uextr, vextr);
665       }
666       else
667       {
668         return Standard_False;
669       }
670       //
671       gp_Pnt2d aP2d(uextr, vextr);
672       TopAbs_State aSt = theFClass.Perform(aP2d);
673       if(aSt == TopAbs_OUT)
674       {
675         return Standard_True;
676       }
677     }
678     else
679     {
680       return Standard_True; //extrema point seems to be out of face UV bounds
681     }
682   }
683   //
684   return Standard_False;
685 }
686 //
687 //=======================================================================
688 //function : AdjustFaceBox
689 //purpose  : 
690 //=======================================================================
691 void AdjustFaceBox(const BRepAdaptor_Surface& BS, 
692                    const Standard_Real umin, const Standard_Real umax, 
693                    const Standard_Real vmin, const Standard_Real vmax,
694                    Bnd_Box& FaceBox,
695                    const Bnd_Box& EdgeBox, const Standard_Real Tol)
696 {
697   Standard_Real fxmin, fymin, fzmin, fxmax, fymax, fzmax;
698   Standard_Real exmin, eymin, ezmin, exmax, eymax, ezmax;
699   //
700   FaceBox.Get(fxmin, fymin, fzmin, fxmax, fymax, fzmax);
701   EdgeBox.Get(exmin, eymin, ezmin, exmax, eymax, ezmax);
702   //
703   Standard_Real TolU = Max(BS.UResolution(Tol), Precision::PConfusion());
704   Standard_Real TolV = Max(BS.VResolution(Tol), Precision::PConfusion());
705   BRepTopAdaptor_FClass2d FClass(BS.Face(), Max(TolU, TolV));
706   //
707   Standard_Boolean isModified = Standard_False;
708   if(exmin > fxmin)
709   {
710     //
711     gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DX()));
712     gp_Pnt aP(fxmin, fymax, fzmax);
713     if(IsModifySize(BS, pl, aP,
714                     umin, umax, vmin, vmax, FClass, TolU, TolV))
715     {
716       fxmin = exmin;
717       isModified = Standard_True;
718     }
719   }
720   if(exmax < fxmax)
721   {
722     //
723     gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DX()));
724     gp_Pnt aP(fxmax, fymin, fzmin);
725     if(IsModifySize(BS, pl, aP,
726                     umin, umax, vmin, vmax, FClass, TolU, TolV))
727     {
728       fxmax = exmax;
729       isModified = Standard_True;
730     }
731   }
732   //
733   if(eymin > fymin)
734   {
735     //
736     gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DY()));
737     gp_Pnt aP(fxmax, fymin, fzmax);
738     if(IsModifySize(BS, pl, aP,
739                     umin, umax, vmin, vmax, FClass, TolU, TolV))
740     {
741       fymin = eymin;
742       isModified = Standard_True;
743     }
744   }
745   if(eymax < fymax)
746   {
747     //
748     gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DY()));
749     gp_Pnt aP(fxmin, fymax, fzmin);
750     if(IsModifySize(BS, pl, aP,
751                     umin, umax, vmin, vmax, FClass, TolU, TolV))
752     {
753       fymax = eymax;
754       isModified = Standard_True;
755     }
756   }
757   //
758   if(ezmin > fzmin)
759   {
760     //
761     gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DZ()));
762     gp_Pnt aP(fxmax, fymax, fzmin);
763     if(IsModifySize(BS, pl, aP,
764                     umin, umax, vmin, vmax, FClass, TolU, TolV))
765     {
766       fzmin = ezmin;
767       isModified = Standard_True;
768     }
769   }
770   if(ezmax < fzmax)
771   {
772     //
773     gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DZ()));
774     gp_Pnt aP(fxmin, fymin, fzmax);
775     if(IsModifySize(BS, pl, aP,
776                     umin, umax, vmin, vmax, FClass, TolU, TolV))
777     {
778       fzmax = ezmax;
779       isModified = Standard_True;
780     }
781   }
782   //
783   if(isModified)
784   {
785     FaceBox.SetVoid();
786     FaceBox.Update(fxmin, fymin, fzmin, fxmax, fymax, fzmax);
787   }
788 }
789