Saket Soni


back to rotation
back to home


// ROTLIB.H
//
// Author : Saket Soni
// Requirements : DOS/Windows, Turbo C++ 3.0
//
// Description : 3D - Animation declaration file
//
//

////////////////////////////////////////////////////////////////////////////
// Header files ...
////////////////////////////////////////////////////////////////////////////
// No header files !!!



////////////////////////////////////////////////////////////////////////////
// Global constant declarations ...
////////////////////////////////////////////////////////////////////////////
const float INF = 700;
enum bool	{ false, true };






////////////////////////////////////////////////////////////////////////////
// Global function declarations ...
////////////////////////////////////////////////////////////////////////////
void drawLine(int x1, int y1, int x2, int y2, int color);// to draw a line

void fillSurface(int x, int y, int fillcolor);				// to fill a surface







////////////////////////////////////////////////////////////////////////////
// Class to model vertices of a 3D object ...
////////////////////////////////////////////////////////////////////////////
class CVertex
{
//private:
public:
	float xw;  // world coordinates of the vertice
	float yw;  //
	float zw;  //

public:
	int xd;	// screen coordinates of the vertice
	int yd;	//

private:
	static float scale;	// temp variable required to calculate
								// the screen coordinates

private:
	static float Theta;  // rotation angle

public:
	bool hidden;

public:
	int VertexNo;

public:
	static VertexCount;

private:
	static float xn;     // static temporary storage for
	static float yn;     // calculating new coordinates
	static float zn;     //
	static float stheta; //
	static float ctheta; //
	static float tx, ty;

private:
	// Function to calculate and set the screen coordinates
	void setDisplayCoordinates()	{
		scale = (INF-yw) / INF;
		tx = xw * scale;
		ty = zw * scale;
		xd = tx;				// for rounding
		yd = ty;
		if ( (tx-xd) >= 0.5 ) xd = xd + 0.5;
		if ( (ty-yd) >= 0.5 ) yd = yd + 0.5;
	}

public:
	// Constructor ...
	CVertex(float vx=0, float vy=0, float vz=0):
		xw(vx),yw(vy),zw(vz),hidden(false)
	{	setDisplayCoordinates(); VertexNo = VertexCount++;	}
	// Function to set new values ...
	void set(float vx=0, float vy=0, float vz=0)
	{	xw = vx;	yw = vy;	zw = vz;	hidden = false; setDisplayCoordinates();	}
	// rotate along x axis by angle theta ...
	void rotate_x()	{		// from y to z
		yn = yw*ctheta - zw*stheta;
		zn = zw*ctheta + yw*stheta;
		yw = yn;	zw = zn;
		setDisplayCoordinates();
	}
	// rotate along y axis by angle theta ...
	void rotate_y()	{		// from x to z
		xn = xw*ctheta - zw*stheta;
		zn = xw*stheta + zw*ctheta;
		xw = xn;	zw = zn;
		setDisplayCoordinates();
	}
	// rotate along z axis by angle theta ...
	void rotate_z()	{		// from x to y
		xn = xw*ctheta - yw*stheta;
		yn = xw*stheta + yw*ctheta;
		xw = xn;	yw = yn;
		setDisplayCoordinates();
	}
	// set rotation angle (in radians) ...
	static void set_theta(float theta=0.02)	{
		Theta = theta;
		stheta = sin(theta);
		ctheta = cos(theta);
	}
	// function to get current rotation angle (in radians)...
	static float getrotangle()	{	return Theta;	}
};







////////////////////////////////////////////////////////////////////////////
// Class to model edges of a 3D object ...
////////////////////////////////////////////////////////////////////////////
class CEdge
{
public:
	CVertex *ver1;  // an edge consists of two vertices
	CVertex *ver2;  //

public:
	bool drawn;

public:
	int color;

public:
	int EdgeNo;

public:
	static int EdgeCount;

public:
	// Default Constructor ...
	CEdge():ver1(0),ver2(0),drawn(false),color(YELLOW)
	{	EdgeNo = EdgeCount++;	}
	// Constructor with vertices as arguments ...
	CEdge(CVertex &v1, CVertex &v2,int clr=YELLOW):
		ver1(&v1),ver2(&v2),drawn(false),color(clr)
	{	EdgeNo = EdgeCount++;	}
	// Function to set the edges explicitly ...
	void set(CVertex &v1, CVertex &v2)
	{	ver1 = &v1;	ver2 = &v2; drawn = false;	}
	// Function to draw the edge ...
	void draw()	{
		if ( drawn != true )	{
			drawn = true;
				drawLine(ver1->xd,ver1->yd,ver2->xd,ver2->yd,color);
		}
	}
	void hide()	{
		if ( drawn == true ) {
			drawn = false;
				drawLine(ver1->xd,ver1->yd,ver2->xd,ver2->yd,BLACK);
		}
	}

};








