# Shapes

## Problem

• You’re making an app that allows kids to create pictures using rectangles and circles of different sizes and colors.
• A pictures is now stored as a file with one shape per line
• Input format for a rectangle is (unit is pixels)
• color Rectangle height width x y
• Input format for a circle is
• color Circle radius x y
• All shapes should have an ID (in case two shapes are otherwise identical)

### Problem-solving

• It helps tremendously to draw the inheritance hierarchy for this problem and place data members and functions in the hierarchy before try to implement the solution

### Part I

• read in a file of shapes
• create an object for each shape
• print a summary of each shape
• For starters, create the base class and create objects of this class
• Your printed summary should include the color and unique ID. For example, for a rectangle:
• ID#0, Yellow
• For a circle:
• ID#1, Blue

### Part II

• Next create derived classes and create objects of these classes instead of the base class
• To the printed summary, add type and dimensions. For example, for a rectangle:
• Rectangle (25 x 30), ID#0, Yellow
• For a circle:
• Circle (radius 12), ID#1, Blue
• Let the user select a color to change all of the shapes to before they are printed to the console

### Part III

• Finally, add functions to find area and edge length for a shape
• To the printed summary, add area and edge length. For example, for a rectangle:
• Rectangle (25 x 30), ID#0, Yellow – area:750 – edge:110
• For a circle:
• Circle (radius 12), ID#1, Blue – area:452.39 – edge:75.4

#### Scaling

• What if we wanted to also be able to scale an object’s size?
• Let the user scale all objects before printing them to the console

#### Moving

• What if we wanted to include x, y coordinates of the shape’s center in the shape summary?
• What if we wanted to be able to move a shape (positive y meaning up and positive x meaning right)?
• Allow the user to move all shapes’ positions by a certain amount before printing them to the console

## Solution

### Source.cpp

/*
Test case classes (you should provide specific test cases)

Test file should include both Circle and a Rectangle

Test file should include shapes with dimension values of 0

Test file should include shapes of many different colors and sizes

*/

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "Circle.h"
#include "Rectangle.h"
#include "Shape.h"

using namespace std;

void create_objects_from_file(string filename, vector<Shape *> & shapes);

int main()
{
vector<Shape *> shapes;

// 1. READ IN A FILE AND CREATE AN OBJECT FOR EACH SHAPE
cout << "Filename:" << endl;
string filename;
getline(cin, filename);

// static helper function
create_objects_from_file(filename, shapes);

// Let the user select a color to change all of the shapes to before they are printed to the console
string user_fav_color;
cout << "Fav color: ";
getline(cin, user_fav_color);

// 2. PRINT A SUMMARY OF THE SHAPES (to_string() is fine)
for (int i = 0; i < shapes.size(); i++)
{
// All derived classes have access to the base class set_color() function
shapes[i]->set_color(user_fav_color);

// Each derived class implements and executes these differently. HERE IS POLYMORPHISM
cout << shapes[i]->to_string() << endl;
cout << "\tAREA:" << shapes[i]->area() << endl;
cout << "\tEDGE:" << shapes[i]->edge_length() << endl;
}

system("pause");
return 0;
}

/*
Function to load contents of a file and create shape objects depending on file contents
@param filename name of file to load shapes from
@param shapes vector into which to load new shape objects
*/
void create_objects_from_file(string filename, vector<Shape *> & shapes)
{
ifstream in_file;

in_file.open(filename);
// Note: we don't test if the filename is valid or not

string line;
// loop continues as long as another line can be read
while (getline(in_file, line))
{
// cout << "LINE: " << line << endl;
// use an istringstream when trying to read different data types from a string
istringstream strm(line);
string color;
string shape_type;

strm >> color;
strm >> shape_type;

// This is a pointer to the shape we are going to create for the given line
Shape * new_shape = NULL;
if (shape_type == "Rectangle")
{
int width, height;
strm >> width >> height;

// The substitution principle allows us to put an object of a derived class
// where an object of the base class is expected
new_shape = new Rectangle(color, width, height);
}
else if (shape_type == "Circle")
{

// The substitution principle allows us to put an object of a derived class
// where an object of the base class is expected
}
// cout << "shape created with color: " << new_shape->get_color() << endl;

// this is NULL if the shape_type was neither Rectangle nor Circle
if (new_shape != NULL)
{
shapes.push_back(new_shape);
}
}

}

### Shape.h

#include <string>

using namespace std;

