// Created on: 1991-09-09
// Created by: Michel Chauvat
// Copyright (c) 1991-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

// Evolutions   JCV Dec 1991 ajout de calculs de derivees et traitement
//              d'entites 2d
//              JCV Mars 1992 ajout method SetLinearForm

#define No_Standard_OutOfRange

#include <ElCLib.hxx>
#include <gp.hxx>
#include <gp_Ax1.hxx>
#include <gp_Ax2.hxx>
#include <gp_Ax2d.hxx>
#include <gp_Ax22d.hxx>
#include <gp_Circ.hxx>
#include <gp_Circ2d.hxx>
#include <gp_Dir.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Elips.hxx>
#include <gp_Elips2d.hxx>
#include <gp_Hypr.hxx>
#include <gp_Hypr2d.hxx>
#include <gp_Lin.hxx>
#include <gp_Lin2d.hxx>
#include <gp_Parab.hxx>
#include <gp_Parab2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <gp_Vec2d.hxx>

static Standard_Real PIPI = M_PI + M_PI;

//=======================================================================
// function : InPeriod
// purpose  : Value theULast is never returned.
//          Example of some case (checked on WIN64 platform)
//          with some surface having period 2*PI = 6.2831853071795862.
//            Let theUFirst be equal to 6.1645624650899675. Then,
//          theULast must be equal to
//              6.1645624650899675+6.2831853071795862=12.4477477722695537.
//
//          However, real result is 12.447747772269555.
//          Therefore, new period value to adjust will be equal to
//              12.447747772269555-6.1645624650899675=6.2831853071795871.
//
//          As we can see, (6.2831853071795871 != 6.2831853071795862).
//
//          According to above said, this method should be used carefully.
//          In order to increase reliability of this method, input arguments
//          needs to be replaced with following:
//            (theU, theUFirst, thePeriod). theULast parameter is excess.
//=======================================================================
Standard_Real ElCLib::InPeriod(const Standard_Real theU,
                               const Standard_Real theUFirst,
                               const Standard_Real theULast)
{
  if (Precision::IsInfinite(theU) || Precision::IsInfinite(theUFirst)
      || Precision::IsInfinite(theULast))
  { // In order to avoid FLT_Overflow exception
    return theU;
  }

  const Standard_Real aPeriod = theULast - theUFirst;

  if (aPeriod < Epsilon(theULast))
    return theU;

  return Max(theUFirst, theU + aPeriod * Ceiling((theUFirst - theU) / aPeriod));
}

//=================================================================================================

void ElCLib::AdjustPeriodic(const Standard_Real UFirst,
                            const Standard_Real ULast,
                            const Standard_Real Preci,
                            Standard_Real&      U1,
                            Standard_Real&      U2)
{
  if (Precision::IsInfinite(UFirst) || Precision::IsInfinite(ULast))
  {
    U1 = UFirst;
    U2 = ULast;
    return;
  }

  Standard_Real period = ULast - UFirst;

  if (period < Epsilon(ULast))
  {
    // In order to avoid FLT_Overflow exception
    // (test bugs moddata_1 bug22757)
    U1 = UFirst;
    U2 = ULast;
    return;
  }

  U1 -= Floor((U1 - UFirst) / period) * period;
  if (ULast - U1 < Preci)
    U1 -= period;
  U2 -= Floor((U2 - U1) / period) * period;
  if (U2 - U1 < Preci)
    U2 += period;
}

//=================================================================================================

gp_Pnt ElCLib::LineValue(const Standard_Real U, const gp_Ax1& Pos)
{
  const gp_XYZ& ZDir = Pos.Direction().XYZ();
  const gp_XYZ& PLoc = Pos.Location().XYZ();
  return gp_Pnt(U * ZDir.X() + PLoc.X(), U * ZDir.Y() + PLoc.Y(), U * ZDir.Z() + PLoc.Z());
}

//=================================================================================================

gp_Pnt ElCLib::CircleValue(const Standard_Real U, const gp_Ax2& Pos, const Standard_Real Radius)
{
  const gp_XYZ& XDir = Pos.XDirection().XYZ();
  const gp_XYZ& YDir = Pos.YDirection().XYZ();
  const gp_XYZ& PLoc = Pos.Location().XYZ();
  Standard_Real A1   = Radius * cos(U);
  Standard_Real A2   = Radius * sin(U);
  return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
}

//=================================================================================================

gp_Pnt ElCLib::EllipseValue(const Standard_Real U,
                            const gp_Ax2&       Pos,
                            const Standard_Real MajorRadius,
                            const Standard_Real MinorRadius)
{
  const gp_XYZ& XDir = Pos.XDirection().XYZ();
  const gp_XYZ& YDir = Pos.YDirection().XYZ();
  const gp_XYZ& PLoc = Pos.Location().XYZ();
  Standard_Real A1   = MajorRadius * cos(U);
  Standard_Real A2   = MinorRadius * sin(U);
  return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
}

//=================================================================================================

