Скачиваний:
26
Добавлен:
01.05.2014
Размер:
14.38 Кб
Скачать
/* By Thomas Mшlhave

  This is file contains the functions for two classes, the CCubicCurve and CCubicPatch classes.
	check http://home10.inet.tele.dk/moelhave for more info
*/


#ifndef CURVES_CPP__
#define CURVES_CPP__
#include <windows.h>
#include <GL\gl.h>
#include <math.h>
#include <stdio.h>
#include "matrix.h"
#include "curves.h"

//little function to convert from Point to Matrix4x1
Matrix4x1 ConvertPoint(Point *p)
{
	Matrix4x1 a;
	a.M[0] = p->x;
	a.M[1] = p->y;
	a.M[2] = p->z;
	a.M[3] = 1.0f;
	return a;
}

/*
Function that subdivides a bezier curve, the two new curves are made at t=Ѕ.
Parameters:
L	 : Left subdivided curve storage var
R	 : Right subdivided curve storage var
*/
void CCubicCurve::SubdivideBezierCurve(CCubicCurve* L, CCubicCurve* R)
{
	if (type != TM_BEZIER)
	{
		//error
		L = NULL;
		R = NULL;
		return;
	}
	
	Matrix4x1 L1, L2, L3, L4, H, R1, R2, R3, R4;
	
	L1.M[0] = Gx.M[0];
	L1.M[1] = Gy.M[0];
	L1.M[2] = Gz.M[0];
	
	L2.M[0] = (Gx.M[0]+Gx.M[1]) / 2.0f;
	L2.M[1] = (Gy.M[0]+Gy.M[1]) / 2.0f;
	L2.M[2] = (Gz.M[0]+Gz.M[1]) / 2.0f;
	L2.M[3] = 1.0f;
	
	H.M[0] = (Gx.M[1] + Gx.M[2])/2.0f;
	H.M[1] = (Gy.M[1] + Gy.M[2])/2.0f;
	H.M[2] = (Gz.M[1] + Gz.M[2])/2.0f;
	
	L3.M[0] = (L2.M[0] + H.M[0])/2.0f;
	L3.M[1] = (L2.M[1] + H.M[1])/2.0f;
	L3.M[2] = (L2.M[2] + H.M[2])/2.0f;
	
	R3.M[0] = (Gx.M[2] + Gx.M[3])/2.0f;
	R3.M[1] = (Gy.M[2] + Gy.M[3])/2.0f;
	R3.M[2] = (Gz.M[2] + Gz.M[3])/2.0f;
	
	R2.M[0] = (H.M[0]+R3.M[0])/2.0f;
	R2.M[1] = (H.M[1]+R3.M[1])/2.0f;
	R2.M[2] = (H.M[2]+R3.M[2])/2.0f;
	
	L4.M[0] = (L3.M[0] + R2.M[0])/2.0f;
	L4.M[1] = (L3.M[1] + R2.M[1])/2.0f;
	L4.M[2] = (L3.M[2] + R2.M[2])/2.0f;
	
	R1 = L4;
	
	R4.M[0] = Gx.M[3];
	R4.M[1] = Gy.M[3];
	R4.M[2] = Gz.M[3];
	
	L->GenerateBezierCoefficients(L1, L2, L3, L4);
	R->GenerateBezierCoefficients(R1, R2, R3, R4);
}

void CCubicCurve::GenerateHermiteCoefficients(Matrix4x1 _p1, Matrix4x1 _p2, Matrix4x1 r1, Matrix4x1 r2)
{
	type = TM_HERMITE;
	
	//build hermite base matrix
	Matrix4x4 mh;
	mh.M[0][0] = 2.0f;
	mh.M[0][1] = -2.0f;
	mh.M[0][2] = 1.0f;
	mh.M[0][3] = 1.0f;
	mh.M[1][0] = -3.0f;
	mh.M[1][1] = 3.0f;
	mh.M[1][2] = -2.0f;
	mh.M[1][3] = -1.0f;
	mh.M[2][0] = 0.0f;
	mh.M[2][1] = 0.0f;
	mh.M[2][2] = 1.0f;
	mh.M[2][3] = 0.0f;
	mh.M[3][0] = 1.0f;
	mh.M[3][1] = 0.0f;
	mh.M[3][2] = 0.0f;
	mh.M[3][3] = 0.0f;
	
	//build geometry matrices
	Gx.M[0] = _p1.M[0];
	Gx.M[1] = _p2.M[0];
	Gx.M[2] = r1.M[0];
	Gx.M[3] = r2.M[0];
	
	Gy.M[0] = _p1.M[1];
	Gy.M[1] = _p2.M[1];
	Gy.M[2] = r1.M[1];
	Gy.M[3] = r2.M[1];
	
	Gz.M[0] = _p1.M[2];
	Gz.M[1] = _p2.M[2];
	Gz.M[2] = r1.M[2];
	Gz.M[3] = r2.M[2];
	
	//computer coefficients
	Matrix4x1 Qx = Gx.MultiplyWith4x4(&mh);
	Matrix4x1 Qy = Gy.MultiplyWith4x4(&mh);
	Matrix4x1 Qz = Gz.MultiplyWith4x4(&mh);
	//store coefficients
	coef[0] = Qx.M[0];
	coef[1] = Qx.M[1];
	coef[2] = Qx.M[2];
	coef[3] = Qx.M[3];
	coef[4] = Qy.M[0];
	coef[5] = Qy.M[1];
	coef[6] = Qy.M[2];
	coef[7] = Qy.M[3];
	coef[8] = Qz.M[0];
	coef[9] = Qz.M[1];
	coef[10] = Qz.M[2];
	coef[11] =	 Qz.M[3];
}