////////////////////////////////////////////////////////////////////////////
// Class to model rectangular surfaces of a 3D object ...
////////////////////////////////////////////////////////////////////////////
class CSurface
{
public:
	CEdge *edge1;
	CEdge *edge2;
	CEdge *edge3;
	CEdge *edge4;

public:
	CVertex *p1;
	CVertex *p2;
	CVertex *p3;
	CVertex *p4;

public:
	bool hidden;

public:
	int fillcolor;

public:
	int SurfaceNo;

public:
	static int SurfaceCount;

public:
	// Constructors ...
	CSurface():edge1(0),edge2(0),edge3(0),edge4(0),
		p1(0),p2(0),p3(0),p4(0),hidden(false),fillcolor(LIGHTRED)
	{	SurfaceNo = SurfaceCount++;	}
	CSurface(CEdge *e1, CEdge *e2, CEdge *e3, CEdge *e4,
		int clr=YELLOW, int fillclr=MAGENTA):
		edge1(e1),edge2(e2),edge3(e3),edge4(e4),hidden(false),
		fillcolor(fillclr)
	{	findVertices();	SurfaceNo = SurfaceCount++;	}
public:
	bool isVertex(CVertex *p)	// checks if p is the vertex of the surface
	{
		if ( (p1==p) || (p2==p) || (p3==p) || (p4==p) )
			return true;
		else
			return false;
	}
	bool isFarther(CVertex *p)	// checks if p is farther away than the surface
	{
		if (	(p->yw > p1->yw) || (p->yw > p2->yw) ||
				(p->yw > p3->yw) || (p->yw > p4->yw) )
			return true;
		else
			return false;
	}

private:
	// function to find the vertices when edges are given ...
	void findVertices()
	{
		if ( edge1->ver1 == edge2->ver1 )	{
			p1 = edge1->ver2;	p2 = edge1->ver1;	p3 = edge2->ver2;
		}
		else if ( edge1->ver1 == edge2->ver2 )		{
			p1 = edge1->ver2;	p2 = edge1->ver1;	p3 = edge2->ver1;
		}
		else if ( edge1->ver2 == edge2->ver1 )		{
			p1 = edge1->ver1;	p2 = edge1->ver2;	p3 = edge2->ver2;
		}
		else /*if ( edge1->ver2 == edge2->ver2 )*/	{
			p1 = edge1->ver1;	p2 = edge1->ver2;	p3 = edge2->ver1;
		}
		if ( p3 == edge3->ver1 )	p4 = edge3->ver2;
		else								p4 = edge3->ver1;
	}

public:
	// Function to set the edges ...
	void set(CEdge &e1, CEdge &e2, CEdge &e3, CEdge &e4)
	{	edge1 = &e1; edge2 = &e2; edge3 = &e3; edge4 = &e4; hidden = false;
		findVertices();
	}

private:
	static float xt,yt;

public:
	// Function to draw the surface ...
	void draw()
	{
		if ( hidden != true )	// if a surface is not hidden then only
		{								// it can be drawn
			edge1->draw(); edge2->draw(); edge3->draw(); edge4->draw();
			xt = (p1->xd+p3->xd)/2.0;
			yt = (p1->yd+p3->yd)/2.0;
			fillSurface(xt,yt,fillcolor);
		}
	}
	void hide()
	{
		if ( hidden != true )	// if a surface is not already hidden
		{								// then hide it
			xt = (p1->xd+p3->xd)/2.0;
			yt = (p1->yd+p3->yd)/2.0;
			fillSurface(xt,yt,BLACK);
			edge1->hide(); edge2->hide(); edge3->hide(); edge4->hide();
		}
	}

private:
	static int f1, f2, f3, f4;
	void findF(int x, int y)
	{
		f1 = f2 = f3 = f4 = 0;
		if ( p1->xd < x )			f1 += 0x80;		// left
		else if ( p1->xd > x )	f1 += 0x20;		// right
		if ( p1->yd < y )			f1 += 0x02;		// down
		else if ( p1->yd > y )	f1 += 0x08;		// up
		if ( p2->xd < x )			f2 += 0x80;		// left
		else if ( p2->xd > x )	f2 += 0x20;		// right
		if ( p2->yd < y )			f2 += 0x02;		// down
		else if ( p2->yd > y )	f2 += 0x08;		// up
		if ( p3->xd < x )			f3 += 0x80;		// left
		else if ( p3->xd > x )	f3 += 0x20;		// right
		if ( p3->yd < y )			f3 += 0x02;		// down
		else if ( p3->yd > y )	f3 += 0x08;		// up
		if ( p4->xd < x )			f4 += 0x80;		// left
		else if ( p4->xd > x )	f4 += 0x20;		// right
		if ( p4->yd < y )			f4 += 0x02;		// down
		else if ( p4->yd > y )	f4 += 0x08;		// up
	}
private:
	static float m, c, d1, d2;
	// sp is one of the vertices of the surface and p is the point
	// to be checked!!
	bool checkLineSide(CVertex *lp1, CVertex *lp2, CVertex *sp, CVertex *p)
	{
		if ( lp1->xd==lp2->xd )
		{
			if ( lp1->yd==lp2->yd )
			{
				return true;
			}
			else		// lp1->y != lp2->y
			{
				d1 = lp1->xd - sp->xd;
				d2 = lp1->xd - p->xd;
				if ( (d1 >= 0.5 && d2 >= 0.5) || (d1 < -0.5 && d2 < -0.5) )
					return true;
				else if ( abs(d1-d2) < 0.5 )	// if d1 == d2 == 0
					return true;
				else if ( abs(d2) < 0.5 )		// ie p lies on the line lp1-lp2.
					return true;
				else
					return false;
			}
		}
		else  // lp1->x != lp2->x
		{
			m = (float(lp2->yd-lp1->yd))/(lp2->xd-lp1->xd);
			c = lp2->yd - m*lp2->xd;
			d1 = sp->yd - (m*sp->xd + c);
			d2 = p->yd  - (m*p->xd  + c);
			if ( (d1 > 0.5 && d2 > 0.5) || (d1 < -0.5 && d2 < -0.5 ) )
				return true;
			else if ( abs(d1-d2) < 0.5 )	// if d1 == d2 == 0
				return true;
			else if ( abs(d2) < 0.5 )		// if p lies on the line lp1-lp2.
				return true;
			else
				return false;
		}
	}
	bool checkCase154(CVertex *p1, CVertex *p2, CVertex *p3, CVertex *p4,
							 CVertex *p)
	{													// for the 2 cases of 0x154
		if (	checkLineSide(p1,p2,p3,p) &&	// when p1 & p2 lie in one screen
				checkLineSide(p3,p4,p2,p) )	// part and p3 & p4 lie in the
			return true;							// diagonally opposite screen part
		else
			return false;
	}
	bool checkInside2(CVertex *p)
	{
		if (	checkLineSide(p1,p2,p3,p) &&
				checkLineSide(p3,p4,p2,p) &&
				checkLineSide(p2,p3,p1,p) &&
				checkLineSide(p1,p4,p2,p) )
			return true;
		else
			return false;
	}

public:
	bool checkInside(CVertex *p)
	{
		int fs;
		findF(p->xd,p->yd);

		fs = f1+f2+f3+f4;
		if ( !(f1&&f2&&f3&&f4) )	// if atleast one lie on the p itself
			return true;
		if ( fs == (f1<<2) )			// for 0x220, 0x208, 0x088, 0x0a0
			return false;
		else if ( fs==0x21a || fs==0x1c0 || fs==0x1a8 || fs==0x20e ||
					 fs==0x08e || fs==0x0e8 || fs==0x100 || fs==0x09a ||
					 fs==0x214 || fs==0x160 || fs==0x148 || fs==0x094 )
			return false;
		else if ( fs==0x154 )
		{
			if ( f1!=f2 && f1!=f4 )	// i.e. each vertex in difrnt screen part
				return true;
			else
			{
				if ( f1!=f2 )
					return checkCase154(p1,p2,p3,p4,p);
				else
					return checkCase154(p1,p4,p3,p2,p);
			}
		}
		return checkInside2(p);
	}

};







