OOP in c++

profileElm20o
asst5OOP.zip

asst5 OOP/bodgeUnitTest.h

#ifndef BODGE_UNIT_TEST_H_INCLUDED #define BODGE_UNIT_TEST_H_INCLUDED #include <cstdlib> #include <functional> #include <iostream> #include <string> #include "bodgeUnitTest.h" /** * This is the Bodge-Unit-Testing... PseUdO-Framework * * Bodge - A clumsy or inelegant job, usually a temporary repair; * a patch, a repair. (From Wiktionary) */ #define bodgeAssert(expression) \ if (!(expression)) { \ std::cout << "FAILURE: "\ << __func__ << ":" << __LINE__\ << " -> (" << #expression << ")\n";\ return false;\ } // End Macro // Unit Aliases using UnitTestFunction = std::function<bool()>; using UnitTestPair = std::pair<UnitTestFunction, std::string>; /** * Run a single unit test function and output PASSED of FAILED based on the * result. * * @TODO I could (and should) probably turn this into a macro. */ inline void runTest(const UnitTestFunction& testFunction, std::string description) { std::cout << " " << (testFunction() ? "PASSED" : "FAILED") << " -> " << description << std::endl; } #endif

asst5 OOP/BoundingBox.cpp

#include "BoundingBox.h" //------------------------------------------------------------------------------ BoundingBox::BoundingBox() :lowerLeftVertex (0, 0, 0), upperRightVertex(0, 0, 0) { } //------------------------------------------------------------------------------ BoundingBox::BoundingBox(Point lowerLeft, Point upperRight) :lowerLeftVertex (lowerLeft), upperRightVertex(upperRight) { } //------------------------------------------------------------------------------ Point BoundingBox::getLowerLeftVertex() const { return lowerLeftVertex; } //------------------------------------------------------------------------------ Point BoundingBox::getUpperRightVertex() const { return upperRightVertex; } //------------------------------------------------------------------------------ void BoundingBox::setUpperRightVertex(Point u) { upperRightVertex = u; } //------------------------------------------------------------------------------ void BoundingBox::setUpperRightVertex(double x, double y, double z) { upperRightVertex.x = x; upperRightVertex.y = y; upperRightVertex.z = z; } //------------------------------------------------------------------------------ void BoundingBox::merge(const BoundingBox& other) { upperRightVertex.x = std::max(this->upperRightVertex.x, other.upperRightVertex.x); upperRightVertex.y = std::max(this->upperRightVertex.y, other.upperRightVertex.y); upperRightVertex.z = std::max(this->upperRightVertex.z, other.upperRightVertex.z); }

asst5 OOP/BoundingBox.h

#ifndef BOUNDINGBOX_H_INCLUDED #define BOUNDINGBOX_H_INCLUDED #include "Point.h" /** * Rectangular prism representing the boundaries * x, y, and z of a polyhedron */ class BoundingBox { private: /** * Lower boundary. In this exercise, it is fixed at (0,0,0) */ Point lowerLeftVertex; /** * Upper boundary */ Point upperRightVertex; public: /** * Default Constructor */ BoundingBox(); /** * Construct a bounding box from lower and upper points that define it */ BoundingBox(Point lowerLeft, Point upperRight); // Use the compiler generated version BoundingBox(const BoundingBox& src) = default; // Use the compiler generated version ~BoundingBox() = default; // Use the compiler generated version BoundingBox& operator=(const BoundingBox& rhs) = default; /** * Retrieve the lower boundary */ Point getLowerLeftVertex() const; /** * Retrieve the upper boundary */ Point getUpperRightVertex() const; /** * Set the upper boundary using a Point */ void setUpperRightVertex(Point u); /** * Set the upper boundary using the x, y, and z components. */ void setUpperRightVertex(double x, double y, double z); /** * Merge two bounding boxes, taking the * largest values for each of x, y, and z */ void merge(const BoundingBox& other); /** * Apply a scaling factor */ void scale(double s); }; //------------------------------------------------------------------------------ inline void BoundingBox::scale(double s) { upperRightVertex.scale(s); } #endif

asst5 OOP/Composite.cpp