gp_Pnt ElCLib::HyperbolaValue(const Standard_Real U,
                              const gp_Ax2&       Pos,
                              const Standard_Real MajorRadius,
                              const Standard_Real MinorRadius)
{
  const gp_XYZ& XDir = Pos.XDirection().XYZ();
  const gp_XYZ& YDir = Pos.YDirection().XYZ();
  const gp_XYZ& PLoc = Pos.Location().XYZ();
  Standard_Real A1   = MajorRadius * Cosh(U);
  Standard_Real A2   = MinorRadius * Sinh(U);
  return gp_Pnt(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y(),
                A1 * XDir.Z() + A2 * YDir.Z() + PLoc.Z());
}

//=================================================================================================

gp_Pnt ElCLib::ParabolaValue(const Standard_Real U, const gp_Ax2& Pos, const Standard_Real Focal)
{
  if (Focal == 0.0)
  {
    const gp_XYZ& XDir = Pos.XDirection().XYZ();
    const gp_XYZ& PLoc = Pos.Location().XYZ();
    return gp_Pnt(U * XDir.X() + PLoc.X(), U * XDir.Y() + PLoc.Y(), U * XDir.Z() + PLoc.Z());
  }
  const gp_XYZ& XDir = Pos.XDirection().XYZ();
  const gp_XYZ& YDir = Pos.YDirection().XYZ();
  const gp_XYZ& PLoc = Pos.Location().XYZ();
  Standard_Real A1   = U * U / (4.0 * Focal);
  return gp_Pnt(A1 * XDir.X() + U * YDir.X() + PLoc.X(),
                A1 * XDir.Y() + U * YDir.Y() + PLoc.Y(),
                A1 * XDir.Z() + U * YDir.Z() + PLoc.Z());
}

//=================================================================================================

void ElCLib::LineD1(const Standard_Real U, const gp_Ax1& Pos, gp_Pnt& P, gp_Vec& V1)
{
  gp_XYZ Coord = Pos.Direction().XYZ();
  V1.SetXYZ(Coord);
  Coord.SetLinearForm(U, Coord, Pos.Location().XYZ());
  P.SetXYZ(Coord);
}

//=================================================================================================

