// This is a part of the Object Oriented Mathematical Library
// Copyright (C) 1999-2008 Renishaw plc
//
// This source file is the confidential property of Renishaw plc.
// Reproduction or transmission in whole or in part, in any form or
// by any means, electronic, mechanical or otherwise, is prohibited
// without the prior written consent of the copyright owner.
//
// objsurf.h -- geometric surface objects


#ifndef __OBJSURF_H__
#define __OBJSURF_H__

#include "OOMathsExport.h"

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaPlane - math library plane (concrete class)

class OOMATHS_API CMaPlane : public CMaGeometry
{
public:
// constructors
   CMaPlane();                                // default plane: z=0, normal=(0,0,1)
   CMaPlane(const CMaPoint& point, const CMaVector& normal);
   CMaPlane(const CMaPoint& point, const CMaLine& line);
   CMaPlane(const CMaPlane& other); //Copy

// destructor
   ~CMaPlane();

// attributes
   CMaPoint GetPoint() const;
   CMaVector GetNormal() const;
   void GetData(CMaPoint* point, CMaVector* normal) const;

// operations
   // Assignment operation
   CMaPlane& operator= (const CMaPlane& other);
   // least-squares fitting: closest fit
   void Fit(const CMaPointArray& points);
   void Fit(const CMaPointArray& points, double* formError, double* sqrErrors);

   // Chebyshev fitting: minimum zone fit
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, double tolerance = MaGetLengthTol());
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, CMaPlane* plane1, CMaPlane* plane2, double tolerance = MaGetLengthTol());

   // comparison
   EMaBoolean IsEqual(const CMaPlane& other, double tol1 = MaGetLengthTol(), double tol2 = MaGetDegreeTol()) const;
   EMaBoolean IsParallelTo (const CMaPlane& other, double tolerance = MaGetDegreeTol()) const;

   // transformation
   void Translate(double x, double y, double z = 0.0);   // incremental translation
   void Translate(const CMaPoint& newpos);               // absolute translation to a new position
   void Rotate(double angle, EAxisType axis);            // rotate around a Cartesian coordinate axis
   void Rotate(double angle, const CMaVector& axis);     // rotate around an arbitrary axis
   void Rotate(double angle, EAxisType axis, const CMaPoint& centre);       // rotation centre specified
   void Rotate(double angle, const CMaVector& axis, const CMaPoint& centre);

   // symmetry calculation
   CMaPlane MidPlane(const CMaPoint& other) const;
   CMaPlane MidPlane(const CMaLine&  other) const;
   CMaPlane MidPlane(const CMaPlane& other) const;
      // note: on MidPlane
      //    all mid planes have the same normal as the first plane

   // angle calculation
   double AngleWith(const CMaPlane& other) const;        // 0 <= return value <= 90 (degree)

   // distance calculation
   double DistanceTo(const CMaPlane& other) const;
      // note: calculate the distance between two parallel planes
      //    if they are not parallel, zero is returned

   // intersection calculation (return number of intersections, <= 2)
   int IntersectWith(const CMaLine& other, CMaPoint* p) const;
   int IntersectWith(const CMaPlane& other, CMaLine* line) const;

   int IntersectWith(const CMaCylSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaConSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaSphSurf& other, CMaObjArray* curves) const;
      // note: on memory deallocation
      //    Use the "delete" operator upon CMaObjArray* variables to deallocate the memory
      //    when the intersection results are no longer needed

private:
// implementation
   CMaPoint  m_cP0;       // the point that the plane passes through
   CMaVector m_cNormal;   // normal of the plane
};

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaSurface - math library surface (abstract base class)

class OOMATHS_API CMaSurface : public CMaNonLinearGeometry
{
public:
// destructor
   virtual ~CMaSurface();

protected:
// constructor
   CMaSurface();

// least-squares fitting
   static void QuadricAxes(const CMaPointArray& points, const CMaPoint& mean, CMaPoint* pp0, CMaVector* axes);
};

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaCylSurf - math library cylindrical surface (concrete class)

