// Created on: 1992-07-01
// Created by: Laurent BUCHARD
// Copyright (c) 1992-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.

#ifndef OCCT_DEBUG
#define No_Standard_RangeError
#define No_Standard_OutOfRange
#endif


#include <gp_Ax3.hxx>
#include <gp_Trsf.hxx>
#include <IntAna_Quadric.hxx>
#include <ElSLib.hxx>

//----------------------------------------------------------------------
//-- 
//--  Equation generale des quadriques :  
//-- 
//--   f(x,y,z) =       CXX X**2  + CYY Y**2  + CZZ Z**2
//--              
//--             + 2 (  CXY X Y   + CXZ X Z   + CYZ Y Z )
//-- 
//--             + 2 (  CX  X     + CY  Y     + CZ  Z)
//-- 
//--             + CCte
//-- 
//-- 
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//-- Quadric Vide
//----------------------------------------------------------------------
IntAna_Quadric::IntAna_Quadric(void) {
  CXX=CYY=CZZ=CXY=CXZ=CYZ=CX=CY=CZ=0.0;   CCte=1.0;
}
//----------------------------------------------------------------------
//-- Pln  -----> Quadric
//-- 
//-- Coefficients sur gp_Pln retourne A,B,C,D 
//-- 	          avec f(x,y,z)  =    A x    + B y   +  C z   + D 
//-- 
//--  que l on identifie a        2(  CX x   + CY y  +  CZ z ) + CCte
//----------------------------------------------------------------------
void IntAna_Quadric::SetQuadric(const gp_Pln& P) {
  P.Coefficients(CX,CY,CZ,CCte);
  CX*=0.5; 
  CY*=0.5;
  CZ*=0.5;
  CXX=CYY=CZZ=CXY=CXZ=CYZ=0.0;
}

IntAna_Quadric::IntAna_Quadric(const gp_Pln& P) {
  P.Coefficients(CX,CY,CZ,CCte);  
  CX*=0.5; 
  CY*=0.5;
  CZ*=0.5;
  CXX=CYY=CZZ=CXY=CXZ=CYZ=0.0;
}
//----------------------------------------------------------------------
//-- Cylinder -----> Quadric
//----------------------------------------------------------------------
void IntAna_Quadric::SetQuadric(const gp_Cylinder& Cyl) {
  Cyl.Coefficients(CXX,CYY,CZZ,CXY,CXZ,CYZ,CX,CY,CZ,CCte);  
}

IntAna_Quadric::IntAna_Quadric(const gp_Cylinder& Cyl) {
  Cyl.Coefficients(CXX,CYY,CZZ,CXY,CXZ,CYZ,CX,CY,CZ,CCte);  
}
//----------------------------------------------------------------------
//-- Cone -----> Quadric
//----------------------------------------------------------------------
IntAna_Quadric::IntAna_Quadric(const gp_Cone& Cone)
{
  SetQuadric(Cone);
}

void IntAna_Quadric::SetQuadric(const gp_Cone& Cone) {
  Cone.Coefficients(CXX,CYY,CZZ,CXY,CXZ,CYZ,CX,CY,CZ,CCte);  
  const Standard_Real aVParam = -Cone.RefRadius() / Sin(Cone.SemiAngle());
  mySpecialPoints.Append(ElSLib::Value(0.0, aVParam, Cone));
}
//----------------------------------------------------------------------
//-- Sphere -----> Quadric
//----------------------------------------------------------------------
void IntAna_Quadric::SetQuadric(const gp_Sphere& Sph) {
  Sph.Coefficients(CXX,CYY,CZZ,CXY,CXZ,CYZ,CX,CY,CZ,CCte);
  mySpecialPoints.Append(ElSLib::Value(0.0, -M_PI_2, Sph));
  mySpecialPoints.Append(ElSLib::Value(0.0, M_PI_2, Sph));
}