////////////////////////////////////////////////////////////////////////////
// Sample Class to model a 3D box ...
////////////////////////////////////////////////////////////////////////////
class CBox
{
protected:
	CVertex verArr[8];  // a box has 8 vertices
	CEdge EdgArr[12];   // a box has 12 edges

public:
	// Class constructor ...
	// this constructor creates a box with the specifications given
	// and the edges of the box are aligned along the 3 axis.
	CBox(float lbx=10, float lby=10, float lbz=10,
		 float width=100, float height=100, float depth=100)
	{
		float xt=lbx+width, yt=lby+depth, zt=lbz+height;

		verArr[0].set(lbx,lby,lbz);	// set the vertices of the 3D box
		verArr[1].set(xt,lby,lbz);		//
		verArr[2].set(xt,lby,zt);		//
		verArr[3].set(lbx,lby,zt);		//
		verArr[4].set(lbx,yt,lbz);		//
		verArr[5].set(xt,yt,lbz);		//
		verArr[6].set(xt,yt,zt);		//
		verArr[7].set(lbx,yt,zt);		//

		EdgArr[0].set(verArr[0],verArr[1]);	// connect the edges of the
		EdgArr[1].set(verArr[1],verArr[2]);	// 3D box
		EdgArr[2].set(verArr[2],verArr[3]);	//
		EdgArr[3].set(verArr[3],verArr[0]);	//
		EdgArr[4].set(verArr[4],verArr[5]);	//
		EdgArr[5].set(verArr[5],verArr[6]);	//
		EdgArr[6].set(verArr[6],verArr[7]);	//
		EdgArr[7].set(verArr[7],verArr[4]);	//
		EdgArr[8].set(verArr[1],verArr[5]);	//
		EdgArr[9].set(verArr[2],verArr[6]);	//
		EdgArr[10].set(verArr[3],verArr[7]);//
		EdgArr[11].set(verArr[0],verArr[4]);//
	}
private:
	static int k;

public:
	void rotate_x();						// to rotate along x axis by theta
	void rotate_y();						// to rotate along y axi by theta
	void rotate_z();						// to rotate along z axis by theta
	void draw();							// to draw the cube
	void hide();							// to hide the cube
};















