Question: #include application.h #include int main() { Application app; app.init(); while(app.getState() == Application::STATE_RUNNING) { app.draw(); app.setUserInput(_getch()); app.update(); } app.release(); return 0; } // INSTRUCTIONS // ------------

#include "application.h"

#include

int main()

{

Application app;

app.init();

while(app.getState() == Application::STATE_RUNNING)

{

app.draw();

app.setUserInput(_getch());

app.update();

}

app.release();

return 0;

}

// INSTRUCTIONS

// ------------

// Compile this code. After pressing any key to clear the instructions, You

// should see three rectangles labeled '#', 'b', and 'c'. You should also see

// two triangles, labeled 'd' and 'e'. Pressing '>' and '<' will change which

// shape is labeled '#'. Pressing 'w', 'a', 's', and 'd' will move the shape

// labeled '#'. Pressing 'space' will randomize the selected shape.

//

// Read through this code! Try to understand it before starting the assignment.

// Comment confusing lines with what you think code is doing, and experiment

// with existing code to test your understanding.

// Once you feel comfortable with this code, accomplish each of the following,

// and make sure your code compiles and runs after each step is completed.

//

// 1. Getting comfortable with the code

// a) Create a "makeRandom" method in both the Rect and Tri classes, based

// on the "makeRandomRect" and "makeRandomTri" functions in

// "application.cpp". The makeRandom function should take no parameters,

// and instead make itself random. Removing the old "makeRandomRect"

// and "makeRandomTri" functions as well. Be sure to consider what to do

// about "screenMin" and "screenMax".

// b) Create a print method for the Tri class, similar to the print method

// for the Rect class. This method may come in very handy when debugging.

// 2. Create Shape base class

// a) Create a header file (without a .cpp file) for a Shape class.

// b) Create the Shape class, which should have no member variables.

// c) Make the Shape class an interface for the Rect and Tri classes. Shape

// should have pure-virtual methods for each method that Rect and Tri have

// in common.

// d) Make sure Shape has a virtual destructor with an empty body.

// 3. Make Rect and Triangle extend Shape

// 4. Change selected

// a) Change the type of "Application::selected" from "void *" to "Shape *".

// b) Every piece of code that typecasts "selected" (and the logic around it)

// can be removed now. Simply call functions using the "Shape" interface.

// c) Remove the "selectedType" variable from Application. Logic that needs

// some form of RunTime Type Information should use dynamic_cast instead.

// 5. Merge all Shape objects into a single array

// a) Create an array of Shape pointers in the Application called "shapes".

// b) Making a complementary NUM_SHAPES variable would make sense.

// b) Remove "rectangles" and "triangles" arrays.

// c) Put each Tri and Rect object managed by the Application class into

// the "shapes" array. This will require re-factoring in multiple files.

// While removing references to "rectangles" and "triangles" arrays, it

// may make sense to replace pairs of for-loops using each of the old

// arrays with a single for-loop using just "shapes".

// 6. Make "shapes" dynamic

// a) Give Application::init() 2 parameters: int numRect, int numTri

// b) Make "shapes" a pointer of type "Shape **", and allocate it to be

// "numShapes" big, where "numShapes" is an int member of Application

// equal to (numRect + numTri), defined in Application::init().

// c) When calling "app.init()" in main, pass valid arguments for numRect

// and numTri.

// d) De-allocate the "shapes" array in Application::Release().

// 7. Clean up old variables

// a) Remove the TYPE_RECT and TYPE_TRI variables from Application.

// b) Remove NUM_TRI and NUM_RECT, and any NUM_SHAPES variable as well. Use

// numShapes where needed.

// 8. Add Circle class

// a) Create a header file AND a source file for a Circle class.

// b) Use Rect and Tri as examples to create the Circle class with.

// c) A Circle class should have at least a 2 dimensional position, and a

// radius.

// d) A simple algorithm for drawing a Circle will be similar to drawing a

// Rect or Tri, thought it might include the following code:

// float dx = center.x - col, dy = center.y - row;

// if( dx*dx + dy*dy <= radius * radius ) {

// moveCursor(col, row);

