0026914: [Regression 7.0alpha] Hang in surface approximation
[occt.git] / src / GeomEvaluator / GeomEvaluator_SurfaceOfRevolution.cxx
1 // Created on: 2015-09-21
2 // Copyright (c) 2015 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 #include <GeomEvaluator_SurfaceOfRevolution.hxx>
16
17 #include <Adaptor3d_HCurve.hxx>
18 #include <gp_Trsf.hxx>
19
20 GeomEvaluator_SurfaceOfRevolution::GeomEvaluator_SurfaceOfRevolution(
21         const Handle(Geom_Curve)& theBase,
22         const gp_Dir& theRevolDir,
23         const gp_Pnt& theRevolLoc)
24   : GeomEvaluator_Surface(),
25     myBaseCurve(theBase),
26     myRotAxis(theRevolLoc, theRevolDir)
27 {
28 }
29
30 GeomEvaluator_SurfaceOfRevolution::GeomEvaluator_SurfaceOfRevolution(
31         const Handle(Adaptor3d_HCurve)& theBase,
32         const gp_Dir& theRevolDir,
33         const gp_Pnt& theRevolLoc)
34   : GeomEvaluator_Surface(),
35     myBaseAdaptor(theBase),
36     myRotAxis(theRevolLoc, theRevolDir)
37 {
38 }
39
40 void GeomEvaluator_SurfaceOfRevolution::D0(
41     const Standard_Real theU, const Standard_Real theV,
42     gp_Pnt& theValue) const
43 {
44   if (!myBaseAdaptor.IsNull())
45     myBaseAdaptor->D0(theV, theValue);
46   else
47     myBaseCurve->D0(theV, theValue);
48
49   gp_Trsf aRotation;
50   aRotation.SetRotation(myRotAxis, theU);
51   theValue.Transform(aRotation);
52 }
53
54 void GeomEvaluator_SurfaceOfRevolution::D1(
55     const Standard_Real theU, const Standard_Real theV,
56     gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V) const
57 {
58   if (!myBaseAdaptor.IsNull())
59     myBaseAdaptor->D1(theV, theValue, theD1V);
60   else
61     myBaseCurve->D1(theV, theValue, theD1V);
62
63   // vector from center of rotation to the point on rotated curve
64   gp_XYZ aCQ = theValue.XYZ() - myRotAxis.Location().XYZ();
65   theD1U = gp_Vec(myRotAxis.Direction().XYZ().Crossed(aCQ));
66   // If the point is placed on the axis of revolution then derivatives on U are undefined.
67   // Manually set them to zero.
68   if (theD1U.SquareMagnitude() < Precision::SquareConfusion())
69     theD1U.SetCoord(0.0, 0.0, 0.0);
70
71   gp_Trsf aRotation;
72   aRotation.SetRotation(myRotAxis, theU);
73   theValue.Transform(aRotation);
74   theD1U.Transform(aRotation);
75   theD1V.Transform(aRotation);
76 }
77
78 void GeomEvaluator_SurfaceOfRevolution::D2(
79     const Standard_Real theU, const Standard_Real theV,
80     gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
81     gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV) const
82 {
83   if (!myBaseAdaptor.IsNull())
84     myBaseAdaptor->D2(theV, theValue, theD1V, theD2V);
85   else
86     myBaseCurve->D2(theV, theValue, theD1V, theD2V);
87
88   // vector from center of rotation to the point on rotated curve
89   gp_XYZ aCQ = theValue.XYZ() - myRotAxis.Location().XYZ();
90   const gp_XYZ& aDir = myRotAxis.Direction().XYZ();
91   theD1U = gp_Vec(aDir.Crossed(aCQ));
92   // If the point is placed on the axis of revolution then derivatives on U are undefined.
93   // Manually set them to zero.
94   if (theD1U.SquareMagnitude() < Precision::SquareConfusion())
95     theD1U.SetCoord(0.0, 0.0, 0.0);
96   theD2U = gp_Vec(aDir.Dot(aCQ) * aDir - aCQ);
97   theD2UV = gp_Vec(aDir.Crossed(theD1V.XYZ()));
98
99   gp_Trsf aRotation;
100   aRotation.SetRotation(myRotAxis, theU);
101   theValue.Transform(aRotation);
102   theD1U.Transform(aRotation);
103   theD1V.Transform(aRotation);
104   theD2U.Transform(aRotation);
105   theD2V.Transform(aRotation);
106   theD2UV.Transform(aRotation);
107 }
108
109 void GeomEvaluator_SurfaceOfRevolution::D3(
110     const Standard_Real theU, const Standard_Real theV,
111     gp_Pnt& theValue, gp_Vec& theD1U, gp_Vec& theD1V,
112     gp_Vec& theD2U, gp_Vec& theD2V, gp_Vec& theD2UV,
113     gp_Vec& theD3U, gp_Vec& theD3V, gp_Vec& theD3UUV, gp_Vec& theD3UVV) const
114 {
115   if (!myBaseAdaptor.IsNull())
116     myBaseAdaptor->D3(theV, theValue, theD1V, theD2V, theD3V);
117   else
118     myBaseCurve->D3(theV, theValue, theD1V, theD2V, theD3V);
119
120   // vector from center of rotation to the point on rotated curve
121   gp_XYZ aCQ = theValue.XYZ() - myRotAxis.Location().XYZ();
122   const gp_XYZ& aDir = myRotAxis.Direction().XYZ();
123   theD1U = gp_Vec(aDir.Crossed(aCQ));
124   // If the point is placed on the axis of revolution then derivatives on U are undefined.
125   // Manually set them to zero.
126   if (theD1U.SquareMagnitude() < Precision::SquareConfusion())
127     theD1U.SetCoord(0.0, 0.0, 0.0);
128   theD2U = gp_Vec(aDir.Dot(aCQ) * aDir - aCQ);
129   theD2UV = gp_Vec(aDir.Crossed(theD1V.XYZ()));
130   theD3U = -theD1U;
131   theD3UUV = gp_Vec(aDir.Dot(theD1V.XYZ()) * aDir - theD1V.XYZ());
132   theD3UVV = gp_Vec(aDir.Crossed(theD2V.XYZ()));
133
134   gp_Trsf aRotation;
135   aRotation.SetRotation(myRotAxis, theU);
136   theValue.Transform(aRotation);
137   theD1U.Transform(aRotation);
138   theD1V.Transform(aRotation);
139   theD2U.Transform(aRotation);
140   theD2V.Transform(aRotation);
141   theD2UV.Transform(aRotation);
142   theD3U.Transform(aRotation);
143   theD3V.Transform(aRotation);
144   theD3UUV.Transform(aRotation);
145   theD3UVV.Transform(aRotation);
146 }
147
148 gp_Vec GeomEvaluator_SurfaceOfRevolution::DN(
149     const Standard_Real theU, const Standard_Real theV,
150     const Standard_Integer theDerU, const Standard_Integer theDerV) const
151 {
152   Standard_RangeError_Raise_if(theDerU < 0, "GeomEvaluator_SurfaceOfRevolution::DN(): theDerU < 0");
153   Standard_RangeError_Raise_if(theDerV < 0, "GeomEvaluator_SurfaceOfRevolution::DN(): theDerV < 0");
154   Standard_RangeError_Raise_if(theDerU + theDerV < 1,
155       "GeomEvaluator_SurfaceOfRevolution::DN(): theDerU + theDerV < 1");
156
157   gp_Trsf aRotation;
158   aRotation.SetRotation(myRotAxis, theU);
159
160   gp_Pnt aP;
161   gp_Vec aDV;
162   gp_Vec aResult;
163   if (theDerU == 0)
164   {
165     if (!myBaseAdaptor.IsNull())
166       aResult = myBaseAdaptor->DN(theV, theDerV);
167     else
168       aResult = myBaseCurve->DN(theV, theDerV);
169   }
170   else
171   {
172     if (theDerV == 0)
173     {
174       if (!myBaseAdaptor.IsNull())
175         myBaseAdaptor->D0(theV, aP);
176       else
177         myBaseCurve->D0(theV, aP);
178       aDV = gp_Vec(aP.XYZ() - myRotAxis.Location().XYZ());
179     }
180     else
181     {
182       if (!myBaseAdaptor.IsNull())
183         aDV = myBaseAdaptor->DN(theV, theDerV);
184       else
185         aDV = myBaseCurve->DN(theV, theDerV);
186     }
187
188     const gp_XYZ& aDir = myRotAxis.Direction().XYZ();
189     if (theDerU % 4 == 1)
190       aResult = gp_Vec(aDir.Crossed(aDV.XYZ()));
191     else if (theDerU % 4 == 2)
192       aResult = gp_Vec(aDir.Dot(aDV.XYZ()) * aDir - aDV.XYZ());
193     else if (theDerU % 4 == 3)
194       aResult = gp_Vec(aDir.Crossed(aDV.XYZ())) * (-1.0);
195     else
196       aResult = gp_Vec(aDV.XYZ() - aDir.Dot(aDV.XYZ()) * aDir);
197   }
198
199   aResult.Transform(aRotation);
200   return aResult;
201 }
202