void CCubicCurve::GenerateBezierCoefficients(Matrix4x1 p1, Matrix4x1 p2, Matrix4x1 p3, Matrix4x1 p4)
{
	type = TM_BEZIER;
	
	//build hermite base matrix
	Matrix4x4 mh;
	mh.M[0][0] = -1.0f;
	mh.M[0][1] = 3.0f;
	mh.M[0][2] = -3.0f;
	mh.M[0][3] = 1.0f;
	
	mh.M[1][0] = 3.0f;
	mh.M[1][1] = -6.0f;
	mh.M[1][2] = 3.0f;
	mh.M[1][3] = 0.0f;
	
	mh.M[2][0] = -3.0f;
	mh.M[2][1] = 3.0f;
	mh.M[2][2] = 0.0f;
	mh.M[2][3] = 0.0f;
	
	mh.M[3][0] = 1.0f;
	mh.M[3][1] = 0.0f;
	mh.M[3][2] = 0.0f;
	mh.M[3][3] = 0.0f;
	
	//build geometry matrices
	Gx.M[0] = p1.M[0];
	Gx.M[1] = p2.M[0];
	Gx.M[2] = p3.M[0];
	Gx.M[3] = p4.M[0];
	
	Gy.M[0] = p1.M[1];
	Gy.M[1] = p2.M[1];
	Gy.M[2] = p3.M[1];
	Gy.M[3] = p4.M[1];
	
	Gz.M[0] = p1.M[2];
	Gz.M[1] = p2.M[2];
	Gz.M[2] = p3.M[2];
	Gz.M[3] = p4.M[2];
	
	//computer coefficients
	Matrix4x1 Qx = Gx.MultiplyWith4x4(&mh);
	Matrix4x1 Qy = Gy.MultiplyWith4x4(&mh);
	Matrix4x1 Qz = Gz.MultiplyWith4x4(&mh);
	
	//store coefficients
	coef[0] = Qx.M[0];
	coef[1] = Qx.M[1];
	coef[2] = Qx.M[2];
	coef[3] = Qx.M[3];
	coef[4] = Qy.M[0];
	coef[5] = Qy.M[1];
	coef[6] = Qy.M[2];
	coef[7] = Qy.M[3];
	coef[8] = Qz.M[0];
	coef[9] = Qz.M[1];
	coef[10] = Qz.M[2];
	coef[11] =	 Qz.M[3];
}