class OOMATHS_API CMaCylSurf : public CMaSurface
{
public:
// constructors
   CMaCylSurf(double radius = 1.0);
   CMaCylSurf(double radius, const CMaPoint& AxisPoint, const CMaVector& AxisDirection);
   CMaCylSurf(const CMaCylSurf& other);

// destructor
   ~CMaCylSurf();

// attributes
   double GetRadius() const;
   CMaPoint GetAxisPoint() const;
   CMaVector GetAxisDirection() const;
   CMaLine GetAxis() const;
   void GetData(double* radius, CMaPoint* AxisPoint, CMaVector* AxisDirection) const;

// operations

   // 05/12/07 - New Ex methods created to explicitly require tolerance and/or iteration 
   // parameters to be passed to the fit methods. This is implemented as part of fix 
   // for CCAR 52918. The existing methods have been wrapped in an ifndef block so that 
   // if OOMATHS_NO_DEF_TOL is given as a preprocessor command by someone using the maths
   // library, these methods will not be visible. Prod+ requested this so that they are
   // forced to use the new Ex methods when they define OOMATHS_NO_DEF_TOL.

#ifndef OOMATHS_NO_DEF_TOL
   // least-squares fitting: closest fit
   void Fit(const CMaPointArray& points, long iterationLimit = MaMaxIterations);
   void Fit(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit = MaMaxIterations);

   // Chebyshev fitting: maximum inscribed, minimum circumscribed, or minimum zone fit
   void FitMax(const CMaPointArray& points, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
   void FitMin(const CMaPointArray& points, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, CMaCylSurf* surf1, CMaCylSurf* surf2, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif

   // Ex- least-squares fitting: closest fit
   EMaFitResult FitEx(const CMaPointArray& points, long iterationLimit);
   EMaFitResult FitEx(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit);

   // Ex- Chebyshev fitting: maximum inscribed, minimum circumscribed, or minimum zone fit
   EMaFitResult FitMaxEx(const CMaPointArray& points, double tolerance, long iterationLimit);
   EMaFitResult FitMinEx(const CMaPointArray& points, double tolerance, long iterationLimit);
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, double tolerance, long iterationLimit);
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, CMaCylSurf* surf1, CMaCylSurf* surf2, double tolerance, long iterationLimit);


   // conversion: from geometric form to algebraic form (coefficient matrix)
   CMaMatrix ToAlgebraicForm() const;                                    // in space coordinate system
   CMaMatrix ToAlgebraicForm(const CMaNonLinearGeometry& other) const;   // in other's coordinate system

   // assignment
   CMaCylSurf& operator= (const CMaCylSurf& other);

   // intersection calculation (return number of intersections, <= 2)
   int IntersectWith(const CMaLine& other, CMaPoint* p1, CMaPoint* p2) const;

   int IntersectWith(const CMaPlane&   other, CMaObjArray* curves) const;
   int IntersectWith(const CMaCylSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaConSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaSphSurf& other, CMaObjArray* curves) const;

private:
// implementation
   void Copy(const CMaCylSurf& other);
   int Intersect(const CMaMatrix& A, CMaTriagPolynomial* Poly, CMaInterval* Intv) const;   // find PCurves

   double m_R;   // radius of the cylinder
};

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaConSurf - math library conical surface (concrete class)

class OOMATHS_API CMaConSurf : public CMaSurface
{
public:
// constructors
   CMaConSurf(double semiangle = 45.0);       // semiangle in open interval (0, 90)
   CMaConSurf(double semiangle, const CMaPoint& apex, const CMaVector& AxisDirection);
   CMaConSurf(const CMaConSurf& other);

// destructor
   ~CMaConSurf();

// attributes
   double GetSemiAngle() const;
   CMaPoint GetApex() const;
   CMaVector GetAxisDirection() const;
   CMaLine GetAxis() const;
   void GetData(double* semiangle, CMaPoint* apex, CMaVector* AxisDirection) const;

// operations