#include "Polyhedron.h" #include "Composite.h" //------------------------------------------------------------------------------ Composite::Composite() :Polyhedron("Composite") { } //------------------------------------------------------------------------------ /** * @todo write this function */ Composite::Composite(const Composite& src) :Polyhedron("Composite") { // Perform a deep copy... maybe the _add_ method can help... } //------------------------------------------------------------------------------ /** * @todo write this function */ Composite::~Composite() { // Delete each component polyhedra } //------------------------------------------------------------------------------ void Composite::read(std::istream& ins){ int numPolyhedra; ins >> numPolyhedra; allPolyhedra.resize(numPolyhedra); for (int i = 0; i < numPolyhedra; i++) { ins >> allPolyhedra[i]; boundingBox.merge(allPolyhedra[i]->getBoundingBox()); } } //------------------------------------------------------------------------------ /** * @todo write this function */ void Composite::display(std::ostream& outs) const { Polyhedron::display(outs); outs << allPolyhedra.size() << " polyhedra" << "\n"; // Loop through all component polyhedra and // print (display) them } //------------------------------------------------------------------------------ /** * @todo write this function */ void Composite::scale(double scalingFactor) { // Loop through all polyhedra and scale them // Do not forget the bounding box... after the loop } //------------------------------------------------------------------------------ Composite& Composite::operator=(Composite rhs) { swap(*this, rhs); return *this; } //------------------------------------------------------------------------------ Composite::iterator Composite::begin() { return allPolyhedra.begin(); } //------------------------------------------------------------------------------ Composite::iterator Composite::end() { return allPolyhedra.end(); } //------------------------------------------------------------------------------ Composite::const_iterator Composite::begin() const { return allPolyhedra.begin(); } //------------------------------------------------------------------------------ Composite::const_iterator Composite::end() const { return allPolyhedra.end(); } //------------------------------------------------------------------------------ /** * @todo write this function */ void Composite::add(const Polyhedron* toAdd) { // Add one new polyhedra and _merge_ its boundingBox with _this->boundingBox_ } //------------------------------------------------------------------------------ void swap(Composite& lhs, Composite& rhs) { using std::swap; std::swap(lhs.allPolyhedra, rhs.allPolyhedra); swap(lhs.boundingBox, rhs.boundingBox); }

asst5 OOP/Composite.h

#ifndef COMPOSITE_H_INCLUDED #define COMPOSITE_H_INCLUDED #include <vector> #include "Polyhedron.h" class Composite : public Polyhedron { public: using Collection = std::vector<Polyhedron*>; using iterator = Collection::iterator; using const_iterator = Collection::const_iterator; private: /** * Collection of polyhedra of which * this composite polyhedron is composed */ Collection allPolyhedra; public: /** * Default Constructor */ Composite(); /** * Copy Constructor */ Composite(const Composite& src); /** * Destructor */ virtual ~Composite(); /** * Assignment Operator */ Composite& operator=(Composite rhs); /** * Return the number of polyhedra that are part of this * Composite object. */ int size() const; // Iterator helpers iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; /** * Add a Polyhedron to the `Composite` collection. * * @post toAdd is cloned and the copy is added. */ void add(const Polyhedron* toAdd); // Polyhedron Interface /** * Copy Constructor Wrapper */ virtual Polyhedron* clone() const; /** * Read all component polyhedra * * @pre numPolyhedra == 0 */ virtual void read(std::istream& ins); /** * Print all polyhedra */ virtual void display(std::ostream& outs) const; /** * Scale all polyhedra */ virtual void scale(double scalingFactor); /** * Swap the contents of two `Composite`s * <p> * I am using a friend function here and only here (under protest) */ friend void swap(Composite& lhs, Composite& rhs); }; //------------------------------------------------------------------------------ inline int Composite::size() const { return this->allPolyhedra.size(); } //------------------------------------------------------------------------------ inline Polyhedron* Composite::clone() const { return new Composite(*this); } #endif

asst5 OOP/Cylinder.cpp

Polyhedra (OOP) Part 1

You have submitted this assignment 1 time(s). You last submitted it on Wed Nov 3 18:36:14 2021

The files you submitted were

File Name Bytes
Cylinder.h 2524
Cylinder.cpp 1453

You may not submit this, because: you have already requested and been given access to the solution;
A grade report was posted on Wed Nov 3 18:45:04 2021
Look at the solution to this assignment. (You will not be permitted to submit again after the solution has been revealed.)
 

asst5 OOP/Cylinder.h

Polyhedra (OOP) Part 1

You have submitted this assignment 1 time(s). You last submitted it on Wed Nov 3 18:36:14 2021

The files you submitted were

File Name Bytes
Cylinder.h 2524
Cylinder.cpp 1453

You may not submit this, because: you have already requested and been given access to the solution;
A grade report was posted on Wed Nov 3 18:45:04 2021
Look at the solution to this assignment. (You will not be permitted to submit again after the solution has been revealed.)
 

asst5 OOP/make.dep.txt

