// 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.
//
//=========================================================================================================================
// objcurve.h -- geometric curve objects
//=========================================================================================================================


#ifndef __OBJCURVE_H__
#define __OBJCURVE_H__


#include "OOMathsExport.h"

//=========================================================================================================================
// CMaLine - math library line (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaLine : public CMaGeometry
{
public:
	// constructors
	CMaLine();                                   // default line: positive x axis
	CMaLine(const CMaPoint& point, const CMaVector& direction);
	CMaLine(const CMaPoint& start, const CMaPoint& end);

	// destructor
	~CMaLine();

	// attributes
	CMaPoint GetPoint() const;
	CMaVector GetDirection() const;              // direction normalised
	void GetData(CMaPoint* point, CMaVector* direction) const;

	// operations
	// least-squares fitting: closest fit
	void Fit(const CMaPointArray& points);
	void Fit(const CMaPointArray& points, double* formError, double* sqrErrors);

	// 04/12/07 - New Ex methods created to explicitly require tolerance (and 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 zone fit 
	void FitMinZone(const CMaPointArray& points, double* zoneWidth, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
	// note:
	//    Chebyshev fitting line -> this
	//    two parallel zone lines -> line1 and line2 (for 2D data fitting only)
	void FitMinZone(const CMaPointArray& points, double* zoneWidth, CMaLine* line1, CMaLine* line2, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif
	EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, double tolerance, long iterationLimit);
	// note:
	//    Chebyshev fitting line -> this
	//    two parallel zone lines -> line1 and line2 (for 2D data fitting only)
	EMaFitResult FitMinZoneEx(const CMaPointArray& points, double* zoneWidth, CMaLine* line1, CMaLine* line2, double tolerance, long iterationLimit);

	// comparison
	EMaBoolean IsParallelTo  (const CMaLine&  other, double tolerance = MaGetDegreeTol()) const;
	EMaBoolean IsParallelTo  (const CMaPlane& other, double tolerance = MaGetDegreeTol()) const;
	EMaBoolean IsCoplanarWith(const CMaLine&  other, double tol1 = MaGetLengthTol(), double tol2 = 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);
	void MoveTo(const CMaNonLinearGeometry& other);       // transform into other's local coordinate system

	// symmetry calculation
	CMaLine  MidLine(const CMaPoint& other) const;        
	CMaLine  MidLine(const CMaLine&  other) const;
	CMaLine  MidLine(const CMaPlane& other) const;
	CMaPlane MidPlane(const CMaLine& other) const;
	// note: on MidLine
	//    all mid lines have the same direction as the first line
	// note: on MidPlane between two lines
	//    normal pointed to the first line

	// angle calculation
	double AngleWith(const CMaLine&  other) const;        // 0 <= return value <= 180 (degree)
	double AngleWith(const CMaPlane& other) const;        // 0 <= return value <=  90 (degree)
	double AngleWith(const CMaLine&  other, const CMaVector& axis) const;   // 0 <= return value < 360 (degree)
	// note: on angle between two lines
	//    equals to the angle between two vectors of line directions
	// note: on angle between line and plane
	//    equals to the angle between line direction vector and its projection on the plane

	// closest points calculation (return number of points on other object <= 2)
	int ClosestPointsTo(const CMaLine&    other, CMaPoint* p) const;
	int ClosestPointsTo(const CMaCircle&  other, CMaPoint* p1, CMaPoint* p2) const;
	int ClosestPointsTo(const CMaCylSurf& other, CMaPoint* p1, CMaPoint* p2) const;
	int ClosestPointsTo(const CMaConSurf& other, CMaPoint* p1, CMaPoint* p2) const;
	int ClosestPointsTo(const CMaSphSurf& other, CMaPoint* p1, CMaPoint* p2) const;
	// note: on calculation conditions
	//    line/line: they are not parallel
	//    line/cylinder: line is not parallel to cylinder axis

	// distance calculation
	double DistanceTo(const CMaLine&    other) const;
	double DistanceTo(const CMaCircle&  other) const;
	double DistanceTo(const CMaPlane&   other) const;
	double DistanceTo(const CMaCylSurf& other) const;
	double DistanceTo(const CMaConSurf& other) const;
	double DistanceTo(const CMaSphSurf& other) const;
	// note: calculate the shortest distance between the line and other object
	//    if they intersect, zero is returned

	// intersection calculation (return number of intersections)
	int IntersectWith(const CMaLine&      other, CMaPoint* p) const;
	int IntersectWith(const CMaCircle&    other, CMaPoint* p1, CMaPoint* p2) const;
	int IntersectWith(const CMaEllipse&   other, CMaPoint* p1, CMaPoint* p2) const;
	int IntersectWith(const CMaHyperbola& other, CMaPoint* p1, CMaPoint* p2) const;
	int IntersectWith(const CMaParabola&  other, CMaPoint* p1, CMaPoint* p2) const;

	int IntersectWith(const CMaPlane&   other, CMaPoint* p) const;
	int IntersectWith(const CMaCylSurf& other, CMaPoint* p1, CMaPoint* p2) const;
	int IntersectWith(const CMaConSurf& other, CMaPoint* p1, CMaPoint* p2) const;
	int IntersectWith(const CMaSphSurf& other, CMaPoint* p1, CMaPoint* p2) const;

	// Intersection calculation by returning the point of intersection
	// Required to create the baseline version of OOMaths
	// CMaPoint IntersectWith(const CMaLine& other) const;
	// This function is potentially dangerous as the user will not be aware of the result
	// and when no intersection is the case, a Point at origin is returned.

private:
	// implementation
	CMaPoint  m_cP0;    // the point that the line passes through
	CMaVector m_cDir;   // direction of the line
};

//=========================================================================================================================
// CMaCurve - math library curve (abstract base class)
//=========================================================================================================================

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

protected:
	// constructor
	CMaCurve();

	// least-squares fitting
	static void QuadraticFit(const CMaVector& x, const CMaVector& y, CMaVector* coefficients);
	static void CentredQuadraticFit(const CMaVector& x, const CMaVector& y, CMaVector* focals, int IsEllipse = 1);
};

