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