0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / BRepOffset / BRepOffset.cxx
1 // Created on: 1995-10-25
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
18 #include <BRepOffset.hxx>
19 #include <BRep_Tool.hxx>
20 #include <Geom_BSplineSurface.hxx>
21 #include <Geom_ConicalSurface.hxx>
22 #include <Geom_CylindricalSurface.hxx>
23 #include <Geom_OffsetSurface.hxx>
24 #include <Geom_Plane.hxx>
25 #include <Geom_RectangularTrimmedSurface.hxx>
26 #include <Geom_SphericalSurface.hxx>
27 #include <Geom_Surface.hxx>
28 #include <Geom_SurfaceOfLinearExtrusion.hxx>
29 #include <Geom_SurfaceOfRevolution.hxx>
30 #include <Geom_ToroidalSurface.hxx>
31 #include <gp_Ax1.hxx>
32 #include <gp_Ax3.hxx>
33 #include <gp_Dir.hxx>
34 #include <gp_Vec.hxx>
35 #include <NCollection_LocalArray.hxx>
36 #include <Precision.hxx>
37 #include <TopExp.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopoDS.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_ListOfShape.hxx>
43 #include <TopoDS_Vertex.hxx>
44
45 //=======================================================================
46 //function : Surface
47 //purpose  : 
48 //=======================================================================
49 Handle(Geom_Surface) BRepOffset::Surface(const Handle(Geom_Surface)& Surface,
50                                                              const Standard_Real Offset,
51                                          BRepOffset_Status& theStatus,
52                                          Standard_Boolean allowC0)
53 {
54   Standard_Real Tol = Precision::Confusion();
55
56   theStatus = BRepOffset_Good;
57   Handle(Geom_Surface) Result;
58   
59   Handle(Standard_Type) TheType = Surface->DynamicType();
60
61   if (TheType == STANDARD_TYPE(Geom_Plane)) {
62     Handle(Geom_Plane) P =
63       Handle(Geom_Plane)::DownCast(Surface);
64     gp_Vec T = P->Position().XDirection()^P->Position().YDirection();
65     T *= Offset;
66     Result = Handle(Geom_Plane)::DownCast(P->Translated(T));
67   }
68   else if (TheType == STANDARD_TYPE(Geom_CylindricalSurface)) {
69     Handle(Geom_CylindricalSurface) C =
70       Handle(Geom_CylindricalSurface)::DownCast(Surface);
71     Standard_Real Radius = C->Radius();
72     gp_Ax3 Axis = C->Position();
73     if (Axis.Direct()) 
74       Radius += Offset;
75     else 
76       Radius -= Offset;
77     if ( Radius >= Tol ) {
78       Result = new Geom_CylindricalSurface( Axis, Radius);
79     }
80     else if ( Radius <= -Tol ){
81       Axis.Rotate(gp_Ax1(Axis.Location(),Axis.Direction()),M_PI);
82       Result = new Geom_CylindricalSurface( Axis, Abs(Radius));
83       theStatus = BRepOffset_Reversed;
84     }
85     else {
86       theStatus = BRepOffset_Degenerated;
87     }
88   }
89   else if (TheType == STANDARD_TYPE(Geom_ConicalSurface)) {
90     Handle(Geom_ConicalSurface) C =
91       Handle(Geom_ConicalSurface)::DownCast(Surface);
92     Standard_Real Alpha = C->SemiAngle();
93     Standard_Real Radius = C->RefRadius() + Offset * Cos(Alpha);
94     gp_Ax3 Axis = C->Position();
95     if ( Radius >= 0.) {
96       gp_Vec Z( Axis.Direction());
97       Z *= - Offset * Sin(Alpha);
98       Axis.Translate(Z);
99     }
100     else {
101       Radius = -Radius; 
102       gp_Vec Z( Axis.Direction());
103       Z *= - Offset * Sin(Alpha);
104       Axis.Translate(Z);
105       Axis.Rotate(gp_Ax1(Axis.Location(),Axis.Direction()),M_PI);
106       Alpha = -Alpha; 
107     }
108     Result = new Geom_ConicalSurface(Axis, Alpha, Radius);
109   }
110   else if (TheType == STANDARD_TYPE(Geom_SphericalSurface)) {
111     Handle(Geom_SphericalSurface) S = 
112       Handle(Geom_SphericalSurface)::DownCast(Surface);
113     Standard_Real Radius = S->Radius();
114     gp_Ax3 Axis = S->Position();
115     if (Axis.Direct()) 
116       Radius += Offset;
117     else 
118       Radius -= Offset;
119     if ( Radius >= Tol) {
120       Result = new Geom_SphericalSurface(Axis, Radius);
121     }
122     else if ( Radius <= -Tol ) {
123       Axis.Rotate(gp_Ax1(Axis.Location(),Axis.Direction()),M_PI);
124       Axis.ZReverse();
125       Result = new Geom_SphericalSurface(Axis, -Radius);
126       theStatus = BRepOffset_Reversed;
127     }
128     else {
129       theStatus = BRepOffset_Degenerated;
130     }
131   }
132   else if (TheType == STANDARD_TYPE(Geom_ToroidalSurface)) {
133     Handle(Geom_ToroidalSurface) S = 
134       Handle(Geom_ToroidalSurface)::DownCast(Surface);
135     Standard_Real MajorRadius = S->MajorRadius();
136     Standard_Real MinorRadius = S->MinorRadius();
137     gp_Ax3 Axis = S->Position();
138     if (MinorRadius < MajorRadius) {  // A FINIR
139       if (Axis.Direct())
140         MinorRadius += Offset;
141       else 
142         MinorRadius -= Offset;
143       if (MinorRadius >= Tol) {
144         Result = new Geom_ToroidalSurface(Axis,MajorRadius,MinorRadius);
145       }
146       else if (MinorRadius <= -Tol) {
147         theStatus = BRepOffset_Reversed;
148       }
149       else {
150         theStatus = BRepOffset_Degenerated;
151       }
152     }
153   }
154   else if (TheType == STANDARD_TYPE(Geom_SurfaceOfRevolution)) {
155   }
156   else if (TheType == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)) {
157   }
158   else if (TheType == STANDARD_TYPE(Geom_BSplineSurface)) {
159   }
160   else if (TheType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
161     Handle(Geom_RectangularTrimmedSurface) S = 
162       Handle(Geom_RectangularTrimmedSurface)::DownCast(Surface);
163     Standard_Real U1,U2,V1,V2;
164     S->Bounds(U1,U2,V1,V2);
165     Handle(Geom_Surface) Off = BRepOffset::Surface (S->BasisSurface(), Offset, theStatus, allowC0);
166     Result = new Geom_RectangularTrimmedSurface (Off,U1,U2,V1,V2);
167   }
168   else if (TheType == STANDARD_TYPE(Geom_OffsetSurface)) {
169   }
170
171   if ( Result.IsNull()) {
172     Result = new Geom_OffsetSurface( Surface, Offset, allowC0);
173   }
174   
175   return Result;
176 }
177
178 //=======================================================================
179 //function : CollapseSingularities
180 //purpose  : 
181 //=======================================================================
182 Handle(Geom_Surface) BRepOffset::CollapseSingularities (const Handle(Geom_Surface)& theSurface,
183                                                         const TopoDS_Face& theFace,
184                                                         Standard_Real thePrecision)
185 {
186   // check surface type to see if it can be processed
187   Handle(Standard_Type) aType = theSurface->DynamicType();
188   if (aType != STANDARD_TYPE(Geom_BSplineSurface))
189   {
190     // for the moment, only bspline surfaces are treated;
191     // in the future, bezier surfaces and surfaces of revolution can be also handled
192     return theSurface;
193   }
194
195   // find singularities (vertices of degenerated edges)
196   NCollection_List<gp_Pnt> aDegenPnt;
197   NCollection_List<Standard_Real> aDegenTol;
198   for (TopExp_Explorer anExp (theFace, TopAbs_EDGE); anExp.More(); anExp.Next())
199   {
200     TopoDS_Edge anEdge = TopoDS::Edge (anExp.Current());
201     if (! BRep_Tool::Degenerated (anEdge))
202     {
203       continue;
204     }
205     TopoDS_Vertex aV1, aV2;
206     TopExp::Vertices (anEdge, aV1, aV2);
207     if (! aV1.IsSame (aV2))
208     {
209       continue;
210     }
211
212     aDegenPnt.Append (BRep_Tool::Pnt (aV1));
213     aDegenTol.Append (BRep_Tool::Tolerance (aV1));
214   }
215
216   // iterate by sides of the surface
217   if (aType == STANDARD_TYPE(Geom_BSplineSurface))
218   {
219     Handle(Geom_BSplineSurface) aBSpline = Handle(Geom_BSplineSurface)::DownCast (theSurface);
220     const TColgp_Array2OfPnt& aPoles = aBSpline->Poles();
221     
222     Handle(Geom_BSplineSurface) aCopy;
223
224     // iterate by sides: {U=0; V=0; U=1; V=1}
225     Standard_Integer RowStart[4] = {aPoles.LowerRow(), aPoles.LowerRow(), aPoles.UpperRow(), aPoles.LowerRow()};
226     Standard_Integer ColStart[4] = {aPoles.LowerCol(), aPoles.LowerCol(), aPoles.LowerCol(), aPoles.UpperCol()};
227     Standard_Integer RowStep[4]  = {0, 1, 0, 1};
228     Standard_Integer ColStep[4]  = {1, 0, 1, 0};
229     Standard_Integer NbSteps[4]  = {aPoles.RowLength(), aPoles.ColLength(), aPoles.RowLength(), aPoles.ColLength()};
230     for (Standard_Integer iSide = 0; iSide < 4; iSide++)
231     {
232       // compute center of gravity of side poles
233       gp_XYZ aSum;
234       for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
235       {
236         aSum += aPoles (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide]).XYZ();
237       }
238       gp_Pnt aCenter (aSum / NbSteps[iSide]);
239
240       // determine if all poles of the side fit into:
241       Standard_Boolean isCollapsed = Standard_True; // aCenter precisely (with gp::Resolution())
242       Standard_Boolean isSingular = Standard_True;  // aCenter with thePrecision
243       NCollection_LocalArray<Standard_Boolean,4> isDegenerated (aDegenPnt.Extent()); // degenerated vertex
244       for (size_t iDegen = 0; iDegen < isDegenerated.Size(); ++iDegen) isDegenerated[iDegen] = Standard_True;
245       for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
246       {
247         const gp_Pnt& aPole = aPoles (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide]);
248
249         // distance from CG
250         Standard_Real aDistCG = aCenter.Distance (aPole);
251         if (aDistCG > gp::Resolution())
252           isCollapsed = Standard_False;
253         if (aDistCG > thePrecision)
254           isSingular = Standard_False;
255
256         // distances from degenerated points
257         NCollection_List<gp_Pnt>::Iterator aDegPntIt (aDegenPnt);
258         NCollection_List<Standard_Real>::Iterator aDegTolIt(aDegenTol);
259         for (size_t iDegen = 0; iDegen < isDegenerated.Size(); aDegPntIt.Next(), aDegTolIt.Next(), ++iDegen)
260         {
261           if (isDegenerated[iDegen] && aDegPntIt.Value().Distance (aPole) >= aDegTolIt.Value())
262           {
263             isDegenerated[iDegen] = Standard_False;
264           }
265         }
266       }
267       if (isCollapsed)
268       {
269         continue; // already Ok, nothing to be done
270       }
271
272       // decide to collapse the side: either if it is singular with thePrecision,
273       // or if it fits into one (and only one) degenerated point
274       if (! isSingular)
275       {
276         Standard_Integer aNbFit = 0;
277         NCollection_List<gp_Pnt>::Iterator aDegPntIt (aDegenPnt);
278         NCollection_List<Standard_Real>::Iterator aDegTolIt(aDegenTol);
279         for (size_t iDegen = 0; iDegen < isDegenerated.Size(); ++iDegen)
280         {
281           if (isDegenerated[iDegen])
282           {
283             // remove degenerated point as soon as it fits at least one side, to prevent total collapse
284             aDegenPnt.Remove (aDegPntIt);
285             aDegenTol.Remove (aDegTolIt);
286             aNbFit++;
287           }
288           else
289           {
290             aDegPntIt.Next();
291             aDegTolIt.Next();
292           }
293         }
294
295         // if side fits more than one degenerated vertex, do not collapse it
296         // to be on the safe side
297         isSingular = (aNbFit == 1);
298       }
299       
300       // do collapse
301       if (isSingular)
302       {
303         if (aCopy.IsNull())
304         {
305           aCopy = Handle(Geom_BSplineSurface)::DownCast (theSurface->Copy());
306         }
307         for (int iPole = 0; iPole < NbSteps[iSide]; iPole++)
308         {
309           aCopy->SetPole (RowStart[iSide] + iPole * RowStep[iSide], ColStart[iSide] + iPole * ColStep[iSide], aCenter);
310         }
311       }
312     }
313
314     if (! aCopy.IsNull())
315       return aCopy;
316   }
317
318   return theSurface;
319 }