// putchar(letter);

// }

// e) Add an additional parameter to Application::init(), "int numCircles".

// Implement init to generate Circle objects along with Rect and Tri

// objects.

// 9. Implement add/remove for the shapes array

// a) Add code that increases the size of the shapes array, adding a random

// shape, whenever the '=' or '+' key is pressed. Take a look at the week

// 5 lecture showing explicit constructors for help with this algorithm.

// a) Add code that decreases the size of the shapes array, removing the last

// shape, whenever the '-' or '_' key is pressed. End the program when the

// last shape is removed. Removing a shape, like adding a shape, can be

// done by allocating an array of a different size (smaller this time).

consoleutil.cpp

#include // SetConsoleCursorPosition(HANDLE,COORD)

#include "consoleutil.h"

/**

* moves the console cursor to the given x/y coordinate

* @param x

* @param y

*/

void moveCursor(int x, int y)

{

COORD c = {x,y};

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);

}

consoleutil.h

#pragma once

/** * moves the console cursor to the given x/y coordinate * @param x * @param y */ void moveCursor(int x, int y);

#define SCREEN_WIDTH 80 #define SCREEN_HEIGHT 24

application.cpp

#include "application.h"

#include

using namespace std;

#include "consoleutil.h"

#include

Vector2 screenMin(0,0), screenMax(SCREEN_WIDTH-1,SCREEN_HEIGHT-1);

void clearScreen()

{

Rect screen(screenMin, screenMax);

screen.draw(' ');

}

void makeRandomTri(Tri & t)

{

t.a = Vector2::random(screenMin, screenMax);

t.b = Vector2::random(screenMin, screenMax);

t.c = Vector2::random(screenMin, screenMax);

}

void makeRandomRect(Rect * r)

{

Vector2 randomv = Vector2::random(screenMin, screenMax);

r->min = randomv;

r->max = randomv;

randomv = Vector2::random(screenMin, screenMax);

r->add(randomv);

}

void Application::init()

{

for(int i = 0; i < NUM_RECT; ++i)

{

rectangles[i] = new Rect;

makeRandomRect(rectangles[i]);

}

for(int i = 0; i < NUM_TRI; ++i)

{

triangles[i] = new Tri;

makeRandomTri(*triangles[i]);

}

selectedIndex = 0;

selected = rectangles[0];

selectedType = Application::TYPE_RECT;

state = Application::STATE_RUNNING;

cout << "'<' and '>' to select shapes" << endl

<< "'w', 'a', 's', 'd' to move the selected shape" << endl

<< "'space' to randomize current shape" << endl

<< endl << "press any key to begin the program" << endl;

_getch();

clearScreen();

}

void Application::release()

{

for(int i = 0; i < NUM_RECT; ++i)

{

delete rectangles[i];

}

for(int i = 0; i < NUM_TRI; ++i)

{

delete triangles[i];

}

}

void Application::draw()

{

// draw all shapes

for(int i = 0; i < NUM_RECT; ++i)

{

rectangles[i]->draw('a'+i);

}

for(int i = 0; i < NUM_TRI; ++i)

{

triangles[i]->draw(NUM_RECT+'a'+i);

}

// draw the selected shape

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->draw('#');

break;

case TYPE_TRI:

((Tri*)selected)->draw('#');

break;

}

// draw extra info at the bottom

moveCursor(0, 0);

cout << "shape[" << selectedIndex << "], a ";

const char * shapeName;

if(selectedType == TYPE_RECT)

{

shapeName = "rectangle ";

}

else

{

shapeName = "triangle ";

}

cout << shapeName << endl;

}

void Application::setUserInput(int input)

{

userKeyPress = input;

}

void Application::update()

