0026252: GeomAdaptor_Surface should use inner adaptor to calculate values of complex...
[occt.git] / src / Geom / Geom_OffsetSurface.cxx
1 // Created on: 1991-06-25
2 // Created by: JCV
3 // Copyright (c) 1991-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     04/10/96 : JCT : derivee des surfaces offset utilisation de
18 //                               CSLib
19 // Modified     15/11/96 : JPI : ajout equivalent surface pour les surfaces canoniques et modif des methodes D0 D1, ... UIso,VIso
20 // Modified     18/11/96 : JPI : inversion de l'offsetValue dans UReverse et Vreverse
21
22 #include <AdvApprox_ApproxAFunction.hxx>
23 #include <BSplCLib.hxx>
24 #include <BSplSLib.hxx>
25 #include <Convert_GridPolynomialToPoles.hxx>
26 #include <CSLib.hxx>
27 #include <Geom_BezierSurface.hxx>
28 #include <Geom_BSplineCurve.hxx>
29 #include <Geom_BSplineSurface.hxx>
30 #include <Geom_Circle.hxx>
31 #include <Geom_ConicalSurface.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_CylindricalSurface.hxx>
34 #include <Geom_ElementarySurface.hxx>
35 #include <Geom_Ellipse.hxx>
36 #include <Geom_Geometry.hxx>
37 #include <Geom_OffsetCurve.hxx>
38 #include <Geom_OffsetSurface.hxx>
39 #include <Geom_Plane.hxx>
40 #include <Geom_RectangularTrimmedSurface.hxx>
41 #include <Geom_SphericalSurface.hxx>
42 #include <Geom_Surface.hxx>
43 #include <Geom_SurfaceOfLinearExtrusion.hxx>
44 #include <Geom_SurfaceOfRevolution.hxx>
45 #include <Geom_ToroidalSurface.hxx>
46 #include <Geom_TrimmedCurve.hxx>
47 #include <Geom_UndefinedDerivative.hxx>
48 #include <Geom_UndefinedValue.hxx>
49 #include <GeomAbs_CurveType.hxx>
50 #include <GeomAbs_IsoType.hxx>
51 #include <GeomAbs_Shape.hxx>
52 #include <GeomEvaluator_OffsetSurface.hxx>
53 #include <gp.hxx>
54 #include <gp_Dir.hxx>
55 #include <gp_GTrsf2d.hxx>
56 #include <gp_Pnt.hxx>
57 #include <gp_Trsf.hxx>
58 #include <gp_Vec.hxx>
59 #include <gp_XYZ.hxx>
60 #include <Precision.hxx>
61 #include <Standard_ConstructionError.hxx>
62 #include <Standard_NoSuchObject.hxx>
63 #include <Standard_NotImplemented.hxx>
64 #include <Standard_RangeError.hxx>
65 #include <Standard_Type.hxx>
66 #include <TColgp_Array1OfPnt.hxx>
67 #include <TColgp_Array2OfVec.hxx>
68 #include <TColgp_HArray2OfPnt.hxx>
69 #include <TColStd_Array1OfInteger.hxx>
70 #include <TColStd_Array1OfReal.hxx>
71 #include <TColStd_HArray1OfInteger.hxx>
72 #include <TColStd_HArray1OfReal.hxx>
73 #include <TColStd_HArray2OfInteger.hxx>
74
75 static const Standard_Real MyAngularToleranceForG1 = Precision::Angular();
76
77
78 //=======================================================================
79 //function : Copy
80 //purpose  : 
81 //=======================================================================
82
83 Handle(Geom_Geometry) Geom_OffsetSurface::Copy () const
84 {
85   Handle(Geom_OffsetSurface) S(new Geom_OffsetSurface(basisSurf, offsetValue, Standard_True));
86   return S;
87 }
88
89 //=======================================================================
90 //function : Geom_OffsetSurface
91 //purpose  : Basis surface cannot be an Offset surface or trimmed from
92 //            offset surface.
93 //=======================================================================
94
95 Geom_OffsetSurface::Geom_OffsetSurface (const Handle(Geom_Surface)& theSurf, 
96   const Standard_Real theOffset,
97   const Standard_Boolean isNotCheckC0) 
98   : offsetValue (theOffset) 
99 {
100   SetBasisSurface(theSurf, isNotCheckC0);
101 }
102
103 //=======================================================================
104 //function : SetBasisSurface
105 //purpose  : 
106 //=======================================================================
107
108 void Geom_OffsetSurface::SetBasisSurface (const Handle(Geom_Surface)& S,
109   const Standard_Boolean isNotCheckC0)
110 {
111   Standard_Real aUf, aUl, aVf, aVl;
112   S->Bounds(aUf, aUl, aVf, aVl);
113
114   Handle(Geom_Surface) aCheckingSurf = Handle(Geom_Surface)::DownCast(S->Copy());
115   Standard_Boolean isTrimmed = Standard_False;
116
117   while(aCheckingSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)) ||
118         aCheckingSurf->IsKind(STANDARD_TYPE(Geom_OffsetSurface)))
119   {
120     if (aCheckingSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
121     {
122       Handle(Geom_RectangularTrimmedSurface) aTrimS = 
123         Handle(Geom_RectangularTrimmedSurface)::DownCast(aCheckingSurf);
124       aCheckingSurf = aTrimS->BasisSurface();
125       isTrimmed = Standard_True;
126     }
127
128     if (aCheckingSurf->IsKind(STANDARD_TYPE(Geom_OffsetSurface)))
129     {
130       Handle(Geom_OffsetSurface) aOS = 
131         Handle(Geom_OffsetSurface)::DownCast(aCheckingSurf);
132       aCheckingSurf = aOS->BasisSurface();
133       offsetValue += aOS->Offset();
134     }
135   }
136
137   myBasisSurfContinuity = aCheckingSurf->Continuity();
138
139   Standard_Boolean isC0 = !isNotCheckC0 && (myBasisSurfContinuity == GeomAbs_C0);
140
141   // Basis surface must be at least C1
142   if (isC0)
143   {
144     Handle(Geom_Curve) aCurve;
145
146     if (aCheckingSurf->IsKind(STANDARD_TYPE(Geom_SurfaceOfRevolution)))
147     {
148       Handle(Geom_SurfaceOfRevolution) aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aCheckingSurf);
149       aCurve = aRevSurf->BasisCurve();
150     }
151     else if (aCheckingSurf->IsKind(STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)))
152     {
153       Handle(Geom_SurfaceOfLinearExtrusion) aLESurf = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(aCheckingSurf);
154       aCurve = aLESurf->BasisCurve();
155     }
156
157     if(!aCurve.IsNull())
158     {
159       while(aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)) ||
160             aCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
161       {
162         if (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
163         {
164           Handle(Geom_TrimmedCurve) aTrimC = 
165             Handle(Geom_TrimmedCurve)::DownCast(aCurve);
166           aCurve = aTrimC->BasisCurve();
167         }
168
169         if (aCurve->IsKind(STANDARD_TYPE(Geom_OffsetCurve)))
170         {
171           Handle(Geom_OffsetCurve) aOC = 
172             Handle(Geom_OffsetCurve)::DownCast(aCurve);
173           aCurve = aOC->BasisCurve();
174         }
175       }
176     }
177
178     const Standard_Real aUIsoPar = (aUf + aUl)/2.0, aVIsoPar = (aVf + aVl)/2.0;
179     Standard_Boolean isUG1 = Standard_False, isVG1 = Standard_False;
180  
181     const Handle(Geom_Curve) aCurv1 = aCurve.IsNull() ? aCheckingSurf->UIso(aUIsoPar) : aCurve;
182     const Handle(Geom_Curve) aCurv2 = aCheckingSurf->VIso(aVIsoPar);
183     isUG1 = !aCurv1->IsKind(STANDARD_TYPE(Geom_BSplineCurve));
184     isVG1 = !aCurv2->IsKind(STANDARD_TYPE(Geom_BSplineCurve));
185
186     if(!isUG1)
187     {
188       Handle(Geom_BSplineCurve) aBC = Handle(Geom_BSplineCurve)::DownCast(aCurv1);
189       isUG1 = aBC->IsG1(aVf, aVl, MyAngularToleranceForG1);
190     }
191     //
192     if(!isVG1)
193     {
194       Handle(Geom_BSplineCurve) aBC = Handle(Geom_BSplineCurve)::DownCast(aCurv2);
195       isVG1 = aBC->IsG1(aUf, aUl, MyAngularToleranceForG1);
196     }
197     //
198     if(isUG1 && isVG1) 
199     {
200       myBasisSurfContinuity = GeomAbs_G1;
201       isC0 = Standard_False;
202     }
203
204     // Raise exception if still C0
205     if (isC0)
206       Standard_ConstructionError::Raise("Offset with no C1 Surface");
207   }
208
209   if(isTrimmed)
210   {
211     basisSurf = 
212       new Geom_RectangularTrimmedSurface(aCheckingSurf, aUf, aUl, aVf, aVl);
213   }
214   else
215   {
216     basisSurf = aCheckingSurf;
217   }
218   
219   equivSurf = Surface();
220
221   if (basisSurf->IsKind(STANDARD_TYPE(Geom_BSplineSurface)) ||
222       basisSurf->IsKind(STANDARD_TYPE(Geom_BezierSurface)))
223   {
224     // Tolerance en dur pour l'instant ,mais on devrait la proposer dans le constructeur
225     // et la mettre en champ, on pourrait utiliser par exemple pour l'extraction d'iso 
226     // et aussi pour les singularite. Pour les surfaces osculatrices, on l'utilise pour
227     // detecter si une iso est degeneree.
228     const Standard_Real Tol = Precision::Confusion(); //0.0001;
229     myOscSurf = new Geom_OsculatingSurface(basisSurf, Tol);
230   }
231
232   // Surface value calculator
233   if (equivSurf.IsNull())
234     myEvaluator = new GeomEvaluator_OffsetSurface(basisSurf, offsetValue, myOscSurf);
235 }
236
237 //=======================================================================
238 //function : SetOffsetValue
239 //purpose  : 
240 //=======================================================================
241
242 void Geom_OffsetSurface::SetOffsetValue (const Standard_Real D)
243 {
244   offsetValue = D;
245   equivSurf = Surface();
246   if (equivSurf.IsNull())
247   {
248     if (myEvaluator.IsNull())
249       myEvaluator = new GeomEvaluator_OffsetSurface(basisSurf, offsetValue, myOscSurf);
250     else
251       myEvaluator->SetOffsetValue(offsetValue);
252   }
253 }
254
255 //=======================================================================
256 //function : UReverse
257 //purpose  : 
258 //=======================================================================
259
260 void Geom_OffsetSurface::UReverse ()
261 {
262   basisSurf->UReverse();
263   offsetValue = -offsetValue;
264   if (!equivSurf.IsNull())
265     equivSurf->UReverse();
266   else
267     myEvaluator->SetOffsetValue(offsetValue);
268 }
269
270 //=======================================================================
271 //function : UReversedParameter
272 //purpose  : 
273 //=======================================================================
274
275 Standard_Real Geom_OffsetSurface::UReversedParameter(const Standard_Real U) const
276 {
277   return basisSurf->UReversedParameter(U);
278 }
279
280 //=======================================================================
281 //function : VReverse
282 //purpose  : 
283 //=======================================================================
284
285 void Geom_OffsetSurface::VReverse ()
286 {
287   basisSurf->VReverse();
288   offsetValue = -offsetValue;
289   if (!equivSurf.IsNull())
290     equivSurf->VReverse();
291   else
292     myEvaluator->SetOffsetValue(offsetValue);
293 }
294
295 //=======================================================================
296 //function : VReversedParameter
297 //purpose  : 
298 //=======================================================================
299
300 Standard_Real Geom_OffsetSurface::VReversedParameter(const Standard_Real V) const
301 {
302   return basisSurf->VReversedParameter(V);
303 }
304
305 //=======================================================================
306 //function : Bounds
307 //purpose  : 
308 //=======================================================================
309
310 void Geom_OffsetSurface::Bounds (Standard_Real& U1, Standard_Real& U2, 
311                                  Standard_Real& V1, Standard_Real& V2) const
312 {
313   basisSurf->Bounds (U1, U2 ,V1, V2);
314 }
315
316 //=======================================================================
317 //function : Continuity
318 //purpose  : 
319 //=======================================================================
320
321 GeomAbs_Shape Geom_OffsetSurface::Continuity () const
322 {
323   switch (myBasisSurfContinuity) {
324     case GeomAbs_C2 : return GeomAbs_C1;
325     case GeomAbs_C3 : return GeomAbs_C2;
326     case GeomAbs_CN : return GeomAbs_CN;
327     default : break;
328   }
329   return GeomAbs_C0;
330 }
331
332 //=======================================================================
333 //function : D0
334 //purpose  : 
335 //=======================================================================
336
337 void Geom_OffsetSurface::D0 (const Standard_Real U, const Standard_Real V, gp_Pnt& P) const
338 {
339 #ifdef CHECK  
340   if (myBasisSurfContinuity == GeomAbs_C0)
341     Geom_UndefinedValue::Raise();
342 #endif
343   if (equivSurf.IsNull())
344     myEvaluator->D0(U, V, P);
345   else
346     equivSurf->D0(U,V,P);
347 }
348
349 //=======================================================================
350 //function : D1
351 //purpose  : 
352 //=======================================================================
353
354 void Geom_OffsetSurface::D1 (const Standard_Real U, const Standard_Real V, 
355   gp_Pnt& P, 
356   gp_Vec& D1U, gp_Vec& D1V) const 
357 {
358 #ifdef CHECK  
359   if (myBasisSurfContinuity == GeomAbs_C0 ||
360       myBasisSurfContinuity == GeomAbs_C1)
361     Geom_UndefinedDerivative::Raise();
362 #endif
363   if (equivSurf.IsNull())
364     myEvaluator->D1(U, V, P, D1U, D1V);
365   else
366     equivSurf->D1(U,V,P,D1U,D1V);
367 }
368
369 //=======================================================================
370 //function : D2
371 //purpose  : 
372 //=======================================================================
373
374 void Geom_OffsetSurface::D2 (const Standard_Real U, const Standard_Real V, 
375   gp_Pnt& P, 
376   gp_Vec& D1U, gp_Vec& D1V,
377   gp_Vec& D2U, gp_Vec& D2V, gp_Vec& D2UV) const
378 {
379 #ifdef CHECK  
380   if (myBasisSurfContinuity == GeomAbs_C0 ||
381       myBasisSurfContinuity == GeomAbs_C1 ||
382       myBasisSurfContinuity == GeomAbs_C2)
383     Geom_UndefinedDerivative::Raise();
384 #endif
385   if (equivSurf.IsNull())
386     myEvaluator->D2(U, V, P, D1U, D1V, D2U, D2V, D2UV);
387   else
388     equivSurf->D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
389 }
390
391 //=======================================================================
392 //function : D3
393 //purpose  : 
394 //=======================================================================
395
396 void Geom_OffsetSurface::D3 (const Standard_Real U, const Standard_Real V,
397   gp_Pnt& P, 
398   gp_Vec& D1U, gp_Vec& D1V, 
399   gp_Vec& D2U, gp_Vec& D2V, gp_Vec& D2UV,
400   gp_Vec& D3U, gp_Vec& D3V, gp_Vec& D3UUV, gp_Vec& D3UVV) const
401 {
402 #ifdef CHECK  
403   if (!(basisSurf->IsCNu (4) && basisSurf->IsCNv (4))) { 
404     Geom_UndefinedDerivative::Raise();
405   }
406 #endif
407   if (equivSurf.IsNull())
408     myEvaluator->D3(U, V, P, D1U, D1V, D2U, D2V, D2UV, D3U, D3V, D3UUV, D3UVV);
409   else
410     equivSurf->D3(U,V,P,D1U,D1V,D2U,D2V,D2UV,D3U,D3V,D3UUV,D3UVV);
411 }
412
413 //=======================================================================
414 //function : DN
415 //purpose  : 
416 //=======================================================================
417
418 gp_Vec Geom_OffsetSurface::DN (const Standard_Real    U, const Standard_Real    V,
419   const Standard_Integer Nu, const Standard_Integer Nv) const
420 {
421   Standard_RangeError_Raise_if (Nu < 0 || Nv < 0 || Nu + Nv < 1, " ");
422 #ifdef CHECK  
423   if (!(basisSurf->IsCNu (Nu) && basisSurf->IsCNv (Nv))) { 
424     Geom_UndefinedDerivative::Raise();
425   }
426 #endif  
427   gp_Vec D(0,0,0);
428
429   if (equivSurf.IsNull())
430     D = myEvaluator->DN(U, V, Nu, Nv);
431   else
432     D = equivSurf->DN(U,V,Nu,Nv);
433   return D; 
434 }
435
436
437 ////*************************************************
438 ////
439 ////   EVALUATOR FOR THE ISO-CURVE APPROXIMATION
440 ////
441 ////*************************************************
442
443 class Geom_OffsetSurface_UIsoEvaluator : public AdvApprox_EvaluatorFunction
444 {
445 public:
446   Geom_OffsetSurface_UIsoEvaluator (const Handle(Geom_Surface)& theSurface, const Standard_Real theU)
447     : CurrentSurface(theSurface), IsoPar(theU) {}
448
449   virtual void Evaluate (Standard_Integer *Dimension,
450     Standard_Real     StartEnd[2],
451     Standard_Real    *Parameter,
452     Standard_Integer *DerivativeRequest,
453     Standard_Real    *Result, // [Dimension]
454     Standard_Integer *ErrorCode);
455
456 private:
457   Handle(Geom_Surface) CurrentSurface;
458   Standard_Real IsoPar;
459 };
460
461 void Geom_OffsetSurface_UIsoEvaluator::Evaluate(Standard_Integer *,/*Dimension*/
462   Standard_Real     /*StartEnd*/[2],
463   Standard_Real    *Parameter,
464   Standard_Integer *DerivativeRequest,
465   Standard_Real    *Result,
466   Standard_Integer *ReturnCode) 
467
468   gp_Pnt P;
469   if (*DerivativeRequest == 0) {
470     P = CurrentSurface->Value(IsoPar,*Parameter);
471     Result[0] = P.X();
472     Result[1] = P.Y();
473     Result[2] = P.Z();
474   }
475   else {
476     gp_Vec DU,DV;
477     CurrentSurface->D1(IsoPar,*Parameter,P,DU,DV);
478     Result[0] = DV.X();
479     Result[1] = DV.Y();
480     Result[2] = DV.Z();
481   }
482   *ReturnCode = 0;
483 }
484
485 class Geom_OffsetSurface_VIsoEvaluator : public AdvApprox_EvaluatorFunction
486 {
487 public:
488   Geom_OffsetSurface_VIsoEvaluator (const Handle(Geom_Surface)& theSurface, const Standard_Real theV)
489     : CurrentSurface(theSurface), IsoPar(theV) {}
490
491   virtual void Evaluate (Standard_Integer *Dimension,
492     Standard_Real     StartEnd[2],
493     Standard_Real    *Parameter,
494     Standard_Integer *DerivativeRequest,
495     Standard_Real    *Result, // [Dimension]
496     Standard_Integer *ErrorCode);
497
498 private:
499   Handle(Geom_Surface) CurrentSurface;
500   Standard_Real IsoPar;
501 };
502
503 void Geom_OffsetSurface_VIsoEvaluator::Evaluate(Standard_Integer *,/*Dimension*/
504   Standard_Real     /*StartEnd*/[2],
505   Standard_Real    *Parameter,
506   Standard_Integer *DerivativeRequest,
507   Standard_Real    *Result,
508   Standard_Integer *ReturnCode) 
509
510   gp_Pnt P;
511   if (*DerivativeRequest == 0) {
512     P = CurrentSurface->Value(*Parameter,IsoPar);
513     Result[0] = P.X();
514     Result[1] = P.Y();
515     Result[2] = P.Z();
516   }
517   else {
518     gp_Vec DU,DV;
519     CurrentSurface->D1(*Parameter,IsoPar,P,DU,DV);
520     Result[0] = DU.X();
521     Result[1] = DU.Y();
522     Result[2] = DU.Z();
523   }
524   *ReturnCode = 0;
525 }
526
527 //=======================================================================
528 //function : UIso
529 //purpose  : The Uiso or the VIso of an OffsetSurface can't be clearly 
530 //           exprimed as a curve from Geom. So, to extract the U or VIso
531 //           an Approximation is needed. This approx always will return a 
532 //           BSplineCurve from Geom.
533 //=======================================================================
534
535 Handle(Geom_Curve) Geom_OffsetSurface::UIso (const Standard_Real UU) const 
536 {
537   if (equivSurf.IsNull()) {
538     const Standard_Integer Num1 = 0, Num2 = 0, Num3 = 1;
539     Handle(TColStd_HArray1OfReal) T1, T2, T3 = new TColStd_HArray1OfReal(1,Num3);
540     T3->Init(Precision::Approximation());
541     Standard_Real U1,U2,V1,V2;
542     Bounds(U1,U2,V1,V2);
543     const GeomAbs_Shape Cont = GeomAbs_C1;
544     const Standard_Integer MaxSeg = 100, MaxDeg = 14;
545
546     Handle(Geom_OffsetSurface) me (this);
547     Geom_OffsetSurface_UIsoEvaluator ev (me, UU);
548     AdvApprox_ApproxAFunction Approx(Num1, Num2, Num3, T1, T2, T3,
549       V1, V2, Cont, MaxDeg, MaxSeg, ev);
550
551     Standard_ConstructionError_Raise_if (!Approx.IsDone(), " Geom_OffsetSurface : UIso");
552
553     const Standard_Integer NbPoles = Approx.NbPoles();
554
555     TColgp_Array1OfPnt      Poles( 1, NbPoles);
556     TColStd_Array1OfReal    Knots( 1, Approx.NbKnots());
557     TColStd_Array1OfInteger Mults( 1, Approx.NbKnots());
558
559     Approx.Poles(1, Poles);
560     Knots = Approx.Knots()->Array1();
561     Mults = Approx.Multiplicities()->Array1();
562
563     Handle(Geom_BSplineCurve) C = 
564       new Geom_BSplineCurve( Poles, Knots, Mults, Approx.Degree());
565     return C;
566   }
567   else
568     return equivSurf->UIso(UU);
569 }
570
571 //=======================================================================
572 //function : VIso
573 //purpose  : 
574 //=======================================================================
575
576 Handle(Geom_Curve) Geom_OffsetSurface::VIso (const Standard_Real VV) const 
577 {
578   if (equivSurf.IsNull()) {
579     const Standard_Integer Num1 = 0, Num2 = 0, Num3 = 1;
580     Handle(TColStd_HArray1OfReal) T1, T2, T3 = new TColStd_HArray1OfReal(1,Num3);
581     T3->Init(Precision::Approximation());
582     Standard_Real U1,U2,V1,V2;
583     Bounds(U1,U2,V1,V2);
584     const GeomAbs_Shape Cont = GeomAbs_C1;
585     const Standard_Integer MaxSeg = 100, MaxDeg = 14;
586
587     Handle(Geom_OffsetSurface) me (this);
588     Geom_OffsetSurface_VIsoEvaluator ev (me, VV);
589     AdvApprox_ApproxAFunction Approx (Num1, Num2, Num3, T1, T2, T3,
590       U1, U2, Cont, MaxDeg, MaxSeg, ev);
591
592     Standard_ConstructionError_Raise_if (!Approx.IsDone(), " Geom_OffsetSurface : VIso");
593
594     TColgp_Array1OfPnt      Poles( 1, Approx.NbPoles());
595     TColStd_Array1OfReal    Knots( 1, Approx.NbKnots());
596     TColStd_Array1OfInteger Mults( 1, Approx.NbKnots());
597
598     Approx.Poles(1, Poles);
599     Knots = Approx.Knots()->Array1();
600     Mults = Approx.Multiplicities()->Array1();
601
602     Handle(Geom_BSplineCurve) C = 
603       new Geom_BSplineCurve( Poles, Knots, Mults, Approx.Degree());
604     return C;
605   }
606   else
607     return equivSurf->VIso(VV);
608 }
609
610 //=======================================================================
611 //function : IsCNu
612 //purpose  : 
613 //=======================================================================
614
615 Standard_Boolean Geom_OffsetSurface::IsCNu (const Standard_Integer N) const
616 {
617   Standard_RangeError_Raise_if (N < 0, " ");
618   return basisSurf->IsCNu (N+1);
619 }
620
621 //=======================================================================
622 //function : IsCNv
623 //purpose  : 
624 //=======================================================================
625
626 Standard_Boolean Geom_OffsetSurface::IsCNv (const Standard_Integer N) const
627 {
628   Standard_RangeError_Raise_if (N < 0, " ");
629   return basisSurf->IsCNv (N+1);
630 }
631
632 //=======================================================================
633 //function : IsUPeriodic
634 //purpose  : 
635 //=======================================================================
636
637 Standard_Boolean Geom_OffsetSurface::IsUPeriodic () const 
638 {
639   return basisSurf->IsUPeriodic();
640 }
641
642 //=======================================================================
643 //function : UPeriod
644 //purpose  : 
645 //=======================================================================
646
647 Standard_Real Geom_OffsetSurface::UPeriod() const
648 {
649   return basisSurf->UPeriod();
650 }
651
652 //=======================================================================
653 //function : IsVPeriodic
654 //purpose  : 
655 //=======================================================================
656
657 Standard_Boolean Geom_OffsetSurface::IsVPeriodic () const 
658 {
659   return basisSurf->IsVPeriodic();
660 }
661
662 //=======================================================================
663 //function : VPeriod
664 //purpose  : 
665 //=======================================================================
666
667 Standard_Real Geom_OffsetSurface::VPeriod() const
668 {
669   return basisSurf->VPeriod();
670 }
671
672 //=======================================================================
673 //function : IsUClosed
674 //purpose  : 
675 //=======================================================================
676
677 Standard_Boolean Geom_OffsetSurface::IsUClosed () const
678 {
679   Standard_Boolean UClosed;
680   Handle(Geom_Surface) SBasis = BasisSurface();
681
682   if (SBasis->IsKind (STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
683     Handle(Geom_RectangularTrimmedSurface) St = 
684       Handle(Geom_RectangularTrimmedSurface)::DownCast(SBasis);
685
686     Handle(Geom_Surface) S = Handle(Geom_Surface)::DownCast(St->BasisSurface());
687     if (S->IsKind (STANDARD_TYPE(Geom_ElementarySurface))) {
688       UClosed = SBasis->IsUClosed();
689     }
690     else if (S->IsKind (STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) { 
691       Handle(Geom_SurfaceOfLinearExtrusion) Extru = 
692         Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(S);
693
694       Handle(Geom_Curve) C = Extru->BasisCurve();
695       if (C->IsKind (STANDARD_TYPE(Geom_Circle)) || C->IsKind (STANDARD_TYPE(Geom_Ellipse))) {
696         UClosed = SBasis->IsUClosed();
697       }
698       else { UClosed = Standard_False; }
699     }
700     else if (S->IsKind (STANDARD_TYPE(Geom_SurfaceOfRevolution))) { 
701       UClosed = SBasis->IsUClosed();
702     }
703     else { UClosed = Standard_False; }
704   }
705   else {
706     if (SBasis->IsKind (STANDARD_TYPE(Geom_ElementarySurface))) {
707       UClosed = SBasis->IsUClosed();
708     }
709     else if (SBasis->IsKind (STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) { 
710       Handle(Geom_SurfaceOfLinearExtrusion) Extru = 
711         Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(SBasis);
712
713       Handle(Geom_Curve) C = Extru->BasisCurve();
714       UClosed = (C->IsKind(STANDARD_TYPE(Geom_Circle)) || C->IsKind(STANDARD_TYPE(Geom_Ellipse)));
715     }
716     else if (SBasis->IsKind (STANDARD_TYPE(Geom_SurfaceOfRevolution))) { 
717       UClosed = Standard_True; 
718     }
719     else { UClosed = Standard_False; }
720   }  
721   return UClosed;
722 }
723
724 //=======================================================================
725 //function : IsVClosed
726 //purpose  : 
727 //=======================================================================
728
729 Standard_Boolean Geom_OffsetSurface::IsVClosed () const
730 {
731   Standard_Boolean VClosed;
732   Handle(Geom_Surface) SBasis = BasisSurface();
733
734   if (SBasis->IsKind (STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
735     Handle(Geom_RectangularTrimmedSurface) St = 
736       Handle(Geom_RectangularTrimmedSurface)::DownCast(SBasis);
737
738     Handle(Geom_Surface) S = Handle(Geom_Surface)::DownCast(St->BasisSurface());
739     if (S->IsKind (STANDARD_TYPE(Geom_ElementarySurface))) {
740       VClosed = SBasis->IsVClosed();
741     }
742     else { VClosed = Standard_False; }
743   }
744   else {
745     if (SBasis->IsKind (STANDARD_TYPE(Geom_ElementarySurface))) {
746       VClosed = SBasis->IsVClosed();
747     }
748     else { VClosed = Standard_False; }
749   }
750   return VClosed;
751 }
752
753 //=======================================================================
754 //function : Transform
755 //purpose  : 
756 //=======================================================================
757
758 void Geom_OffsetSurface::Transform (const gp_Trsf& T)
759 {
760   basisSurf->Transform (T);
761   offsetValue *= T.ScaleFactor();
762   equivSurf.Nullify();
763   if (myEvaluator.IsNull())
764     myEvaluator = new GeomEvaluator_OffsetSurface(basisSurf, offsetValue, myOscSurf);
765   else
766     myEvaluator->SetOffsetValue(offsetValue);
767 }
768
769 //=======================================================================
770 //function : TransformParameters
771 //purpose  : 
772 //=======================================================================
773
774 void Geom_OffsetSurface::TransformParameters(Standard_Real& U, Standard_Real& V,
775   const gp_Trsf& T) const
776 {
777   basisSurf->TransformParameters(U,V,T);
778   if(!equivSurf.IsNull()) equivSurf->TransformParameters(U,V,T);
779 }
780
781 //=======================================================================
782 //function : ParametricTransformation
783 //purpose  : 
784 //=======================================================================
785
786 gp_GTrsf2d Geom_OffsetSurface::ParametricTransformation (const gp_Trsf& T) const
787 {
788   return basisSurf->ParametricTransformation(T);
789 }
790
791 //=======================================================================
792 //function : Surface
793 //purpose  : Trouve si elle existe, une surface non offset, equivalente
794 //           a l'offset surface.
795 //=======================================================================
796
797 Handle(Geom_Surface) Geom_OffsetSurface::Surface() const 
798 {
799   if (offsetValue == 0.0) return  basisSurf; // Cas direct 
800
801   Standard_Real Tol = Precision::Confusion();
802   Handle(Geom_Surface) Result, Base;
803   Result.Nullify();
804   Handle(Standard_Type) TheType = basisSurf->DynamicType();
805   Standard_Boolean IsTrimmed;
806   Standard_Real U1 = 0., V1 = 0., U2 = 0., V2 = 0.;
807
808   // Preambule pour les surface trimmes
809   if (TheType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
810     Handle(Geom_RectangularTrimmedSurface) S = 
811       Handle(Geom_RectangularTrimmedSurface)::DownCast(basisSurf);
812     Base = S->BasisSurface();
813     TheType = Base->DynamicType();
814     S->Bounds(U1,U2,V1,V2);  
815     IsTrimmed = Standard_True;
816   }
817   else {
818     IsTrimmed = Standard_False;
819     Base = basisSurf;
820   }
821
822   // Traite les surfaces cannonique
823   if (TheType == STANDARD_TYPE(Geom_Plane)) 
824   {
825     Handle(Geom_Plane) P =
826       Handle(Geom_Plane)::DownCast(Base);
827     gp_Vec T = P->Position().XDirection()^P->Position().YDirection();
828     T *= offsetValue;
829     Result = Handle(Geom_Plane)::DownCast(P->Translated(T));
830   }
831   else if (TheType == STANDARD_TYPE(Geom_CylindricalSurface)) 
832   {
833     Handle(Geom_CylindricalSurface) C =
834       Handle(Geom_CylindricalSurface)::DownCast(Base);
835     Standard_Real Radius = C->Radius();
836     gp_Ax3 Axis = C->Position();
837     if (Axis.Direct()) 
838       Radius += offsetValue;
839     else 
840       Radius -= offsetValue;
841     if ( Radius >= Tol ) {
842       Result = new Geom_CylindricalSurface( Axis, Radius);
843     }
844     else if ( Radius <= -Tol ){
845       Axis.Rotate(gp_Ax1(Axis.Location(),Axis.Direction()),M_PI);
846       Result = new Geom_CylindricalSurface( Axis, Abs(Radius));
847       Result->UReverse();
848     }
849     else 
850     {
851       // surface degeneree      
852     }
853   }
854   else if (TheType == STANDARD_TYPE(Geom_ConicalSurface)) 
855   {
856     Handle(Geom_ConicalSurface) C =
857       Handle(Geom_ConicalSurface)::DownCast(Base);
858     gp_Ax3 anAxis = C->Position();
859     Standard_Boolean isDirect = anAxis.Direct();
860     Standard_Real anAlpha = C->SemiAngle();
861     Standard_Real aRadius;
862     if (isDirect)
863     {
864       aRadius = C->RefRadius() + offsetValue * Cos (anAlpha);
865     }
866     else
867     {
868       aRadius = C->RefRadius() - offsetValue * Cos (anAlpha);
869     }
870     if (aRadius >= 0.)
871     {
872       gp_Vec aZ (anAxis.Direction());
873       if (isDirect)
874       {
875         aZ *= -offsetValue * Sin (anAlpha);
876       }
877       else
878       {
879         aZ *=  offsetValue * Sin (anAlpha);
880       }
881       anAxis.Translate (aZ);
882       Result = new Geom_ConicalSurface (anAxis, anAlpha, aRadius);
883     }
884     else
885     {
886       // surface degeneree      
887     }
888   }
889   else if (TheType == STANDARD_TYPE(Geom_SphericalSurface)) {
890     Handle(Geom_SphericalSurface) S = 
891       Handle(Geom_SphericalSurface)::DownCast(Base);
892     Standard_Real Radius = S->Radius();
893     gp_Ax3 Axis = S->Position();
894     if (Axis.Direct()) 
895       Radius += offsetValue;
896     else 
897       Radius -= offsetValue;
898     if ( Radius >= Tol) {
899       Result = new Geom_SphericalSurface(Axis, Radius);
900     }
901     else if ( Radius <= -Tol ) {
902       Axis.Rotate(gp_Ax1(Axis.Location(),Axis.Direction()),M_PI);
903       Axis.ZReverse();
904       Result = new Geom_SphericalSurface(Axis, -Radius);
905       Result->UReverse();
906     }
907     else {
908       //      surface degeneree
909     }
910   }
911   else if (TheType == STANDARD_TYPE(Geom_ToroidalSurface)) 
912
913   {
914     Handle(Geom_ToroidalSurface) 
915       S = Handle(Geom_ToroidalSurface)::DownCast(Base);
916     Standard_Real MajorRadius = S->MajorRadius();
917     Standard_Real MinorRadius = S->MinorRadius();
918     gp_Ax3 Axis = S->Position();
919     if (MinorRadius <= MajorRadius) 
920     {  
921       if (Axis.Direct())
922         MinorRadius += offsetValue;
923       else 
924         MinorRadius -= offsetValue;
925       if (MinorRadius >= Tol) 
926         Result = new Geom_ToroidalSurface(Axis,MajorRadius,MinorRadius);
927       //      else if (MinorRadius <= -Tol) 
928       //        Result->UReverse();
929       else 
930       {
931         //      surface degeneree
932       }
933     }
934   }
935
936   // S'il le faut on trimme le resultat
937   if (IsTrimmed && !Result.IsNull()) {
938     Base = Result;
939     Result = new Geom_RectangularTrimmedSurface (Base, U1, U2, V1,V2);
940   }
941
942   return Result;
943 }
944
945 //=======================================================================
946 //function : UOsculatingSurface
947 //purpose  : 
948 //=======================================================================
949
950 Standard_Boolean Geom_OffsetSurface::UOsculatingSurface(const Standard_Real U, const Standard_Real V,
951   Standard_Boolean& t, Handle(Geom_BSplineSurface)& L) const
952 {
953   return !myOscSurf.IsNull() && myOscSurf->UOscSurf(U,V,t,L);
954 }
955
956 //=======================================================================
957 //function : VOsculatingSurface
958 //purpose  : 
959 //=======================================================================
960
961 Standard_Boolean Geom_OffsetSurface::VOsculatingSurface(const Standard_Real U, const Standard_Real V,
962   Standard_Boolean& t, Handle(Geom_BSplineSurface)& L) const
963 {
964   return !myOscSurf.IsNull() && myOscSurf->VOscSurf(U, V, t, L);
965 }