////////////////////////////////////////////////////////////////////////////
// Sample Class to model a 3D box using CSurface objects ...
////////////////////////////////////////////////////////////////////////////
class CBoxS:public CBox
{
protected:
	CSurface surfArr[6];// a box has 6 surface

public:
	// Class constructor ...
	// this constructor creates a box with the specifications given
	// and the edges of the box are aligned along the 3 axis.
	CBoxS(float lbx=30, float lby=30, float lbz=30,
		 float width=100, float height=100, float depth=100):
		 CBox(lbx,lby,lbz,width,height,depth)
	{
		surfArr[0].set(EdgArr[0],EdgArr[1],EdgArr[2],EdgArr[3]);
		surfArr[1].set(EdgArr[4],EdgArr[5],EdgArr[6],EdgArr[7]);
		surfArr[2].set(EdgArr[2],EdgArr[9],EdgArr[6],EdgArr[10]);
		surfArr[3].set(EdgArr[0],EdgArr[8],EdgArr[4],EdgArr[11]);
		surfArr[4].set(EdgArr[1],EdgArr[8],EdgArr[5],EdgArr[9]);
		surfArr[5].set(EdgArr[3],EdgArr[11],EdgArr[7],EdgArr[10]);
		surfArr[0].fillcolor = LIGHTRED;
		surfArr[1].fillcolor = LIGHTMAGENTA;
		surfArr[2].fillcolor = LIGHTCYAN;
		surfArr[3].fillcolor = LIGHTGREEN;
		surfArr[4].fillcolor = LIGHTBLUE;
		surfArr[5].fillcolor = BLUE;
	}
	void draw();			// to draw the box
	void hide();			// to hide the box

private:
	static int i, j;
	void FindHiddenPoints();	// to find the hidden points
	void FindHiddenSurfaces();	// to find the hidden surfaces

};



back to rotation
back to home

Locations of visitors to this page 1