void CCubicCurve::GenerateBezierCoefficients(Point _p1, Point _p2, Point _p3, Point _p4)
{
	
	type = TM_BEZIER;
	
	Matrix4x1 p1 = ConvertPoint(&_p1);
	Matrix4x1 p2 = ConvertPoint(&_p2);
	Matrix4x1 p3 = ConvertPoint(&_p3);
	Matrix4x1 p4 = ConvertPoint(&_p4);
	
	//build hermite base matrix
	Matrix4x4 mh;
	mh.M[0][0] = -1.0f;
	mh.M[0][1] = 3.0f;
	mh.M[0][2] = -3.0f;
	mh.M[0][3] = 1.0f;
	
	mh.M[1][0] = 3.0f;
	mh.M[1][1] = -6.0f;
	mh.M[1][2] = 3.0f;
	mh.M[1][3] = 0.0f;
	
	mh.M[2][0] = -3.0f;
	mh.M[2][1] = 3.0f;
	mh.M[2][2] = 0.0f;
	mh.M[2][3] = 0.0f;
	
	mh.M[3][0] = 1.0f;
	mh.M[3][1] = 0.0f;
	mh.M[3][2] = 0.0f;
	mh.M[3][3] = 0.0f;
	
	//build geometry matrices
	Gx.M[0] = p1.M[0];
	Gx.M[1] = p2.M[0];
	Gx.M[2] = p3.M[0];
	Gx.M[3] = p4.M[0];
	
	Gy.M[0] = p1.M[1];
	Gy.M[1] = p2.M[1];
	Gy.M[2] = p3.M[1];
	Gy.M[3] = p4.M[1];
	
	Gz.M[0] = p1.M[2];
	Gz.M[1] = p2.M[2];
	Gz.M[2] = p3.M[2];
	Gz.M[3] = p4.M[2];
	
	//computer coefficients
	Matrix4x1 Qx = Gx.MultiplyWith4x4(&mh);
	Matrix4x1 Qy = Gy.MultiplyWith4x4(&mh);
	Matrix4x1 Qz = Gz.MultiplyWith4x4(&mh);
	
	//store coefficients
	coef[0] = Qx.M[0];
	coef[1] = Qx.M[1];
	coef[2] = Qx.M[2];
	coef[3] = Qx.M[3];
	coef[4] = Qy.M[0];
	coef[5] = Qy.M[1];
	coef[6] = Qy.M[2];
	coef[7] = Qy.M[3];
	coef[8] = Qz.M[0];
	coef[9] = Qz.M[1];
	coef[10] = Qz.M[2];
	coef[11] =	 Qz.M[3];
}

/*
Draw the cubic curve
*/
void CCubicCurve::Draw()
{
	//create pointers to coefficients
	float *a = coef;
	float *b = coef+4;
	float *c = coef+8;
	
	//initialise loop vars
	float t = 0.0f;
	float t2, t3;
	float t_step = (1.0f)/(float)steps;
	
	//save old color
	glPushAttrib(GL_CURRENT_BIT);
	glColor4fv(color);
	//main loop, curves drawn as triangle strips
	glBegin(GL_LINE_STRIP);
	for (int j = 0; j <= steps; j++)
	{
		t2 = t*t;
		t3 = t2*t;
		
		float x = a[0]*t3 + a[1]*t2 + a[2]*t  + a[3];
		float y = b[0]*t3 + b[1]*t2 + b[2]*t  + b[3];
		float z = c[0]*t3 + c[1]*t2 + c[2]*t + c[3];
		glVertex3f(x,y,z);
		t+=t_step;
	}
	glEnd();
	
	//restore old color
	glPopAttrib();
}
/*
Draw cotrol points
bezier curve: the points are drawn
hermite curve: the tangent vectors are drawn at the starting points
*/
void CCubicCurve::DrawControlPoints()
{
	glPushAttrib(GL_CURRENT_BIT);
	glPointSize(4);
	glColor4fv(color);
	if (type == TM_BEZIER)
	{
		glBegin(GL_POINTS);
		glVertex3f(Gx.M[0], Gy.M[0], Gz.M[0]);
		glVertex3f(Gx.M[1], Gy.M[1], Gz.M[1]);
		glVertex3f(Gx.M[2], Gy.M[2], Gz.M[2]);
		glVertex3f(Gx.M[3], Gy.M[3], Gz.M[3]);
		glEnd();
		
	}
	else if (type == TM_HERMITE)
	{
		glBegin(GL_LINES);
		glVertex3f(Gx.M[0], Gy.M[0], Gz.M[0]);
		glVertex3f(Gx.M[1], Gy.M[1], Gz.M[1]);
		glVertex3f(Gx.M[2], Gy.M[2], Gz.M[2]);
		glVertex3f(Gx.M[3], Gy.M[3], Gz.M[3]);
		glEnd();
	}
	glPopAttrib();
}

Point CCubicCurve::GetPoint(float t)
{
	Point result;
	float *a = coef;
	float *b = coef+4;
	float *c = coef+8;
	
	float t2, t3;
	t2 = t*t;
	t3 = t2*t;
	
	result.x = a[0]*t3 + a[1]*t2 + a[2]*t  + a[3];
	result.y = b[0]*t3 + b[1]*t2 + b[2]*t  + b[3];
	result.z = c[0]*t3 + c[1]*t2 + c[2]*t + c[3];
	return result;
}



void CCubicCurve::SetGeometryMatrixGx(Matrix4x1 a)
{
	Gx = a;
}

void CCubicCurve::SetGeometryMatrixGy(Matrix4x1 a)
{
	Gy = a;
}

void CCubicCurve::SetGeometryMatrixGz(Matrix4x1 a)
{
	Gz = a;
}