createPolyhedra.o: createPolyhedra.cpp Polyhedron.h Point.h BoundingBox.h \ PolyhedronFactory.h Polyhedron.o: Polyhedron.cpp Polyhedron.h Point.h BoundingBox.h \ PolyhedronFactory.h Sphere.o: Sphere.cpp Sphere.h Polyhedron.h Point.h BoundingBox.h Point.o: Point.cpp Point.h utilities.h PolyhedronFactory.o: PolyhedronFactory.cpp PolyhedronFactory.h Sphere.h \ Polyhedron.h Point.h BoundingBox.h Cylinder.h Composite.h BoundingBox.o: BoundingBox.cpp BoundingBox.h Point.h Cylinder.o: Cylinder.cpp Cylinder.h Polyhedron.h Point.h BoundingBox.h Composite.o: Composite.cpp Polyhedron.h Point.h BoundingBox.h Composite.h utilities.o: utilities.cpp utilities.h

asst5 OOP/makefile.txt

MAINPROG=createPolyhedra CPPS= createPolyhedra.cpp Polyhedron.cpp Sphere.cpp Point.cpp \ PolyhedronFactory.cpp BoundingBox.cpp Cylinder.cpp Composite.cpp \ utilities.cpp TEST_CPPS= Polyhedron.cpp Sphere.cpp Point.cpp \ PolyhedronFactory.cpp BoundingBox.cpp Cylinder.cpp Composite.cpp \ utilities.cpp TEST_DRIVERS=TestCylinder.cpp TestComposite.cpp DIR=${PWD} ASST=$(notdir ${DIR}) ifneq (,$(findstring MinGW,$(PATH))) DISTR=MinGW EXE=.exe LFLAGS= else DISTR=Unix EXE= LFLAGS=-fsanitize=leak,address -fuse-ld=gold endif # ######################################################################## # Macro definitions for "standard" C and C++ compilations # CPPFLAGS=-g -std=c++11 -D$(DISTR) -Wall -Wextra -Wpedantic -Weffc++ CFLAGS=-g TARGET=$(MAINPROG)$(EXE) LINK=g++ $(CPPFLAGS) # CC=gcc CPP=g++ # # # In most cases, you should not change anything below this line. # # The following is "boilerplate" to set up the standard compilation # commands: # OBJS=$(CPPS:%.cpp=%.o) DEPENDENCIES = $(CPPS:%.cpp=%.d) TEST_OBJS=$(TEST_CPPS:%.cpp=%.o) TEST_DRIVER_OBJS=$(TEST_DRIVERS:%.cpp=%.o) %.d: %.cpp touch $@ %.o: %.cpp $(CPP) $(CPPFLAGS) -MMD -o $@ -c $*.cpp # # Targets: # all: $(TARGET) tests win: $(OBJS) $(LINK) $(FLAGS) -o $(TARGET) $(OBJS) $(TARGET): $(OBJS) $(LINK) $(FLAGS) -o $(TARGET) $(OBJS) $(LFLAGS) tests: $(TEST_OBJS) $(TEST_DRIVER_OBJS) $(LINK) $(FLAGS) -o testCylinder $(TEST_OBJS) TestCylinder.o $(LFLAGS) $(LINK) $(FLAGS) -o testComposite $(TEST_OBJS) TestComposite.o $(LFLAGS) clean: -/bin/rm -f *.d *.o $(TARGET) $(TEST_DRIVER_OBJS) testCylinder.o TestComposite.o make.dep: $(DEPENDENCIES) -cat $(DEPENDENCIES) > $@ include make.dep

asst5 OOP/Point.cpp

#include "Point.h" #include "utilities.h" //------------------------------------------------------------------------------ Point::Point() :x(0), y(0), z(0) { } //------------------------------------------------------------------------------ Point::Point(double x_, double y_, double z_) :x(x_), y(y_), z(z_) { } //------------------------------------------------------------------------------ void Point::scale(double scalingFactor) { x *= scalingFactor; y *= scalingFactor; z *= scalingFactor; } //------------------------------------------------------------------------------ void Point::display(std::ostream& outs) const { outs << "(" << x << ", " << y << ", " << z << ")"; } //------------------------------------------------------------------------------ bool operator==(const Point& lhs, const Point& rhs) { if (!fpNumsAreEqual(lhs.x, rhs.x)) { return false; } if (!fpNumsAreEqual(lhs.y, rhs.y)) { return false; } if (!fpNumsAreEqual(lhs.z, rhs.z)) { return false; } return true; }

asst5 OOP/Point.h

