Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 1991-06-25 |
2 | // Created by: JCV | |
3 | // Copyright (c) 1991-1999 Matra Datavision | |
4 | // Copyright (c) 1999-2012 OPEN CASCADE SAS | |
5 | // | |
6 | // The content of this file is subject to the Open CASCADE Technology Public | |
7 | // License Version 6.5 (the "License"). You may not use the content of this file | |
8 | // except in compliance with the License. Please obtain a copy of the License | |
9 | // at http://www.opencascade.org and read it completely before using this file. | |
10 | // | |
11 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its | |
12 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. | |
13 | // | |
14 | // The Original Code and all software distributed under the License is | |
15 | // distributed on an "AS IS" basis, without warranty of any kind, and the | |
16 | // Initial Developer hereby disclaims all such warranties, including without | |
17 | // limitation, any warranties of merchantability, fitness for a particular | |
18 | // purpose or non-infringement. Please see the License for the specific terms | |
19 | // and conditions governing the rights and limitations under the License. | |
20 | ||
7fd59977 | 21 | |
7fd59977 | 22 | // 24-Aug-95 : xab removed C1 and C2 test : appeller D1 et D2 |
23 | // avec discernement ! | |
24 | // 19-09-97 : JPI correction derivee seconde | |
7fd59977 | 25 | |
26 | ||
27 | #include <Geom_OffsetCurve.ixx> | |
28 | ||
29 | ||
30 | #include <gp.hxx> | |
31 | #include <gp_XYZ.hxx> | |
32 | #include <Geom_Line.hxx> | |
33 | #include <Geom_Circle.hxx> | |
34 | #include <Geom_Ellipse.hxx> | |
35 | #include <Geom_Hyperbola.hxx> | |
36 | #include <Geom_Parabola.hxx> | |
37 | #include <Geom_BezierCurve.hxx> | |
38 | #include <Geom_TrimmedCurve.hxx> | |
39 | #include <Geom_BSplineCurve.hxx> | |
40 | #include <Geom_Geometry.hxx> | |
41 | ||
42 | #include <Geom_UndefinedDerivative.hxx> | |
43 | #include <Geom_UndefinedValue.hxx> | |
44 | #include <Standard_ConstructionError.hxx> | |
45 | #include <Standard_RangeError.hxx> | |
46 | #include <Standard_NotImplemented.hxx> | |
47 | ||
48 | typedef Geom_OffsetCurve OffsetCurve; | |
49 | typedef Handle(Geom_OffsetCurve) Handle(OffsetCurve); | |
50 | typedef Geom_Curve Curve; | |
51 | typedef Handle(Geom_Curve) Handle(Curve); | |
52 | typedef Handle(Geom_Geometry) Handle(Geometry); | |
53 | ||
54 | typedef gp_Dir Dir; | |
55 | typedef gp_Pnt Pnt; | |
56 | typedef gp_Trsf Trsf; | |
57 | typedef gp_Vec Vec; | |
58 | typedef gp_XYZ XYZ; | |
59 | ||
60 | ||
61 | ||
62 | ||
32ca7a51 | 63 | //ordre de derivation maximum pour la recherche de la premiere |
64 | //derivee non nulle | |
65 | static const int maxDerivOrder = 3; | |
66 | static const Standard_Real MinStep = 1e-7; | |
7fd59977 | 67 | |
7fd59977 | 68 | |
69 | ||
70 | ||
71 | //======================================================================= | |
72 | //function : Copy | |
73 | //purpose : | |
74 | //======================================================================= | |
75 | ||
76 | Handle(Geom_Geometry) Geom_OffsetCurve::Copy () const { | |
77 | ||
78 | Handle(OffsetCurve) C; | |
79 | C = new OffsetCurve (basisCurve, offsetValue, direction); | |
80 | return C; | |
81 | } | |
82 | ||
83 | ||
84 | ||
85 | //======================================================================= | |
86 | //function : Geom_OffsetCurve | |
87 | //purpose : | |
88 | //======================================================================= | |
89 | ||
90 | Geom_OffsetCurve::Geom_OffsetCurve (const Handle(Curve)& C, | |
91 | const Standard_Real Offset, | |
92 | const Dir& V ) | |
06be28a4 RL |
93 | : direction(V), offsetValue(Offset) |
94 | { | |
7fd59977 | 95 | if (C->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve)) { |
b9e76f05 | 96 | Handle(OffsetCurve) OC = Handle(OffsetCurve)::DownCast(C); |
06be28a4 | 97 | SetBasisCurve (OC->BasisCurve()); |
7fd59977 | 98 | |
7fd59977 | 99 | Standard_Real PrevOff = OC->Offset(); |
100 | gp_Vec V1(OC->Direction()); | |
101 | gp_Vec V2(direction); | |
102 | gp_Vec Vdir(PrevOff*V1 + offsetValue*V2); | |
103 | ||
104 | if (Offset >= 0.) { | |
105 | offsetValue = Vdir.Magnitude(); | |
106 | direction.SetXYZ(Vdir.XYZ()); | |
107 | } else { | |
108 | offsetValue = -Vdir.Magnitude(); | |
109 | direction.SetXYZ((-Vdir).XYZ()); | |
110 | } | |
06be28a4 RL |
111 | } |
112 | else { | |
113 | SetBasisCurve(C); | |
7fd59977 | 114 | } |
115 | } | |
116 | ||
117 | ||
118 | //======================================================================= | |
119 | //function : Reverse | |
120 | //purpose : | |
121 | //======================================================================= | |
122 | ||
123 | void Geom_OffsetCurve::Reverse () | |
124 | { | |
125 | basisCurve->Reverse(); | |
126 | offsetValue = -offsetValue; | |
127 | } | |
128 | ||
129 | ||
130 | //======================================================================= | |
131 | //function : ReversedParameter | |
132 | //purpose : | |
133 | //======================================================================= | |
134 | ||
135 | Standard_Real Geom_OffsetCurve::ReversedParameter( const Standard_Real U) const | |
136 | { | |
137 | return basisCurve->ReversedParameter( U); | |
138 | } | |
139 | ||
140 | //======================================================================= | |
141 | //function : Direction | |
142 | //purpose : | |
143 | //======================================================================= | |
144 | ||
145 | const gp_Dir& Geom_OffsetCurve::Direction () const | |
146 | { return direction; } | |
147 | ||
148 | //======================================================================= | |
149 | //function : SetDirection | |
150 | //purpose : | |
151 | //======================================================================= | |
152 | ||
153 | void Geom_OffsetCurve::SetDirection (const Dir& V) | |
154 | { direction = V; } | |
155 | ||
156 | //======================================================================= | |
157 | //function : SetOffsetValue | |
158 | //purpose : | |
159 | //======================================================================= | |
160 | ||
161 | void Geom_OffsetCurve::SetOffsetValue (const Standard_Real D) | |
162 | { offsetValue = D; } | |
163 | ||
164 | ||
165 | //======================================================================= | |
166 | //function : IsPeriodic | |
167 | //purpose : | |
168 | //======================================================================= | |
169 | ||
170 | Standard_Boolean Geom_OffsetCurve::IsPeriodic () const | |
171 | { | |
172 | return basisCurve->IsPeriodic(); | |
173 | } | |
174 | ||
175 | //======================================================================= | |
176 | //function : Period | |
177 | //purpose : | |
178 | //======================================================================= | |
179 | ||
180 | Standard_Real Geom_OffsetCurve::Period () const | |
181 | { | |
182 | return basisCurve->Period(); | |
183 | } | |
184 | ||
185 | //======================================================================= | |
186 | //function : SetBasisCurve | |
187 | //purpose : | |
188 | //======================================================================= | |
189 | ||
06be28a4 RL |
190 | void Geom_OffsetCurve::SetBasisCurve (const Handle(Curve)& C) |
191 | { | |
192 | Handle(Curve) aBasisCurve = Handle(Curve)::DownCast(C->Copy()); | |
193 | ||
194 | // Basis curve must be at least C1 | |
195 | if (aBasisCurve->Continuity() == GeomAbs_C0) | |
196 | { | |
197 | // For B-splines it is sometimes possible to increase continuity by removing | |
198 | // unnecessarily duplicated knots | |
199 | if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) | |
200 | { | |
201 | Handle(Geom_BSplineCurve) aBCurve = Handle(Geom_BSplineCurve)::DownCast(aBasisCurve); | |
202 | Standard_Integer degree = aBCurve->Degree(); | |
203 | Standard_Real Toler = Precision::Confusion(); | |
204 | Standard_Integer start = aBCurve->IsPeriodic() ? 1 : aBCurve->FirstUKnotIndex(), | |
205 | finish = aBCurve->IsPeriodic() ? aBCurve->NbKnots() : aBCurve->LastUKnotIndex(); | |
206 | for (Standard_Integer i = start; i <= finish; i++) | |
207 | { | |
208 | Standard_Integer mult = aBCurve->Multiplicity(i); | |
209 | if ( mult == degree ) | |
210 | aBCurve->RemoveKnot(i,degree - 1, Toler); | |
211 | } | |
212 | } | |
213 | ||
214 | // Raise exception if still C0 | |
215 | if (aBasisCurve->Continuity() == GeomAbs_C0) | |
216 | Standard_ConstructionError::Raise("Offset on C0 curve"); | |
217 | } | |
7fd59977 | 218 | |
06be28a4 | 219 | basisCurve = aBasisCurve; |
7fd59977 | 220 | } |
221 | ||
222 | ||
223 | ||
224 | //======================================================================= | |
225 | //function : BasisCurve | |
226 | //purpose : | |
227 | //======================================================================= | |
228 | ||
229 | Handle(Curve) Geom_OffsetCurve::BasisCurve () const | |
230 | { | |
231 | return basisCurve; | |
232 | } | |
233 | ||
234 | ||
235 | //======================================================================= | |
236 | //function : Continuity | |
237 | //purpose : | |
238 | //======================================================================= | |
239 | ||
240 | GeomAbs_Shape Geom_OffsetCurve::Continuity () const { | |
241 | ||
242 | GeomAbs_Shape OffsetShape=GeomAbs_C0; | |
243 | switch (basisCurve->Continuity()) { | |
244 | case GeomAbs_C0 : OffsetShape = GeomAbs_C0; break; | |
245 | case GeomAbs_C1 : OffsetShape = GeomAbs_C0; break; | |
246 | case GeomAbs_C2 : OffsetShape = GeomAbs_C1; break; | |
247 | case GeomAbs_C3 : OffsetShape = GeomAbs_C2; break; | |
248 | case GeomAbs_CN : OffsetShape = GeomAbs_CN; break; | |
249 | case GeomAbs_G1 : OffsetShape = GeomAbs_G1; break; | |
250 | case GeomAbs_G2 : OffsetShape = GeomAbs_G2; break; | |
251 | } | |
252 | return OffsetShape; | |
253 | } | |
254 | ||
255 | ||
256 | //======================================================================= | |
257 | //function : D0 | |
258 | //purpose : | |
259 | //======================================================================= | |
260 | ||
261 | void Geom_OffsetCurve::D0 (const Standard_Real U, Pnt& P) const | |
262 | { | |
263 | gp_Pnt PBasis; | |
264 | gp_Vec VBasis; | |
265 | D0(U,P,PBasis,VBasis); | |
266 | } | |
267 | ||
268 | ||
269 | //======================================================================= | |
270 | //function : D1 | |
271 | //purpose : | |
272 | //======================================================================= | |
273 | ||
274 | void Geom_OffsetCurve::D1 (const Standard_Real U, Pnt& P, Vec& V1) const | |
275 | { | |
276 | gp_Pnt PBasis; | |
277 | gp_Vec V1Basis,V2Basis; | |
278 | D1(U,P,PBasis,V1,V1Basis,V2Basis); | |
279 | } | |
280 | ||
281 | ||
282 | ||
283 | //======================================================================= | |
284 | //function : D2 | |
285 | //purpose : | |
286 | //======================================================================= | |
287 | ||
288 | void Geom_OffsetCurve::D2 (const Standard_Real U, Pnt& P, Vec& V1, Vec& V2) const | |
289 | { | |
290 | gp_Pnt PBasis; | |
291 | gp_Vec V1Basis,V2Basis,V3Basis; | |
292 | D2(U,P,PBasis,V1,V2,V1Basis,V2Basis,V3Basis); | |
293 | } | |
294 | ||
295 | ||
296 | //======================================================================= | |
297 | //function : D3 | |
298 | //purpose : | |
299 | //======================================================================= | |
300 | ||
32ca7a51 | 301 | void Geom_OffsetCurve::D3 (const Standard_Real theU, Pnt& P, Vec& theV1, Vec& V2, Vec& V3) |
7fd59977 | 302 | const { |
303 | ||
304 | ||
305 | // P(u) = p(u) + Offset * Ndir / R | |
306 | // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction) | |
307 | ||
308 | // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R)) | |
309 | ||
310 | // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) + | |
311 | // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2))) | |
312 | ||
313 | //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2) * D2Ndir - | |
314 | // (3.0 * D2r / R2) * DNdir + (3.0 * Dr * Dr / R4) * DNdir - | |
315 | // (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir + | |
316 | // (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir | |
317 | ||
32ca7a51 | 318 | const Standard_Real aTol = gp::Resolution(); |
319 | ||
320 | Standard_Boolean IsDirectionChange = Standard_False; | |
321 | ||
322 | basisCurve->D3 (theU, P, theV1, V2, V3); | |
323 | Vec V4 = basisCurve->DN (theU, 4); | |
324 | if(theV1.Magnitude() <= aTol) | |
325 | { | |
326 | const Standard_Real anUinfium = basisCurve->FirstParameter(); | |
327 | const Standard_Real anUsupremum = basisCurve->LastParameter(); | |
328 | ||
329 | const Standard_Real DivisionFactor = 1.e-3; | |
330 | Standard_Real du; | |
331 | if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) | |
332 | du = 0.0; | |
333 | else | |
334 | du = anUsupremum-anUinfium; | |
335 | ||
336 | const Standard_Real aDelta = Max(du*DivisionFactor,MinStep); | |
337 | //Derivative is approximated by Taylor-series | |
338 | ||
339 | Standard_Integer anIndex = 1; //Derivative order | |
340 | Vec V; | |
341 | ||
342 | do | |
343 | { | |
344 | V = basisCurve->DN(theU,++anIndex); | |
345 | } | |
346 | while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder); | |
347 | ||
348 | Standard_Real u; | |
349 | ||
350 | if(theU-anUinfium < aDelta) | |
351 | u = theU+aDelta; | |
352 | else | |
353 | u = theU-aDelta; | |
354 | ||
355 | Pnt P1, P2; | |
356 | basisCurve->D0(Min(theU, u),P1); | |
357 | basisCurve->D0(Max(theU, u),P2); | |
358 | ||
359 | Vec V1(P1,P2); | |
360 | Standard_Real aDirFactor = V.Dot(V1); | |
361 | ||
362 | if(aDirFactor < 0.0) | |
363 | { | |
364 | theV1 = -V; | |
365 | V2 = -basisCurve->DN (theU, anIndex + 1); | |
366 | V3 = -basisCurve->DN (theU, anIndex + 2); | |
367 | V4 = -basisCurve->DN (theU, anIndex + 3); | |
368 | ||
369 | IsDirectionChange = Standard_True; | |
370 | } | |
371 | else | |
372 | { | |
373 | theV1 = V; | |
374 | V2 = basisCurve->DN (theU, anIndex + 1); | |
375 | V3 = basisCurve->DN (theU, anIndex + 2); | |
376 | V4 = basisCurve->DN (theU, anIndex + 3); | |
377 | } | |
378 | }//if(V1.Magnitude() <= aTol) | |
7fd59977 | 379 | |
380 | ||
7fd59977 | 381 | XYZ OffsetDir = direction.XYZ(); |
32ca7a51 | 382 | XYZ Ndir = (theV1.XYZ()).Crossed (OffsetDir); |
7fd59977 | 383 | XYZ DNdir = (V2.XYZ()).Crossed (OffsetDir); |
384 | XYZ D2Ndir = (V3.XYZ()).Crossed (OffsetDir); | |
385 | XYZ D3Ndir = (V4.XYZ()).Crossed (OffsetDir); | |
386 | Standard_Real R2 = Ndir.SquareModulus(); | |
387 | Standard_Real R = Sqrt (R2); | |
388 | Standard_Real R3 = R2 * R; | |
389 | Standard_Real R4 = R2 * R2; | |
390 | Standard_Real R5 = R3 * R2; | |
391 | Standard_Real R6 = R3 * R3; | |
392 | Standard_Real R7 = R5 * R2; | |
393 | Standard_Real Dr = Ndir.Dot (DNdir); | |
394 | Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir); | |
395 | Standard_Real D3r = Ndir.Dot (D3Ndir) + 3.0 * DNdir.Dot (D2Ndir); | |
396 | if (R7 <= gp::Resolution()) { | |
397 | if (R6 <= gp::Resolution()) Geom_UndefinedDerivative::Raise(); | |
398 | // V3 = P"' (U) : | |
399 | D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R2)); | |
400 | D3Ndir.Subtract (DNdir.Multiplied (3.0 * ((D2r/R2) + (Dr*Dr/R4)))); | |
401 | D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 - | |
402 | 15.0*Dr*Dr*Dr/R6 - D3r)); | |
403 | D3Ndir.Multiply (offsetValue/R); | |
32ca7a51 | 404 | |
405 | if(IsDirectionChange) | |
406 | V3=-V3; | |
407 | ||
7fd59977 | 408 | V3.Add (Vec(D3Ndir)); |
32ca7a51 | 409 | |
7fd59977 | 410 | // V2 = P" (U) : |
411 | Standard_Real R4 = R2 * R2; | |
412 | D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2)); | |
413 | D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R4) - (D2r / R2))); | |
414 | D2Ndir.Multiply (offsetValue / R); | |
415 | V2.Add (Vec(D2Ndir)); | |
416 | // V1 = P' (U) : | |
417 | DNdir.Multiply(R); | |
418 | DNdir.Subtract (Ndir.Multiplied (Dr/R)); | |
419 | DNdir.Multiply (offsetValue/R2); | |
32ca7a51 | 420 | theV1.Add (Vec(DNdir)); |
7fd59977 | 421 | } |
422 | else { | |
423 | // V3 = P"' (U) : | |
424 | D3Ndir.Divide (R); | |
425 | D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * Dr / R3)); | |
426 | D3Ndir.Subtract (DNdir.Multiplied ((3.0 * ((D2r/R3) + (Dr*Dr)/R5)))); | |
427 | D3Ndir.Add (Ndir.Multiplied (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - | |
428 | 15.0*Dr*Dr*Dr/R7 - D3r)); | |
429 | D3Ndir.Multiply (offsetValue); | |
32ca7a51 | 430 | |
431 | if(IsDirectionChange) | |
432 | V3=-V3; | |
433 | ||
7fd59977 | 434 | V3.Add (Vec(D3Ndir)); |
32ca7a51 | 435 | |
7fd59977 | 436 | // V2 = P" (U) : |
437 | D2Ndir.Divide (R); | |
438 | D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R3)); | |
439 | D2Ndir.Subtract (Ndir.Multiplied ((3.0 * Dr * Dr / R5) - (D2r / R3))); | |
440 | D2Ndir.Multiply (offsetValue); | |
441 | V2.Add (Vec(D2Ndir)); | |
442 | // V1 = P' (U) : | |
443 | DNdir.Multiply (offsetValue/R); | |
444 | DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3)); | |
32ca7a51 | 445 | theV1.Add (Vec(DNdir)); |
7fd59977 | 446 | } |
447 | //P (U) : | |
32ca7a51 | 448 | D0(theU,P); |
7fd59977 | 449 | } |
450 | ||
451 | ||
452 | //======================================================================= | |
453 | //function : DN | |
454 | //purpose : | |
455 | //======================================================================= | |
456 | ||
32ca7a51 | 457 | Vec Geom_OffsetCurve::DN (const Standard_Real U, const Standard_Integer N) const |
458 | { | |
459 | Standard_RangeError_Raise_if (N < 1, "Exception: " | |
460 | "Geom_OffsetCurve::DN(...). N<1."); | |
7fd59977 | 461 | |
32ca7a51 | 462 | gp_Vec VN, Vtemp; |
463 | gp_Pnt Ptemp; | |
464 | switch (N) | |
465 | { | |
466 | case 1: | |
467 | D1( U, Ptemp, VN); | |
468 | break; | |
469 | case 2: | |
470 | D2( U, Ptemp, Vtemp, VN); | |
471 | break; | |
472 | case 3: | |
473 | D3( U, Ptemp, Vtemp, Vtemp, VN); | |
474 | break; | |
475 | default: | |
476 | Standard_NotImplemented::Raise("Exception: " | |
477 | "Derivative order is greater than 3. Cannot compute of derivative."); | |
7fd59977 | 478 | } |
32ca7a51 | 479 | |
480 | return VN; | |
7fd59977 | 481 | } |
482 | ||
483 | //======================================================================= | |
484 | //function : D0 | |
485 | //purpose : | |
486 | //======================================================================= | |
487 | ||
32ca7a51 | 488 | void Geom_OffsetCurve::D0(const Standard_Real theU, gp_Pnt& theP, |
489 | gp_Pnt& thePbasis, gp_Vec& theV1basis)const | |
490 | { | |
491 | const Standard_Real aTol = gp::Resolution(); | |
7fd59977 | 492 | |
32ca7a51 | 493 | basisCurve->D1 (theU, thePbasis, theV1basis); |
494 | Standard_Real Ndu = theV1basis.Magnitude(); | |
495 | ||
496 | if(Ndu <= aTol) | |
497 | { | |
498 | const Standard_Real anUinfium = basisCurve->FirstParameter(); | |
499 | const Standard_Real anUsupremum = basisCurve->LastParameter(); | |
500 | ||
501 | const Standard_Real DivisionFactor = 1.e-3; | |
502 | Standard_Real du; | |
503 | if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) | |
504 | du = 0.0; | |
505 | else | |
506 | du = anUsupremum-anUinfium; | |
507 | ||
508 | const Standard_Real aDelta = Max(du*DivisionFactor,MinStep); | |
509 | //Derivative is approximated by Taylor-series | |
510 | ||
511 | Standard_Integer anIndex = 1; //Derivative order | |
512 | gp_Vec V; | |
513 | ||
514 | do | |
515 | { | |
516 | V = basisCurve->DN(theU,++anIndex); | |
517 | Ndu = V.Magnitude(); | |
518 | } | |
519 | while((Ndu <= aTol) && anIndex < maxDerivOrder); | |
520 | ||
521 | Standard_Real u; | |
522 | ||
523 | if(theU-anUinfium < aDelta) | |
524 | u = theU+aDelta; | |
525 | else | |
526 | u = theU-aDelta; | |
527 | ||
528 | gp_Pnt P1, P2; | |
529 | basisCurve->D0(Min(theU, u),P1); | |
530 | basisCurve->D0(Max(theU, u),P2); | |
531 | ||
532 | gp_Vec V1(P1,P2); | |
533 | Standard_Real aDirFactor = V.Dot(V1); | |
534 | ||
535 | if(aDirFactor < 0.0) | |
536 | theV1basis = -V; | |
537 | else | |
538 | theV1basis = V; | |
539 | ||
540 | Ndu = theV1basis.Magnitude(); | |
541 | }//if(Ndu <= aTol) | |
542 | ||
543 | XYZ Ndir = (theV1basis.XYZ()).Crossed (direction.XYZ()); | |
7fd59977 | 544 | Standard_Real R = Ndir.Modulus(); |
32ca7a51 | 545 | if (R <= gp::Resolution()) |
546 | Geom_UndefinedValue::Raise("Exception: Undefined normal vector " | |
547 | "because tangent vector has zero-magnitude!"); | |
548 | ||
7fd59977 | 549 | Ndir.Multiply (offsetValue/R); |
32ca7a51 | 550 | Ndir.Add (thePbasis.XYZ()); |
551 | theP.SetXYZ(Ndir); | |
7fd59977 | 552 | } |
553 | ||
554 | //======================================================================= | |
555 | //function : D1 | |
556 | //purpose : | |
557 | //======================================================================= | |
558 | ||
32ca7a51 | 559 | void Geom_OffsetCurve::D1 ( const Standard_Real theU, |
7fd59977 | 560 | Pnt& P , Pnt& PBasis , |
32ca7a51 | 561 | Vec& theV1, Vec& V1basis, Vec& V2basis) const { |
7fd59977 | 562 | |
563 | // P(u) = p(u) + Offset * Ndir / R | |
564 | // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction) | |
565 | ||
566 | // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R)) | |
567 | ||
32ca7a51 | 568 | const Standard_Real aTol = gp::Resolution(); |
569 | ||
570 | basisCurve->D2 (theU, PBasis, V1basis, V2basis); | |
571 | theV1 = V1basis; | |
7fd59977 | 572 | Vec V2 = V2basis; |
32ca7a51 | 573 | |
574 | if(theV1.Magnitude() <= aTol) | |
575 | { | |
576 | const Standard_Real anUinfium = basisCurve->FirstParameter(); | |
577 | const Standard_Real anUsupremum = basisCurve->LastParameter(); | |
578 | ||
579 | const Standard_Real DivisionFactor = 1.e-3; | |
580 | Standard_Real du; | |
581 | if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) | |
582 | du = 0.0; | |
583 | else | |
584 | du = anUsupremum-anUinfium; | |
585 | ||
586 | const Standard_Real aDelta = Max(du*DivisionFactor,MinStep); | |
587 | //Derivative is approximated by Taylor-series | |
588 | ||
589 | Standard_Integer anIndex = 1; //Derivative order | |
590 | Vec V; | |
591 | ||
592 | do | |
593 | { | |
594 | V = basisCurve->DN(theU,++anIndex); | |
595 | } | |
596 | while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder); | |
597 | ||
598 | Standard_Real u; | |
599 | ||
600 | if(theU-anUinfium < aDelta) | |
601 | u = theU+aDelta; | |
602 | else | |
603 | u = theU-aDelta; | |
604 | ||
605 | Pnt P1, P2; | |
606 | basisCurve->D0(Min(theU, u),P1); | |
607 | basisCurve->D0(Max(theU, u),P2); | |
608 | ||
609 | Vec V1(P1,P2); | |
610 | Standard_Real aDirFactor = V.Dot(V1); | |
611 | ||
612 | if(aDirFactor < 0.0) | |
613 | { | |
614 | theV1 = -V; | |
615 | V2 = - basisCurve->DN (theU, anIndex+1); | |
616 | } | |
617 | else | |
618 | { | |
619 | theV1 = V; | |
620 | V2 = basisCurve->DN (theU, anIndex+1); | |
621 | } | |
622 | ||
623 | V2basis = V2; | |
624 | V1basis = theV1; | |
625 | }//if(theV1.Magnitude() <= aTol) | |
626 | ||
7fd59977 | 627 | XYZ OffsetDir = direction.XYZ(); |
32ca7a51 | 628 | XYZ Ndir = (theV1.XYZ()).Crossed (OffsetDir); |
7fd59977 | 629 | XYZ DNdir = (V2.XYZ()).Crossed (OffsetDir); |
630 | Standard_Real R2 = Ndir.SquareModulus(); | |
631 | Standard_Real R = Sqrt (R2); | |
632 | Standard_Real R3 = R * R2; | |
633 | Standard_Real Dr = Ndir.Dot (DNdir); | |
634 | if (R3 <= gp::Resolution()) { | |
635 | //We try another computation but the stability is not very good. | |
636 | if (R2 <= gp::Resolution()) Geom_UndefinedDerivative::Raise(); | |
637 | DNdir.Multiply(R); | |
638 | DNdir.Subtract (Ndir.Multiplied (Dr/R)); | |
639 | DNdir.Multiply (offsetValue/R2); | |
32ca7a51 | 640 | theV1.Add (Vec(DNdir)); |
7fd59977 | 641 | } |
642 | else { | |
643 | // Same computation as IICURV in EUCLID-IS because the stability is | |
644 | // better | |
645 | DNdir.Multiply (offsetValue/R); | |
646 | DNdir.Subtract (Ndir.Multiplied (offsetValue * Dr/R3)); | |
32ca7a51 | 647 | theV1.Add (Vec(DNdir)); |
7fd59977 | 648 | } |
32ca7a51 | 649 | D0(theU,P); |
7fd59977 | 650 | } |
651 | ||
652 | ||
653 | //======================================================================= | |
654 | //function : D2 | |
655 | //purpose : | |
656 | //======================================================================= | |
657 | ||
32ca7a51 | 658 | void Geom_OffsetCurve::D2 (const Standard_Real theU, |
7fd59977 | 659 | Pnt& P , Pnt& PBasis , |
32ca7a51 | 660 | Vec& theV1 , Vec& V2 , |
7fd59977 | 661 | Vec& V1basis, Vec& V2basis, Vec& V3basis) const { |
662 | ||
663 | // P(u) = p(u) + Offset * Ndir / R | |
664 | // with R = || p' ^ V|| and Ndir = P' ^ direction (local normal direction) | |
665 | ||
666 | // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R)) | |
667 | ||
668 | // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) + | |
669 | // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2))) | |
670 | ||
32ca7a51 | 671 | const Standard_Real aTol = gp::Resolution(); |
672 | ||
673 | Standard_Boolean IsDirectionChange = Standard_False; | |
674 | ||
675 | basisCurve->D3 (theU, PBasis, V1basis, V2basis, V3basis); | |
676 | ||
677 | theV1 = V1basis; | |
7fd59977 | 678 | V2 = V2basis; |
679 | Vec V3 = V3basis; | |
32ca7a51 | 680 | |
681 | if(theV1.Magnitude() <= aTol) | |
682 | { | |
683 | const Standard_Real anUinfium = basisCurve->FirstParameter(); | |
684 | const Standard_Real anUsupremum = basisCurve->LastParameter(); | |
685 | ||
686 | const Standard_Real DivisionFactor = 1.e-3; | |
687 | Standard_Real du; | |
688 | if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) | |
689 | du = 0.0; | |
690 | else | |
691 | du = anUsupremum-anUinfium; | |
692 | ||
693 | const Standard_Real aDelta = Max(du*DivisionFactor,MinStep); | |
694 | //Derivative is approximated by Taylor-series | |
695 | ||
696 | Standard_Integer anIndex = 1; //Derivative order | |
697 | Vec V; | |
698 | ||
699 | do | |
700 | { | |
701 | V = basisCurve->DN(theU,++anIndex); | |
702 | } | |
703 | while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder); | |
704 | ||
705 | Standard_Real u; | |
706 | ||
707 | if(theU-anUinfium < aDelta) | |
708 | u = theU+aDelta; | |
709 | else | |
710 | u = theU-aDelta; | |
711 | ||
712 | Pnt P1, P2; | |
713 | basisCurve->D0(Min(theU, u),P1); | |
714 | basisCurve->D0(Max(theU, u),P2); | |
715 | ||
716 | Vec V1(P1,P2); | |
717 | Standard_Real aDirFactor = V.Dot(V1); | |
718 | ||
719 | if(aDirFactor < 0.0) | |
720 | { | |
721 | theV1 = -V; | |
722 | V2 = -basisCurve->DN (theU, anIndex+1); | |
723 | V3 = -basisCurve->DN (theU, anIndex + 2); | |
724 | ||
725 | IsDirectionChange = Standard_True; | |
726 | } | |
727 | else | |
728 | { | |
729 | theV1 = V; | |
730 | V2 = basisCurve->DN (theU, anIndex+1); | |
731 | V3 = basisCurve->DN (theU, anIndex + 2); | |
732 | } | |
733 | ||
734 | V2basis = V2; | |
735 | V1basis = theV1; | |
736 | }//if(V1.Magnitude() <= aTol) | |
737 | ||
7fd59977 | 738 | XYZ OffsetDir = direction.XYZ(); |
32ca7a51 | 739 | XYZ Ndir = (theV1.XYZ()).Crossed (OffsetDir); |
7fd59977 | 740 | XYZ DNdir = (V2.XYZ()).Crossed (OffsetDir); |
741 | XYZ D2Ndir = (V3.XYZ()).Crossed (OffsetDir); | |
742 | Standard_Real R2 = Ndir.SquareModulus(); | |
743 | Standard_Real R = Sqrt (R2); | |
744 | Standard_Real R3 = R2 * R; | |
745 | Standard_Real R4 = R2 * R2; | |
746 | Standard_Real R5 = R3 * R2; | |
747 | Standard_Real Dr = Ndir.Dot (DNdir); | |
748 | Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir); | |
32ca7a51 | 749 | |
7fd59977 | 750 | if (R5 <= gp::Resolution()) { |
751 | //We try another computation but the stability is not very good | |
752 | //dixit ISG. | |
753 | if (R4 <= gp::Resolution()) Geom_UndefinedDerivative::Raise(); | |
754 | // V2 = P" (U) : | |
755 | Standard_Real R4 = R2 * R2; | |
756 | D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2)); | |
757 | D2Ndir.Add (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2))); | |
758 | D2Ndir.Multiply (offsetValue / R); | |
32ca7a51 | 759 | |
760 | if(IsDirectionChange) | |
761 | V2=-V2; | |
762 | ||
7fd59977 | 763 | V2.Add (Vec(D2Ndir)); |
32ca7a51 | 764 | |
7fd59977 | 765 | // V1 = P' (U) : |
766 | DNdir.Multiply(R); | |
767 | DNdir.Subtract (Ndir.Multiplied (Dr/R)); | |
768 | DNdir.Multiply (offsetValue/R2); | |
32ca7a51 | 769 | theV1.Add (Vec(DNdir)); |
7fd59977 | 770 | } |
771 | else { | |
772 | // Same computation as IICURV in EUCLID-IS because the stability is | |
773 | // better. | |
774 | // V2 = P" (U) : | |
775 | D2Ndir.Multiply (offsetValue/R); | |
776 | D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3)); | |
777 | D2Ndir.Add (Ndir.Multiplied ( | |
778 | offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3)) | |
779 | ) | |
780 | ); | |
32ca7a51 | 781 | |
782 | if(IsDirectionChange) | |
783 | V2=-V2; | |
784 | ||
7fd59977 | 785 | V2.Add (Vec(D2Ndir)); |
32ca7a51 | 786 | |
7fd59977 | 787 | // V1 = P' (U) : |
788 | DNdir.Multiply (offsetValue/R); | |
789 | DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3)); | |
32ca7a51 | 790 | theV1.Add (Vec(DNdir)); |
7fd59977 | 791 | } |
792 | //P (U) : | |
32ca7a51 | 793 | D0(theU,P); |
7fd59977 | 794 | } |
795 | ||
796 | ||
797 | //======================================================================= | |
798 | //function : FirstParameter | |
799 | //purpose : | |
800 | //======================================================================= | |
801 | ||
802 | Standard_Real Geom_OffsetCurve::FirstParameter () const { | |
803 | ||
804 | return basisCurve->FirstParameter(); | |
805 | } | |
806 | ||
807 | ||
808 | //======================================================================= | |
809 | //function : LastParameter | |
810 | //purpose : | |
811 | //======================================================================= | |
812 | ||
813 | Standard_Real Geom_OffsetCurve::LastParameter () const { | |
814 | ||
815 | return basisCurve->LastParameter(); | |
816 | } | |
817 | ||
818 | ||
819 | //======================================================================= | |
820 | //function : Offset | |
821 | //purpose : | |
822 | //======================================================================= | |
823 | ||
824 | Standard_Real Geom_OffsetCurve::Offset () const { return offsetValue; } | |
825 | ||
826 | //======================================================================= | |
827 | //function : Value | |
828 | //purpose : | |
829 | //======================================================================= | |
830 | ||
32ca7a51 | 831 | void Geom_OffsetCurve::Value (const Standard_Real theU, Pnt& theP, |
832 | Pnt& thePbasis, Vec& theV1basis) const | |
833 | { | |
834 | if (basisCurve->Continuity() == GeomAbs_C0) | |
835 | Geom_UndefinedValue::Raise("Exception: Basis curve is C0 continuity!"); | |
7fd59977 | 836 | |
32ca7a51 | 837 | basisCurve->D1(theU, thePbasis, theV1basis); |
838 | D0(theU,theP); | |
7fd59977 | 839 | } |
7fd59977 | 840 | |
841 | ||
842 | //======================================================================= | |
843 | //function : IsClosed | |
844 | //purpose : | |
845 | //======================================================================= | |
846 | ||
847 | Standard_Boolean Geom_OffsetCurve::IsClosed () const | |
848 | { | |
849 | gp_Pnt PF,PL; | |
850 | D0(FirstParameter(),PF); | |
851 | D0(LastParameter(),PL); | |
852 | return ( PF.Distance(PL) <= gp::Resolution()); | |
853 | } | |
854 | ||
855 | ||
856 | ||
857 | //======================================================================= | |
858 | //function : IsCN | |
859 | //purpose : | |
860 | //======================================================================= | |
861 | ||
862 | Standard_Boolean Geom_OffsetCurve::IsCN (const Standard_Integer N) const { | |
863 | ||
864 | Standard_RangeError_Raise_if (N < 0, " "); | |
865 | return basisCurve->IsCN (N + 1); | |
866 | } | |
867 | ||
868 | ||
869 | //======================================================================= | |
870 | //function : Transform | |
871 | //purpose : | |
872 | //======================================================================= | |
873 | ||
874 | void Geom_OffsetCurve::Transform (const Trsf& T) { | |
875 | ||
876 | basisCurve->Transform (T); | |
877 | direction.Transform(T); | |
878 | offsetValue *= T.ScaleFactor(); | |
879 | } | |
880 | ||
881 | //======================================================================= | |
882 | //function : TransformedParameter | |
883 | //purpose : | |
884 | //======================================================================= | |
885 | ||
886 | Standard_Real Geom_OffsetCurve::TransformedParameter(const Standard_Real U, | |
887 | const gp_Trsf& T) const | |
888 | { | |
889 | return basisCurve->TransformedParameter(U,T); | |
890 | } | |
891 | ||
892 | //======================================================================= | |
893 | //function : ParametricTransformation | |
894 | //purpose : | |
895 | //======================================================================= | |
896 | ||
897 | Standard_Real Geom_OffsetCurve::ParametricTransformation(const gp_Trsf& T) | |
898 | const | |
899 | { | |
900 | return basisCurve->ParametricTransformation(T); | |
901 | } |