void CCubicCurve::RecalculateBezier()
{
	Matrix4x4 mh;
	mh.M[0][0] = -1.0f;
	mh.M[0][1] = 3.0f;
	mh.M[0][2] = -3.0f;
	mh.M[0][3] = 1.0f;
	
	mh.M[1][0] = 3.0f;
	mh.M[1][1] = -6.0f;
	mh.M[1][2] = 3.0f;
	mh.M[1][3] = 0.0f;
	
	mh.M[2][0] = -3.0f;
	mh.M[2][1] = 3.0f;
	mh.M[2][2] = 0.0f;
	mh.M[2][3] = 0.0f;
	
	mh.M[3][0] = 1.0f;
	mh.M[3][1] = 0.0f;
	mh.M[3][2] = 0.0f;
	mh.M[3][3] = 0.0f;
	
	//computer coefficients
	Matrix4x1 Qx = Gx.MultiplyWith4x4(&mh);
	Matrix4x1 Qy = Gy.MultiplyWith4x4(&mh);
	Matrix4x1 Qz = Gz.MultiplyWith4x4(&mh);
	
	//store coefficients
	coef[0] = Qx.M[0];
	coef[1] = Qx.M[1];
	coef[2] = Qx.M[2];
	coef[3] = Qx.M[3];
	coef[4] = Qy.M[0];
	coef[5] = Qy.M[1];
	coef[6] = Qy.M[2];
	coef[7] = Qy.M[3];
	coef[8] = Qz.M[0];
	coef[9] = Qz.M[1];
	coef[10] = Qz.M[2];
	coef[11] =	 Qz.M[3];
}

void CCubicCurve::SetColor(float r, float g, float b, float a)
{
	color[0] = r;
	color[1] = g;
	color[2] = b;
	color[3] = a;
}

CCubicCurve::CCubicCurve() : steps(10), type(TM_NOTHING)
{
	color[0] = color[1] = color[2] = 0.5f;
	color[3] = 0.5f;
}

CCubicCurve::~CCubicCurve()
{
	
}

//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/////////////////// PATCH ////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

CCubicPatch::CCubicPatch() : s_evals(10), curve_evals(10), recompute(true), calc_normals(false)
{  			
}

CCubicPatch::~CCubicPatch()
{
	printf("\nDeallocating memory for patch\n");
	delete[] tris;
	delete[] normals;
}

/* Creates patch, assumes that p is an array of 16 points */
void CCubicPatch::GeneratePatch(Point *p)
{
	printf("\nGenerates patch");
	//one way
	Curve[0].GenerateBezierCoefficients(p[0], p[1], p[2], p[3]);
	Curve[1].GenerateBezierCoefficients(p[4], p[5], p[6], p[7]);
	Curve[2].GenerateBezierCoefficients(p[8], p[9], p[10], p[11]);
	Curve[3].GenerateBezierCoefficients(p[12], p[13], p[14], p[15]);
	
	//the other way round
	Curve[4].GenerateBezierCoefficients(p[0], p[4], p[8], p[12]);
	Curve[5].GenerateBezierCoefficients(p[1], p[5], p[9], p[13]);
	Curve[6].GenerateBezierCoefficients(p[2], p[6], p[10], p[14]);
	Curve[7].GenerateBezierCoefficients(p[3], p[7], p[11], p[15]);
	
	//save points
	for (int i = 0; i < 16; i++)
	{
		ControlPoints[i] = p[i];
	}
}

void CCubicPatch::ChangeEval(int eval, int factor)
{
	if (eval == TM_S_EVALS)
	{
		s_evals += factor;
		if (s_evals < 2)
			s_evals = 2;
		recompute = true;
	} else if (eval == TM_CURVE_EVALS)
	{
		curve_evals += factor;
		if (curve_evals < 2)
			curve_evals = 2;
		recompute = true;		
	}
}

inline void CrossProduct(Point *v, Point *v1, Point *result)
{
	result->x = v->y * v1->z - v1->y * v->z;
	result->y = v->z * v1->x - v1->z * v->x;
	result->z = v->x * v1->y - v1->x * v->y;
	float length = (float)sqrt(result->x*result->x+result->y*result->y+result->z*result->z);
	result->x /= length;
	result->y /= length;
	result->z /= length;
}

void CCubicPatch::ToggleNormals()
{
	calc_normals = !calc_normals;
	recompute = true;
}