IntAna_Quadric::IntAna_Quadric(const gp_Sphere& Sph) {
  SetQuadric(Sph);
}
//----------------------------------------------------------------------
//-- Returns the Coefficients of the Quadric
//----------------------------------------------------------------------
void IntAna_Quadric::Coefficients(Standard_Real& _CXX,Standard_Real& _CYY,Standard_Real& _CZZ,
				  Standard_Real& _CXY,Standard_Real& _CXZ,Standard_Real& _CYZ,
				  Standard_Real& _CX, Standard_Real& _CY, Standard_Real& _CZ,
				  Standard_Real& _CCte) const 
{
  _CXX=CXX; _CYY=CYY; _CZZ=CZZ;
  _CXY=CXY; _CXZ=CXZ; _CYZ=CYZ;
  _CX=CX;   _CY=CY;   _CZ=CZ;
  _CCte=CCte;
}
//----------------------------------------------------------------------
//-- Computes the Coefficients in a new coordinate system
//----------------------------------------------------------------------
void IntAna_Quadric::NewCoefficients( Standard_Real& _CXX,Standard_Real& _CYY,Standard_Real& _CZZ
				     ,Standard_Real& _CXY,Standard_Real& _CXZ,Standard_Real& _CYZ
				     ,Standard_Real& _CX, Standard_Real& _CY, Standard_Real& _CZ
				     ,Standard_Real& _CCte
				     ,const gp_Ax3& Axis) const 
{
  Standard_Real t11,t12,t13,t14;                  // x = t11 X + t12 Y + t13 Z + t14
  Standard_Real t21,t22,t23,t24;                  // y = t21 X + t22 Y + t23 Z + t24
  Standard_Real t31,t32,t33,t34;                  // z = t31 X + t32 Y + t33 Z + t34
                                 
                                                  //   = X DirX + Y DirY + Z DirZ + Loc
  
  Standard_Real Cxx,Cyy,Czz,Cxy,Cxz,Cyz,Cx,Cy,Cz,Ccte;            
  
  gp_Trsf Trans;
  Trans.SetTransformation(Axis);
  Trans.Invert();
  t11=Trans.Value(1,1);  t12=Trans.Value(1,2); t13=Trans.Value(1,3); t14=Trans.Value(1,4);
  t21=Trans.Value(2,1);  t22=Trans.Value(2,2); t23=Trans.Value(2,3); t24=Trans.Value(2,4);
  t31=Trans.Value(3,1);  t32=Trans.Value(3,2); t33=Trans.Value(3,3); t34=Trans.Value(3,4);
  
  
  //      P0(x,y,z)=_CXX x x + _CYY y y + ... + _CCte =0  (x,y,z "absolute" coordinates)
  // and  P1(X(x,y,z),Y(x,y,z),Z(x,y,z))=P0(x,y,z)
  //
  // with P1(X,Y,Z)= Cxx X X + Cyy Y Y + Czz Z Z + 2 Cxy X Y ... + Ccte
  //               = _CXX  x x + _CYY  y y  +  ...  +  _CCte
  
  Standard_Real t11_P2=t11*t11;  Standard_Real t21_P2=t21*t21;  Standard_Real t31_P2=t31*t31;
  Standard_Real t12_P2=t12*t12;  Standard_Real t22_P2=t22*t22;  Standard_Real t32_P2=t32*t32;
  Standard_Real t13_P2=t13*t13;  Standard_Real t23_P2=t23*t23;  Standard_Real t33_P2=t33*t33;
  Standard_Real t14_P2=t14*t14;  Standard_Real t24_P2=t24*t24;  Standard_Real t34_P2=t34*t34;

  Ccte = ((_CCte) 
	  + t14_P2* (_CXX) 
	  + t24_P2* (_CYY) 
	  + t34_P2* (_CZZ)
	  + 2.0 * ( t14*( (_CX) 
			 +t24* (_CXY) 
			 +t34* (_CXZ))
		   +t24*( (_CY) 
			 +t34* (_CYZ))
		   +t34* (_CZ)));
  
  Cxx = (  t11_P2* (_CXX) 
	 + t21_P2* (_CYY)
	 + t31_P2* (_CZZ)
	 + 2.0*( t11*( t21* (_CXY) 
		      +t31* (_CXZ))
 		+t21*t31* (_CYZ)));
  
  Cyy = (t12_P2* (_CXX) 
	 + t22_P2* (_CYY) 
	 + t32_P2* (_CZZ)
	 + 2.0*( t12*( t22* (_CXY) 
		      +t32* (_CXZ))
		+t22*t32* (_CYZ)));

  Czz = (t13_P2* (_CXX) 
	 + t33_P2* (_CZZ)
	 + t23_P2* (_CYY) 
	 + 2.0*( t13*( t23* (_CXY) 
		      +t33* (_CXZ))
		+t23*t33* (_CYZ)));

  Cz = (t13* (_CX) 
	+ t13*( t14* (_CXX) 
	       + t24* (_CXY) 
	       + t34* (_CXZ))
	+ t14*( t23* (_CXY) 
	       +t33* (_CXZ))
	+ t23*( (_CY) 
	       +t24* (_CYY) 
	       +t34* (_CYZ))
	+ t33*( t24* (_CYZ) 
	       +(_CZ)  
	       + t34* (_CZZ)));

  Cx = (t11* ((_CX) 
	      +t14* (_CXX) 
	      +t24* (_CXY) 
	      +t34* (_CXZ))
	+ t14*( t21* (_CXY) 
	       +t31* (_CXZ))
	+ t21*( (_CY) 
	       +t24* (_CYY)
	       +t34* (_CYZ))
	+ t31*( t24* (_CYZ) 
	       +(_CZ)
	       +t34* (_CZZ)));

  Cxy = (t11*( t12* (_CXX) 
	      +t22* (_CXY) 
	      +t32* (_CXZ))
	 + t12*( t21* (_CXY) 
		+t31* (_CXZ))
	 + t21*( t22* (_CYY) 
		+t32* (_CYZ))
	 + t31*( t22* (_CYZ) 
		+t32* (_CZZ)));

  Cxz = (t11*( t13* (_CXX) 
	      +t23* (_CXY) 
	      +t33* (_CXZ))
	 + t13*( t21* (_CXY) 
		+t31* (_CXZ))
	 + t21*( t23* (_CYY) 
		+t33* (_CYZ))
	 + t31*( t23* (_CYZ) 
		+t33* (_CZZ)));

  Cy = (t12* ( (_CX) 
	      +t14* (_CXX) 
	      +t24* (_CXY) 
	      +t34* (_CXZ))
	+ t14*( t22* (_CXY) 
	       +t32* (_CXZ))
	+ t22*( (_CY) 
	       +t24* (_CYY) 
	       +t34* (_CYZ))
	+ t32*( (_CZ) 
	       + t24* (_CYZ) 
	       + t34* (_CZZ)));

  Cyz = (t12*( t13* (_CXX) 
	      +t23* (_CXY) 
	      +t33* (_CXZ))
	 + t13*( t22* (_CXY) 
		+t32* (_CXZ))
	 + t22*( t23* (_CYY) 
		+t33* (_CYZ))
	 + t32*( t23* (_CYZ) 
		+t33* (_CZZ)));
  

  _CXX=Cxx; _CYY=Cyy; _CZZ=Czz;   _CX=Cx;   _CY=Cy;   _CZ=Cz;
  _CXY=Cxy; _CXZ=Cxz; _CYZ=Cyz;  _CCte=Ccte; 


}
  