   // 04/12/07 - New Ex methods created to explicitly require tolerance and/or iteration 
   // parameters to be passed to the fit methods. This is implemented as part of fix 
   // for CCAR 52918. The existing methods have been wrapped in an ifndef block so that 
   // if OOMATHS_NO_DEF_TOL is given as a preprocessor command by someone using the maths
   // library, these methods will not be visible. Prod+ requested this so that they are
   // forced to use the new Ex methods when they define OOMATHS_NO_DEF_TOL.

#ifndef OOMATHS_NO_DEF_TOL
   // least-squares fitting: closest fit
   void Fit(const CMaPointArray& points, long iterationLimit = MaMaxIterations);
   void Fit(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit = MaMaxIterations);

   // Chebyshev fitting: minimum zone fit
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, CMaConSurf* surf1, CMaConSurf* surf2, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif

   // Ex-least-squares fitting: closest fit
   EMaFitResult FitEx(const CMaPointArray& points, long iterationLimit);
   EMaFitResult FitEx(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit);

   // Ex-Chebyshev fitting: minimum zone fit
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, double tolerance, long iterationLimit);
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, CMaConSurf* surf1, CMaConSurf* surf2, double tolerance, long iterationLimit);

   // conversion: from geometric form to algebraic form (coefficient matrix)
   CMaMatrix ToAlgebraicForm() const;                                    // in space coordinate system
   CMaMatrix ToAlgebraicForm(const CMaNonLinearGeometry& other) const;   // in other's coordinate system

   // assignment
   CMaConSurf& operator= (const CMaConSurf& other);

   // intersection calculation (return number of intersections, <= 2)
   int IntersectWith(const CMaLine& other, CMaPoint* p1, CMaPoint* p2) const;

   int IntersectWith(const CMaPlane&   other, CMaObjArray* curves) const;
   int IntersectWith(const CMaCylSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaConSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaSphSurf& other, CMaObjArray* curves) const;

private:
// implementation
   void Copy(const CMaConSurf& other);
   int Intersect(const CMaMatrix& A, CMaTriagPolynomial* Poly, CMaInterval* Intv,
                 double* Para, int* Dual, int* Apex, int* Discriminant) const;

   double m_A;   // semiangle of the cone (in degree)
};

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaSphSurf - math library spherical surface (concrete class)

class OOMATHS_API CMaSphSurf : public CMaSurface
{
public:
// constructors
   CMaSphSurf(double radius = 1.0);                     // default: unit sphere
   CMaSphSurf(double radius, const CMaPoint& centre);
   CMaSphSurf(const CMaSphSurf& other);

// destructor
   ~CMaSphSurf();

// attributes
   double GetRadius() const;
   CMaPoint GetCentre() const;
   
   // The co-ordinates of the center is to be returned
   // Required to create the baseline version of OOMaths to be 
   // used by the Generic controller
   void GetCentre(double *pX, double *pY, double *pZ) const;

   void GetData(double* radius, CMaPoint* centre) const;

// operations

   // 04/12/07 - New Ex methods created to explicitly require tolerance and/or iteration 
   // parameters to be passed to the fit methods. This is implemented as part of fix 
   // for CCAR 52918. The existing methods have been wrapped in an ifndef block so that 
   // if OOMATHS_NO_DEF_TOL is given as a preprocessor command by someone using the maths
   // library, these methods will not be visible. Prod+ requested this so that they are
   // forced to use the new Ex methods when they define OOMATHS_NO_DEF_TOL.

#ifndef OOMATHS_NO_DEF_TOL
   // least-squares fitting: closest fit
   void Fit(const CMaPointArray& points, long iterationLimit = MaMaxIterations);
   void Fit(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit = MaMaxIterations);