//=========================================================================================================================
// CMaCircle - math library circle (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaCircle : public CMaCurve
{
public:
	// constructors
	CMaCircle(double radius = 1.0);      // default: unit circle on z=0 plane
	CMaCircle(double radius, const CMaPoint& centre);   // on z=0 plane
	CMaCircle(double radius, const CMaPoint& centre, const CMaVector& normal);
	CMaCircle(const CMaCircle& other);   // copy

	// destructor
	~CMaCircle();

	// attributes
	double GetRadius() const;
	CMaPoint GetCentre() const;
	CMaVector GetNormal() const;
	CMaPlane GetPlane() const;
	void GetData(double* radius, CMaPoint* centre, CMaVector* normal) 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());
	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, CMaCircle* circle1, CMaCircle* circle2, double tolerance = MaGetLengthTol(), long iterationLimit = MaMaxIterations);
#endif

	// Ex Methods (see comment above).
	// 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, CMaCircle* circle1, CMaCircle* circle2, double tolerance, long iterationLimit);

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

	// conversions
	CMaPolyline   ToPolyline  (int Size) const;   // Size > 1
	CMaPointArray ToPointArray(int Size) const;

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

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

	double m_R;   // radius of the circle
};

//=========================================================================================================================
// CMaEllipse - math library ellipse (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaEllipse : public CMaCurve
{
public:
	// constructors
	CMaEllipse(double a = 1.0, double b = 0.5);   // semimajor axis a > semiminor axis b > 0.0
	CMaEllipse(double a, double b, const CMaPoint& centre);                           // on z=0 plane
	CMaEllipse(double a, double b, const CMaPoint& centre, const CMaVector& xaxis);   // on z=0 plane
	CMaEllipse(double a, double b, const CMaPoint& centre, const CMaVector& xaxis, const CMaVector& normal);
	CMaEllipse(const CMaEllipse& other);          // copy

	// destructor
	~CMaEllipse();

	// attributes
	double GetXRadius() const;   // define X axis as major axis, Y axis as minor axis
	double GetYRadius() const;
	CMaPoint GetCentre() const;
	CMaVector GetNormal() const;
	CMaVector GetXaxis() const;
	CMaPlane GetPlane() const;
	void GetData(double* a, double* b, CMaPoint* centre, CMaVector* xaxis, CMaVector* normal) 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);
#endif

	EMaFitResult FitEx(const CMaPointArray& points, long iterationLimit);
	EMaFitResult FitEx(const CMaPointArray& points, double* formError, double* sqrErrors, long iterationLimit);


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

	// conversions
	CMaPolyline   ToPolyline  (int Size) const;   // Size > 1
	CMaPointArray ToPointArray(int Size) const;

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

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

	double m_A;   // semimajor axis
	double m_B;   // semiminor axis
};

//=========================================================================================================================
// CMaHyperbola - math library hyperbola (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaHyperbola : public CMaCurve
{
public:
	// constructors
	CMaHyperbola(double a = 1.0, double b = 1.0);   // real/imaginary semi-axis > 0.0
	CMaHyperbola(double a, double b, const CMaPoint& centre);                           // on z=0 plane
	CMaHyperbola(double a, double b, const CMaPoint& centre, const CMaVector& xaxis);   // on z=0 plane
	CMaHyperbola(double a, double b, const CMaPoint& centre, const CMaVector& xaxis, const CMaVector& normal);
	CMaHyperbola(const CMaHyperbola& other);        // copy

	// destructor
	~CMaHyperbola();

	// attributes
	double GetXRadius() const;   // define X axis as real axis, Y axis as imaginary axis
	double GetYRadius() const;
	CMaPoint GetCentre() const;
	CMaVector GetNormal() const;
	CMaVector GetXaxis() const;
	CMaPlane GetPlane() const;
	void GetData(double* a, double* b, CMaPoint* centre, CMaVector* xaxis, CMaVector* normal) 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);