#ifndef POINT_H_INCLUDED #define POINT_H_INCLUDED #include <iostream> /** * Coordinate in 3 dimensional Cartesian space */ struct Point { double x, y, z; /** * Default Constructor */ Point(); /** * Construct a Point from specified * x, y, and z values */ Point(double x, double y, double z); // Use the compiler generated version Point(const Point& src) = default; // Use the compiler generated version ~Point() = default; // Use the compiler generated version Point& operator=(const Point& rhs) = default; /** * Apply geometric scaling function */ void scale(double scalingFactor); /** * Print a point */ void display(std::ostream& outs) const; /** * Swap the contents of two `Point`s * <p> * I am using a friend function here and only here (under protest) */ friend void swap(Point& lhs, Point& rhs); }; /** * Logical Equivalence Operator - Weak Equality */ bool operator==(const Point& lhs, const Point& rhs); /** * Stream insertion (output) operator */ inline std::ostream& operator<<(std::ostream& outs, const Point prt) { prt.display(outs); return outs; } //------------------------------------------------------------------------------ inline void swap(Point& lhs, Point& rhs) { std::swap(lhs.x, rhs.x); std::swap(lhs.y, rhs.y); std::swap(lhs.z, rhs.z); } #endif

asst5 OOP/polyhedra1.txt

sphere 1 cylinder 2 1 sphere 4 cylinder 2 3 sphere 3

asst5 OOP/polyhedra2.txt

sphere 1 cylinder 2 1 sphere 4 cylinder 2 3 composite 3 sphere 3 sphere 5 sphere 7 composite 2 cylinder 1 2 sphere 5 sphere 3

asst5 OOP/Polyhedron.cpp

#include "Polyhedron.h" #include "PolyhedronFactory.h" //------------------------------------------------------------------------------ Polyhedron::Polyhedron() :type("Polyhedron"), boundingBox() { } //------------------------------------------------------------------------------ Polyhedron::Polyhedron(const char* t) :type(t), boundingBox() { } //------------------------------------------------------------------------------ Polyhedron::~Polyhedron() { // No dynamic memory } //------------------------------------------------------------------------------ void Polyhedron::display(std::ostream& outs) const { outs << "[" << type << "] " << boundingBox.getUpperRightVertex() << "->"; } //------------------------------------------------------------------------------ void Polyhedron::scale(double scalingFactor) { boundingBox.scale(scalingFactor); } //------------------------------------------------------------------------------ std::istream& operator>>(std::istream& ins, Polyhedron*& ply) { std::string polyhedronType; if (ins >> polyhedronType) { ply = PolyhedronFactory::createPolyhedron(polyhedronType); if (ply != nullptr) { ply->read(ins); } else { getline(ins, polyhedronType); } } return ins; }

asst5 OOP/Polyhedron.h

#ifndef POLYHEDRON_H_INCLUDED #define POLYHEDRON_H_INCLUDED #include <cmath> #include <cstdlib> #include <iostream> #include <string> #include "Point.h" #include "BoundingBox.h" /** * Abstract Polyhedron Base Class */ class Polyhedron { private: /** * A string representing the name of this polyhedron */ std::string type; protected: /** * Box (rectangular prism) that contains this element */ BoundingBox boundingBox; public: /** * Default Constructor */ Polyhedron(); /** * Constructor which allows * a name to be set * * @param t c-string representing the polyhedron name */ Polyhedron(const char* t); /** * Destructor */ virtual ~Polyhedron(); /** * Get the polyhedron name */ std::string getType() const; /** * set the polyhedron name */ void setType(std::string t); /** * Retrieve the bounding box */ BoundingBox getBoundingBox() const; /** * Duplicate the polyhedron */ virtual Polyhedron* clone() const = 0; /** * Retrieve and reconstruct the polyhedron * from an input stream */ virtual void read(std::istream& ins) = 0; /** * Print the polyhedron */ virtual void display(std::ostream& outs) const; /** * Check if two polyhedra have matching types */ bool isTypeMatch(const Polyhedron* rhs) const; /** * Apply a geometric scaling operation */ virtual void scale(double scalingFactor); }; //------------------------------------------------------------------------------ inline std::string Polyhedron::getType() const { return type; } //------------------------------------------------------------------------------ inline void Polyhedron::setType(std::string t) { type = t; } //------------------------------------------------------------------------------ inline BoundingBox Polyhedron::getBoundingBox() const { return boundingBox; } //------------------------------------------------------------------------------ inline bool Polyhedron::isTypeMatch(const Polyhedron* rhs) const { return this->getType() == rhs->getType(); } /** * Stream insertion operator (inline wrapper for display) */ inline std::ostream& operator<<(std::ostream& outs, const Polyhedron& ply) { ply.display(outs); return outs; } /** * Stream extraction (input) operator */ std::istream& operator>>(std::istream& ins, Polyhedron*& ply); #endif

