/* curvetest.cpp */
/* Programed by AZO */
/* This code is free. At Your Own Risk. */

/* This program uses wxWidget >3.0.0 */
/* build: g++ `wx-config --cppflags` curvetest.cpp curve.c `wx-config --libs` -lm -o curvetest */

#include "curve.h"

#include <wx/wx.h>
#include <wx/image.h>
#include <wx/graphics.h>

void DrawBSpline(void) {
	#define NUMOFCONTROL 5
	pos2d_t Controls[NUMOFCONTROL] = {0};
	pos2d_t Output;
	pos2d_t preOutput;
	double myt;

	Controls[0].x = 0;
	Controls[0].y = 0;
	Controls[1].x = 100;
	Controls[1].y = 500;
	Controls[2].x = 200;
	Controls[2].y = 100;
	Controls[3].x = 400;
	Controls[3].y = 300;
	Controls[4].x = 500;
	Controls[4].y = 500;

	wxImage oImage(500, 500, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 500, 500);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		for(myt = 0.0; myt < NUMOFCONTROL; myt += 0.01) {
			bspline3(&Output, NUMOFCONTROL, Controls, myt);
//			bspline2(&Output, NUMOFCONTROL, Controls, myt);
			path.MoveToPoint((int)(preOutput.x), (int)(preOutput.y));
			path.AddLineToPoint((int)(Output.x), (int)(Output.y));
			preOutput.x = Output.x;
			preOutput.y = Output.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("bspline.png", wxBITMAP_TYPE_PNG);
}

void DrawBezier(void) {
	pos2d_t Output;
	pos2d_t From;
	pos2d_t Control1;
	pos2d_t Control2;
	pos2d_t To;
	pos2d_t preOutput;
	double myt;
	
	From.x = 0;
	From.y = 0;
	Control1.x = 0;
	Control1.y = 100;
	Control2.x = 100;
	Control2.y = 100;
	To.x = 100;
	To.y = 0;

	wxImage oImage(100, 100, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 100, 100);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		for(myt = 0.0; myt <= 1.0; myt += 0.01) {
			cubic_bezier(&Output, &From, &Control1, &Control2, &To, myt);
//			quadratic_bezier(&Output, &From, &Control1, &To, myt);
			path.MoveToPoint((int)(preOutput.x), (int)(preOutput.y));
			path.AddLineToPoint((int)(Output.x), (int)(Output.y));
			preOutput.x = Output.x;
			preOutput.y = Output.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("bezier.png", wxBITMAP_TYPE_PNG);
}

void DrawEllipse(void) {
	ellipse2d_t Ellipse;
	pos2d_t From;
	pos2d_t To;
	double val;

	Ellipse.center.x = 200;
	Ellipse.center.y = 200;
	Ellipse.radius1 = 200;
	Ellipse.radius2 = 100;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		ellipse(&From, &Ellipse, 0, 0);
		for(val = 0.0; val <= 2.0; val += 0.01) {
			ellipse(&To, &Ellipse, 0, M_PI * val);
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("ellipse.png", wxBITMAP_TYPE_PNG);
}

void DrawShearedEllipse(void) {
	ellipse2d_t Ellipse;
	pos2d_t From;
	pos2d_t To;
	double val;

	Ellipse.center.x = 200;
	Ellipse.center.y = 200;
	Ellipse.radius1 = 200;
	Ellipse.radius2 = 100;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		sheared_ellipse(&From, &Ellipse, 0, M_PI * 0.1, 0);
		for(val = 0.0; val <= 2.0; val += 0.01) {
			sheared_ellipse(&To, &Ellipse, 0, M_PI * 0.1, M_PI * val);
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("shared_ellipse.png", wxBITMAP_TYPE_PNG);
}

void DrawInvolute(void) {
	pos2d_t Center;
	pos2d_t From;
	pos2d_t To;
	double val;

	Center.x = 200;
	Center.y = 200;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		involute(&From, &Center, 10, 0);
		for(val = 0.0; val <= 4.0; val += 0.01) {
			involute(&To, &Center, 10, M_PI * val);
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("involute.png", wxBITMAP_TYPE_PNG);
}

void DrawTrochoid(void) {
	pos2d_t From;
	pos2d_t To;
	double val;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		trochoid(&From, 20, 25, 0);
		From.y += 200;
		for(val = 0.0; val <= 4.0; val += 0.01) {
			trochoid(&To, 20, 25, M_PI * val);
			To.y += 200;
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("trochoid.png", wxBITMAP_TYPE_PNG);
}

void DrawEpitrochoid(void) {
	pos2d_t From;
	pos2d_t To;
	double val;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		epitrochoid(&From, 100, 20, 30, 0);
		From.x += 200;
		From.y += 200;
		for(val = 0.0; val <= 4.0; val += 0.01) {
			epitrochoid(&To, 100, 20, 30, M_PI * val);
			To.x += 200;
			To.y += 200;
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("epitrochoid.png", wxBITMAP_TYPE_PNG);
}

void DrawHypotrochoid(void) {
	pos2d_t From;
	pos2d_t To;
	double val;

	wxImage oImage(400, 400, false);
	wxGraphicsContext *pGC = wxGraphicsContext::Create(oImage);
	if(pGC) {
		pGC->SetBrush( *wxBLACK_BRUSH );
		pGC->DrawRectangle(0, 0, 400, 400);
		pGC->SetPen( *wxWHITE_PEN );
		wxGraphicsPath path = pGC->CreatePath();
		path.MoveToPoint(0, 0);

		hypotrochoid(&From, 100, 20, 30, 0);
		From.x += 200;
		From.y += 200;
		for(val = 0.0; val <= 4.0; val += 0.01) {
			hypotrochoid(&To, 100, 20, 30, M_PI * val);
			To.x += 200;
			To.y += 200;
			path.MoveToPoint((int)(From.x), (int)(From.y));
			path.AddLineToPoint((int)(To.x), (int)(To.y));
			From.x = To.x;
			From.y = To.y;
		}
		pGC->StrokePath(path);

		delete pGC;
	}
	oImage.SaveFile("hypotrochoid.png", wxBITMAP_TYPE_PNG);
}

int main(void) {
	wxPNGHandler *handler = new wxPNGHandler;
	wxImage::AddHandler(handler);

	DrawBSpline();
	DrawBezier();
	DrawEllipse();
	DrawShearedEllipse();
	DrawInvolute();
	DrawTrochoid();
	DrawEpitrochoid();
	DrawHypotrochoid();

	return 0;
}	