   // Chebyshev fitting: maximum inscribed, minimum circumscribed, or minimum zone fit
   void FitMax(const CMaPointArray& points, double tolerance = MaGetLengthTol());
   void FitMin(const CMaPointArray& points, double tolerance = MaGetLengthTol());
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
   void FitMinZone(const CMaPointArray& points, double* zoneWidth, CMaSphSurf* surf1, CMaSphSurf* surf2, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif

   // Ex - least-squares fitting: closest fit
   EMaFitResult FitEx(const CMaPointArray& points, long iterationLimit);
   EMaFitResult FitEx(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit);

   // Ex -  Chebyshev fitting: maximum inscribed, minimum circumscribed, or minimum zone fit
   EMaFitResult FitMaxEx(const CMaPointArray& points, double tolerance);
   EMaFitResult FitMinEx(const CMaPointArray& points, double tolerance);
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, double tolerance, long iterationLimit);
   EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, CMaSphSurf* surf1, CMaSphSurf* surf2, double tolerance, long iterationLimit);

   // conversion: from geometric form to algebraic form (coefficient matrix)
   CMaMatrix ToAlgebraicForm() const;                                    // in space coordinate system
   CMaMatrix ToAlgebraicForm(const CMaNonLinearGeometry& other) const;   // in other's coordinate system

   // assignment
   CMaSphSurf& operator= (const CMaSphSurf& other);

   // intersection calculation (return number of intersections, <= 2)
   int IntersectWith(const CMaLine& other, CMaPoint* p1, CMaPoint* p2) const;

   int IntersectWith(const CMaPlane&   other, CMaObjArray* curves) const;
   int IntersectWith(const CMaCylSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaConSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaSphSurf& other, CMaObjArray* curves) const;

private:
// implementation
   void Copy(const CMaSphSurf& other);

   double m_R;   // radius of the sphere
};

// ========================================================================================================================
////////////////////////////////////////////////////////////////////////////////
// CMaTorSurf - math library toroidal surface (concrete class)

class OOMATHS_API CMaTorSurf : public CMaSurface
{
public:
// constructors
   CMaTorSurf(double a = 1.0, double b = 0.5);   // major radius a > minor radius b > 0
   CMaTorSurf(double a, double b, const CMaPoint& centre);
   CMaTorSurf(double a, double b, const CMaPoint& centre, const CMaVector& AxisDirection);
   CMaTorSurf(const CMaTorSurf& other);

// destructor
   ~CMaTorSurf();

// attributes
   double GetMajorRadius() const;
   double GetMinorRadius() const;
   CMaPoint GetCentre() const;
   CMaVector GetAxisDirection() const;
   CMaLine GetAxis() const;
   void GetData(double* a, double* b, CMaPoint* centre, CMaVector* AxisDirection) const;

// operations

   // 04/12/07 - New Ex methods created to explicitly require tolerance and/or iteration 
   // parameters to be passed to the fit methods. This is implemented as part of fix 
   // for CCAR 52918. The existing methods have been wrapped in an ifndef block so that 
   // if OOMATHS_NO_DEF_TOL is given as a preprocessor command by someone using the maths
   // library, these methods will not be visible. Prod+ requested this so that they are
   // forced to use the new Ex methods when they define OOMATHS_NO_DEF_TOL.

#ifndef OOMATHS_NO_DEF_TOL
   // Chebyshev fitting: minimum circumscribed fit
   void FitMin(const CMaPointArray& points, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif
   // Chebyshev fitting: minimum circumscribed fit
   EMaFitResult FitMinEx(const CMaPointArray& points, double tolerance, long iterationLimit);

   // assignment
   CMaTorSurf& operator= (const CMaTorSurf& other);

   // intersection calculation (return number of intersections, <= 4)
   int IntersectWith(const CMaPlane&   other, CMaObjArray* curves) const;
   int IntersectWith(const CMaCylSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaConSurf& other, CMaObjArray* curves) const;
   int IntersectWith(const CMaSphSurf& other, CMaObjArray* curves) const;

private:
// implementation
   void Copy(const CMaTorSurf& other);

   double m_A;   // major radius of the torus
   double m_B;   // minor radius of the torus
};

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

#endif // __OBJSURF_H__
// ========================================================================================================================
