renaming labs

This commit is contained in:
Jidong Xiao
2025-01-07 17:20:18 -05:00
parent b6b2f01b8a
commit a1ec479522
20 changed files with 1365 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
7 Polygon(s): blue brown grey olive orange purple red
3 Triangle(s): brown purple red
2 IsoscelesTriangle(s): purple red
1 EquilateralTriangle(s): red
3 Quadrilateral(s): blue olive orange
2 Rectangle(s): blue orange
1 Square(s): blue
3 Shape(s) with all equal sides: blue grey red

View File

@@ -0,0 +1,7 @@
blue (0,0) (0,1) (1,1) (1,0)
brown (2,0) (0,1) (3,3)
grey (1,0) (1.5,0.866) (1,1.732) (2,1.732) (2.5,0.866) (2,0)
olive (0,0) (1,2) (6,3) (4,0)
orange (0,0) (0,3) (2,3) (2,0)
purple (0,0) (0,2) (3,1)
red (0,0) (0.5,0.866) (1,0)

View File

@@ -0,0 +1,168 @@
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include "polygons.h"
// helper function prototypes
Polygon* CreatePolygon(const std::string &name, const std::vector<Point> &points);
void OutputStats(const std::vector<Polygon*> &polygons, std::ofstream &ostr);
// ------------------------------------------------------------------------------
int main(int argc, char* argv[]) {
// command line arguments & opening files
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " input.txt output.txt" << std::endl;
exit(1);
}
std::ifstream istr(argv[1]);
if (!istr) {
std::cerr << "ERROR: could not open " << argv[1] << std::endl;
exit(1);
}
std::ofstream ostr(argv[2]);
if (!ostr) {
std::cerr << "ERROR: could not open " << argv[2] << std::endl;
exit(1);
}
// the master container of polygons
std::vector<Polygon*> polygons;
// read the input file one line at a time
std::string line;
while (getline(istr,line)) {
std::stringstream ss(line);
std::string name, token;
if (!(ss >> name)) continue;
std::vector<Point> points;
while (ss >> token) {
std::stringstream ss2(token);
char c;
double x,y;
ss2 >> c;
assert (c == '(');
ss2 >> x;
ss2 >> c;
assert (c == ',');
ss2 >> y;
ss2 >> c;
assert (c == ')');
points.push_back(Point(x,y));
}
assert (points.size() >= 3);
Polygon* p = CreatePolygon(name,points);
// add the new polygon to the master container
polygons.push_back(p);
}
// write out the statistics
OutputStats(polygons,ostr);
// delete the dynamically allocated polygons
for (int i = 0; i < polygons.size(); i++) {
delete polygons[i];
}
}
// ------------------------------------------------------------------------------
// This function determines the most specific type of shape that can
// be created from the sequence of points. It does this by process of
// elimination. Note that the order in which it attempts to create
// the shapes is important.
Polygon* CreatePolygon(const std::string &name, const std::vector<Point> &points) {
Polygon *answer = NULL;
try{
answer = new EquilateralTriangle(name,points);
}
catch (int) {
try {
answer= new IsoscelesTriangle(name,points);
}
catch (int) {
try {
answer= new Triangle(name,points);
}
catch (int) {
try {
answer= new Square(name,points);
}
catch (int) {
try {
answer= new Rectangle(name,points);
}
catch (int) {
try {
answer= new Quadrilateral(name,points);
}
catch (int) {
answer= new Polygon(name,points);
}
}
}
}
}
}
assert (answer != NULL);
return answer;
}
// ------------------------------------------------------------------------------
// This function prints the output. C++ macros are used to abbreviate
// some repetitive code. The function call-like macros are actually
// replaced using substitution by the preprocessor before the code is
// given to the compiler. (You are not required to understand the
// details of the macros. You do not need to edit this code.)
void OutputStats(const std::vector<Polygon*> &polygons, std::ofstream &ostr) {
// define and initialize variables
# define InitializeCount(type) std::vector<std::string> all_##type
InitializeCount(Polygon);
InitializeCount(Triangle);
InitializeCount(IsoscelesTriangle);
InitializeCount(EquilateralTriangle);
InitializeCount(Quadrilateral);
InitializeCount(Rectangle);
InitializeCount(Square);
std::vector<std::string> equal_sides;
// count & record the names of shapes in each category
for (std::vector<Polygon*>::const_iterator i = polygons.begin(); i!=polygons.end(); ++i) {
# define IncrementCount(type) if (dynamic_cast<type*> (*i)) all_##type.push_back((*i)->getName())
IncrementCount(Polygon);
IncrementCount(Triangle);
IncrementCount(IsoscelesTriangle);
IncrementCount(EquilateralTriangle);
IncrementCount(Quadrilateral);
IncrementCount(Rectangle);
IncrementCount(Square);
if ((*i)->HasAllEqualSides()) equal_sides.push_back((*i)->getName());
}
// output data for each category, sorted alphabetically by the shape's name
# define PrintVector(vecname) std::sort((vecname).begin(),(vecname).end()); \
for (unsigned int j = 0; j < (vecname).size(); j++) { ostr << " " << (vecname)[j]; } ostr << std::endl
# define PrintCount(type) do { ostr << all_##type.size() << " " #type"(s): "; PrintVector(all_##type); } while (0)
PrintCount(Polygon);
PrintCount(Triangle);
PrintCount(IsoscelesTriangle);
PrintCount(EquilateralTriangle);
PrintCount(Quadrilateral);
PrintCount(Rectangle);
PrintCount(Square);
ostr << equal_sides.size() << " Shape(s) with all equal sides: ";
PrintVector(equal_sides);
}
// ------------------------------------------------------------------------------