void CCubicPatch::Draw()
{
	glPointSize(1);
	
	if (recompute)
	{
		Point* s_points;
		s_points = new Point[s_evals*curve_evals]; ///points from different s values
		Point *dir1 = s_points;
		float step_s = (1.0f)/(float(s_evals-1));
		float step = (1.0f)/((float)(curve_evals-1));
		
		Point p[4];	//storage for control points
		CCubicCurve c;	//curve created in loop
		float s = 0.0f;
		float s_c = 0.0f; //eval for each curve
		for (unsigned int index_s = 0; index_s < s_evals; index_s++, s += step_s)
		{
			c.SetColor(0,1.0f,0,0.5f);
			//get the four points
			p[0] = Curve[4].GetPoint(s);
			p[1] = Curve[5].GetPoint(s);
			p[2] = Curve[6].GetPoint(s);
			p[3] = Curve[7].GetPoint(s);
			c.GenerateBezierCoefficients(p[0], p[1], p[2], p[3]); //generate new curve
			s_c = 0.0f;
			for (unsigned int c1 = 0; c1 < curve_evals; c1++, s_c+=step)
			{
				(*dir1) = c.GetPoint(s_c);
				dir1++;
			}
		}
		
		printf("\nComputes/Recomputes patch triangles");
		unsigned int number_of_triangles = 2*(s_evals-1)*(curve_evals-1);
		
		dir1 = s_points;
		delete[] tris;
		tris = new  Triangle[number_of_triangles];//number of triangles
		
		//create triangles
		int tris_count = 0;
		for (unsigned int j = 0; j < s_evals-1; j++)
		{
			for (unsigned int i = 0; i < curve_evals-1; i++)
			{
				tris[tris_count].verts[0] = dir1[j*curve_evals + i];
				tris[tris_count].verts[1] = dir1[(j+1)*curve_evals + i];
				tris[tris_count].verts[2] = dir1[(j+1)*curve_evals + i+1];
				tris_count++;
				tris[tris_count].verts[2] = dir1[j*curve_evals + i];
				tris[tris_count].verts[1] = dir1[j*curve_evals + i+1];
				tris[tris_count].verts[0] = dir1[(j+1)*curve_evals + i+1];
				tris_count++;
				
			}
		}
					
		if (calc_normals)
		{
			delete[] normals;
			normals = new Point[number_of_triangles];	//allocate space for normals
			
			//calculate normals (one normal for each triangle.
			for (unsigned int index = 0; index < number_of_triangles; index++)
			{
				//create two vectors
				Point v,v1;
				v.x = tris[index].verts[1].x - tris[index].verts[0].x;
				v.y = tris[index].verts[1].y - tris[index].verts[0].y;
				v.z = tris[index].verts[1].z - tris[index].verts[0].z;
				
				v1.x = tris[index].verts[2].x - tris[index].verts[0].x;
				v1.y = tris[index].verts[2].y - tris[index].verts[0].y;
				v1.z = tris[index].verts[2].z - tris[index].verts[0].z;
				
				//calculate and store normal
				CrossProduct(&v, &v1, &normals[index]);
			}
			
		}
		printf("\nNumber of triangles: %d", number_of_triangles);
		delete[] s_points;
		recompute = false;
	}
	
	
	int num_tris = 2*(s_evals-1)*(curve_evals-1);
	//	glEnable(GL_CULL_FACE);
	glBegin(GL_TRIANGLES);
	bool red = true;
	for (int tris_count = 0; tris_count < num_tris; tris_count++)
	{
		if (calc_normals)	//if normals should be specified
			glNormal3f(normals[tris_count].x,normals[tris_count].y,normals[tris_count].z);
		glVertex3f(tris[tris_count].verts[0].x, tris[tris_count].verts[0].y, tris[tris_count].verts[0].z);
		glVertex3f(tris[tris_count].verts[1].x, tris[tris_count].verts[1].y, tris[tris_count].verts[1].z);
		glVertex3f(tris[tris_count].verts[2].x, tris[tris_count].verts[2].y, tris[tris_count].verts[2].z);
	}
	glEnd();
	
	
}
#endif CURVES_CPP__


Соседние файлы в папке bezier
  • #
    01.05.20145.02 Кб25CubicCurves.dsp
  • #
    01.05.2014547 б25CubicCurves.dsw
  • #
    01.05.201441.98 Кб25CubicCurves.ncb
  • #
    01.05.201448.64 Кб26CubicCurves.opt
  • #
    01.05.201414.38 Кб26Curves.cpp
  • #
    01.05.20141.93 Кб25Curves.h
  • #
    01.05.20147.76 Кб25main.cpp
  • #
    01.05.20143.38 Кб25main.dsp
  • #
    01.05.2014533 б25main.dsw
  • #
    01.05.201450.18 Кб25main.ncb