{

bool changedSelection = false;

bool shapeMoving = false;

switch(userKeyPress)

{

case 27:

state = Application::STATE_QUIT;

break;

case ',':

case '<':

selectedIndex--;

changedSelection = true;

break;

case '.':

case '>':

selectedIndex++;

changedSelection = true;

break;

case 'w':

case 'a':

case 's':

case 'd':

case ' ':

shapeMoving = true;

break;

}

if(shapeMoving)

{

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->draw(' ');

break;

case TYPE_TRI:

((Tri*)selected)->draw(' ');

break;

}

switch(userKeyPress)

{

case 'w':

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->translate(Vector2(0,-1));

break;

case TYPE_TRI:

((Tri*)selected)->translate(Vector2(0,-1));

break;

}

break;

case 'a':

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->translate(Vector2(-1,0));

break;

case TYPE_TRI:

((Tri*)selected)->translate(Vector2(-1,0));

break;

}

break;

case 's':

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->translate(Vector2(0,+1));

break;

case TYPE_TRI:

((Tri*)selected)->translate(Vector2(0,+1));

break;

}

break;

case 'd':

switch(selectedType)

{

case TYPE_RECT:

((Rect*)selected)->translate(Vector2(+1,0));

break;

case TYPE_TRI:

((Tri*)selected)->translate(Vector2(+1,0));

break;

}

break;

case ' ':

switch(selectedType)

{

case TYPE_RECT:

makeRandomRect( (Rect*)selected );

break;

case TYPE_TRI:

makeRandomTri( *((Tri*)selected) );

break;

}

break;

}

}

userKeyPress = 0;

if(changedSelection)

{

int TOTAL_NUMBER_OF_SHAPES = NUM_RECT + NUM_TRI;

if(selectedIndex < 0)

{

selectedIndex = TOTAL_NUMBER_OF_SHAPES-1;

}

else if (selectedIndex >= TOTAL_NUMBER_OF_SHAPES)

{

selectedIndex = 0;

}

if(selectedIndex >= 0 && selectedIndex < NUM_RECT)

{

selectedType = TYPE_RECT;

selected = rectangles[selectedIndex];

}

else if(selectedIndex >= NUM_RECT && selectedIndex < NUM_RECT+NUM_TRI)

{

selectedType = TYPE_TRI;

selected = triangles[selectedIndex - NUM_RECT];

}

if(selectedIndex < 0 || selectedIndex >= TOTAL_NUMBER_OF_SHAPES)

{

selected = 0;

selectedType = -1;

}

}

}

application.h

#pragma once

#include "rect.h"

#include "tri.h"

class Application

{

private:

int state;

int userKeyPress;

/** what shape is selected */

int selectedIndex;

/** address to the selected object */

void * selected;

/** type of the selected object */

int selectedType;

/** which type the "selected" pointer could be pointed at */

static const int TYPE_RECT = 1, TYPE_TRI = 2;

int numShapes;

public:

static const int NUM_RECT = 3, NUM_TRI = 2;

Rect * rectangles[NUM_RECT];

Tri * triangles[NUM_TRI];

static const int

STATE_INIT = 0, // an application not yet fully initialized

STATE_RUNNING = 1, // running

STATE_QUIT = 2; // user requested quit

/** @return Application::STATE_* */

int getState(){ return state; }

Application():state(STATE_INIT){}

void init();

void release();

void draw();

void setUserInput(int input);

void update();

};

rect.cpp

#include "consoleutil.h"

#include "rect.h"

#include

void Rect::print()

{

printf("[(%f, %f), (%f, %f)]", min.x, min.y, max.x, max.y);

}

void Rect::draw(char letter)

{

Vector2 i;

for(i.y = (float)((int)min.y); i.y < max.y; ++i.y)

{

for(i.x = (float)((int)min.x); i.x < max.x; ++i.x)

{

// only print in a standard console window

if(i.isWithin(0, 0, 80, 24))

{

moveCursor((int)i.x, (int)i.y);

putchar(letter);

}

}

}

}

void Rect::translate(Vector2 delta)

{

min += delta;

max += delta;

}

float Rect::getArea()

{

return getWidth() * getHeight();

}

/** @param v if the argument is out of the Rect, the Rect will extend */

void Rect::add(Vector2 v)

{

if(v.x < min.x) { min.x = v.x; }

if(v.y < min.y) { min.y = v.y; }

if(v.x > max.x) { max.x = v.x; }

if(v.y > max.y) { max.y = v.y; }

}

rect.h

#pragma once