asst5 OOP/PolyhedronFactory.cpp

#include "PolyhedronFactory.h" #include "Sphere.h" #include "Cylinder.h" #include "Composite.h" #include <iterator> #include <algorithm> PolyhedronFactory::PolyhedronPair PolyhedronFactory::_known_polyhedra[] = { {"sphere" , new Sphere()}, {"composite", new Composite()}, {"cylinder" , new Cylinder()} }; //------------------------------------------------------------------------------ Polyhedron* PolyhedronFactory::createPolyhedron(std::string name) { for(const PolyhedronPair& pair : _known_polyhedra) { if(pair.first == name) { return pair.second->clone(); } } // A polygon with the given name could not be found return nullptr; } //------------------------------------------------------------------------------ bool PolyhedronFactory::isKnown(std::string name) { const auto it = std::find_if(std::begin(_known_polyhedra), std::end(_known_polyhedra), [&name](const PolyhedronPair& pairToCheck) { return pairToCheck.first == name; }); return it != std::end(_known_polyhedra); } //------------------------------------------------------------------------------ void PolyhedronFactory::listKnown(std::ostream& outs) { for(const PolyhedronPair& pair : _known_polyhedra) { outs << " " << pair.first << "\n"; } } //------------------------------------------------------------------------------ int PolyhedronFactory::numberKnown() { return std::end(_known_polyhedra) - std::begin(_known_polyhedra); }

asst5 OOP/PolyhedronFactory.h

#ifndef POLYHEDRONFACTORY_H_INCLUDED #define POLYHEDRONFACTORY_H_INCLUDED #include <iostream> #include <array> class Polyhedron; /** * The Polyhedron Creating Wizard */ class PolyhedronFactory { private: /** * Name Polyhedron Pair 2-tuple( name, model ) * <p> * Note how this is now a std::pair */ using PolyhedronPair = std::pair<std::string, Polyhedron*>; static PolyhedronPair _known_polyhedra[]; ///< Listing of known polyhedra public: /** * Create a Polyhedron * * @param name the polyhedron to be created * * @return A polyhedron with the specified name * or nullptr if no matching polyhedron is found */ static Polyhedron* createPolyhedron(std::string name); /** * Determine whether a given polyhedron is known * * @param name the polyhedron for which to query */ static bool isKnown(std::string name); /** * Print a list of known Polyhedrons * * @param outs the output stream */ static void listKnown(std::ostream& outs); /** * Determine the number of known Polyhedrons * * @return the number of known polyhedrons * */ static int numberKnown(); }; #endif

asst5 OOP/Sphere.cpp

#include "Sphere.h" //------------------------------------------------------------------------------ Sphere::Sphere() :Sphere(1) { } //------------------------------------------------------------------------------ Sphere::Sphere(double r) :Polyhedron("Sphere"), radius(r) { double d = this->getDiameter(); boundingBox.setUpperRightVertex(d, d, d); } //------------------------------------------------------------------------------ void Sphere::read(std::istream& ins) { ins >> radius; double d = this->getDiameter(); boundingBox.setUpperRightVertex(d, d, d); } //------------------------------------------------------------------------------ void Sphere::display(std::ostream& outs) const { Polyhedron::display(outs); outs << "Radius: " << radius << " " << "Diameter: " << getDiameter(); } //------------------------------------------------------------------------------ void Sphere::scale(double scalingFactor) { radius *= scalingFactor; boundingBox.scale(scalingFactor); }

asst5 OOP/Sphere.h

#ifndef SPHERE_H_INCLUDED #define SPHERE_H_INCLUDED #include "Polyhedron.h" /** * Sphere */ class Sphere : public Polyhedron { private: double radius; public: /** * Default Constructor */ Sphere(); /** * Construct a sphere from a provided radius */ Sphere(double r); // Use the compiler generated version Sphere(const Sphere& src) = default; // Use the compiler generated version virtual ~Sphere() = default; // Use the compiler generated version Sphere& operator=(const Sphere& rhs) = default; /** * Retrieve the radius */ double getRadius() const; /** * Update the radius */ void setRadius(double r); /** * Compute and return the diameter */ double getDiameter() const; virtual Polyhedron* clone() const; virtual void read(std::istream& ins); virtual void display(std::ostream& outs) const; virtual void scale(double scalingFactor); }; //------------------------------------------------------------------------------ inline double Sphere::getRadius() const { return this->radius; } //------------------------------------------------------------------------------ inline void Sphere::setRadius(double r) { radius = r; double d = getDiameter(); boundingBox.setUpperRightVertex(d, d, d); } //------------------------------------------------------------------------------ inline double Sphere::getDiameter() const { return (2 * radius); } //------------------------------------------------------------------------------ inline Polyhedron* Sphere::clone() const { return new Sphere(*this); } #endif

