1 // Created on: 1991-06-25
3 // Copyright (c) 1991-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
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.
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.
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.
23 // modified by Edward AGAPOV (eap) Jan 28 2002 --- DN(), occ143(BUC60654)
27 #include <Geom2d_OffsetCurve.ixx>
29 #include <Standard_ConstructionError.hxx>
30 #include <Standard_RangeError.hxx>
31 #include <Standard_NotImplemented.hxx>
32 #include <Geom2d_UndefinedDerivative.hxx>
33 #include <Geom2d_UndefinedValue.hxx>
34 #include <Geom2d_Line.hxx>
35 #include <Geom2d_Circle.hxx>
36 #include <Geom2d_Ellipse.hxx>
37 #include <Geom2d_Hyperbola.hxx>
38 #include <Geom2d_Parabola.hxx>
39 #include <Geom2d_BezierCurve.hxx>
40 #include <Geom2d_BSplineCurve.hxx>
41 #include <Geom2d_TrimmedCurve.hxx>
44 typedef Handle(Geom2d_OffsetCurve) Handle(OffsetCurve);
45 typedef Geom2d_OffsetCurve OffsetCurve;
46 typedef Handle(Geom2d_Geometry) Handle(Geometry);
47 typedef Handle(Geom2d_Curve) Handle(Curve);
48 typedef Geom2d_Curve Curve;
49 typedef gp_Dir2d Dir2d;
50 typedef gp_Pnt2d Pnt2d;
51 typedef gp_Vec2d Vec2d;
52 typedef gp_Trsf2d Trsf2d;
57 static const int MaxDegree = 9;
58 //ordre de derivation maximum pour la recherche de la premiere
63 //=======================================================================
66 //=======================================================================
68 Handle(Geom2d_Geometry) Geom2d_OffsetCurve::Copy () const
70 Handle(OffsetCurve) C;
71 C = new OffsetCurve (basisCurve, offsetValue);
76 //=======================================================================
77 //function : Geom2d_OffsetCurve
79 //=======================================================================
81 Geom2d_OffsetCurve::Geom2d_OffsetCurve (const Handle(Curve)& C,
82 const Standard_Real Offset)
83 : offsetValue (Offset)
85 if (C->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)) {
86 Handle(OffsetCurve) OC = Handle(OffsetCurve)::DownCast(C);
87 if ((OC->BasisCurve())->Continuity() == GeomAbs_C0)
88 Standard_ConstructionError::Raise();
90 basisCurve = Handle(Curve)::DownCast((OC->BasisCurve())->Copy());
91 offsetValue += OC->Offset();
93 if (C->Continuity() == GeomAbs_C0)
94 Standard_ConstructionError::Raise();
96 basisCurve = Handle(Curve)::DownCast(C->Copy());
100 //=======================================================================
103 //=======================================================================
105 void Geom2d_OffsetCurve::Reverse ()
107 basisCurve->Reverse();
108 offsetValue = -offsetValue;
111 //=======================================================================
112 //function : ReversedParameter
114 //=======================================================================
116 Standard_Real Geom2d_OffsetCurve::ReversedParameter( const Standard_Real U) const
118 return basisCurve->ReversedParameter( U);
121 //=======================================================================
122 //function : SetBasisCurve
124 //=======================================================================
126 void Geom2d_OffsetCurve::SetBasisCurve (const Handle(Curve)& C)
128 if (C->Continuity() == GeomAbs_C0) Standard_ConstructionError::Raise();
129 basisCurve = Handle(Geom2d_Curve)::DownCast(C->Copy());
132 //=======================================================================
133 //function : SetOffsetValue
135 //=======================================================================
137 void Geom2d_OffsetCurve::SetOffsetValue (const Standard_Real D) { offsetValue = D; }
139 //=======================================================================
140 //function : BasisCurve
142 //=======================================================================
144 Handle(Curve) Geom2d_OffsetCurve::BasisCurve () const
149 //=======================================================================
150 //function : Continuity
152 //=======================================================================
154 GeomAbs_Shape Geom2d_OffsetCurve::Continuity () const
156 GeomAbs_Shape OffsetShape=GeomAbs_C0;
157 switch (basisCurve->Continuity()) {
158 case GeomAbs_C0 : OffsetShape = GeomAbs_C0; break;
159 case GeomAbs_C1 : OffsetShape = GeomAbs_C0; break;
160 case GeomAbs_C2 : OffsetShape = GeomAbs_C1; break;
161 case GeomAbs_C3 : OffsetShape = GeomAbs_C2; break;
162 case GeomAbs_CN : OffsetShape = GeomAbs_CN; break;
163 case GeomAbs_G1 : OffsetShape = GeomAbs_G1; break;
164 case GeomAbs_G2 : OffsetShape = GeomAbs_G2; break;
169 //=======================================================================
172 //=======================================================================
174 void Geom2d_OffsetCurve::D0 (const Standard_Real U,
179 basisCurve->D1 (U, P, V1);
180 Standard_Integer Index = 2;
181 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
182 V1 = basisCurve->DN (U, Index);
185 Standard_Real A = V1.Y();
186 Standard_Real B = - V1.X();
187 Standard_Real R = Sqrt(A*A + B * B);
188 if (R <= gp::Resolution()) Geom2d_UndefinedValue::Raise();
189 A = A * offsetValue/R;
190 B = B * offsetValue/R;
191 P.SetCoord(P.X() + A, P.Y() + B);
194 //=======================================================================
197 //=======================================================================
199 void Geom2d_OffsetCurve::D1 (const Standard_Real U, Pnt2d& P, Vec2d& V1) const {
201 // P(u) = p(u) + Offset * Ndir / R
202 // with R = || p' ^ Z|| and Ndir = P' ^ Z
204 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
207 basisCurve->D2 (U, P, V1, V2);
208 Standard_Integer Index = 2;
209 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
210 V1 = basisCurve->DN (U, Index);
213 if (Index != 2) { V2 = basisCurve->DN (U, Index); }
214 XY Ndir (V1.Y(), -V1.X());
215 XY DNdir (V2.Y(), -V2.X());
216 Standard_Real R2 = Ndir.SquareModulus();
217 Standard_Real R = Sqrt (R2);
218 Standard_Real R3 = R * R2;
219 Standard_Real Dr = Ndir.Dot (DNdir);
220 if (R3 <= gp::Resolution()) {
221 //We try another computation but the stability is not very good.
222 if (R2 <= gp::Resolution()) Geom2d_UndefinedDerivative::Raise();
224 DNdir.Subtract (Ndir.Multiplied (Dr/R));
225 DNdir.Multiply (offsetValue/R2);
226 V1.Add (Vec2d(DNdir));
229 // Same computation as IICURV in EUCLID-IS because the stability is
231 DNdir.Multiply (offsetValue/R);
232 DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));
233 V1.Add (Vec2d(DNdir));
235 Ndir.Multiply (offsetValue/R);
240 //=======================================================================
243 //=======================================================================
245 void Geom2d_OffsetCurve::D2 (const Standard_Real U,
247 Vec2d& V1, Vec2d& V2) const
249 // P(u) = p(u) + Offset * Ndir / R
250 // with R = || p' ^ Z|| and Ndir = P' ^ Z
252 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
254 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
255 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
258 basisCurve->D3 (U, P, V1, V2, V3);
259 Standard_Integer Index = 2;
260 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
261 V1 = basisCurve->DN (U, Index);
265 V2 = basisCurve->DN (U, Index);
266 V3 = basisCurve->DN (U, Index + 1);
268 XY Ndir (V1.Y(), -V1.X());
269 XY DNdir (V2.Y(), -V2.X());
270 XY D2Ndir (V3.Y(), -V3.X());
271 Standard_Real R2 = Ndir.SquareModulus();
272 Standard_Real R = Sqrt (R2);
273 Standard_Real R3 = R2 * R;
274 Standard_Real R4 = R2 * R2;
275 Standard_Real R5 = R3 * R2;
276 Standard_Real Dr = Ndir.Dot (DNdir);
277 Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
278 if (R5 <= gp::Resolution()) {
279 //We try another computation but the stability is not very good
281 if (R4 <= gp::Resolution()) { Geom2d_UndefinedDerivative::Raise(); }
283 Standard_Real R4 = R2 * R2;
284 D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
285 D2Ndir.Add (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
286 D2Ndir.Multiply (offsetValue / R);
287 V2.Add (Vec2d(D2Ndir));
290 DNdir.Subtract (Ndir.Multiplied (Dr/R));
291 DNdir.Multiply (offsetValue/R2);
292 V1.Add (Vec2d(DNdir));
295 // Same computation as IICURV in EUCLID-IS because the stability is
298 D2Ndir.Multiply (offsetValue/R);
299 D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
300 D2Ndir.Add (Ndir.Multiplied
301 (offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))));
302 V2.Add (Vec2d(D2Ndir));
304 DNdir.Multiply (offsetValue/R);
305 DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));
306 V1.Add (Vec2d(DNdir));
309 Ndir.Multiply (offsetValue/R);
315 //=======================================================================
318 //=======================================================================
320 void Geom2d_OffsetCurve::D3 (const Standard_Real U,
322 Vec2d& V1, Vec2d& V2, Vec2d& V3) const {
325 // P(u) = p(u) + Offset * Ndir / R
326 // with R = || p' ^ Z|| and Ndir = P' ^ Z
328 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
330 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
331 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
333 //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
334 // (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
335 // (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
336 // (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
340 basisCurve->D3 (U, P, V1, V2, V3);
341 Vec2d V4 = basisCurve->DN (U, 4);
342 Standard_Integer Index = 2;
343 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
344 V1 = basisCurve->DN (U, Index);
348 V2 = basisCurve->DN (U, Index);
349 V3 = basisCurve->DN (U, Index + 1);
350 V4 = basisCurve->DN (U, Index + 2);
352 XY Ndir (V1.Y(), -V1.X());
353 XY DNdir (V2.Y(), -V2.X());
354 XY D2Ndir (V3.Y(), -V3.X());
355 XY D3Ndir (V4.Y(), -V4.X());
356 Standard_Real R2 = Ndir.SquareModulus();
357 Standard_Real R = Sqrt (R2);
358 Standard_Real R3 = R2 * R;
359 Standard_Real R4 = R2 * R2;
360 Standard_Real R5 = R3 * R2;
361 Standard_Real R6 = R3 * R3;
362 Standard_Real R7 = R5 * R2;
363 Standard_Real Dr = Ndir.Dot (DNdir);
364 Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
365 Standard_Real D3r = Ndir.Dot (D3Ndir) + 3.0 * DNdir.Dot (D2Ndir);
366 if (R7 <= gp::Resolution()) {
367 //We try another computation but the stability is not very good
369 if (R6 <= gp::Resolution()) Geom2d_UndefinedDerivative::Raise();
371 D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * offsetValue * Dr / R2));
373 (DNdir.Multiplied ((3.0 * offsetValue) * ((D2r/R2) + (Dr*Dr)/R4))));
374 D3Ndir.Add (Ndir.Multiplied (
375 (offsetValue * (6.0*Dr*Dr/R4 + 6.0*Dr*D2r/R4 - 15.0*Dr*Dr*Dr/R6 - D3r))
377 D3Ndir.Multiply (offsetValue/R);
378 V3.Add (Vec2d(D3Ndir));
380 Standard_Real R4 = R2 * R2;
381 D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
382 D2Ndir.Subtract (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
383 D2Ndir.Multiply (offsetValue / R);
384 V2.Add (Vec2d(D2Ndir));
387 DNdir.Subtract (Ndir.Multiplied (Dr/R));
388 DNdir.Multiply (offsetValue/R2);
389 V1.Add (Vec2d(DNdir));
392 // Same computation as IICURV in EUCLID-IS because the stability is
395 D3Ndir.Multiply (offsetValue/R);
396 D3Ndir.Subtract (D2Ndir.Multiplied (3.0 * offsetValue * Dr / R3));
397 D3Ndir.Subtract (DNdir.Multiplied (
398 ((3.0 * offsetValue) * ((D2r/R3) + (Dr*Dr)/R5))) );
399 D3Ndir.Add (Ndir.Multiplied (
400 (offsetValue * (6.0*Dr*Dr/R5 + 6.0*Dr*D2r/R5 - 15.0*Dr*Dr*Dr/R7 - D3r))
402 V3.Add (Vec2d(D3Ndir));
404 D2Ndir.Multiply (offsetValue/R);
405 D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
406 D2Ndir.Subtract (Ndir.Multiplied (
407 offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))
410 V2.Add (Vec2d(D2Ndir));
412 DNdir.Multiply (offsetValue/R);
413 DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));
414 V1.Add (Vec2d(DNdir));
417 Ndir.Multiply (offsetValue/R);
422 //=======================================================================
425 //=======================================================================
427 Vec2d Geom2d_OffsetCurve::DN (const Standard_Real U,
428 const Standard_Integer N) const
430 Standard_RangeError_Raise_if (N < 1, "Geom2d_OffsetCurve::DN()");
435 case 1: D1( U, PBidon, VN); break;
436 case 2: D2( U, PBidon, VBidon, VN); break;
437 case 3: D3( U, PBidon, VBidon, VBidon, VN); break;
439 Standard_NotImplemented::Raise();
446 //=======================================================================
449 //=======================================================================
451 void Geom2d_OffsetCurve::Value (const Standard_Real U,
452 Pnt2d& P, Pnt2d& Pbasis,
453 Vec2d& V1basis ) const
456 basisCurve->D1 (U, Pbasis, V1basis);
457 Standard_Integer Index = 2;
458 while (V1basis.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
459 V1basis = basisCurve->DN (U, Index);
462 Standard_Real A = V1basis.Y();
463 Standard_Real B = - V1basis.X();
464 Standard_Real R = Sqrt(A*A + B * B);
465 if (R <= gp::Resolution()) Geom2d_UndefinedValue::Raise();
466 A = A * offsetValue/R;
467 B = B * offsetValue/R;
468 P.SetCoord (A + Pbasis.X(), B + Pbasis.Y());
472 //=======================================================================
475 //=======================================================================
477 void Geom2d_OffsetCurve::D1 (const Standard_Real U,
478 Pnt2d& P, Pnt2d& Pbasis,
479 Vec2d& V1, Vec2d& V1basis,
480 Vec2d& V2basis ) const
482 // P(u) = p(u) + Offset * Ndir / R
483 // with R = || p' ^ Z|| and Ndir = P' ^ Z
485 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
487 basisCurve->D2 (U, Pbasis, V1basis, V2basis);
490 Standard_Integer Index = 2;
491 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
492 V1 = basisCurve->DN (U, Index);
496 V2 = basisCurve->DN (U, Index);
498 XY Ndir (V1.Y(), -V1.X());
499 XY DNdir (V2.Y(), -V2.X());
500 Standard_Real R2 = Ndir.SquareModulus();
501 Standard_Real R = Sqrt (R2);
502 Standard_Real R3 = R * R2;
503 Standard_Real Dr = Ndir.Dot (DNdir);
504 if (R3 <= gp::Resolution()) {
505 //We try another computation but the stability is not very good.
506 if (R2 <= gp::Resolution()) { Geom2d_UndefinedDerivative::Raise(); }
508 DNdir.Subtract (Ndir.Multiplied (Dr/R));
509 DNdir.Multiply (offsetValue / R2);
510 V1.Add (Vec2d(DNdir));
513 // Same computation as IICURV in EUCLID-IS because the stability is
515 DNdir.Multiply (offsetValue/R);
516 DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));
517 V1.Add (Vec2d(DNdir));
519 Ndir.Multiply (offsetValue/R);
520 Ndir.Add (Pbasis.XY());
525 //=======================================================================
528 //=======================================================================
530 void Geom2d_OffsetCurve::D2 (const Standard_Real U,
531 Pnt2d& P, Pnt2d& Pbasis,
532 Vec2d& V1, Vec2d& V2,
533 Vec2d& V1basis, Vec2d& V2basis,
534 Vec2d& V3basis ) const
536 // P(u) = p(u) + Offset * Ndir / R
537 // with R = || p' ^ Z|| and Ndir = P' ^ Z
539 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
541 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
542 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
544 basisCurve->D3 (U, Pbasis, V1basis, V2basis, V3basis);
545 Standard_Integer Index = 2;
549 while (V1.Magnitude() <= gp::Resolution() && Index <= MaxDegree) {
550 V1 = basisCurve->DN (U, Index);
554 V2 = basisCurve->DN (U, Index);
555 V3 = basisCurve->DN (U, Index + 1);
557 XY Ndir (V1.Y(), -V1.X());
558 XY DNdir (V2.Y(), -V2.X());
559 XY D2Ndir (V3.Y(), -V3.X());
560 Standard_Real R2 = Ndir.SquareModulus();
561 Standard_Real R = Sqrt (R2);
562 Standard_Real R3 = R2 * R;
563 Standard_Real R4 = R2 * R2;
564 Standard_Real R5 = R3 * R2;
565 Standard_Real Dr = Ndir.Dot (DNdir);
566 Standard_Real D2r = Ndir.Dot (D2Ndir) + DNdir.Dot (DNdir);
567 if (R5 <= gp::Resolution()) {
568 //We try another computation but the stability is not very good
570 if (R4 <= gp::Resolution()) { Geom2d_UndefinedDerivative::Raise(); }
572 Standard_Real R4 = R2 * R2;
573 D2Ndir.Subtract (DNdir.Multiplied (2.0 * Dr / R2));
574 D2Ndir.Subtract (Ndir.Multiplied (((3.0 * Dr * Dr)/R4) - (D2r/R2)));
575 D2Ndir.Multiply (offsetValue / R);
576 V2.Add (Vec2d(D2Ndir));
579 DNdir.Subtract (Ndir.Multiplied (Dr/R));
580 DNdir.Multiply (offsetValue/R2);
581 V1.Add (Vec2d(DNdir));
584 // Same computation as IICURV in EUCLID-IS because the stability is
587 D2Ndir.Multiply (offsetValue/R);
588 D2Ndir.Subtract (DNdir.Multiplied (2.0 * offsetValue * Dr / R3));
589 D2Ndir.Subtract (Ndir.Multiplied (
590 offsetValue * (((3.0 * Dr * Dr) / R5) - (D2r / R3))
593 V2.Add (Vec2d(D2Ndir));
595 DNdir.Multiply (offsetValue/R);
596 DNdir.Subtract (Ndir.Multiplied (offsetValue*Dr/R3));
597 V1.Add (Vec2d(DNdir));
600 Ndir.Multiply (offsetValue/R);
601 Ndir.Add (Pbasis.XY());
605 //=======================================================================
606 //function : FirstParameter
608 //=======================================================================
610 Standard_Real Geom2d_OffsetCurve::FirstParameter () const
612 return basisCurve->FirstParameter();
615 //=======================================================================
616 //function : LastParameter
618 //=======================================================================
620 Standard_Real Geom2d_OffsetCurve::LastParameter () const
622 return basisCurve->LastParameter();
626 //=======================================================================
629 //=======================================================================
631 Standard_Real Geom2d_OffsetCurve::Offset () const { return offsetValue; }
633 //=======================================================================
634 //function : IsClosed
636 //=======================================================================
638 Standard_Boolean Geom2d_OffsetCurve::IsClosed () const
641 D0(FirstParameter(),PF);
642 D0(LastParameter(),PL);
643 return ( PF.Distance(PL) <= gp::Resolution());
646 //=======================================================================
649 //=======================================================================
651 Standard_Boolean Geom2d_OffsetCurve::IsCN (const Standard_Integer N) const
653 Standard_RangeError_Raise_if (N < 0, " " );
654 return basisCurve->IsCN (N + 1);
657 //=======================================================================
658 //function : IsPeriodic
660 //=======================================================================
662 Standard_Boolean Geom2d_OffsetCurve::IsPeriodic () const
664 return basisCurve->IsPeriodic();
667 //=======================================================================
670 //=======================================================================
672 Standard_Real Geom2d_OffsetCurve::Period() const
674 return basisCurve->Period();
677 //=======================================================================
678 //function : Transform
680 //=======================================================================
682 void Geom2d_OffsetCurve::Transform (const Trsf2d& T)
684 basisCurve->Transform (T);
685 offsetValue *= Abs(T.ScaleFactor());
689 //=======================================================================
690 //function : TransformedParameter
692 //=======================================================================
694 Standard_Real Geom2d_OffsetCurve::TransformedParameter(const Standard_Real U,
695 const gp_Trsf2d& T) const
697 return basisCurve->TransformedParameter(U,T);
700 //=======================================================================
701 //function : ParametricTransformation
703 //=======================================================================
705 Standard_Real Geom2d_OffsetCurve::ParametricTransformation(const gp_Trsf2d& T) const
707 return basisCurve->ParametricTransformation(T);