/**------------------------------------------------------------------------
 * @file
 *
 * Copyright 2001 by the University of Toronto (UT).
 *
 *                       All Rights Reserved
 * 
 * Permission to copy and modify this software and its documentation 
 * only for internal use in your organization is hereby granted, 
 * provided that this notice is retained thereon and on all copies.  
 * UT makes no representations as to the suitability and operability 
 * of this software for any purpose.  It is provided "as is" without 
 * express or implied warranty.
 *
 * UT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
 * SHALL UT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redistribute 
 * this software and its documentation or the right to prepare 
 * derivative works, are granted unless specifically provided in a 
 * separate license agreement.
 *
 * Author: Diego Macrini
 * 
 * $Log: ApproxBezier.h,v $
 *
 *-----------------------------------------------------------------------*/

#ifndef __APROX_BEZIER_H__
#define __APROX_BEZIER_H__

#include "ApproxPoly.h"

namespace dml {

/*!
	@brief Cubic Bezier Segment class
*/
struct CBSegment : public SEGMENT
{
	//POINT m_points[4];
	POINT p2;
	POINT p3;

//public:
	//double m_dError;
	//POSITION m_endKnotPos;

	/*!
		THIS FUNCTION CANNOT BE VIRTUAL. USE A VIRTUAL SET AT THE LEVEL OF APPROXPOLY
	*/
	SEGMENT& Set(const SEGMENT& s)
	{
		const CBSegment& cbs = static_cast<const CBSegment&>(s);

		p0 = cbs.p0;
		p1 = cbs.p1;
		p2 = cbs.p2;
		p3 = cbs.p3;
		
		m = tan((p3.y - p0.y) / (p3.x - p0.x));
		b = 1;
		
		return *this;
	}
    
	void Draw(/*CDC* pDC, int nWidth, COLORREF color*/);
	/*void Set(double dError, POSITION endKnotPos, 
		int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
	{
		m_dError = dError;
		m_endKnotPos = endKnotPos;
		m_points[0].x = x0;
		m_points[0].y = y0;
		m_points[1].x = x1;
		m_points[1].y = y1;
		m_points[2].x = x2;
		m_points[2].y = y2;
		m_points[3].x = x3;
		m_points[3].y = y3;
	}*/
};

class ApproxBezier : public ApproxPoly
{
	double x0, y0, x1, y1, x2, y2, x3, y3;
	double a0, b0, a1, b1, a2, b2, a3, b3;

	int m_nMaxRetry;
	double x1g, y1g;
	
public:
	ApproxBezier(int nMaxRetry, double dMinError, double dMinSlope, double dMaxSegments, double dMaxYDiff);
	virtual ~ApproxBezier();
	void Clear();
	
	virtual SEGMENT* NewSegment() { return new CBSegment; }
	virtual double LeastSquares(const POINT* vertices, int n, SEGMENT& s);
	virtual void Fit(const POINTS vertices);
	
	void CalcError(double x4, double y4, const double& u, double* s, double* z);
	double GetDistance(const POINT* rawdata, int n);
	void SetFirstEndPtSlope(double x, double y) { x1g = x; y1g = y; }
	void Draw(/*CDC* pDC, int nWidth, COLORREF color*/);
};

} //namespace dml

#endif //__APROX_BEZIER_H__