#pragma once
class Shape
{
public:
// CONSTRUCTOR
/*
Default constructor for a Shape object
*/
Shape();

// OTHER MEMBER FUNCTIONS
/*
@return color of *this* Shape object
*/
string get_color() const;

/*
@param new_color color to be set as *this* Shape object's color
*/
void set_color(string new_color);

/*
@return the unique id for this Shape
*/
int get_id() const;

/*
Function to compute shape's area. Note that this can't be computed for a generic shape
hence why it is a pure virtual function
@return the area of *this* Shape object
*/
// a Pure Virtual Function must, by definition, be overwritten by any derived class
virtual double area() const = 0;

/*
Function to compute shape's perimeter edge length. Note that this can't be computed for a generic shape
hence why it is a pure virtual function
@returns the perimeter of *this* Shape object
*/
// a Pure Virtual Function must, by definition, be overwritten by any derived class
virtual double edge_length() const = 0;

/*
@return a string representation of *this* Shape object
*/
virtual string to_string() const;

private:
// DATA MEMBERS
string color;
int id;

// static variables exist once for all instances of the class
static int next_id;
};

### Shape.cpp

Note that even though Shape is an abstract class (by virtue of having a pure virtual function), there is still an implementation file.

#include <sstream>
#include "Shape.h"

// initialize our static variable
int Shape::next_id = 0;

Shape::Shape()
{
color = "";
id = next_id; // static variable at work
next_id++;
}

string Shape::get_color() const
{
return color;
}

void Shape::set_color(string new_color)
{
color = new_color;
}

int Shape::get_id() const
{
return id;
}

string Shape::to_string() const
{
// use an ostringstream when creating a string from different data types
ostringstream strm;

strm << "ID# " << id << ", " << color;

return strm.str();
}

### Circle.h

#pragma once
// to BE a Shape, we must know what a Shape is
#include "Shape.h"

// Here is where we define that a Circle IS-A Shape and inherits all of its members and functions
class Circle : public Shape
{
public:
// CONSTRUCTOR
/*
Constructor to construct a new Circle object
@param _color color of new Circle object
*/

// MEMBER FUNCTION
/*
@return a string representation of *this* Circle object
*/
virtual string to_string() const;

/*
@return area of *this* Circle object
*/
virtual double area() const;

/*
@return perimeter edge length of *this* Circle object
*/
virtual double edge_length() const;

private:
// DATA MEMBERS

// Note that this inherits all other data members and member functions that it needs from the base class
};

### Circle.cpp

#include <sstream>
#include "Circle.h"

// Everything after ':' is the initializer list
// The Shape() constructor is called by default but we include it for emphasis
{
set_color(_color);
}

string Circle::to_string() const
{
// use an ostringstream when creating a string from different data types
ostringstream strm;

<< Shape::to_string();

return strm.str();
}

double Circle::area() const
{
}

double Circle::edge_length() const
{
return 2 * 3.14159 * radius;
}

### Rectangle.h

#pragma once
// to BE a Shape, we must know what a Shape is
#include "Shape.h"

// Here is where we define that a Rectangle IS-A Shape and inherits all of its members and functions
class Rectangle : public Shape
{
public:
// CONSTRUCTOR
/*
Constructor to construct a new Rectangle object
@param _color color of new Rectangle object
*/
Rectangle(string _color, int _width, int _height);

// MEMBER FUNCTION
/*
@return a string representation of *this* Rectangle object
*/
virtual string to_string() const;

/*
@return area of *this* Rectangle object
*/
virtual double area() const;

/*
@return perimeter edge length of *this* Rectangle object
*/
virtual double edge_length() const;

private:
int width;
int height;

// Note that this inherits all other data members and member functions that it needs from the base class
};

### Rectangle.cpp

#include <sstream>
#include "Rectangle.h"

Rectangle::Rectangle(string _color, int _width, int _height)
:Shape(), width(_width), height(_height)
// Everything after ':' is the initializer list
// The Shape() constructor is called by default but we include it for emphasis
{
set_color(_color);
}

string Rectangle::to_string() const
{
// use an ostringstream when creating a string from different data types
ostringstream strm;

strm << "Rectangle (" << width << " x " << height << "), "
<< Shape::to_string();

return strm.str();
}

double Rectangle::area() const
{
return width * height;
}

double Rectangle::edge_length() const
{
return 2 * width + 2 * height;
}

### shapes.txt

Here is a possible input file

Red Circle 38 12 22
Blue Circle 18 56 79
Green Rectangle 22 42 190 76
Yellow Circle 78 78 190
Black Circle 1 78 78
Supercalifragilisticexpialidocious this is the only error we test
Grey Circle 3 78 78
Black Circle 5 78 78
Green Rectangle 10 10 100 100
Pink Circle 10 50 50 