0031303: Different calculation of offset direction in Adaptor2d_OffsetCurve and Geom2...
[occt.git] / src / Geom2dEvaluator / Geom2dEvaluator_OffsetCurve.cxx
CommitLineData
d660a72a 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 <Geom2dEvaluator_OffsetCurve.hxx>
68ad329c 16#include <Geom2dEvaluator.hxx>
d660a72a 17#include <Geom2dAdaptor_HCurve.hxx>
18#include <Standard_NullValue.hxx>
19
20
92efcf78 21IMPLEMENT_STANDARD_RTTIEXT(Geom2dEvaluator_OffsetCurve,Geom2dEvaluator_Curve)
22
d660a72a 23Geom2dEvaluator_OffsetCurve::Geom2dEvaluator_OffsetCurve(
24 const Handle(Geom2d_Curve)& theBase,
25 const Standard_Real theOffset)
26 : Geom2dEvaluator_Curve(),
27 myBaseCurve(theBase),
28 myOffset(theOffset)
29{
30}
31
32Geom2dEvaluator_OffsetCurve::Geom2dEvaluator_OffsetCurve(
33 const Handle(Geom2dAdaptor_HCurve)& theBase,
34 const Standard_Real theOffset)
35 : Geom2dEvaluator_Curve(),
36 myBaseAdaptor(theBase),
37 myOffset(theOffset)
38{
39}
40
41void Geom2dEvaluator_OffsetCurve::D0(const Standard_Real theU,
42 gp_Pnt2d& theValue) const
43{
44 gp_Vec2d aD1;
45 BaseD1(theU, theValue, aD1);
68ad329c 46 Geom2dEvaluator::CalculateD0(theValue, aD1, myOffset);
d660a72a 47}
48
49void Geom2dEvaluator_OffsetCurve::D1(const Standard_Real theU,
50 gp_Pnt2d& theValue,
51 gp_Vec2d& theD1) const
52{
53 gp_Vec2d aD2;
54 BaseD2(theU, theValue, theD1, aD2);
68ad329c 55 Geom2dEvaluator::CalculateD1(theValue, theD1, aD2, myOffset);
d660a72a 56}
57
58void Geom2dEvaluator_OffsetCurve::D2(const Standard_Real theU,
59 gp_Pnt2d& theValue,
60 gp_Vec2d& theD1,
61 gp_Vec2d& theD2) const
62{
63 gp_Vec2d aD3;
64 BaseD3(theU, theValue, theD1, theD2, aD3);
65
66 Standard_Boolean isDirectionChange = Standard_False;
67 if (theD1.SquareMagnitude() <= gp::Resolution())
68 {
69 gp_Vec2d aDummyD4;
70 isDirectionChange = AdjustDerivative(3, theU, theD1, theD2, aD3, aDummyD4);
71 }
72
68ad329c 73 Geom2dEvaluator::CalculateD2(theValue, theD1, theD2, aD3, isDirectionChange, myOffset);
d660a72a 74}
75
76void Geom2dEvaluator_OffsetCurve::D3(const Standard_Real theU,
77 gp_Pnt2d& theValue,
78 gp_Vec2d& theD1,
79 gp_Vec2d& theD2,
80 gp_Vec2d& theD3) const
81{
82 gp_Vec2d aD4;
83 BaseD4(theU, theValue, theD1, theD2, theD3, aD4);
84
85 Standard_Boolean isDirectionChange = Standard_False;
86 if (theD1.SquareMagnitude() <= gp::Resolution())
87 isDirectionChange = AdjustDerivative(4, theU, theD1, theD2, theD3, aD4);
88
68ad329c 89 Geom2dEvaluator::CalculateD3(theValue, theD1, theD2, theD3, aD4, isDirectionChange, myOffset);
d660a72a 90}
91
92gp_Vec2d Geom2dEvaluator_OffsetCurve::DN(const Standard_Real theU,
93 const Standard_Integer theDeriv) const
94{
95 Standard_RangeError_Raise_if(theDeriv < 1, "Geom2dEvaluator_OffsetCurve::DN(): theDeriv < 1");
96
97 gp_Pnt2d aPnt;
98 gp_Vec2d aDummy, aDN;
99 switch (theDeriv)
100 {
101 case 1:
102 D1(theU, aPnt, aDN);
103 break;
104 case 2:
105 D2(theU, aPnt, aDummy, aDN);
106 break;
107 case 3:
108 D3(theU, aPnt, aDummy, aDummy, aDN);
109 break;
110 default:
111 aDN = BaseDN(theU, theDeriv);
112 }
113 return aDN;
114}
115
116
117void Geom2dEvaluator_OffsetCurve::BaseD0(const Standard_Real theU,
118 gp_Pnt2d& theValue) const
119{
120 if (!myBaseAdaptor.IsNull())
121 myBaseAdaptor->D0(theU, theValue);
122 else
123 myBaseCurve->D0(theU, theValue);
124}
125
126void Geom2dEvaluator_OffsetCurve::BaseD1(const Standard_Real theU,
127 gp_Pnt2d& theValue,
128 gp_Vec2d& theD1) const
129{
130 if (!myBaseAdaptor.IsNull())
131 myBaseAdaptor->D1(theU, theValue, theD1);
132 else
133 myBaseCurve->D1(theU, theValue, theD1);
134}
135
136void Geom2dEvaluator_OffsetCurve::BaseD2(const Standard_Real theU,
137 gp_Pnt2d& theValue,
138 gp_Vec2d& theD1,
139 gp_Vec2d& theD2) const
140{
141 if (!myBaseAdaptor.IsNull())
142 myBaseAdaptor->D2(theU, theValue, theD1, theD2);
143 else
144 myBaseCurve->D2(theU, theValue, theD1, theD2);
145}
146
147void Geom2dEvaluator_OffsetCurve::BaseD3(const Standard_Real theU,
148 gp_Pnt2d& theValue,
149 gp_Vec2d& theD1,
150 gp_Vec2d& theD2,
151 gp_Vec2d& theD3) const
152{
153 if (!myBaseAdaptor.IsNull())
154 myBaseAdaptor->D3(theU, theValue, theD1, theD2, theD3);
155 else
156 myBaseCurve->D3(theU, theValue, theD1, theD2, theD3);
157}
158
159void Geom2dEvaluator_OffsetCurve::BaseD4(const Standard_Real theU,
160 gp_Pnt2d& theValue,
161 gp_Vec2d& theD1,
162 gp_Vec2d& theD2,
163 gp_Vec2d& theD3,
164 gp_Vec2d& theD4) const
165{
166 if (!myBaseAdaptor.IsNull())
167 {
168 myBaseAdaptor->D3(theU, theValue, theD1, theD2, theD3);
169 theD4 = myBaseAdaptor->DN(theU, 4);
170 }
171 else
172 {
173 myBaseCurve->D3(theU, theValue, theD1, theD2, theD3);
174 theD4 = myBaseCurve->DN(theU, 4);
175 }
176}
177
178gp_Vec2d Geom2dEvaluator_OffsetCurve::BaseDN(const Standard_Real theU,
179 const Standard_Integer theDeriv) const
180{
181 if (!myBaseAdaptor.IsNull())
182 return myBaseAdaptor->DN(theU, theDeriv);
183 return myBaseCurve->DN(theU, theDeriv);
184}
185
186
d660a72a 187
188
189Standard_Boolean Geom2dEvaluator_OffsetCurve::AdjustDerivative(
190 const Standard_Integer theMaxDerivative, const Standard_Real theU,
191 gp_Vec2d& theD1, gp_Vec2d& theD2, gp_Vec2d& theD3, gp_Vec2d& theD4) const
192{
193 static const Standard_Real aTol = gp::Resolution();
194 static const Standard_Real aMinStep = 1e-7;
195 static const Standard_Integer aMaxDerivOrder = 3;
196
197 Standard_Boolean isDirectionChange = Standard_False;
198 Standard_Real anUinfium;
199 Standard_Real anUsupremum;
200 if (!myBaseAdaptor.IsNull())
201 {
202 anUinfium = myBaseAdaptor->FirstParameter();
203 anUsupremum = myBaseAdaptor->LastParameter();
204 }
205 else
206 {
207 anUinfium = myBaseCurve->FirstParameter();
208 anUsupremum = myBaseCurve->LastParameter();
209 }
210
211 static const Standard_Real DivisionFactor = 1.e-3;
212 Standard_Real du;
213 if ((anUsupremum >= RealLast()) || (anUinfium <= RealFirst()))
214 du = 0.0;
215 else
216 du = anUsupremum - anUinfium;
217
218 const Standard_Real aDelta = Max(du * DivisionFactor, aMinStep);
219
220 //Derivative is approximated by Taylor-series
221 Standard_Integer anIndex = 1; //Derivative order
222 gp_Vec2d V;
223
224 do
225 {
226 V = BaseDN(theU, ++anIndex);
227 } while ((V.SquareMagnitude() <= aTol) && anIndex < aMaxDerivOrder);
228
229 Standard_Real u;
230
231 if (theU - anUinfium < aDelta)
232 u = theU + aDelta;
233 else
234 u = theU - aDelta;
235
236 gp_Pnt2d P1, P2;
237 BaseD0(Min(theU, u), P1);
238 BaseD0(Max(theU, u), P2);
239
240 gp_Vec2d V1(P1, P2);
241 isDirectionChange = V.Dot(V1) < 0.0;
242 Standard_Real aSign = isDirectionChange ? -1.0 : 1.0;
243
244 theD1 = V * aSign;
245 gp_Vec2d* aDeriv[3] = { &theD2, &theD3, &theD4 };
246 for (Standard_Integer i = 1; i < theMaxDerivative; i++)
247 *(aDeriv[i - 1]) = BaseDN(theU, anIndex + i) * aSign;
248
249 return isDirectionChange;
250}
251