void ElCLib::CircleD1(const Standard_Real U,
                      const gp_Ax2&       Pos,
                      const Standard_Real Radius,
                      gp_Pnt&             P,
                      gp_Vec&             V1)
{
  Standard_Real Xc = Radius * Cos(U);
  Standard_Real Yc = Radius * Sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant :
  Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc, Coord1, Xc, Coord2);
  V1.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::EllipseD1(const Standard_Real U,
                       const gp_Ax2&       Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt&             P,
                       gp_Vec&             V1)
{
  Standard_Real Xc = Cos(U);
  Standard_Real Yc = Sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant :
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::HyperbolaD1(const Standard_Real U,
                         const gp_Ax2&       Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt&             P,
                         gp_Vec&             V1)
{
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant :
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::ParabolaD1(const Standard_Real U,
                        const gp_Ax2&       Pos,
                        const Standard_Real Focal,
                        gp_Pnt&             P,
                        gp_Vec&             V1)
{
  gp_XYZ Coord0;
  gp_XYZ Coord1(Pos.XDirection().XYZ());
  if (Focal == 0.0)
  { // Parabole degenere en une droite
    V1.SetXYZ(Coord1);
    Coord1.Multiply(U);
    Coord1.Add(Pos.Location().XYZ());
    P.SetXYZ(Coord1);
  }
  else
  {
    gp_XYZ Coord2(Pos.YDirection().XYZ());
    Coord0.SetLinearForm(U / (2.0 * Focal), Coord1, Coord2);
    V1.SetXYZ(Coord0);
    Coord0.SetLinearForm((U * U) / (4.0 * Focal), Coord1, U, Coord2, Pos.Location().XYZ());
    P.SetXYZ(Coord0);
  }
}

//=================================================================================================

void ElCLib::CircleD2(const Standard_Real U,
                      const gp_Ax2&       Pos,
                      const Standard_Real Radius,
                      gp_Pnt&             P,
                      gp_Vec&             V1,
                      gp_Vec&             V2)
{
  Standard_Real Xc = Radius * cos(U);
  Standard_Real Yc = Radius * sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant :
  Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc, Coord1, Xc, Coord2);
  V1.SetXYZ(Coord0);
  // D2 :
  Coord0.SetLinearForm(-Xc, Coord1, -Yc, Coord2);
  V2.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::EllipseD2(const Standard_Real U,
                       const gp_Ax2&       Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt&             P,
                       gp_Vec&             V1,
                       gp_Vec&             V2)
{
  Standard_Real Xc = cos(U);
  Standard_Real Yc = sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant :
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
  // D2 :
  Coord0.SetLinearForm(-Xc * MajorRadius, Coord1, -Yc * MinorRadius, Coord2);
  V2.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::HyperbolaD2(const Standard_Real U,
                         const gp_Ax2&       Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt&             P,
                         gp_Vec&             V1,
                         gp_Vec&             V2)
{
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());

  // Point courant et D2:
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2);
  V2.SetXYZ(Coord0);
  Coord0.Add(Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::ParabolaD2(const Standard_Real U,
                        const gp_Ax2&       Pos,
                        const Standard_Real Focal,
                        gp_Pnt&             P,
                        gp_Vec&             V1,
                        gp_Vec&             V2)
{
  gp_XYZ Coord0(0.0, 0.0, 0.0);
  gp_XYZ Coord1(Pos.XDirection().XYZ());
  if (Focal == 0.0)
  {
    V2.SetCoord(0.0, 0.0, 0.0);
    V1.SetXYZ(Coord1);
    Coord1.Multiply(U);
    Coord1.Add(Pos.Location().XYZ());
    P.SetXYZ(Coord1); // was: P.SetXYZ (Coord0);
  }
  else
  {
    gp_XYZ Coord2(Pos.YDirection().XYZ());
    Coord0.SetLinearForm((U * U) / (4.0 * Focal), Coord1, U, Coord2, Pos.Location().XYZ());
    P.SetXYZ(Coord0);
    Coord0.SetLinearForm(U / (2.0 * Focal), Coord1, Coord2);
    V1.SetXYZ(Coord0);
    Coord1.Multiply(1.0 / (2.0 * Focal));
    V2.SetXYZ(Coord1);
  }
}

//=================================================================================================

void ElCLib::CircleD3(const Standard_Real U,
                      const gp_Ax2&       Pos,
                      const Standard_Real Radius,
                      gp_Pnt&             P,
                      gp_Vec&             V1,
                      gp_Vec&             V2,
                      gp_Vec&             V3)
{
  Standard_Real Xc = Radius * cos(U);
  Standard_Real Yc = Radius * sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point Courant :
  Coord0.SetLinearForm(Xc, Coord1, Yc, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc, Coord1, Xc, Coord2);
  V1.SetXYZ(Coord0);
  // D2 :
  Coord0.SetLinearForm(-Xc, Coord1, -Yc, Coord2);
  V2.SetXYZ(Coord0);
  // D3 :
  Coord0.SetLinearForm(Yc, Coord1, -Xc, Coord2);
  V3.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::EllipseD3(const Standard_Real U,
                       const gp_Ax2&       Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt&             P,
                       gp_Vec&             V1,
                       gp_Vec&             V2,
                       gp_Vec&             V3)
{
  Standard_Real Xc = cos(U);
  Standard_Real Yc = sin(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point Courant :
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2, Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 :
  Coord0.SetLinearForm(-Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
  // D2 :
  Coord0.SetLinearForm(-Xc * MajorRadius, Coord1, -Yc * MinorRadius, Coord2);
  V2.SetXYZ(Coord0);
  // D3
  Coord0.SetLinearForm(Yc * MajorRadius, Coord1, -Xc * MinorRadius, Coord2);
  V3.SetXYZ(Coord0);
}

//=================================================================================================

void ElCLib::HyperbolaD3(const Standard_Real U,
                         const gp_Ax2&       Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt&             P,
                         gp_Vec&             V1,
                         gp_Vec&             V2,
                         gp_Vec&             V3)
{
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);
  gp_XYZ        Coord0;
  gp_XYZ        Coord1(Pos.XDirection().XYZ());
  gp_XYZ        Coord2(Pos.YDirection().XYZ());
  // Point courant et D2 :
  Coord0.SetLinearForm(Xc * MajorRadius, Coord1, Yc * MinorRadius, Coord2);
  V2.SetXYZ(Coord0);
  Coord0.Add(Pos.Location().XYZ());
  P.SetXYZ(Coord0);
  // D1 et D3 :
  Coord0.SetLinearForm(Yc * MajorRadius, Coord1, Xc * MinorRadius, Coord2);
  V1.SetXYZ(Coord0);
  V3.SetXYZ(Coord0);
}

//=================================================================================================

gp_Pnt2d ElCLib::LineValue(const Standard_Real U, const gp_Ax2d& Pos)
{
  const gp_XY& ZDir = Pos.Direction().XY();
  const gp_XY& PLoc = Pos.Location().XY();
  return gp_Pnt2d(U * ZDir.X() + PLoc.X(), U * ZDir.Y() + PLoc.Y());
}

//=================================================================================================

gp_Pnt2d ElCLib::CircleValue(const Standard_Real U, const gp_Ax22d& Pos, const Standard_Real Radius)
{
  const gp_XY&  XDir = Pos.XDirection().XY();
  const gp_XY&  YDir = Pos.YDirection().XY();
  const gp_XY&  PLoc = Pos.Location().XY();
  Standard_Real A1   = Radius * cos(U);
  Standard_Real A2   = Radius * sin(U);
  return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                  A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
}

//=================================================================================================

gp_Pnt2d ElCLib::EllipseValue(const Standard_Real U,
                              const gp_Ax22d&     Pos,
                              const Standard_Real MajorRadius,
                              const Standard_Real MinorRadius)
{
  const gp_XY&  XDir = Pos.XDirection().XY();
  const gp_XY&  YDir = Pos.YDirection().XY();
  const gp_XY&  PLoc = Pos.Location().XY();
  Standard_Real A1   = MajorRadius * cos(U);
  Standard_Real A2   = MinorRadius * sin(U);
  return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                  A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
}

//=================================================================================================

gp_Pnt2d ElCLib::HyperbolaValue(const Standard_Real U,
                                const gp_Ax22d&     Pos,
                                const Standard_Real MajorRadius,
                                const Standard_Real MinorRadius)
{
  const gp_XY&  XDir = Pos.XDirection().XY();
  const gp_XY&  YDir = Pos.YDirection().XY();
  const gp_XY&  PLoc = Pos.Location().XY();
  Standard_Real A1   = MajorRadius * Cosh(U);
  Standard_Real A2   = MinorRadius * Sinh(U);
  return gp_Pnt2d(A1 * XDir.X() + A2 * YDir.X() + PLoc.X(),
                  A1 * XDir.Y() + A2 * YDir.Y() + PLoc.Y());
}

//=================================================================================================

gp_Pnt2d ElCLib::ParabolaValue(const Standard_Real U,
                               const gp_Ax22d&     Pos,
                               const Standard_Real Focal)
{
  if (Focal == 0.0)
  {
    const gp_XY& XDir = Pos.XDirection().XY();
    const gp_XY& PLoc = Pos.Location().XY();
    return gp_Pnt2d(U * XDir.X() + PLoc.X(), U * XDir.Y() + PLoc.Y());
  }
  const gp_XY&  XDir = Pos.XDirection().XY();
  const gp_XY&  YDir = Pos.YDirection().XY();
  const gp_XY&  PLoc = Pos.Location().XY();
  Standard_Real A1   = U * U / (4.0 * Focal);
  return gp_Pnt2d(A1 * XDir.X() + U * YDir.X() + PLoc.X(), A1 * XDir.Y() + U * YDir.Y() + PLoc.Y());
}

//=================================================================================================

void ElCLib::LineD1(const Standard_Real U, const gp_Ax2d& Pos, gp_Pnt2d& P, gp_Vec2d& V1)
{
  gp_XY Coord = Pos.Direction().XY();
  V1.SetXY(Coord);
  Coord.SetLinearForm(U, Coord, Pos.Location().XY());
  P.SetXY(Coord);
}

//=================================================================================================

void ElCLib::CircleD1(const Standard_Real U,
                      const gp_Ax22d&     Pos,
                      const Standard_Real Radius,
                      gp_Pnt2d&           P,
                      gp_Vec2d&           V1)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = Radius * cos(U);
  Standard_Real Yc = Radius * sin(U);
  // Point courant :
  Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir, Pos.Location().XY());
  P.SetXY(Vxy);
  // V1 :
  Vxy.SetLinearForm(-Yc, Xdir, Xc, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::EllipseD1(const Standard_Real U,
                       const gp_Ax22d&     Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt2d&           P,
                       gp_Vec2d&           V1)
{
  gp_XY         Vxy;
  gp_XY         Xdir((Pos.XDirection()).XY());
  gp_XY         Ydir((Pos.YDirection()).XY());
  Standard_Real Xc = cos(U);
  Standard_Real Yc = sin(U);
  // Point courant :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir, Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(-Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::HyperbolaD1(const Standard_Real U,
                         const gp_Ax22d&     Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt2d&           P,
                         gp_Vec2d&           V1)
{
  gp_XY         Vxy;
  gp_XY         Xdir((Pos.XDirection()).XY());
  gp_XY         Ydir((Pos.YDirection()).XY());
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);
  // Point courant :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir, Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::ParabolaD1(const Standard_Real U,
                        const gp_Ax22d&     Pos,
                        const Standard_Real Focal,
                        gp_Pnt2d&           P,
                        gp_Vec2d&           V1)
{
  gp_XY Vxy;
  gp_XY Xdir(Pos.XDirection().XY());
  if (Focal == 0.0)
  { // Parabole degenere en une droite
    V1.SetXY(Xdir);
    Vxy.SetLinearForm(U, Xdir, Pos.Location().XY());
  }
  else
  {
    gp_XY Ydir(Pos.YDirection().XY());
    Vxy.SetLinearForm(U / (2.0 * Focal), Xdir, Ydir);
    V1.SetXY(Vxy);
    Vxy.SetLinearForm((U * U) / (4.0 * Focal), Xdir, U, Ydir, Pos.Location().XY());
  }
  P.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::CircleD2(const Standard_Real U,
                      const gp_Ax22d&     Pos,
                      const Standard_Real Radius,
                      gp_Pnt2d&           P,
                      gp_Vec2d&           V1,
                      gp_Vec2d&           V2)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = Radius * cos(U);
  Standard_Real Yc = Radius * sin(U);
  // V2 :
  Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir);
  V2.SetXY(Vxy);
  V2.Reverse();
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(-Yc, Xdir, Xc, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::EllipseD2(const Standard_Real U,
                       const gp_Ax22d&     Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt2d&           P,
                       gp_Vec2d&           V1,
                       gp_Vec2d&           V2)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = cos(U);
  Standard_Real Yc = sin(U);

  // V2 :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
  V2.SetXY(Vxy);
  V2.Reverse();

  // Point courant :
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(-Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::HyperbolaD2(const Standard_Real U,
                         const gp_Ax22d&     Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt2d&           P,
                         gp_Vec2d&           V1,
                         gp_Vec2d&           V2)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);

  // V2 :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
  V2.SetXY(Vxy);

  // Point courant :
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::ParabolaD2(const Standard_Real U,
                        const gp_Ax22d&     Pos,
                        const Standard_Real Focal,
                        gp_Pnt2d&           P,
                        gp_Vec2d&           V1,
                        gp_Vec2d&           V2)
{
  gp_XY Vxy;
  gp_XY Xdir(Pos.XDirection().XY());
  if (Focal == 0.0)
  {
    V2.SetCoord(0.0, 0.0);
    V1.SetXY(Xdir);
    Vxy.SetLinearForm(U, Xdir, Pos.Location().XY());
  }
  else
  {
    gp_XY Ydir(Pos.YDirection().XY());
    Vxy = Xdir.Multiplied(1.0 / (2.0 * Focal));
    V2.SetXY(Vxy);
    Vxy.SetLinearForm(U, Vxy, Ydir);
    V1.SetXY(Vxy);
    Vxy.SetLinearForm(U * U / (4.0 * Focal), Xdir, U, Ydir);
    Vxy.Add(Pos.Location().XY());
  }
  P.SetXY(Vxy);
}

//=================================================================================================

void ElCLib::CircleD3(const Standard_Real U,
                      const gp_Ax22d&     Pos,
                      const Standard_Real Radius,
                      gp_Pnt2d&           P,
                      gp_Vec2d&           V1,
                      gp_Vec2d&           V2,
                      gp_Vec2d&           V3)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = Radius * cos(U);
  Standard_Real Yc = Radius * sin(U);

  // V2 :
  Vxy.SetLinearForm(Xc, Xdir, Yc, Ydir);
  V2.SetXY(Vxy);
  V2.Reverse();

  // Point courant :
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(-Yc, Xdir, Xc, Ydir);
  V1.SetXY(Vxy);

  // V3 :
  V3.SetXY(Vxy);
  V3.Reverse();
}

//=================================================================================================

void ElCLib::EllipseD3(const Standard_Real U,
                       const gp_Ax22d&     Pos,
                       const Standard_Real MajorRadius,
                       const Standard_Real MinorRadius,
                       gp_Pnt2d&           P,
                       gp_Vec2d&           V1,
                       gp_Vec2d&           V2,
                       gp_Vec2d&           V3)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = cos(U);
  Standard_Real Yc = sin(U);

  // V2 :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
  V2.SetXY(Vxy);
  V2.Reverse();

  // Point courant :
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(-Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);

  // V3 :
  V3.SetXY(Vxy);
  V3.Reverse();
}

//=================================================================================================

void ElCLib::HyperbolaD3(const Standard_Real U,
                         const gp_Ax22d&     Pos,
                         const Standard_Real MajorRadius,
                         const Standard_Real MinorRadius,
                         gp_Pnt2d&           P,
                         gp_Vec2d&           V1,
                         gp_Vec2d&           V2,
                         gp_Vec2d&           V3)
{
  gp_XY         Vxy;
  gp_XY         Xdir(Pos.XDirection().XY());
  gp_XY         Ydir(Pos.YDirection().XY());
  Standard_Real Xc = Cosh(U);
  Standard_Real Yc = Sinh(U);

  // V2 :
  Vxy.SetLinearForm(Xc * MajorRadius, Xdir, Yc * MinorRadius, Ydir);
  V2.SetXY(Vxy);

  // Point courant :
  Vxy.Add(Pos.Location().XY());
  P.SetXY(Vxy);

  // V1 :
  Vxy.SetLinearForm(Yc * MajorRadius, Xdir, Xc * MinorRadius, Ydir);
  V1.SetXY(Vxy);

  // V3 :
  V3.SetXY(Vxy);
}

//=================================================================================================

gp_Vec ElCLib::LineDN(const Standard_Real, const gp_Ax1& Pos, const Standard_Integer N)
{
  if (N == 1)
  {
    return gp_Vec(Pos.Direction());
  }
  return gp_Vec(0., 0., 0.);
}

//=================================================================================================

gp_Vec ElCLib::CircleDN(const Standard_Real    U,
                        const gp_Ax2&          Pos,
                        const Standard_Real    Radius,
                        const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (N == 1)
  {
    Xc = Radius * -sin(U);
    Yc = Radius * cos(U);
  }
  else if ((N + 2) % 4 == 0)
  {
    Xc = Radius * -cos(U);
    Yc = Radius * -sin(U);
  }
  else if ((N + 1) % 4 == 0)
  {
    Xc = Radius * sin(U);
    Yc = Radius * -cos(U);
  }
  else if (N % 4 == 0)
  {
    Xc = Radius * cos(U);
    Yc = Radius * sin(U);
  }
  else if ((N - 1) % 4 == 0)
  {
    Xc = Radius * -sin(U);
    Yc = Radius * cos(U);
  }
  gp_XYZ Coord1(Pos.XDirection().XYZ());
  Coord1.SetLinearForm(Xc, Coord1, Yc, Pos.YDirection().XYZ());
  return gp_Vec(Coord1);
}

//=================================================================================================

gp_Vec ElCLib::EllipseDN(const Standard_Real    U,
                         const gp_Ax2&          Pos,
                         const Standard_Real    MajorRadius,
                         const Standard_Real    MinorRadius,
                         const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (N == 1)
  {
    Xc = MajorRadius * -sin(U);
    Yc = MinorRadius * cos(U);
  }
  else if ((N + 2) % 4 == 0)
  {
    Xc = MajorRadius * -cos(U);
    Yc = MinorRadius * -sin(U);
  }
  else if ((N + 1) % 4 == 0)
  {
    Xc = MajorRadius * sin(U);
    Yc = MinorRadius * -cos(U);
  }
  else if (N % 4 == 0)
  {
    Xc = MajorRadius * cos(U);
    Yc = MinorRadius * sin(U);
  }
  else if ((N - 1) % 4 == 0)
  {
    Xc = MajorRadius * -sin(U);
    Yc = MinorRadius * cos(U);
  }
  gp_XYZ Coord1(Pos.XDirection().XYZ());
  Coord1.SetLinearForm(Xc, Coord1, Yc, Pos.YDirection().XYZ());
  return gp_Vec(Coord1);
}

//=================================================================================================

gp_Vec ElCLib::HyperbolaDN(const Standard_Real    U,
                           const gp_Ax2&          Pos,
                           const Standard_Real    MajorRadius,
                           const Standard_Real    MinorRadius,
                           const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (IsOdd(N))
  {
    Xc = MajorRadius * Sinh(U);
    Yc = MinorRadius * Cosh(U);
  }
  else if (IsEven(N))
  {
    Xc = MajorRadius * Cosh(U);
    Yc = MinorRadius * Sinh(U);
  }
  gp_XYZ Coord1(Pos.XDirection().XYZ());
  Coord1.SetLinearForm(Xc, Coord1, Yc, Pos.YDirection().XYZ());
  return gp_Vec(Coord1);
}

//=================================================================================================

gp_Vec ElCLib::ParabolaDN(const Standard_Real    U,
                          const gp_Ax2&          Pos,
                          const Standard_Real    Focal,
                          const Standard_Integer N)
{
  if (N <= 2)
  {
    gp_XYZ Coord1(Pos.XDirection().XYZ());
    if (N == 1)
    {
      if (Focal == 0.0)
      {
        return gp_Vec(Coord1);
      }
      else
      {
        Coord1.SetLinearForm(U / (2.0 * Focal), Coord1, Pos.YDirection().XYZ());
        return gp_Vec(Coord1);
      }
    }
    else if (N == 2)
    {
      if (Focal == 0.0)
      {
        return gp_Vec(0.0, 0.0, 0.0);
      }
      else
      {
        Coord1.Multiply(1.0 / (2.0 * Focal));
        return gp_Vec(Coord1);
      }
    }
  }
  return gp_Vec(0., 0., 0.);
}

//=================================================================================================

gp_Vec2d ElCLib::LineDN(const Standard_Real, const gp_Ax2d& Pos, const Standard_Integer N)
{
  if (N == 1)
  {
    return gp_Vec2d(Pos.Direction());
  }
  return gp_Vec2d(0.0, 0.0);
}

//=================================================================================================

gp_Vec2d ElCLib::CircleDN(const Standard_Real    U,
                          const gp_Ax22d&        Pos,
                          const Standard_Real    Radius,
                          const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (N == 1)
  {
    Xc = Radius * -sin(U);
    Yc = Radius * cos(U);
  }
  else if ((N + 2) % 4 == 0)
  {
    Xc = Radius * -cos(U);
    Yc = Radius * -sin(U);
  }
  else if ((N + 1) % 4 == 0)
  {
    Xc = Radius * sin(U);
    Yc = Radius * -cos(U);
  }
  else if (N % 4 == 0)
  {
    Xc = Radius * cos(U);
    Yc = Radius * sin(U);
  }
  else if ((N - 1) % 4 == 0)
  {
    Xc = Radius * -sin(U);
    Yc = Radius * cos(U);
  }
  gp_XY Xdir(Pos.XDirection().XY());
  gp_XY Ydir(Pos.YDirection().XY());
  Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
  return gp_Vec2d(Xdir);
}

//=================================================================================================

gp_Vec2d ElCLib::EllipseDN(const Standard_Real    U,
                           const gp_Ax22d&        Pos,
                           const Standard_Real    MajorRadius,
                           const Standard_Real    MinorRadius,
                           const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (N == 1)
  {
    Xc = MajorRadius * -sin(U);
    Yc = MinorRadius * cos(U);
  }
  else if ((N + 2) % 4 == 0)
  {
    Xc = MajorRadius * -cos(U);
    Yc = MinorRadius * -sin(U);
  }
  else if ((N + 1) % 4 == 0)
  {
    Xc = MajorRadius * sin(U);
    Yc = MinorRadius * -cos(U);
  }
  else if (N % 4 == 0)
  {
    Xc = MajorRadius * cos(U);
    Yc = MinorRadius * sin(U);
  }
  else if ((N - 1) % 4 == 0)
  {
    Xc = MajorRadius * -sin(U);
    Yc = MinorRadius * cos(U);
  }
  gp_XY Xdir(Pos.XDirection().XY());
  gp_XY Ydir(Pos.YDirection().XY());
  Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
  return gp_Vec2d(Xdir);
}

//=================================================================================================

gp_Vec2d ElCLib::HyperbolaDN(const Standard_Real    U,
                             const gp_Ax22d&        Pos,
                             const Standard_Real    MajorRadius,
                             const Standard_Real    MinorRadius,
                             const Standard_Integer N)
{
  Standard_Real Xc = 0, Yc = 0;
  if (IsOdd(N))
  {
    Xc = MajorRadius * Sinh(U);
    Yc = MinorRadius * Cosh(U);
  }
  else if (IsEven(N))
  {
    Xc = MajorRadius * Cosh(U);
    Yc = MinorRadius * Sinh(U);
  }
  gp_XY Xdir(Pos.XDirection().XY());
  gp_XY Ydir(Pos.YDirection().XY());
  Xdir.SetLinearForm(Xc, Xdir, Yc, Ydir);
  return gp_Vec2d(Xdir);
}

//=================================================================================================

gp_Vec2d ElCLib::ParabolaDN(const Standard_Real    U,
                            const gp_Ax22d&        Pos,
                            const Standard_Real    Focal,
                            const Standard_Integer N)
{
  if (N <= 2)
  {
    gp_XY Xdir(Pos.XDirection().XY());
    if (N == 1)
    {
      if (Focal == 0.0)
      {
        return gp_Vec2d(Xdir);
      }
      else
      {
        gp_XY Ydir(Pos.YDirection().XY());
        Xdir.SetLinearForm(U / (2.0 * Focal), Xdir, Ydir);
        return gp_Vec2d(Xdir);
      }
    }
    else if (N == 2)
    {
      if (Focal == 0.0)
      {
        return gp_Vec2d(0.0, 0.0);
      }
      else
      {
        Xdir.Multiply(1.0 / (2.0 * Focal));
        return gp_Vec2d(Xdir);
      }
    }
  }
  return gp_Vec2d(0.0, 0.0);
}

//=================================================================================================

Standard_Real ElCLib::LineParameter(const gp_Ax1& L, const gp_Pnt& P)
{
  return (P.XYZ() - L.Location().XYZ()).Dot(L.Direction().XYZ());
}

//=================================================================================================

Standard_Real ElCLib::CircleParameter(const gp_Ax2& Pos, const gp_Pnt& P)
{
  gp_Vec aVec(Pos.Location(), P);
  if (aVec.SquareMagnitude() < gp::Resolution())
    // coinciding points -> infinite number of parameters
    return 0.0;

  const gp_Dir& dir = Pos.Direction();
  // Project vector on circle's plane
  gp_XYZ aVProj = dir.XYZ().CrossCrossed(aVec.XYZ(), dir.XYZ());

  if (aVProj.SquareModulus() < gp::Resolution())
    return 0.0;

  // Angle between X direction and projected vector
  Standard_Real Teta = (Pos.XDirection()).AngleWithRef(aVProj, dir);

  if (Teta < -1.e-16)
    Teta += PIPI;
  else if (Teta < 0)
    Teta = 0;
  return Teta;
}

//=================================================================================================

Standard_Real ElCLib::EllipseParameter(const gp_Ax2&       Pos,
                                       const Standard_Real MajorRadius,
                                       const Standard_Real MinorRadius,
                                       const gp_Pnt&       P)
{
  gp_XYZ        OP    = P.XYZ() - Pos.Location().XYZ();
  gp_XYZ        xaxis = Pos.XDirection().XYZ();
  gp_XYZ        yaxis = Pos.YDirection().XYZ();
  Standard_Real NY    = OP.Dot(yaxis);
  Standard_Real NX    = OP.Dot(xaxis);

  if ((Abs(NX) <= gp::Resolution()) && (Abs(NY) <= gp::Resolution()))
    //-- The point P is on the Axis of the Ellipse.
    return (0.0);

  yaxis.Multiply(NY * (MajorRadius / MinorRadius));
  gp_XYZ Om = xaxis.Multiplied(NX);
  Om.Add(yaxis);
  Standard_Real Teta = gp_Vec(xaxis).AngleWithRef(gp_Vec(Om), gp_Vec(Pos.Direction()));
  if (Teta < -1.e-16)
    Teta += PIPI;
  else if (Teta < 0)
    Teta = 0;
  return Teta;
}

//=================================================================================================

Standard_Real ElCLib::HyperbolaParameter(const gp_Ax2& Pos,
                                         const Standard_Real,
                                         const Standard_Real MinorRadius,
                                         const gp_Pnt&       P)
{
  Standard_Real sht = gp_Vec(Pos.Location(), P).Dot(gp_Vec(Pos.YDirection())) / MinorRadius;

#if defined(__QNX__)
  return std::asinh(sht);
#else
  return asinh(sht);
#endif
}

//=================================================================================================

Standard_Real ElCLib::ParabolaParameter(const gp_Ax2& Pos, const gp_Pnt& P)
{
  return gp_Vec(Pos.Location(), P).Dot(gp_Vec(Pos.YDirection()));
}

//=================================================================================================

Standard_Real ElCLib::LineParameter(const gp_Ax2d& L, const gp_Pnt2d& P)
{
  gp_XY Coord = P.XY();
  Coord.Subtract(L.Location().XY());
  return Coord.Dot(L.Direction().XY());
}

//=================================================================================================

Standard_Real ElCLib::CircleParameter(const gp_Ax22d& Pos, const gp_Pnt2d& P)
{
  Standard_Real Teta = (Pos.XDirection()).Angle(gp_Vec2d(Pos.Location(), P));
  Teta               = ((Pos.XDirection() ^ Pos.YDirection()) >= 0.0) ? Teta : -Teta;
  if (Teta < -1.e-16)
    Teta += PIPI;
  else if (Teta < 0)
    Teta = 0;
  return Teta;
}

//=================================================================================================

Standard_Real ElCLib::EllipseParameter(const gp_Ax22d&     Pos,
                                       const Standard_Real MajorRadius,
                                       const Standard_Real MinorRadius,
                                       const gp_Pnt2d&     P)
{
  gp_XY OP = P.XY();
  OP.Subtract(Pos.Location().XY());
  gp_XY xaxis = Pos.XDirection().XY();
  gp_XY yaxis = Pos.YDirection().XY();
  gp_XY Om    = xaxis.Multiplied(OP.Dot(xaxis));
  yaxis.Multiply((OP.Dot(yaxis)) * (MajorRadius / MinorRadius));
  Om.Add(yaxis);
  Standard_Real Teta = gp_Vec2d(xaxis).Angle(gp_Vec2d(Om));
  Teta               = ((Pos.XDirection() ^ Pos.YDirection()) >= 0.0) ? Teta : -Teta;
  if (Teta < -1.e-16)
    Teta += PIPI;
  else if (Teta < 0)
    Teta = 0;
  return Teta;
}

//=================================================================================================

Standard_Real ElCLib::HyperbolaParameter(const gp_Ax22d& Pos,
                                         const Standard_Real,
                                         const Standard_Real MinorRadius,
                                         const gp_Pnt2d&     P)
{
  gp_Vec2d      V(Pos.YDirection().XY());
  Standard_Real sht = gp_Vec2d(Pos.Location(), P).Dot(V) / MinorRadius;
#if defined(__QNX__)
  return std::asinh(sht);
#else
  return asinh(sht);
#endif
}

//=================================================================================================

Standard_Real ElCLib::ParabolaParameter(const gp_Ax22d& Pos, const gp_Pnt2d& P)
{
  gp_Vec2d Directrix(Pos.YDirection().XY());
  return gp_Vec2d(Pos.Location(), P).Dot(Directrix);
}

//=================================================================================================

gp_Pnt ElCLib::To3d(const gp_Ax2& Pos, const gp_Pnt2d& P)
{
  gp_XYZ Vxy = Pos.XDirection().XYZ();
  Vxy.SetLinearForm(P.X(), Vxy, P.Y(), Pos.YDirection().XYZ(), Pos.Location().XYZ());
  return gp_Pnt(Vxy);
}

//=================================================================================================

gp_Dir ElCLib::To3d(const gp_Ax2& Pos, const gp_Dir2d& V)
{
  gp_Vec Vx = Pos.XDirection();
  gp_Vec Vy = Pos.YDirection();
  Vx.Multiply(V.X());
  Vy.Multiply(V.Y());
  Vx.Add(Vy);
  return gp_Dir(Vx);
}

//=================================================================================================

gp_Vec ElCLib::To3d(const gp_Ax2& Pos, const gp_Vec2d& V)
{
  gp_Vec Vx = Pos.XDirection();
  gp_Vec Vy = Pos.YDirection();
  Vx.Multiply(V.X());
  Vy.Multiply(V.Y());
  Vx.Add(Vy);
  return Vx;
}

//=================================================================================================

gp_Ax1 ElCLib::To3d(const gp_Ax2& Pos, const gp_Ax2d& A)
{
  gp_Pnt P = ElCLib::To3d(Pos, A.Location());
  gp_Vec V = ElCLib::To3d(Pos, A.Direction());
  return gp_Ax1(P, V);
}

//=================================================================================================

gp_Ax2 ElCLib::To3d(const gp_Ax2& Pos, const gp_Ax22d& A)
{
  gp_Pnt P  = ElCLib::To3d(Pos, A.Location());
  gp_Vec VX = ElCLib::To3d(Pos, A.XDirection());
  gp_Vec VY = ElCLib::To3d(Pos, A.YDirection());
  return gp_Ax2(P, VX.Crossed(VY), VX);
}

//=================================================================================================

gp_Lin ElCLib::To3d(const gp_Ax2& Pos, const gp_Lin2d& L)
{
  return gp_Lin(ElCLib::To3d(Pos, L.Position()));
}

//=================================================================================================

gp_Circ ElCLib::To3d(const gp_Ax2& Pos, const gp_Circ2d& C)
{
  return gp_Circ(ElCLib::To3d(Pos, C.Axis()), C.Radius());
}

//=================================================================================================

gp_Elips ElCLib::To3d(const gp_Ax2& Pos, const gp_Elips2d& E)
{
  return gp_Elips(ElCLib::To3d(Pos, E.Axis()), E.MajorRadius(), E.MinorRadius());
}

//=================================================================================================

gp_Hypr ElCLib::To3d(const gp_Ax2& Pos, const gp_Hypr2d& H)
{
  return gp_Hypr(ElCLib::To3d(Pos, H.Axis()), H.MajorRadius(), H.MinorRadius());
}

//=================================================================================================

gp_Parab ElCLib::To3d(const gp_Ax2& Pos, const gp_Parab2d& Prb)
{
  return gp_Parab(ElCLib::To3d(Pos, Prb.Axis()), Prb.Focal());
}