#include "vector2.h"

class Rect

{

public:

Vector2 min, max;

Rect(){}

Rect(Vector2 min, Vector2 max):min(min),max(max){}

float getWidth(){return max.x-min.x;}

float getHeight(){return max.x-min.x;}

Vector2 getCenter(){ return (min+max)/2; }

void draw(char letter);

void translate(Vector2 delta);

float getArea();

void print();

/** @param v if the argument is out of the Rect, the Rect will extend */

void add(Vector2 v);

};

tri.cpp

#include "tri.h"

#include "consoleutil.h"

#include

float Tri::getWidth() {return (b-a).magnitude();}

float Tri::getHeight() {

// calculate base line, which is a->b

Vector2 baseSlope = b - a;

// create perpendicular slope, which goes along the height

Vector2 perpSlope = baseSlope;

perpSlope.x = -baseSlope.y;

perpSlope.y = baseSlope.x;

// get distance of point C from the base

Vector2 basePoint;

float dist;

Vector2::lineIntersection(a, b, c, c+perpSlope, dist, basePoint);

if(dist < 0) {

dist *= -1;

}

return dist;

}

#include "rect.h"

void Tri::draw(char letter) {

Rect area;

area.add(a);

area.add(b);

area.add(c);

Vector2 i;

for(i.y = (float)((int)area.min.y); i.y < area.max.y; ++i.y) {

for(i.x = (float)((int)area.min.x); i.x < area.max.x; ++i.x) {

if(i.isWithin(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)

&& i.isInsideTriangle(a, b, c)) {

moveCursor((int)i.x, (int)i.y);

putchar(letter);

}

}

}

}

void Tri::translate(Vector2 delta) {

a += delta;

b += delta;

c += delta;

}

float Tri::getArea() {

return (getWidth() * getHeight() ) / 2;

}

tri.h

#pragma once

#include "vector2.h"

class Tri

{

public:

Vector2 a, b, c;

Tri(){}

Tri(Vector2 a, Vector2 b, Vector2 c):a(a),b(b),c(c){}

float getWidth();

float getHeight();

/** @return average location (TODO replace with "triangle centroid") */

Vector2 getCenter(){ return (a+b+c)/3; }

void draw(char letter);

void translate(Vector2 delta);

float getArea();

};

vector2.cpp

#include "vector2.h"

#include

/** @return true if the given x, y coordinate mathes this Vector2's data */

bool Vector2::is(float x, float y) const

{

return this->x == x && this->y == y;

}

/** @return true if the given x, y coordinate mathes this Vector2's data */

bool Vector2::is(Vector2 xy) const

{

return xy.x == x && xy.y == y;

}

/** @return true if the Vector2 is within the given rectangular boundary */

bool Vector2::isWithin(float minx, float miny, float maxx, float maxy)

{

return x >= minx && y >= miny && x < maxx && y < maxy;

}

/** re-initialize */

void Vector2::init(float a_x, float a_y)

{

x = a_x;

y = a_y;

}

/** @return pythagorean distance from the origin */

float Vector2::magnitude()

{

return std::sqrt(x*x+y*y);

}

Vector2 Vector2::operator+(Vector2 const & v) const { return Vector2(x+v.x, y+v.y); }

Vector2 Vector2::operator-(Vector2 const & v) const { return Vector2(x-v.x, y-v.y); }

Vector2 Vector2::operator*(float value) const { return Vector2(x*value, y*value); }

Vector2 Vector2::operator/(float value) const { return Vector2(x/value, y/value); }

Vector2 & Vector2::operator+=(Vector2& v) { x += v.x; y += v.y; return *this; }

Vector2 & Vector2::operator-=(Vector2& v) { x -= v.x; y -= v.y; return *this; }

Vector2 & Vector2::operator*=(float value) { x *= value; y *= value; return *this; }

Vector2 & Vector2::operator/=(float value) { x /= value; y /= value; return *this; }

#include "stdlib.h"

float randInUnitInterval()

{

const int RANDMAX = 32768;

return (rand() % RANDMAX)/((float)RANDMAX);

}

/** @return a random Vector2 within the specified boundary */

