1 // Created on: 2015-09-21
2 // Copyright (c) 2015 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <GeomEvaluator_OffsetSurface.hxx>
17 #include <GeomAdaptor_HSurface.hxx>
19 #include <CSLib_NormalStatus.hxx>
20 #include <Geom_BezierSurface.hxx>
21 #include <Geom_BSplineSurface.hxx>
22 #include <Geom_UndefinedValue.hxx>
23 #include <GeomAdaptor_HSurface.hxx>
25 #include <Standard_RangeError.hxx>
26 #include <Standard_NumericError.hxx>
28 IMPLEMENT_STANDARD_RTTIEXT(GeomEvaluator_OffsetSurface,GeomEvaluator_Surface)
32 // tolerance for considering derivative to be null
33 const Standard_Real the_D1MagTol = 1.e-9;
35 // If calculation of normal fails, try shifting the point towards the center
36 // of the parametric space of the surface, in the hope that derivatives
37 // are better defined there.
39 // This shift is iterative, starting with Precision::PConfusion()
40 // and increasing by multiple of 2 on each step.
42 // NB: temporarily this is made as static function and not class method,
43 // hence code duplications
44 static Standard_Boolean shiftPoint (const Standard_Real theUStart, const Standard_Real theVStart,
45 Standard_Real& theU, Standard_Real& theV,
46 const Handle(Geom_Surface)& theSurf,
47 const Handle(GeomAdaptor_HSurface)& theAdaptor,
48 const gp_Vec& theD1U, const gp_Vec& theD1V)
50 // Get parametric bounds and closure status
51 Standard_Real aUMin, aUMax, aVMin, aVMax;
52 Standard_Boolean isUPeriodic, isVPeriodic;
53 if (! theSurf.IsNull())
55 theSurf->Bounds (aUMin, aUMax, aVMin, aVMax);
56 isUPeriodic = theSurf->IsUPeriodic();
57 isVPeriodic = theSurf->IsVPeriodic();
61 aUMin = theAdaptor->FirstUParameter();
62 aUMax = theAdaptor->LastUParameter();
63 aVMin = theAdaptor->FirstVParameter();
64 aVMax = theAdaptor->LastVParameter();
65 isUPeriodic = theAdaptor->IsUPeriodic();
66 isVPeriodic = theAdaptor->IsVPeriodic();
69 // check if either U or V is singular (normally one of them is)
70 Standard_Boolean isUSingular = (theD1U.SquareMagnitude() < the_D1MagTol * the_D1MagTol);
71 Standard_Boolean isVSingular = (theD1V.SquareMagnitude() < the_D1MagTol * the_D1MagTol);
73 // compute vector to shift from start point to center of the surface;
74 // if surface is periodic or singular in some direction, take shift in that direction zero
75 Standard_Real aDirU = (isUPeriodic || (isUSingular && ! isVSingular) ? 0. : 0.5 * (aUMin + aUMax) - theUStart);
76 Standard_Real aDirV = (isVPeriodic || (isVSingular && ! isUSingular) ? 0. : 0.5 * (aVMin + aVMax) - theVStart);
77 Standard_Real aDist = Sqrt (aDirU * aDirU + aDirV * aDirV);
79 // shift current point from its current position towards center, by value of twice
80 // current distance from it to start (but not less than Precision::PConfusion());
81 // fail if center is overpassed.
82 Standard_Real aDU = theU - theUStart;
83 Standard_Real aDV = theV - theVStart;
84 Standard_Real aStep = Max (2. * Sqrt (aDU * aDU + aDV * aDV), Precision::PConfusion());
87 return Standard_False;
91 theU += aDirU * aStep;
92 theV += aDirV * aStep;
94 // std::cout << "Normal calculation failed at (" << theUStart << ", " << theVStart << "), shifting to (" << theU << ", " << theV << ")" << std::endl;
100 template<class SurfOrAdapt>
101 static void derivatives(Standard_Integer theMaxOrder,
102 Standard_Integer theMinOrder,
103 const Standard_Real theU,
104 const Standard_Real theV,
105 const SurfOrAdapt& theBasisSurf,
106 const Standard_Integer theNU,
107 const Standard_Integer theNV,
108 const Standard_Boolean theAlongU,
109 const Standard_Boolean theAlongV,
110 const Handle(Geom_BSplineSurface)& theL,
111 TColgp_Array2OfVec& theDerNUV,
112 TColgp_Array2OfVec& theDerSurf)
114 Standard_Integer i, j;
116 gp_Vec DL1U, DL1V, DL2U, DL2V, DL2UV, DL3U, DL3UUV, DL3UVV, DL3V;
118 if (theAlongU || theAlongV)
121 TColgp_Array2OfVec DerSurfL(0, theMaxOrder + theNU + 1, 0, theMaxOrder + theNV + 1);
125 theL->D1(theU, theV, P, DL1U, DL1V);
126 DerSurfL.SetValue(1, 0, DL1U);
127 DerSurfL.SetValue(0, 1, DL1V);
130 theL->D2(theU, theV, P, DL1U, DL1V, DL2U, DL2V, DL2UV);
131 DerSurfL.SetValue(1, 0, DL1U);
132 DerSurfL.SetValue(0, 1, DL1V);
133 DerSurfL.SetValue(1, 1, DL2UV);
134 DerSurfL.SetValue(2, 0, DL2U);
135 DerSurfL.SetValue(0, 2, DL2V);
138 theL->D3(theU, theV, P, DL1U, DL1V, DL2U, DL2V, DL2UV, DL3U, DL3V, DL3UUV, DL3UVV);
139 DerSurfL.SetValue(1, 0, DL1U);
140 DerSurfL.SetValue(0, 1, DL1V);
141 DerSurfL.SetValue(1, 1, DL2UV);
142 DerSurfL.SetValue(2, 0, DL2U);
143 DerSurfL.SetValue(0, 2, DL2V);
144 DerSurfL.SetValue(3, 0, DL3U);
145 DerSurfL.SetValue(2, 1, DL3UUV);
146 DerSurfL.SetValue(1, 2, DL3UVV);
147 DerSurfL.SetValue(0, 3, DL3V);
155 for (i = 0; i <= theMaxOrder + 1 + theNU; i++)
156 for (j = i; j <= theMaxOrder + theNV + 1; j++)
157 if (i + j > theMinOrder)
159 DerSurfL.SetValue(i, j, theL->DN(theU, theV, i, j));
160 theDerSurf.SetValue(i, j, theBasisSurf->DN(theU, theV, i, j));
161 if (i != j && j <= theNU + 1)
163 theDerSurf.SetValue(j, i, theBasisSurf->DN(theU, theV, j, i));
164 DerSurfL.SetValue(j, i, theL->DN(theU, theV, j, i));
170 for (j = 0; j <= theMaxOrder + 1 + theNV; j++)
171 for (i = j; i <= theMaxOrder + theNU + 1; i++)
172 if (i + j > theMinOrder)
174 DerSurfL.SetValue(i, j, theL->DN(theU, theV, i, j));
175 theDerSurf.SetValue(i, j, theBasisSurf->DN(theU, theV, i, j));
176 if (i != j && i <= theNV + 1)
178 theDerSurf.SetValue(j, i, theBasisSurf->DN(theU, theV, j, i));
179 DerSurfL.SetValue(j, i, theL->DN(theU, theV, j, i));
183 for (i = 0; i <= theMaxOrder + theNU; i++)
184 for (j = 0; j <= theMaxOrder + theNV; j++)
187 theDerNUV.SetValue(i, j, CSLib::DNNUV(i, j, DerSurfL, theDerSurf));
189 theDerNUV.SetValue(i, j, CSLib::DNNUV(i, j, theDerSurf, DerSurfL));
194 for (i = 0; i <= theMaxOrder + theNU+ 1; i++)
196 for (j = i; j <= theMaxOrder + theNV + 1; j++)
198 if (i + j > theMinOrder)
200 theDerSurf.SetValue(i, j, theBasisSurf->DN(theU, theV, i, j));
202 && j <= theDerSurf.UpperRow()
203 && i <= theDerSurf.UpperCol())
205 theDerSurf.SetValue(j, i, theBasisSurf->DN(theU, theV, j, i));
210 for (i = 0; i <= theMaxOrder + theNU; i++)
211 for (j = 0; j <= theMaxOrder + theNV; j++)
212 theDerNUV.SetValue(i, j, CSLib::DNNUV(i, j, theDerSurf));
216 inline Standard_Boolean IsInfiniteCoord (const gp_Vec& theVec)
218 return Precision::IsInfinite (theVec.X()) ||
219 Precision::IsInfinite (theVec.Y()) ||
220 Precision::IsInfinite (theVec.Z());
223 inline void CheckInfinite (const gp_Vec& theVecU, const gp_Vec& theVecV)
225 if (IsInfiniteCoord (theVecU) || IsInfiniteCoord (theVecV))
227 throw Standard_NumericError ("GeomEvaluator_OffsetSurface: Evaluation of infinite parameters");
231 } // end of anonymous namespace
233 GeomEvaluator_OffsetSurface::GeomEvaluator_OffsetSurface(
234 const Handle(Geom_Surface)& theBase,
235 const Standard_Real theOffset,
236 const Handle(Geom_OsculatingSurface)& theOscSurf)
237 : GeomEvaluator_Surface(),
240 myOscSurf(theOscSurf)
242 if (!myOscSurf.IsNull())
243 return; // osculating surface already exists
245 // Create osculating surface for B-spline and Besier surfaces only
246 if (myBaseSurf->IsKind(STANDARD_TYPE(Geom_BSplineSurface)) ||
247 myBaseSurf->IsKind(STANDARD_TYPE(Geom_BezierSurface)))
248 myOscSurf = new Geom_OsculatingSurface(myBaseSurf, Precision::Confusion());
251 GeomEvaluator_OffsetSurface::GeomEvaluator_OffsetSurface(
252 const Handle(GeomAdaptor_HSurface)& theBase,
253 const Standard_Real theOffset,
254 const Handle(Geom_OsculatingSurface)& theOscSurf)
255 : GeomEvaluator_Surface(),
256 myBaseAdaptor(theBase),
258 myOscSurf(theOscSurf)
262 void GeomEvaluator_OffsetSurface::D0(
263 const Standard_Real theU, const Standard_Real theV, gp_Pnt& theValue) const
265 Standard_Real aU = theU, aV = theV;
269 BaseD1 (aU, aV, theValue, aD1U, aD1V);
271 CheckInfinite (aD1U, aD1V);
275 CalculateD0(aU, aV, theValue, aD1U, aD1V);
278 catch (Geom_UndefinedValue&)
280 // if failed at parametric boundary, try taking derivative at shifted point
281 if (! shiftPoint (theU, theV, aU, aV, myBaseSurf, myBaseAdaptor, aD1U, aD1V))
289 void GeomEvaluator_OffsetSurface::D1(
290 const Standard_Real theU, const Standard_Real theV,
291 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V) const
293 Standard_Real aU = theU, aV = theV;
296 gp_Vec aD2U, aD2V, aD2UV;
297 BaseD2 (aU, aV, theValue, theD1U, theD1V, aD2U, aD2V, aD2UV);
299 CheckInfinite (theD1U, theD1V);
303 CalculateD1(aU, aV, theValue, theD1U, theD1V, aD2U, aD2V, aD2UV);
306 catch (Geom_UndefinedValue&)
308 // if failed at parametric boundary, try taking derivative at shifted point
309 if (! shiftPoint (theU, theV, aU, aV, myBaseSurf, myBaseAdaptor, theD1U, theD1V))
317 void GeomEvaluator_OffsetSurface::D2(
318 const Standard_Real theU, const Standard_Real theV,
319 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
320 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV) const
322 Standard_Real aU = theU, aV = theV;
325 gp_Vec aD3U, aD3V, aD3UUV, aD3UVV;
326 BaseD3 (aU, aV, theValue, theD1U, theD1V,
327 theD2U, theD2V, theD2UV, aD3U, aD3V, aD3UUV, aD3UVV);
329 CheckInfinite (theD1U, theD1V);
333 CalculateD2 (aU, aV, theValue, theD1U, theD1V,
334 theD2U, theD2V, theD2UV, aD3U, aD3V, aD3UUV, aD3UVV);
337 catch (Geom_UndefinedValue&)
339 // if failed at parametric boundary, try taking derivative at shifted point
340 if (! shiftPoint (theU, theV, aU, aV, myBaseSurf, myBaseAdaptor, theD1U, theD1V))
348 void GeomEvaluator_OffsetSurface::D3(
349 const Standard_Real theU, const Standard_Real theV,
350 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
351 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV,
352 gp_Vec& theD3U, gp_Vec& theD3V, gp_Vec& theD3UUV, gp_Vec& theD3UVV) const
354 Standard_Real aU = theU, aV = theV;
357 BaseD3 (aU, aV, theValue, theD1U, theD1V,
358 theD2U, theD2V, theD2UV, theD3U, theD3V, theD3UUV, theD3UVV);
360 CheckInfinite (theD1U, theD1V);
364 CalculateD3 (aU, aV, theValue, theD1U, theD1V,
365 theD2U, theD2V, theD2UV, theD3U, theD3V, theD3UUV, theD3UVV);
368 catch (Geom_UndefinedValue&)
370 // if failed at parametric boundary, try taking derivative at shifted point
371 if (! shiftPoint (theU, theV, aU, aV, myBaseSurf, myBaseAdaptor, theD1U, theD1V))
379 gp_Vec GeomEvaluator_OffsetSurface::DN(
380 const Standard_Real theU, const Standard_Real theV,
381 const Standard_Integer theDerU, const Standard_Integer theDerV) const
383 Standard_RangeError_Raise_if(theDerU < 0, "GeomEvaluator_OffsetSurface::DN(): theDerU < 0");
384 Standard_RangeError_Raise_if(theDerV < 0, "GeomEvaluator_OffsetSurface::DN(): theDerV < 0");
385 Standard_RangeError_Raise_if(theDerU + theDerV < 1,
386 "GeomEvaluator_OffsetSurface::DN(): theDerU + theDerV < 1");
388 Standard_Real aU = theU, aV = theV;
393 BaseD1 (aU, aV, aP, aD1U, aD1V);
395 CheckInfinite (aD1U, aD1V);
399 return CalculateDN (aU, aV, theDerU, theDerV, aD1U, aD1V);
401 catch (Geom_UndefinedValue&)
403 // if failed at parametric boundary, try taking derivative at shifted point
404 if (! shiftPoint (theU, theV, aU, aV, myBaseSurf, myBaseAdaptor, aD1U, aD1V))
413 void GeomEvaluator_OffsetSurface::BaseD0(const Standard_Real theU, const Standard_Real theV,
414 gp_Pnt& theValue) const
416 if (!myBaseAdaptor.IsNull())
417 myBaseAdaptor->D0(theU, theV, theValue);
419 myBaseSurf->D0(theU, theV, theValue);
422 void GeomEvaluator_OffsetSurface::BaseD1(const Standard_Real theU, const Standard_Real theV,
423 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V) const
425 if (!myBaseAdaptor.IsNull())
426 myBaseAdaptor->D1(theU, theV, theValue, theD1U, theD1V);
428 myBaseSurf->D1(theU, theV, theValue, theD1U, theD1V);
431 void GeomEvaluator_OffsetSurface::BaseD2(const Standard_Real theU, const Standard_Real theV,
432 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
433 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV) const
435 if (!myBaseAdaptor.IsNull())
436 myBaseAdaptor->D2(theU, theV, theValue, theD1U, theD1V, theD2U, theD2V, theD2UV);
438 myBaseSurf->D2(theU, theV, theValue, theD1U, theD1V, theD2U, theD2V, theD2UV);
441 void GeomEvaluator_OffsetSurface::BaseD3(
442 const Standard_Real theU, const Standard_Real theV,
443 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
444 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV,
445 gp_Vec& theD3U, gp_Vec& theD3V, gp_Vec& theD3UUV, gp_Vec& theD3UVV) const
447 if (!myBaseAdaptor.IsNull())
448 myBaseAdaptor->D3(theU, theV, theValue, theD1U, theD1V,
449 theD2U, theD2V, theD2UV, theD3U, theD3V, theD3UUV, theD3UVV);
451 myBaseSurf->D3(theU, theV, theValue, theD1U, theD1V,
452 theD2U, theD2V, theD2UV, theD3U, theD3V, theD3UUV, theD3UVV);
456 void GeomEvaluator_OffsetSurface::CalculateD0(
457 const Standard_Real theU, const Standard_Real theV,
459 const gp_Vec& theD1U, const gp_Vec& theD1V) const
461 // Normalize derivatives before normal calculation because it gives more stable result.
462 // There will be normalized only derivatives greater than 1.0 to avoid differences in last significant digit
465 Standard_Real aD1UNorm2 = aD1U.SquareMagnitude();
466 Standard_Real aD1VNorm2 = aD1V.SquareMagnitude();
468 aD1U /= Sqrt(aD1UNorm2);
470 aD1V /= Sqrt(aD1VNorm2);
472 gp_Vec aNorm = aD1U.Crossed(aD1V);
473 if (aNorm.SquareMagnitude() > the_D1MagTol * the_D1MagTol)
475 // Non singular case. Simple computations.
477 theValue.SetXYZ(theValue.XYZ() + myOffset * aNorm.XYZ());
481 const Standard_Integer MaxOrder = 3;
483 Handle(Geom_BSplineSurface) L;
484 Standard_Boolean isOpposite = Standard_False;
485 Standard_Boolean AlongU = Standard_False;
486 Standard_Boolean AlongV = Standard_False;
487 if (!myOscSurf.IsNull())
489 AlongU = myOscSurf->UOscSurf(theU, theV, isOpposite, L);
490 AlongV = myOscSurf->VOscSurf(theU, theV, isOpposite, L);
492 const Standard_Real aSign = ((AlongV || AlongU) && isOpposite) ? -1. : 1.;
494 TColgp_Array2OfVec DerNUV(0, MaxOrder, 0, MaxOrder);
495 TColgp_Array2OfVec DerSurf(0, MaxOrder + 1, 0, MaxOrder + 1);
496 Standard_Integer OrderU, OrderV;
497 Standard_Real Umin = 0, Umax = 0, Vmin = 0, Vmax = 0;
498 Bounds(Umin, Umax, Vmin, Vmax);
500 DerSurf.SetValue(1, 0, theD1U);
501 DerSurf.SetValue(0, 1, theD1V);
502 if (!myBaseSurf.IsNull())
503 derivatives(MaxOrder, 1, theU, theV, myBaseSurf, 0, 0, AlongU, AlongV, L, DerNUV, DerSurf);
505 derivatives(MaxOrder, 1, theU, theV, myBaseAdaptor, 0, 0, AlongU, AlongV, L, DerNUV, DerSurf);
508 CSLib_NormalStatus NStatus = CSLib_Singular;
509 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax,
510 NStatus, Normal, OrderU, OrderV);
511 if (NStatus == CSLib_InfinityOfSolutions)
513 // Replace zero derivative and try to calculate normal
514 gp_Vec aNewDU = theD1U;
515 gp_Vec aNewDV = theD1V;
516 if (ReplaceDerivative(theU, theV, aNewDU, aNewDV, the_D1MagTol * the_D1MagTol))
517 CSLib::Normal(aNewDU, aNewDV, the_D1MagTol, NStatus, Normal);
520 if (NStatus != CSLib_Defined)
521 throw Geom_UndefinedValue(
522 "GeomEvaluator_OffsetSurface::CalculateD0(): Unable to calculate normal");
524 theValue.SetXYZ(theValue.XYZ() + myOffset * aSign * Normal.XYZ());
528 void GeomEvaluator_OffsetSurface::CalculateD1(
529 const Standard_Real theU, const Standard_Real theV,
530 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
531 const gp_Vec& theD2U, const gp_Vec& theD2V, const gp_Vec& theD2UV) const
533 // Check offset side.
534 Handle(Geom_BSplineSurface) L;
535 Standard_Boolean isOpposite = Standard_False;
536 Standard_Boolean AlongU = Standard_False;
537 Standard_Boolean AlongV = Standard_False;
539 // Normalize derivatives before normal calculation because it gives more stable result.
540 // There will be normalized only derivatives greater than 1.0 to avoid differences in last significant digit
543 Standard_Real aD1UNorm2 = aD1U.SquareMagnitude();
544 Standard_Real aD1VNorm2 = aD1V.SquareMagnitude();
546 aD1U /= Sqrt(aD1UNorm2);
548 aD1V /= Sqrt(aD1VNorm2);
550 Standard_Boolean isSingular = Standard_False;
551 Standard_Integer MaxOrder = 0;
552 gp_Vec aNorm = aD1U.Crossed(aD1V);
553 if (aNorm.SquareMagnitude() <= the_D1MagTol * the_D1MagTol)
555 if (!myOscSurf.IsNull())
557 AlongU = myOscSurf->UOscSurf(theU, theV, isOpposite, L);
558 AlongV = myOscSurf->VOscSurf(theU, theV, isOpposite, L);
562 isSingular = Standard_True;
565 const Standard_Real aSign = ((AlongV || AlongU) && isOpposite) ? -1. : 1.;
569 // AlongU or AlongV leads to more complex D1 computation
570 // Try to compute D0 and D1 much simpler
572 theValue.SetXYZ(theValue.XYZ() + myOffset * aSign * aNorm.XYZ());
574 gp_Vec aN0(aNorm.XYZ()), aN1U, aN1V;
575 Standard_Real aScale = (theD1U^theD1V).Dot(aN0);
576 aN1U.SetX(theD2U.Y() * theD1V.Z() + theD1U.Y() * theD2UV.Z()
577 - theD2U.Z() * theD1V.Y() - theD1U.Z() * theD2UV.Y());
578 aN1U.SetY((theD2U.X() * theD1V.Z() + theD1U.X() * theD2UV.Z()
579 - theD2U.Z() * theD1V.X() - theD1U.Z() * theD2UV.X()) * -1.0);
580 aN1U.SetZ(theD2U.X() * theD1V.Y() + theD1U.X() * theD2UV.Y()
581 - theD2U.Y() * theD1V.X() - theD1U.Y() * theD2UV.X());
582 Standard_Real aScaleU = aN1U.Dot(aN0);
583 aN1U.Subtract(aScaleU * aN0);
586 aN1V.SetX(theD2UV.Y() * theD1V.Z() + theD2V.Z() * theD1U.Y()
587 - theD2UV.Z() * theD1V.Y() - theD2V.Y() * theD1U.Z());
588 aN1V.SetY((theD2UV.X() * theD1V.Z() + theD2V.Z() * theD1U.X()
589 - theD2UV.Z() * theD1V.X() - theD2V.X() * theD1U.Z()) * -1.0);
590 aN1V.SetZ(theD2UV.X() * theD1V.Y() + theD2V.Y() * theD1U.X()
591 - theD2UV.Y() * theD1V.X() - theD2V.X() * theD1U.Y());
592 Standard_Real aScaleV = aN1V.Dot(aN0);
593 aN1V.Subtract(aScaleV * aN0);
596 theD1U += myOffset * aSign * aN1U;
597 theD1V += myOffset * aSign * aN1V;
602 Standard_Integer OrderU, OrderV;
603 TColgp_Array2OfVec DerNUV(0, MaxOrder + 1, 0, MaxOrder + 1);
604 TColgp_Array2OfVec DerSurf(0, MaxOrder + 2, 0, MaxOrder + 2);
605 Standard_Real Umin = 0, Umax = 0, Vmin = 0, Vmax = 0;
606 Bounds(Umin, Umax, Vmin, Vmax);
608 DerSurf.SetValue(1, 0, theD1U);
609 DerSurf.SetValue(0, 1, theD1V);
610 DerSurf.SetValue(1, 1, theD2UV);
611 DerSurf.SetValue(2, 0, theD2U);
612 DerSurf.SetValue(0, 2, theD2V);
613 if (!myBaseSurf.IsNull())
614 derivatives(MaxOrder, 2, theU, theV, myBaseSurf, 1, 1, AlongU, AlongV, L, DerNUV, DerSurf);
616 derivatives(MaxOrder, 2, theU, theV, myBaseAdaptor, 1, 1, AlongU, AlongV, L, DerNUV, DerSurf);
619 CSLib_NormalStatus NStatus;
620 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax, NStatus, Normal, OrderU, OrderV);
621 if (NStatus == CSLib_InfinityOfSolutions)
623 gp_Vec aNewDU = theD1U;
624 gp_Vec aNewDV = theD1V;
625 // Replace zero derivative and try to calculate normal
626 if (ReplaceDerivative(theU, theV, aNewDU, aNewDV, the_D1MagTol * the_D1MagTol))
628 DerSurf.SetValue(1, 0, aNewDU);
629 DerSurf.SetValue(0, 1, aNewDV);
630 if (!myBaseSurf.IsNull())
631 derivatives(MaxOrder, 2, theU, theV, myBaseSurf, 1, 1, AlongU, AlongV, L, DerNUV, DerSurf);
633 derivatives(MaxOrder, 2, theU, theV, myBaseAdaptor, 1, 1, AlongU, AlongV, L, DerNUV, DerSurf);
634 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax,
635 NStatus, Normal, OrderU, OrderV);
639 if (NStatus != CSLib_Defined)
640 throw Geom_UndefinedValue(
641 "GeomEvaluator_OffsetSurface::CalculateD1(): Unable to calculate normal");
643 theValue.SetXYZ(theValue.XYZ() + myOffset * aSign * Normal.XYZ());
645 theD1U = DerSurf(1, 0) + myOffset * aSign * CSLib::DNNormal(1, 0, DerNUV, OrderU, OrderV);
646 theD1V = DerSurf(0, 1) + myOffset * aSign * CSLib::DNNormal(0, 1, DerNUV, OrderU, OrderV);
649 void GeomEvaluator_OffsetSurface::CalculateD2(
650 const Standard_Real theU, const Standard_Real theV,
651 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
652 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV,
653 const gp_Vec& theD3U, const gp_Vec& theD3V, const gp_Vec& theD3UUV, const gp_Vec& theD3UVV) const
656 CSLib_NormalStatus NStatus;
657 CSLib::Normal(theD1U, theD1V, the_D1MagTol, NStatus, Normal);
659 const Standard_Integer MaxOrder = (NStatus == CSLib_Defined) ? 0 : 3;
660 Standard_Integer OrderU, OrderV;
661 TColgp_Array2OfVec DerNUV(0, MaxOrder + 2, 0, MaxOrder + 2);
662 TColgp_Array2OfVec DerSurf(0, MaxOrder + 3, 0, MaxOrder + 3);
664 Standard_Real Umin = 0, Umax = 0, Vmin = 0, Vmax = 0;
665 Bounds(Umin, Umax, Vmin, Vmax);
667 DerSurf.SetValue(1, 0, theD1U);
668 DerSurf.SetValue(0, 1, theD1V);
669 DerSurf.SetValue(1, 1, theD2UV);
670 DerSurf.SetValue(2, 0, theD2U);
671 DerSurf.SetValue(0, 2, theD2V);
672 DerSurf.SetValue(3, 0, theD3U);
673 DerSurf.SetValue(2, 1, theD3UUV);
674 DerSurf.SetValue(1, 2, theD3UVV);
675 DerSurf.SetValue(0, 3, theD3V);
676 //*********************
678 Handle(Geom_BSplineSurface) L;
679 Standard_Boolean isOpposite = Standard_False;
680 Standard_Boolean AlongU = Standard_False;
681 Standard_Boolean AlongV = Standard_False;
682 if ((NStatus != CSLib_Defined) && !myOscSurf.IsNull())
684 AlongU = myOscSurf->UOscSurf(theU, theV, isOpposite, L);
685 AlongV = myOscSurf->VOscSurf(theU, theV, isOpposite, L);
687 const Standard_Real aSign = ((AlongV || AlongU) && isOpposite) ? -1. : 1.;
689 if (!myBaseSurf.IsNull())
690 derivatives(MaxOrder, 3, theU, theV, myBaseSurf, 2, 2, AlongU, AlongV, L, DerNUV, DerSurf);
692 derivatives(MaxOrder, 3, theU, theV, myBaseAdaptor, 2, 2, AlongU, AlongV, L, DerNUV, DerSurf);
694 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax,
695 NStatus, Normal, OrderU, OrderV);
696 if (NStatus != CSLib_Defined)
697 throw Geom_UndefinedValue(
698 "GeomEvaluator_OffsetSurface::CalculateD2(): Unable to calculate normal");
700 theValue.SetXYZ(theValue.XYZ() + myOffset * aSign * Normal.XYZ());
702 theD1U = DerSurf(1, 0) + myOffset * aSign * CSLib::DNNormal(1, 0, DerNUV, OrderU, OrderV);
703 theD1V = DerSurf(0, 1) + myOffset * aSign * CSLib::DNNormal(0, 1, DerNUV, OrderU, OrderV);
705 if (!myBaseSurf.IsNull())
707 theD2U = myBaseSurf->DN(theU, theV, 2, 0);
708 theD2V = myBaseSurf->DN(theU, theV, 0, 2);
709 theD2UV = myBaseSurf->DN(theU, theV, 1, 1);
713 theD2U = myBaseAdaptor->DN(theU, theV, 2, 0);
714 theD2V = myBaseAdaptor->DN(theU, theV, 0, 2);
715 theD2UV = myBaseAdaptor->DN(theU, theV, 1, 1);
718 theD2U += aSign * myOffset * CSLib::DNNormal(2, 0, DerNUV, OrderU, OrderV);
719 theD2V += aSign * myOffset * CSLib::DNNormal(0, 2, DerNUV, OrderU, OrderV);
720 theD2UV += aSign * myOffset * CSLib::DNNormal(1, 1, DerNUV, OrderU, OrderV);
723 void GeomEvaluator_OffsetSurface::CalculateD3(
724 const Standard_Real theU, const Standard_Real theV,
725 gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
726 gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV,
727 gp_Vec& theD3U, gp_Vec& theD3V, gp_Vec& theD3UUV, gp_Vec& theD3UVV) const
730 CSLib_NormalStatus NStatus;
731 CSLib::Normal(theD1U, theD1V, the_D1MagTol, NStatus, Normal);
732 const Standard_Integer MaxOrder = (NStatus == CSLib_Defined) ? 0 : 3;
733 Standard_Integer OrderU, OrderV;
734 TColgp_Array2OfVec DerNUV(0, MaxOrder + 3, 0, MaxOrder + 3);
735 TColgp_Array2OfVec DerSurf(0, MaxOrder + 4, 0, MaxOrder + 4);
736 Standard_Real Umin = 0, Umax = 0, Vmin = 0, Vmax = 0;
737 Bounds(Umin, Umax, Vmin, Vmax);
739 DerSurf.SetValue(1, 0, theD1U);
740 DerSurf.SetValue(0, 1, theD1V);
741 DerSurf.SetValue(1, 1, theD2UV);
742 DerSurf.SetValue(2, 0, theD2U);
743 DerSurf.SetValue(0, 2, theD2V);
744 DerSurf.SetValue(3, 0, theD3U);
745 DerSurf.SetValue(2, 1, theD3UUV);
746 DerSurf.SetValue(1, 2, theD3UVV);
747 DerSurf.SetValue(0, 3, theD3V);
750 //*********************
751 Handle(Geom_BSplineSurface) L;
752 Standard_Boolean isOpposite = Standard_False;
753 Standard_Boolean AlongU = Standard_False;
754 Standard_Boolean AlongV = Standard_False;
755 if ((NStatus != CSLib_Defined) && !myOscSurf.IsNull())
757 AlongU = myOscSurf->UOscSurf(theU, theV, isOpposite, L);
758 AlongV = myOscSurf->VOscSurf(theU, theV, isOpposite, L);
760 const Standard_Real aSign = ((AlongV || AlongU) && isOpposite) ? -1. : 1.;
762 if (!myBaseSurf.IsNull())
763 derivatives(MaxOrder, 3, theU, theV, myBaseSurf, 3, 3, AlongU, AlongV, L, DerNUV, DerSurf);
765 derivatives(MaxOrder, 3, theU, theV, myBaseAdaptor, 3, 3, AlongU, AlongV, L, DerNUV, DerSurf);
767 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax,
768 NStatus, Normal, OrderU, OrderV);
769 if (NStatus != CSLib_Defined)
770 throw Geom_UndefinedValue(
771 "GeomEvaluator_OffsetSurface::CalculateD3(): Unable to calculate normal");
773 theValue.SetXYZ(theValue.XYZ() + myOffset * aSign * Normal.XYZ());
775 theD1U = DerSurf(1, 0) + myOffset * aSign * CSLib::DNNormal(1, 0, DerNUV, OrderU, OrderV);
776 theD1V = DerSurf(0, 1) + myOffset * aSign * CSLib::DNNormal(0, 1, DerNUV, OrderU, OrderV);
778 if (!myBaseSurf.IsNull())
780 theD2U = myBaseSurf->DN(theU, theV, 2, 0);
781 theD2V = myBaseSurf->DN(theU, theV, 0, 2);
782 theD2UV = myBaseSurf->DN(theU, theV, 1, 1);
783 theD3U = myBaseSurf->DN(theU, theV, 3, 0);
784 theD3V = myBaseSurf->DN(theU, theV, 0, 3);
785 theD3UUV = myBaseSurf->DN(theU, theV, 2, 1);
786 theD3UVV = myBaseSurf->DN(theU, theV, 1, 2);
790 theD2U = myBaseAdaptor->DN(theU, theV, 2, 0);
791 theD2V = myBaseAdaptor->DN(theU, theV, 0, 2);
792 theD2UV = myBaseAdaptor->DN(theU, theV, 1, 1);
793 theD3U = myBaseAdaptor->DN(theU, theV, 3, 0);
794 theD3V = myBaseAdaptor->DN(theU, theV, 0, 3);
795 theD3UUV = myBaseAdaptor->DN(theU, theV, 2, 1);
796 theD3UVV = myBaseAdaptor->DN(theU, theV, 1, 2);
799 theD2U += aSign * myOffset * CSLib::DNNormal(2, 0, DerNUV, OrderU, OrderV);
800 theD2V += aSign * myOffset * CSLib::DNNormal(0, 2, DerNUV, OrderU, OrderV);
801 theD2UV += aSign * myOffset * CSLib::DNNormal(1, 1, DerNUV, OrderU, OrderV);
802 theD3U += aSign * myOffset * CSLib::DNNormal(3, 0, DerNUV, OrderU, OrderV);
803 theD3V += aSign * myOffset * CSLib::DNNormal(0, 3, DerNUV, OrderU, OrderV);
804 theD3UUV += aSign * myOffset * CSLib::DNNormal(2, 1, DerNUV, OrderU, OrderV);
805 theD3UVV += aSign * myOffset * CSLib::DNNormal(1, 2, DerNUV, OrderU, OrderV);
808 gp_Vec GeomEvaluator_OffsetSurface::CalculateDN(
809 const Standard_Real theU, const Standard_Real theV,
810 const Standard_Integer theNu, const Standard_Integer theNv,
811 const gp_Vec& theD1U, const gp_Vec& theD1V) const
814 CSLib_NormalStatus NStatus;
815 CSLib::Normal(theD1U, theD1V, the_D1MagTol, NStatus, Normal);
816 const Standard_Integer MaxOrder = (NStatus == CSLib_Defined) ? 0 : 3;
817 Standard_Integer OrderU, OrderV;
818 TColgp_Array2OfVec DerNUV(0, MaxOrder + theNu, 0, MaxOrder + theNv);
819 TColgp_Array2OfVec DerSurf(0, MaxOrder + theNu + 1, 0, MaxOrder + theNv + 1);
821 Standard_Real Umin = 0, Umax = 0, Vmin = 0, Vmax = 0;
822 Bounds(Umin, Umax, Vmin, Vmax);
824 DerSurf.SetValue(1, 0, theD1U);
825 DerSurf.SetValue(0, 1, theD1V);
827 //*********************
828 Handle(Geom_BSplineSurface) L;
829 // Is there any osculatingsurface along U or V;
830 Standard_Boolean isOpposite = Standard_False;
831 Standard_Boolean AlongU = Standard_False;
832 Standard_Boolean AlongV = Standard_False;
833 if ((NStatus != CSLib_Defined) && !myOscSurf.IsNull())
835 AlongU = myOscSurf->UOscSurf(theU, theV, isOpposite, L);
836 AlongV = myOscSurf->VOscSurf(theU, theV, isOpposite, L);
838 const Standard_Real aSign = ((AlongV || AlongU) && isOpposite) ? -1. : 1.;
840 if (!myBaseSurf.IsNull())
841 derivatives(MaxOrder, 1, theU, theV, myBaseSurf, theNu, theNv, AlongU, AlongV, L, DerNUV, DerSurf);
843 derivatives(MaxOrder, 1, theU, theV, myBaseAdaptor, theNu, theNv, AlongU, AlongV, L, DerNUV, DerSurf);
845 CSLib::Normal(MaxOrder, DerNUV, the_D1MagTol, theU, theV, Umin, Umax, Vmin, Vmax,
846 NStatus, Normal, OrderU, OrderV);
847 if (NStatus != CSLib_Defined)
848 throw Geom_UndefinedValue(
849 "GeomEvaluator_OffsetSurface::CalculateDN(): Unable to calculate normal");
852 if (!myBaseSurf.IsNull())
853 D = myBaseSurf->DN(theU, theV, theNu, theNv);
855 D = myBaseAdaptor->DN(theU, theV, theNu, theNv);
857 D += aSign * myOffset * CSLib::DNNormal(theNu, theNv, DerNUV, OrderU, OrderV);
862 void GeomEvaluator_OffsetSurface::Bounds(Standard_Real& theUMin, Standard_Real& theUMax,
863 Standard_Real& theVMin, Standard_Real& theVMax) const
865 if (!myBaseSurf.IsNull())
866 myBaseSurf->Bounds(theUMin, theUMax, theVMin, theVMax);
869 theUMin = myBaseAdaptor->FirstUParameter();
870 theUMax = myBaseAdaptor->LastUParameter();
871 theVMin = myBaseAdaptor->FirstVParameter();
872 theVMax = myBaseAdaptor->LastVParameter();
877 Standard_Boolean GeomEvaluator_OffsetSurface::ReplaceDerivative(
878 const Standard_Real theU, const Standard_Real theV,
879 gp_Vec& theDU, gp_Vec& theDV,
880 const Standard_Real theSquareTol) const
882 Standard_Boolean isReplaceDU = theDU.SquareMagnitude() < theSquareTol;
883 Standard_Boolean isReplaceDV = theDV.SquareMagnitude() < theSquareTol;
884 Standard_Boolean isReplaced = Standard_False;
885 if (isReplaceDU ^ isReplaceDV)
887 Standard_Real aU = theU;
888 Standard_Real aV = theV;
889 Standard_Real aUMin = 0, aUMax = 0, aVMin = 0, aVMax = 0;
890 Bounds(aUMin, aUMax, aVMin, aVMax);
892 // Calculate step along non-zero derivative
894 Handle(Adaptor3d_HSurface) aSurfAdapt;
895 if (!myBaseAdaptor.IsNull())
896 aSurfAdapt = myBaseAdaptor;
898 aSurfAdapt = new GeomAdaptor_HSurface(myBaseSurf);
901 aStep = Precision::Confusion() * theDU.Magnitude();
902 if (aStep > aUMax - aUMin)
903 aStep = (aUMax - aUMin) / 100.;
907 aStep = Precision::Confusion() * theDV.Magnitude();
908 if (aStep > aVMax - aVMin)
909 aStep = (aVMax - aVMin) / 100.;
914 // Step away from currect parametric coordinates and calculate derivatives once again.
915 // Replace zero derivative by the obtained.
916 for (Standard_Real aStepSign = -1.0; aStepSign <= 1.0 && !isReplaced; aStepSign += 2.0)
920 aU = theU + aStepSign * aStep;
921 if (aU < aUMin || aU > aUMax)
926 aV = theV + aStepSign * aStep;
927 if (aV < aVMin || aV > aVMax)
931 BaseD1(aU, aV, aP, aDU, aDV);
933 if (isReplaceDU && aDU.SquareMagnitude() > theSquareTol)
936 isReplaced = Standard_True;
938 if (isReplaceDV && aDV.SquareMagnitude() > theSquareTol)
941 isReplaced = Standard_True;