#endif

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


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

	// conversions
	CMaPolyline   ToPolyline  (int Size, double x1, double x2, int upper = 1) const;
	CMaPointArray ToPointArray(int Size, double x1, double x2, int upper = 1) const;
	// note: Size > 1
	//    x1 < x2 <= -a or a <= x1 < x2
	//    curve part flag: lower/upper 0/1

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

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

	double m_A;   // real semi-axis
	double m_B;   // imaginary semi-axis
};

//=========================================================================================================================
// CMaParabola - math library parabola (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaParabola : public CMaCurve
{
public:
	// constructors
	CMaParabola(double f = 1.0);                     // focal length > 0
	CMaParabola(double f, const CMaPoint& vertex);                           // on z=0 plane
	CMaParabola(double f, const CMaPoint& vertex, const CMaVector& xaxis);   // on z=0 plane
	CMaParabola(double f, const CMaPoint& vertex, const CMaVector& xaxis, const CMaVector& normal);
	CMaParabola(const CMaParabola& other);           // copy

	// destructor
	~CMaParabola();

	// attributes
	double GetFocalLength() const;   // define X axis as axis of symmetry
	CMaPoint GetVertex() const;
	CMaVector GetNormal() const;
	CMaVector GetXaxis() const;
	CMaPlane GetPlane() const;
	void GetData(double* f, CMaPoint* vertex, CMaVector* xaxis, CMaVector* normal) 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);
#endif

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

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

	// conversions
	CMaPolyline   ToPolyline  (int Size, double x1, double x2, int upper = 1) const;
	CMaPointArray ToPointArray(int Size, double x1, double x2, int upper = 1) const;
	// note: Size > 1
	//    0 <= x1 < x2
	//    curve part flag: lower/upper 0/1

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

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

	double m_A;   // focal length: distance bewteen focal point and vertex
};

//=========================================================================================================================
// CMaPCurve - math library PCurve (concrete class)
//=========================================================================================================================

class OOMATHS_API CMaPCurve : public CMaCurve
{
public:
	// constructors
	CMaPCurve(const CMaTriagPolynomial& rep, const CMaInterval& range, const CMaCylSurf& surf, int half = 0);
	CMaPCurve(const CMaTriagPolynomial& rep, const CMaInterval& range, const CMaConSurf& surf, int half = 0);
	CMaPCurve(const CMaTriagPolynomial& rep, const CMaInterval& range, const CMaConSurf& surf, double singular, int infinity = 1, int half = 0);
	CMaPCurve(const CMaTriagPolynomial& rep, double parameter, const CMaConSurf& surf);   // second kind
	CMaPCurve(const CMaPCurve& other);
	// note: on curve part flag
	//    looking towards positive axis direction of reference surface
	//    lower half -1, upper half 1, both parts 0
	// note: on curve with singular range
	//    infinity -1 negative, 1 positive
	// note: on pcurve of second kind
	//    curve varies only along cone axis: angular parameter t is a constant,
	//    axis direction variable s is relevant to cone apex

	// destructor
	~CMaPCurve();

	// attributes
	int GetHalfFlag() const;
	CMaInterval GetParametricRange() const;
	CMaTriagPolynomial GetRepresentation() const;
	const CMaSurface* GetReferenceSurface() const;
	void GetData(CMaTriagPolynomial* rep, CMaInterval* range, int* half) const;

	EMaBoolean IsClosed() const;
	EMaBoolean IsSecondKind() const;
	EMaBoolean IsSingularRange() const;
	EMaBoolean IsNegativeInfinity() const;
	double GetParameter() const;
	void GetData(CMaTriagPolynomial* rep, double* parameter) const;

	// operations
	// assignment
	CMaPCurve& operator= (const CMaPCurve& other);

	// conversions
	CMaPolyline   ToPolyline  (int Size, double s1 = 0.0, double s2 = 0.0) const;
	CMaPointArray ToPointArray(int Size, double s1 = 0.0, double s2 = 0.0) const;
	// note: Size > 1
	//    s2 > s1, given for curve of second kind

	// point calculation
	CMaPoint GetCurvePoint(double t, int half = 1);
	// note: t in parametric range, half +/-1,
	//    or t is value of axis direction variable

private:
	// implementation
	void Copy(const CMaPCurve& other);
	double ValueAt(double t, int half = 1) const;

	int m_nHalf;
	int m_nSingular;
	double m_T;
	CMaInterval* m_cRange;
	CMaTriagPolynomial m_cRep;
	CMaCylSurf* m_pRefCylSurf;
	CMaConSurf* m_pRefConSurf;
};


#endif // __OBJCURVE_H__

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