asst5 OOP/TestComposite.cpp

#include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <vector> #include <sstream> #include <algorithm> #include <functional> #include <cmath> #include <memory> #include "Polyhedron.h" #include "Sphere.h" #include "Cylinder.h" #include "Composite.h" #include "utilities.h" #include "bodgeUnitTest.h" //----------------------------------------------------------------------------- // Unit Tests //----------------------------------------------------------------------------- const Point ORIGIN(0, 0, 0); const Composite EMPTY_POLY; const std::string INPUT_STR = R"(2 cylinder 1 2 sphere 5)"; bool testDefaultConstructor() { Point lowerPoint = (EMPTY_POLY.getBoundingBox()).getLowerLeftVertex(); Point upperPoint = (EMPTY_POLY.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == ORIGIN); bodgeAssert(EMPTY_POLY.size() == 0); bodgeAssert(EMPTY_POLY.begin() == EMPTY_POLY.end()); // I am skipping display in this test return true; } //----------------------------------------------------------------------------- bool testAdd() { Polyhedron* sphere = new Sphere(2); Polyhedron* cylinder = new Cylinder(3, 5); Composite comp1; comp1.add(sphere); bodgeAssert(comp1.size() == 1); bodgeAssert(comp1.begin() != comp1.end()); Point lowerPoint = (comp1.getBoundingBox()).getLowerLeftVertex(); Point upperPoint = (comp1.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == Point(4, 4, 4)); comp1.add(cylinder); bodgeAssert(comp1.size() == 2); bodgeAssert(comp1.begin() != comp1.end()); lowerPoint = (comp1.getBoundingBox()).getLowerLeftVertex(); upperPoint = (comp1.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == Point(6, 6, 5)); // I am skipping display in this test delete sphere; delete cylinder; return true; } //----------------------------------------------------------------------------- bool testClone() { Polyhedron* sphere = new Sphere(2); Polyhedron* cylinder = new Cylinder(3, 5); Composite comp1; comp1.add(sphere); comp1.add(cylinder); // Sanity Check Original bodgeAssert(comp1.size() == 2); bodgeAssert(comp1.begin() != comp1.end()); Point lowerPoint = (comp1.getBoundingBox()).getLowerLeftVertex(); Point upperPoint = (comp1.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == Point(6, 6, 5)); // Make the copy and check it Polyhedron* theCopyAsBase = comp1.clone(); Composite& theCopyAsComp = *((Composite*) theCopyAsBase); bodgeAssert(theCopyAsComp.size() == 2); bodgeAssert(theCopyAsComp.begin() != theCopyAsComp.end()); lowerPoint = (theCopyAsComp.getBoundingBox()).getLowerLeftVertex(); upperPoint = (theCopyAsComp.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == Point(6, 6, 5)); // Technically I should use the iterator to check that I // have copies of `sphere` and `cylinder` // I am skipping display in this test delete theCopyAsBase; delete sphere; delete cylinder; return true; } //----------------------------------------------------------------------------- bool testRead() { std::istringstream ins(INPUT_STR); Composite comp1; comp1.read(ins); bodgeAssert(comp1.size() == 2); bodgeAssert(comp1.begin() != comp1.end()); // Technically I should use the iterator to check that I // have the correct `sphere` and `cylinder` // BoundingBox... Point expectedPoint(10, 10, 10); const Point& point = (comp1.getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test return true; } //----------------------------------------------------------------------------- /** This comment contains the markup to render a sequence diagram in sdedit: #![testScale] test:TestComposite[a] /sphere:unique_ptr<Sphere>[a] /rawSphere:Sphere*[a] /sphereBB:BoundingBox[a] /cylinder:unique_ptr<Cylinder>[a] /rawCylinder:Cylinder*[a] /cylinderBB:BoundingBox[a] /comp:Composite[a] /compBB:BoundingBox[a] /allPolyhedra:vector<Polyhedron*>[a] # # Setup test:rawSphere=rawSphere.new(2) rawSphere:sphereBB.new() rawSphere:d=rawSphere.getDiameter() rawSphere:sphereBB.setUpperRightVertex(d, d, d) test:sphere.new(rawSphere) test:rawCylinder=rawCylinder.new(3, 5) rawCylinder:cylinderBB.new() rawCylinder:d=rawCylinder.getDiameter() rawCylinder:cylinderBB.setUpperRightVertex(d, d, height) test:cylinder.new(rawCylinder) test:comp.new() comp:compBB.new() comp:allPolyhedra.new() # # Add rawSphere and rawCylinder to comp test:rawSphere=sphere.get() test:comp.add(rawSphere) comp:cpy=rawSphere.clone() comp:allPolyhedra.push_back(cpy) comp:compBB.merge(cpy.getBoundingBox()) test:rawCylinder=cylinder.get() test:comp.add(rawCylinder) comp:cpy=rawCylinder.clone() comp:allPolyhedra.push_back(cpy) comp:compBB.merge(cpy.getBoundingBox()) # test:comp.scale(5) [c:loop for each idx in {0, 1}] comp:poly=allPolyhedra.at(idx) comp:poly->scale() is invoked (omitted for brevity) [/c] test:All Checks (assertions run) test:sphere.destroy() sphere:rawSphere.destroy() rawSphere:sphereBB.destroy() test:cylinder.destroy() cylinder:rawCylinder.destroy() rawCylinder:cylinderBB.destroy() test:comp.destroy() [c:loop for each idx in {0, 1}] comp:poly=allPolyhedra.at(idx) comp:delete poly (omitted for brevity) [/c] comp:allPolyhedra.destroy() **/ bool testScale() { std::unique_ptr<Polyhedron> sphere(new Sphere(2)); std::unique_ptr<Polyhedron> cylinder(new Cylinder(3, 5)); Composite comp1; comp1.add(sphere.get()); comp1.add(cylinder.get()); comp1.scale(5); // Sanity Check Original bodgeAssert(comp1.size() == 2); bodgeAssert(comp1.begin() != comp1.end()); // Technically I should use the iterator to check that I // have the correct `sphere` and `cylinder` Point lowerPoint = (comp1.getBoundingBox()).getLowerLeftVertex(); Point upperPoint = (comp1.getBoundingBox()).getUpperRightVertex(); bodgeAssert(lowerPoint == ORIGIN); bodgeAssert(upperPoint == Point(30, 30, 25)); return true; } //----------------------------------------------------------------------------- bool testDisplay() { std::unique_ptr<Polyhedron> sphere(new Sphere(2)); std::unique_ptr<Polyhedron> cylinder(new Cylinder(3, 5)); Composite comp1; comp1.add(sphere.get()); comp1.add(cylinder.get()); comp1.scale(5); std::ostringstream outs; std::string expectedOutput = R"([Composite] (30, 30, 25)->2 polyhedra [Sphere] (20, 20, 20)->Radius: 10 Diameter: 20 [Cylinder] (30, 30, 25)->Radius: 15 Height: 25 )"; comp1.display(outs); bodgeAssert(outs.str() == expectedOutput); return true; } //------------------------------------------------------------------------------ int main(int argc, char** argv) { UnitTestPair tests[] = { {testDefaultConstructor, "testDefaultConstructor"}, {testAdd, "testAdd"}, {testClone, "testClone"}, {testRead, "testRead"}, {testScale, "testScale"}, {testDisplay, "testDisplay"} }; for (const UnitTestPair& testPair : tests) { runTest(testPair.first, testPair.second); } return 0; }