Vector2 Vector2::random(Vector2 min, Vector2 max)

{

float w = max.x-min.x, h = max.y-min.y;

return Vector2(

randInUnitInterval() * w + min.x,

randInUnitInterval() * h + min.y);

}

/**

* @param A,B line 1

* @param C,D line 2

* @param point __OUT to the intersection of line AB and CD

* @param dist __OUT the distance along line AB to the intersection

* @return true if intersection occurs between the lines

*/

bool Vector2::lineIntersection(const Vector2 & A, const Vector2 & B,

const Vector2 & C, const Vector2 & D,

float & dist, Vector2 & point)

{

float rTop = (A.y-C.y)*(D.x-C.x)-(A.x-C.x)*(D.y-C.y);

float rBot = (B.x-A.x)*(D.y-C.y)-(B.y-A.y)*(D.x-C.x);

float sTop = (A.y-C.y)*(B.x-A.x)-(A.x-C.x)*(B.y-A.y);

float sBot = (B.x-A.x)*(D.y-C.y)-(B.y-A.y)*(D.x-C.x);

if ( (rBot == 0) || (sBot == 0))

{

//lines are parallel

return false;

}

float r = rTop/rBot;

float s = sTop/sBot;

Vector2 delta = B - A;

dist = delta.magnitude() * r;

point = A + ( delta * r);

return ( (r > 0) && (r < 1) && (s > 0) && (s < 1) );

}

/**

* @return positive if v2 is clockwise of this vector

* (assume Y points down, X to right)

*/

float Vector2::sign(const Vector2 & v) const

{

return (x*v.y) - (y*v.x);

}

/** @return true if this point is inside the given triangle */

bool Vector2::isInsideTriangle(Vector2 const & a, Vector2 const & b,

Vector2 const & c) const

{

float signab = (*this-a).sign(b-a),

signbc = (*this-b).sign(c-b),

signac = (*this-c).sign(a-c);

return(((signab>=0) == (signbc>=0)) && ((signbc>=0) == (signac>=0)))

||(((signab<=0) == (signbc<=0)) && ((signbc<=0) == (signac<=0)));

}

vector2.h

#pragma once

/**

* Object Oriented implementation of a 2 dimensional (math) vector

*/

struct Vector2

{

/** the x, y coordinates */

float x, y;

/** initializes the Vector2 */

Vector2(float x, float y)

{

this->x = x;

this->y = y;

}

/** default constructor - sets x,y to 0,0 */

Vector2()

{

x = 0;

y = 0;

}

/** @return true if the given x, y coordinate mathes this Vector2's data */

bool is(float x, float y) const;

/** @return true if the given x, y coordinate mathes this Vector2's data */

bool is(Vector2 xy) const ;

/** @return true if the Vector2 is within the given rectangular boundary */

bool isWithin(float minx, float miny, float maxx, float maxy);

/** re-initialize */

void init(float x, float y);

/** @return a random Vector2 within the specified boundary */

static Vector2 random(Vector2 min, Vector2 max);

/** @return pythagorean distance from the origin */

float magnitude();

Vector2 operator+(Vector2 const & v) const;

Vector2 operator-(Vector2 const & v) const;

Vector2 operator*(float value) const;

Vector2 operator/(float value) const;

Vector2 & operator+=(Vector2& v);

Vector2 & operator-=(Vector2& v);

Vector2 & operator*=(float value);

Vector2 & operator/=(float value);

/**

* @param A,B line 1

* @param C,D line 2

* @param point __OUT to the intersection of line AB and CD

* @param dist __OUT the distance along line AB to the intersection

* @return true if intersection occurs between the lines

*/

static bool lineIntersection(const Vector2 & A, const Vector2 & B,

const Vector2 & C, const Vector2 & D,

float & dist, Vector2 & point);

/**

* @return positive if v2 is clockwise of this vector

* (assume Y points down, X to right)

*/

float sign(const Vector2 & v) const;

/** @return true if this point is inside the given triangle */

bool isInsideTriangle(Vector2 const & a, Vector2 const & b,

Vector2 const & c) const;

};

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Databases Questions!