// 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
};