View File

@@ -0,0 +1,120 @@
// =========================================
//
// IMPORTANT NOTE: DO NOT EDIT THIS FILE
//
// =========================================
#ifndef _UTILITIES_H_
#define _UTILITIES_H_
#include <iostream>
#include <cmath>
#include <cassert>
// epsilon values used in comparing the edge lengths & angles between
// edges note that these values are dependent on the precision of
// the coordinates and the overall scale of the objects
#define DISTANCE_EPSILON 0.0001
#define ANGLE_EPSILON 0.1
// -----------------------------------------------------------------
// Stores a 2D coordinate
class Point {
public:
Point(double _x, double _y) : x(_x),y(_y) {}
double x;
double y;
};
// Stores a 2D vector, constructed from 2 Points
class Vector {
public:
Vector(const Point &a, const Point &b) { dx = b.x-a.x; dy = b.y-a.y; }
double Length() const { return sqrt(dx*dx+dy*dy); }
void Normalize() {
// make this a unit vector (length = 1)
double length = Length();
if (length < DISTANCE_EPSILON) throw std::string("LENGTH = 0");
assert (length > DISTANCE_EPSILON);
dx /= length;
dy /= length;
}
// representation
double dx;
double dy;
};
inline std::ostream& operator<< (std::ostream &ostr, const Vector &v) {
ostr << "<" << v.dx << "," << v.dy << ">";
return ostr;
}
// -----------------------------------------------------------------
// calculate the length of an edge, the distance between 2 points
inline double DistanceBetween(const Point &a, const Point &b) {
Vector v(a,b);
return v.Length();
}
// Calculate the angle at vertex b in degrees, that is, the angle
// between edges ab and bc. This will return a positive number
// measured as the clockwise rotation in the xy plane from point c to
// point a (rotating around point b).
inline double Angle(const Point &a, const Point &b, const Point &c) {
// make unit vector along each of the edges
Vector ba(b,a); ba.Normalize();
Vector bc(b,c); bc.Normalize();
// calculate the angle in radians
double dot_product = ba.dx * bc.dx + ba.dy * bc.dy;
if (dot_product < -1 || dot_product > 1) throw std::string("DOT PRODUCT RANGE");
assert (dot_product >= -1 && dot_product <= 1);
float perpDot = ba.dx * bc.dy - ba.dy * bc.dx;
// using atan2 to ensure than we get a signed answer.
double angle_in_radians = atan2(perpDot, dot_product);
// convert to degrees
double answer = angle_in_radians * 180.0 / M_PI;
if (answer < 0) {
answer += 360;
}
assert (answer >= 0 && answer <= 360);
return answer;
}
// returns true if these two vectors are parallel
inline bool Parallel(const Vector &a, const Vector &b) {
Vector a2 = a; a2.Normalize();
Vector b2 = b; b2.Normalize();
double dot_product = a2.dx * b2.dx + a2.dy * b2.dy;
// parallel vectors have dot product == 1
if (fabs(dot_product) > 1-DISTANCE_EPSILON) return true;
return false;
}
// -----------------------------------------------------------------
// simple functions for angles & sides
inline bool EqualSides(double a, double b) {
return (fabs(a-b) < DISTANCE_EPSILON);
}
inline bool EqualAngles(double a, double b) {
assert (a >= 0.0 && a < 360.0);
assert (b >= 0.0 && b < 360.0);
return (fabs(a-b) < ANGLE_EPSILON);
}
inline bool RightAngle(double a) {
assert (a >= 0.0 && a < 360.0);
return (fabs(a-90.0) < ANGLE_EPSILON);
}
// -----------------------------------------------------------------
#endif