asst5 OOP/TestCylinder.cpp

#include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <vector> #include <sstream> #include <algorithm> #include <functional> #include <cmath> #include "Polyhedron.h" #include "Sphere.h" #include "Cylinder.h" #include "utilities.h" #include "bodgeUnitTest.h" //----------------------------------------------------------------------------- // Unit Tests //----------------------------------------------------------------------------- Cylinder* defaultCylinder = new Cylinder(); bool testDefaultConstructor() { bodgeAssert(fpNumsAreEqual(defaultCylinder->getRadius(), 1)); bodgeAssert(fpNumsAreEqual(defaultCylinder->getDiameter(), 2)); bodgeAssert(fpNumsAreEqual(defaultCylinder->getHeight(), 1)); // BoundingBox... Point expectedPoint(2, 2, 1); const Point& point = (defaultCylinder->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test return true; } //----------------------------------------------------------------------------- bool testNonDefaultConstructor() { Cylinder* cyl = new Cylinder(3, 2); bodgeAssert(fpNumsAreEqual(cyl->getRadius(), 3)); bodgeAssert(fpNumsAreEqual(cyl->getDiameter(), 6)); bodgeAssert(fpNumsAreEqual(cyl->getHeight(), 2)); // BoundingBox... Point expectedPoint(6, 6, 2); const Point& point = (cyl->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; return true; } //----------------------------------------------------------------------------- bool testSetRadius() { Cylinder* cyl = new Cylinder(1, 2); cyl->setRadius(12); bodgeAssert(fpNumsAreEqual(cyl->getRadius(), 12)); bodgeAssert(fpNumsAreEqual(cyl->getDiameter(), 24)); bodgeAssert(fpNumsAreEqual(cyl->getHeight(), 2)); // BoundingBox... Point expectedPoint(24, 24, 2); const Point& point = (cyl->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; return true; } //----------------------------------------------------------------------------- bool testSetHeight() { Cylinder* cyl = new Cylinder(1, 2); cyl->setHeight(8); bodgeAssert(fpNumsAreEqual(cyl->getRadius(), 1)); bodgeAssert(fpNumsAreEqual(cyl->getDiameter(), 2)); bodgeAssert(fpNumsAreEqual(cyl->getHeight(), 8)); // BoundingBox... Point expectedPoint(2, 2, 8); const Point& point = (cyl->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; return true; } //----------------------------------------------------------------------------- bool testClone() { Cylinder* cyl = new Cylinder(3, 2); Cylinder* cpy = (Cylinder*) cyl->clone(); bodgeAssert(fpNumsAreEqual(cpy->getRadius(), 3)); bodgeAssert(fpNumsAreEqual(cpy->getDiameter(), 6)); bodgeAssert(fpNumsAreEqual(cpy->getHeight(), 2)); // BoundingBox... Point expectedPoint(6, 6, 2); const Point& point = (cpy->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; delete cpy; return true; } //----------------------------------------------------------------------------- bool testRead() { Cylinder* cyl = new Cylinder(); std::istringstream ins("4 12"); cyl->read(ins); bodgeAssert(fpNumsAreEqual(cyl->getRadius(), 12)); bodgeAssert(fpNumsAreEqual(cyl->getDiameter(), 24)); bodgeAssert(fpNumsAreEqual(cyl->getHeight(), 4)); // BoundingBox... Point expectedPoint(24, 24, 4); const Point& point = (cyl->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; return true; } //----------------------------------------------------------------------------- bool testScale() { Cylinder* cyl = new Cylinder(5, 3); cyl->scale(2); bodgeAssert(fpNumsAreEqual(cyl->getRadius(), 10)); bodgeAssert(fpNumsAreEqual(cyl->getDiameter(), 20)); bodgeAssert(fpNumsAreEqual(cyl->getHeight(), 6)); // BoundingBox... Point expectedPoint(20, 20, 6); const Point& point = (cyl->getBoundingBox()).getUpperRightVertex(); bodgeAssert(point == expectedPoint); // I am skipping display in this test delete cyl; return true; } //----------------------------------------------------------------------------- bool testDisplay() { Cylinder* cyl = new Cylinder(3, 5); std::ostringstream outs; const std::string expectedOutput = "[Cylinder] (6, 6, 5)->Radius: 3 Height: 5"; cyl->display(outs); bodgeAssert(outs.str() == expectedOutput); delete cyl; return true; } //------------------------------------------------------------------------------ int main(int argc, char** argv) { UnitTestPair tests[] = { {testDefaultConstructor, "testDefaultConstructor"}, {testNonDefaultConstructor, "testNonDefaultConstructor"}, {testSetRadius, "testSetRadius"}, {testSetHeight, "testSetHeight"}, {testClone, "testClone"}, {testRead, "testRead"}, {testScale, "testScale"}, {testDisplay, "testDisplay"} }; for (const UnitTestPair& testPair : tests) { runTest(testPair.first, testPair.second); } return 0; }

asst5 OOP/utilities.cpp

#include <cmath> #include "utilities.h" //------------------------------------------------------------------------------ const double FP_TOLERANCE = 0.01; //------------------------------------------------------------------------------ bool fpNumsAreEqual(double fp1, double fp2, double eps) { return std::abs(fp2 - fp1) <= eps; }

asst5 OOP/utilities.h

#ifndef UTILITIES_H_INCLUDED #define UTILITIES_H_INCLUDED extern const double FP_TOLERANCE; /** * Compare two floating point numbers for equivalence. Allow them to differ * within a set tolerance * * Note there exists a tremendous amount of literature on how to * compare floating point number. For this exercise/example we will * use a slightly-better-than naive fp1 == fp2 approach. * * @param fp1 first floating point number * @param fp2 second floating point number * @param eps tolerance */ bool fpNumsAreEqual(double fp1, double fp2, double eps=FP_TOLERANCE); #endif