From bc195296d077c30e4d89f5e3122e2201c47ef6e6 Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Wed, 31 Oct 2018 21:33:23 -0400 Subject: [PATCH 01/95] Implementation of Number class --- include/Number.h | 43 ++++++++------- makefile | 3 +- postgres_ext.cpp | 14 ++--- src/Number.cpp | 132 +++++++++++++++++++++++++++++++++++++---------- 4 files changed, 137 insertions(+), 55 deletions(-) diff --git a/include/Number.h b/include/Number.h index c1c14cc..ffeb40f 100644 --- a/include/Number.h +++ b/include/Number.h @@ -4,8 +4,6 @@ #include #include -struct PrivateRec; - class Number { public: @@ -20,32 +18,33 @@ class Number ~Number(); // Override arithmetic operators - Number& operator+(const Number& n) const; - Number& operator+=(const Number& n); - Number& operator-(const Number& n) const; - Number& operator-=(const Number& n); - Number& operator*(const Number& n) const; - Number& operator*=(const Number& n); - Number& operator/(const Number& n) const; - Number& operator/=(const Number& n); - Number& operator^(const int n) const; + Number &operator=(const Number &n); + Number &operator+(const Number &n) const; + Number &operator+=(const Number &n); + Number &operator-(const Number &n) const; + Number &operator-=(const Number &n); + Number &operator*(const Number &n) const; + Number &operator*=(const Number &n); + Number &operator/(const Number &n) const; + Number &operator/=(const Number &n); + Number &operator^(const int n) const; // Override comparison operators - bool operator<(const Number& n) const; - bool operator<=(const Number& n) const; - bool operator>(const Number& n) const; - bool operator>=(const Number& n) const; - bool operator==(const Number& n) const; - bool operator!=(const Number& n) const; - - Number& sqrt() const; + bool operator<(const Number &n) const; + bool operator<=(const Number &n) const; + bool operator>(const Number &n) const; + bool operator>=(const Number &n) const; + bool operator==(const Number &n) const; + bool operator!=(const Number &n) const; + Number &sqrt() const; // Overriding the output and input operator - friend std::ostream& operator<<(std::ostream& os, const Number& n); - friend std::istream& operator>>(std::istream& is, Number& n); + friend std::ostream &operator<<(std::ostream &os, const Number &n); + friend std::istream &operator>>(std::istream &is, Number &n); private: - PrivateRec* p; + struct NumberImpl; + struct NumberImpl *p; }; #endif // NUMBER_H diff --git a/makefile b/makefile index 6514198..0ef5fbd 100644 --- a/makefile +++ b/makefile @@ -3,6 +3,7 @@ INC_DIR := ./include OBJ_DIR := ./obj CC := g++ CFLAGS := -std=c++17 -g +LDFLAGS := -lgmpxx -lgmp TARGET := postgres_ext SRCS := $(wildcard $(SRC_DIR)/*.cpp postgres_ext.cpp) @@ -10,7 +11,7 @@ OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRCS)) all: $(TARGET) $(TARGET): $(OBJS) - $(CC) $(CFLAGS) -o $@ $^ + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(CC) $(CFLAGS) -o $@ -c $< clean: diff --git a/postgres_ext.cpp b/postgres_ext.cpp index 8e6e89a..abfee4d 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -1,15 +1,17 @@ #include "iostream" // Including all headers to test -#include "include/Region2D.h" #include "include/RGPHalfSegment2D.h" #include "include/RGPOperations.h" #include "include/RGPPoint2D.h" #include "include/RGPSegment2D.h" +#include "include/Region2D.h" -int main(void) { - Number n(); - Number a(5, 7); - std::cout << "All includes successfull!" << std::endl; - return 0; +int +main(void) +{ + Number n; + Number a("5"); + std::cout << "All includes successfull!" << std::endl; + return 0; } \ No newline at end of file diff --git a/src/Number.cpp b/src/Number.cpp index 9a36d0d..a55a8f5 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -1,42 +1,122 @@ #include "../include/Number.h" +#include "gmpxx.h" + +struct Number::NumberImpl { +mpq_class num; +}; // Constructors // Default number value is 0 -Number::Number() {} +Number::Number() { + p = new NumberImpl; + mpq_class temp; + p->num = temp; +} // The string will be converted to a rational number -Number::Number(std::string number) {} +Number::Number(std::string number) { + p = new NumberImpl; + mpq_class temp(number, 10); + p->num = temp; +} -// Fraction of the form n/1 -Number::Number(int n) {} +// Destructor +Number::~Number() { + delete p; +} -// Fraction of the form n/d -Number::Number(int n, int d) {} +// Override arithmetic operators +Number &Number::operator=(const Number &n) { + p->num = n.p->num; + return *this; +} -// Destructor -Number::~Number() {} +Number &Number::operator+(const Number &n) const { + Number *ret = new Number(); + ret->p->num = p->num + n.p->num; + return *ret; +} +Number &Number::operator+=(const Number &n) { + p->num = p->num + n.p->num; + return *this; +} -// Override arithmetic operators -Number& Number::operator+ (const Number& n) const {} -Number& Number::operator+= (const Number& n) {} -Number& Number::operator- (const Number& n) const {} -Number& Number::operator-= (const Number& n) {} -Number& Number::operator* (const Number& n) const {} -Number& Number::operator*= (const Number& n) {} -Number& Number::operator/ (const Number& n) const {} -Number& Number::operator/= (const Number& n) {} -Number& Number::operator^ (const int n) const {} +Number &Number::operator-(const Number &n) const { + Number *ret = new Number(); + ret->p->num = p->num - n.p->num; + return *ret; +} + +Number &Number::operator-=(const Number &n) { + p->num = p->num - n.p->num; + return *this; +} + +Number &Number::operator*(const Number &n) const { + Number *ret = new Number(); + ret->p->num = p->num * n.p->num; + return *ret; +} + +Number &Number::operator*=(const Number &n) { + p->num = p->num *= n.p->num; + return *this; +} + +Number &Number::operator/(const Number &n) const { + Number *ret = new Number(); + ret->p->num = p->num / n.p->num; + return *ret; +} + +Number &Number::operator/=(const Number &n) { + p->num = p->num /= n.p->num; + return *this; +} + +Number &Number::operator^(const int n) const { + // TODO: Optimize! + mpq_class val = p->num; + for(int i = 0; i < n; i++) { + p->num = p->num * val; + } +} // Override comparison operators -bool Number::operator< (const Number& n) const {} -bool Number::operator<= (const Number& n) const {} -bool Number::operator> (const Number& n) const {} -bool Number::operator>= (const Number& n) const {} -bool Number::operator== (const Number& n) const {} +bool Number::operator<(const Number &n) const { + return p->num < n.p->num; +} + +bool Number::operator<=(const Number &n) const { + return p->num <= n.p->num; +} + +bool Number::operator>(const Number &n) const { + return p->num > n.p->num; +} + +bool Number::operator>=(const Number &n) const { + return p->num >= n.p->num; +} + +bool Number::operator==(const Number &n) const { + return p->num == n.p->num; +} + +bool Number::operator!=(const Number &n) const { + return p->num != n.p->num; +} -Number& Number::sqrt() const {} +Number &Number::sqrt() const {} // Overriding the output and input operator -// std::ostream& Number::operator<<(std::ostream& os, const Number& n) {} -// std::istream& Number::operator>>(std::istream& is, Number& n) {} +std::ostream &operator<<(std::ostream &os, const Number &n) { + // TODO: Support arbitrary precision + os << n.p->num.get_d(); + return os; +} +std::istream &operator>>(std::istream &is, Number &n) { + is >> n.p->num; + return is; +} \ No newline at end of file From ccfd4e86227f9ddd0a591bd8066fbf24f83be87b Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Wed, 31 Oct 2018 22:50:57 -0400 Subject: [PATCH 02/95] Fixing and optimizing flawed implementation of power function --- src/Number.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Number.cpp b/src/Number.cpp index 59b6f44..0b8e355 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -76,11 +76,11 @@ Number &Number::operator/=(const Number &n) { } Number &Number::operator^(const int n) const { - // TODO: Optimize! - mpq_class val = p->num; - for(int i = 0; i < n; i++) { - p->num = p->num * val; - } + Number *ret = new Number(); + mpz_pow_ui(ret->p->num.get_num_mpz_t(), p->num.get_num_mpz_t(), (unsigned long) n); + mpz_pow_ui(ret->p->num.get_den_mpz_t(), p->num.get_den_mpz_t(), (unsigned long) n); + ret->p->num.canonicalize(); + return *ret; } // Override comparison operators From 83754e16d9d23fac59a07c21a9fb5726d5f48581 Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Wed, 31 Oct 2018 23:14:57 -0400 Subject: [PATCH 03/95] Temporary implementation of sqrt --- src/Number.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Number.cpp b/src/Number.cpp index 0b8e355..4f6a2c7 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -108,7 +108,14 @@ bool Number::operator!=(const Number &n) const { return p->num != n.p->num; } -Number &Number::sqrt() const {} +Number &Number::sqrt() const { + // TODO: Temporary implementation, limited precision + Number *ret = new Number(); + mpf_class float_num(p->num); + mpf_sqrt(float_num.get_mpf_t(), float_num.get_mpf_t()); + ret->p->num = mpq_class(float_num); + return *ret; +} // Overriding the output and input operator std::ostream &operator<<(std::ostream &os, const Number &n) { From 80ed2515ab8f083ce6bd39de19b69de6612ca90c Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Tue, 6 Nov 2018 15:39:00 -0500 Subject: [PATCH 04/95] Edited Point2D.h, Point2D.cpp, and re-added missing Point2DImpl.h. Tried to make code structure for handling struct and data inside. --- include/Point2D.h | 11 +++++++---- include/Point2DImpl.h | 23 +++++++++++++++++++++++ src/Point2D.cpp | 21 ++++++++++++++++----- 3 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 include/Point2DImpl.h diff --git a/include/Point2D.h b/include/Point2D.h index 499e809..bda2895 100644 --- a/include/Point2D.h +++ b/include/Point2D.h @@ -1,3 +1,5 @@ +// PUBLIC HEADER FILE + #ifndef POINT2D_H #define POINT2D_H @@ -25,16 +27,17 @@ class Point2D{ bool operator==(const Point2D &p2d); // Override of operator == to check equality of two Point2Ds bool operator!=(const Point2D &p2d); // Override of operator != to check inequality of two Point2Ds int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed - std::vector getBoundingBox(); + std::vector getBoundingBox(); bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object bool update(int index, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index bool remove(int index); // Removes a RGPPoint2D at specified index RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index -private: - class Point2DImpl; + struct Point2DStruct; + Point2DStruct *getStruct(); + // Fields - Point2DImpl *impl; + Point2DStruct *impl; }; #endif //POINT2D_H diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h new file mode 100644 index 0000000..f953e59 --- /dev/null +++ b/include/Point2DImpl.h @@ -0,0 +1,23 @@ +// PRIVATE HEADER FILE + +#ifndef POINT2DIMPL_H +#define POINT2DIMPL_H + +#include "Number.h" +#include "RGP.h" +#include "Point2D.h" +#include +#include +#include + +class Point2DImpl : public Point2D{ +private: + struct Point2DStruct + { + std::vector points; + }; + + Point2DStruct mystruct; +}; + +#endif //POINT2DIMPL_H \ No newline at end of file diff --git a/src/Point2D.cpp b/src/Point2D.cpp index 8b81f86..897ca5d 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -1,15 +1,25 @@ +// PRIVATE SOURCE FILE + #include "Point2D.h" +#include "Point2DImpl.h" + +//class Point2D::Point2DImpl {}; -class Point2D::Point2DImpl {}; +Point2D::Point2DStruct *getStruct() +{ + // return someObject->mystruct; +} Point2D::Point2D() { - // Emtpy + // Will NOT be used. Never create Point2D object without points. } Point2D::Point2D(std::vector listOfPoints) { - // Emtpy + // 1) Takes in listOfPoints + // 2) gets '.points' vector from struct (call *getStruct()) + // 3) re-assign struct vector to listOfPoints } Point2D::Point2D(std::ifstream& file) @@ -19,12 +29,13 @@ Point2D::Point2D(std::ifstream& file) Point2D::Point2D(std::string listOfPoint2DString) { - // Emtpy + // Takes in listOfPoint2DString and converts to vector + // and assigns vector to vector in struct } Point2D::~Point2D() { - // Emtpy + // Assign vector in struct = null } From a6172127f719f21358ff6490c15b3ab4c50a51f6 Mon Sep 17 00:00:00 2001 From: JasonCochran Date: Fri, 9 Nov 2018 18:28:37 -0500 Subject: [PATCH 05/95] Updates to readme for GMP... not fully working though --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index a172f37..d26a762 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,16 @@ Spatial database course extension to PostGRES Currently the build builds all the implementation files and builds postgres_ext.cpp file which includes all interfaces. ```bash +# Get the repo and setup GMP +git clone [URL] +cd PostGRES_ext +wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz +tar -xf gmp-6.1.2.tar.xz +cd gmp-6.1.2 +./configure +make +cd .. +# Build PostGRES_ext make clean make ./postgres_ext From bc0da8eba7275187c9b6ab7ac32305edc3439878 Mon Sep 17 00:00:00 2001 From: kotaprabhakar Date: Tue, 13 Nov 2018 01:10:42 -0500 Subject: [PATCH 06/95] RGPs --- include/RGPHalfSegment2D.h | 54 ++++++++++++++++++------------------ include/RGPPoint2D.h | 41 +++++++++++++--------------- include/RGPSegment2D.h | 43 ++++++++++++++--------------- src/RGPHalfSegment2D.cpp | 56 ++++++++++++++++++++++++++++++++++++-- src/RGPPoint2D.cpp | 42 +++++++++++++++++++++++----- src/RGPSegment2D.cpp | 29 ++++++++++++++++++-- 6 files changed, 179 insertions(+), 86 deletions(-) diff --git a/include/RGPHalfSegment2D.h b/include/RGPHalfSegment2D.h index b1953bf..7bfaa8f 100644 --- a/include/RGPHalfSegment2D.h +++ b/include/RGPHalfSegment2D.h @@ -4,46 +4,44 @@ #include "RGPPoint2D.h" #include "RGPSegment2D.h" -class RGPHalfSegment2D -{ +class RGPHalfSegment2D { public: + // Members - // Members + RGPSegment2D segment; + RGPPoint2D dominantPoint; + bool isLeftFlag; + Number m; // Slope - RGPSegment2D segment; - RGPPoint2D dominantPoint; + // Constructors - // Constructors + RGPHalfSegment2D(RGPSegment2D s, RGPPoint2D dp); + ~RGPHalfSegment2D(); - RGPHalfSegment2D(RGPSegment2D s, RGPPoint2D dp); - ~RGPHalfSegment2D(); - - // Methods - - bool operator==(const RGPHalfSegment2D &rhs); - bool operator!=(const RGPHalfSegment2D &rhs); - bool operator<(const RGPHalfSegment2D &rhs); - bool operator<=(const RGPHalfSegment2D &rhs); - bool operator>(const RGPHalfSegment2D &rhs); - bool operator>=(const RGPHalfSegment2D &rhs); + // Methods + bool operator==(const RGPHalfSegment2D &rhs); + bool operator!=(const RGPHalfSegment2D &rhs); + bool operator<(const RGPHalfSegment2D &rhs); + bool operator<=(const RGPHalfSegment2D &rhs); + bool operator>(const RGPHalfSegment2D &rhs); + bool operator>=(const RGPHalfSegment2D &rhs); + bool isLeft(); + Number sqLen() const; // Square of length }; -class RGPAnnotatedHalfSegment2D : public RGPHalfSegment2D -{ +class RGPAnnotatedHalfSegment2D : public RGPHalfSegment2D { public: + // Members - // Members - - bool insideIsAbove; - - // Constructors + bool insideIsAbove; - RGPAnnotatedHalfSegment2D(RGPSegment2D s, RGPPoint2D dp, bool regAbove); - ~RGPAnnotatedHalfSegment2D(); + // Constructors - // Methods + RGPAnnotatedHalfSegment2D(RGPSegment2D s, RGPPoint2D dp, bool regAbove); + ~RGPAnnotatedHalfSegment2D(); + // Methods }; -#endif //RGPHALFSEGMENT2D_H +#endif // RGPHALFSEGMENT2D_H diff --git a/include/RGPPoint2D.h b/include/RGPPoint2D.h index d14a787..3303df8 100644 --- a/include/RGPPoint2D.h +++ b/include/RGPPoint2D.h @@ -7,35 +7,32 @@ #include "Number.h" -class RGPPoint2D -{ +class RGPPoint2D { public: + // Members - // Members + Number x, y; - Number x, y; + // Constructors - // Constructors + RGPPoint2D(Number x, Number y); + ~RGPPoint2D(); - RGPPoint2D(Number x, Number y); - ~RGPPoint2D(); + // Methods - // Methods + bool operator==(const RGPPoint2D &rhs); + bool operator!=(const RGPPoint2D &rhs); + bool operator<(const RGPPoint2D &rhs); + bool operator<=(const RGPPoint2D &rhs); + bool operator>(const RGPPoint2D &rhs); + bool operator>=(const RGPPoint2D &rhs); - bool operator==(const RGPPoint2D &rhs); - bool operator!=(const RGPPoint2D &rhs); - bool operator<(const RGPPoint2D &rhs); - bool operator<=(const RGPPoint2D &rhs); - bool operator>(const RGPPoint2D &rhs); - bool operator>=(const RGPPoint2D &rhs); - - // Allows ouptut of an RGPPoint2D in the format of "(x,y)" - friend std::ostream& operator<<(std::ostream& os, const RGPPoint2D p); - - // Allows input of an RGPPoint2D in the format of "(x,y)" where ',' will be - // the delimiter between the x and y values - friend std::istream& operator>>(std::istream& is, const RGPPoint2D p); + // Allows ouptut of an RGPPoint2D in the format of "(x,y)" + friend std::ostream &operator<<(std::ostream &os, const RGPPoint2D p); + // Allows input of an RGPPoint2D in the format of "(x,y)" where ',' will be + // the delimiter between the x and y values + friend std::istream &operator>>(std::istream &is, RGPPoint2D p); }; -#endif //RGPPOINT2D_H +#endif // RGPPOINT2D_H diff --git a/include/RGPSegment2D.h b/include/RGPSegment2D.h index e378a0d..95ffac7 100644 --- a/include/RGPSegment2D.h +++ b/include/RGPSegment2D.h @@ -7,36 +7,33 @@ #include "RGPPoint2D.h" -class RGPSegment2D -{ +class RGPSegment2D { public: + // Members - // Members + RGPPoint2D point1, point2; - RGPPoint2D point1, point2; + // Constructors - // Constructors + RGPSegment2D(RGPPoint2D p1, RGPPoint2D p2); + ~RGPSegment2D(); - RGPSegment2D(RGPPoint2D p1, RGPPoint2D p2); - ~RGPSegment2D(); + // Methods - // Methods + bool operator==(const RGPSegment2D &rhs); + bool operator!=(const RGPSegment2D &rhs); + bool operator<(const RGPSegment2D &rhs); + bool operator<=(const RGPSegment2D &rhs); + bool operator>(const RGPSegment2D &rhs); + bool operator>=(const RGPSegment2D &rhs); - bool operator==(const RGPSegment2D &rhs); - bool operator!=(const RGPSegment2D &rhs); - bool operator<(const RGPSegment2D &rhs); - bool operator<=(const RGPSegment2D &rhs); - bool operator>(const RGPSegment2D &rhs); - bool operator>=(const RGPSegment2D &rhs); - - // Allows ouptut of an RGPSegment2D in the format of "(x1,y1),(x2,y2)" - friend std::ostream& operator<<(std::ostream& os, const RGPSegment2D p); - - // Allows input of an RGPSegment2D in the format of "(x1,y1),(x2,y2)" - // where ',' will be the delimiter between the x and y values of point1 - // and point2 - friend std::istream& operator>>(std::istream& is, const RGPSegment2D p); + // Allows ouptut of an RGPSegment2D in the format of "(x1,y1),(x2,y2)" + friend std::ostream &operator<<(std::ostream &os, const RGPSegment2D p); + // Allows input of an RGPSegment2D in the format of "(x1,y1),(x2,y2)" + // where ',' will be the delimiter between the x and y values of point1 + // and point2 + friend std::istream &operator>>(std::istream &is, const RGPSegment2D p); }; -#endif //RGPSEGMENT2D_H +#endif // RGPSEGMENT2D_H diff --git a/src/RGPHalfSegment2D.cpp b/src/RGPHalfSegment2D.cpp index 471d664..b04dd26 100644 --- a/src/RGPHalfSegment2D.cpp +++ b/src/RGPHalfSegment2D.cpp @@ -3,16 +3,66 @@ // RGPHalfSegment2D // Constructors -RGPHalfSegment2D::RGPHalfSegment2D(RGPSegment2D s, RGPPoint2D dp) : segment(s), dominantPoint(dp) {} +RGPHalfSegment2D::RGPHalfSegment2D(RGPSegment2D s, RGPPoint2D dp) + : segment(s), dominantPoint(dp) { + if (dp == s.point1) + isLeftFlag = true; + else + isLeftFlag = false; + m = (s.point2.y - s.point1.y) / (s.point2.x - s.point2.x); +} RGPHalfSegment2D::~RGPHalfSegment2D() {} +bool RGPHalfSegment2D::operator==(const RGPHalfSegment2D &rhs) { + if (segment == rhs.segment && dominantPoint == rhs.dominantPoint && + isLeftFlag == rhs.isLeftFlag) + return true; + else + return false; +} +bool RGPHalfSegment2D::operator!=(const RGPHalfSegment2D &rhs) { + return !((*this) == rhs); +} +bool RGPHalfSegment2D::operator<(const RGPHalfSegment2D &rhs) { + // TODO: When both half segments are collinear + if (dominantPoint < rhs.dominantPoint || + (dominantPoint == rhs.dominantPoint && isLeftFlag == false && + rhs.isLeftFlag == true) || + (dominantPoint == rhs.dominantPoint && isLeftFlag == rhs.isLeftFlag && + m < rhs.m) || + (dominantPoint == rhs.dominantPoint && isLeftFlag == rhs.isLeftFlag && + m == rhs.m && sqLen() < rhs.sqLen())) { + return true; + } else + return false; +} +bool RGPHalfSegment2D::operator<=(const RGPHalfSegment2D &rhs) { + return (*this) == rhs || (*this) < rhs; +} +bool RGPHalfSegment2D::operator>(const RGPHalfSegment2D &rhs) { + return !((*this) <= rhs); +} +bool RGPHalfSegment2D::operator>=(const RGPHalfSegment2D &rhs) { + return !((*this) < rhs); +} + +bool RGPHalfSegment2D::isLeft() { return isLeftFlag; } + +Number RGPHalfSegment2D::sqLen() const { + return (segment.point1.x - segment.point2.x) * + (segment.point1.x - segment.point2.x) + + (segment.point1.y - segment.point2.y) * + (segment.point1.y - segment.point2.y); +} // RGPAnnotatedHalfSegment2D // Constructors RGPAnnotatedHalfSegment2D::RGPAnnotatedHalfSegment2D(RGPSegment2D s, - RGPPoint2D dp, bool regAbove) : RGPHalfSegment2D::RGPHalfSegment2D(s, dp) { - this->insideIsAbove = regAbove; + RGPPoint2D dp, + bool regAbove) + : RGPHalfSegment2D::RGPHalfSegment2D(s, dp) { + this->insideIsAbove = regAbove; } RGPAnnotatedHalfSegment2D::~RGPAnnotatedHalfSegment2D() {} diff --git a/src/RGPPoint2D.cpp b/src/RGPPoint2D.cpp index 95dd799..2d94b6a 100644 --- a/src/RGPPoint2D.cpp +++ b/src/RGPPoint2D.cpp @@ -2,14 +2,42 @@ // Constructors -RGPPoint2D::RGPPoint2D(Number x, Number y) : y(x), x(y) {} +RGPPoint2D::RGPPoint2D(Number x, Number y) : x(x), y(y) {} RGPPoint2D::~RGPPoint2D() {} // Methods -bool RGPPoint2D::operator==(const RGPPoint2D &rhs) {} -bool RGPPoint2D::operator!=(const RGPPoint2D &rhs) {} -bool RGPPoint2D::operator<(const RGPPoint2D &rhs) {} -bool RGPPoint2D::operator<=(const RGPPoint2D &rhs) {} -bool RGPPoint2D::operator>(const RGPPoint2D &rhs) {} -bool RGPPoint2D::operator>=(const RGPPoint2D &rhs) {} +bool RGPPoint2D::operator==(const RGPPoint2D &rhs) { + if (x == rhs.x && y == rhs.y) + return true; + else + return false; +} +bool RGPPoint2D::operator!=(const RGPPoint2D &rhs) { return !((*this) == rhs); } +bool RGPPoint2D::operator<(const RGPPoint2D &rhs) { + if (x < rhs.x || (x == rhs.x && y < rhs.y)) + return true; + else + return false; +} +bool RGPPoint2D::operator<=(const RGPPoint2D &rhs) { + return (*this) < rhs || (*this) == rhs; +} +bool RGPPoint2D::operator>(const RGPPoint2D &rhs) { return !((*this) <= rhs); } +bool RGPPoint2D::operator>=(const RGPPoint2D &rhs) { return !((*this) < rhs); } + +std::ostream &operator<<(std::ostream &os, const RGPPoint2D p) { + os << "(" << p.x << "," << p.y << ")"; + return os; +} + +std::istream &operator>>(std::istream &is, RGPPoint2D p) { + // TODO: Check for invalid conditions + char c; + is >> c; + is >> p.x; + is >> c; + is >> p.y; + is >> c; + return is; +} \ No newline at end of file diff --git a/src/RGPSegment2D.cpp b/src/RGPSegment2D.cpp index ca79255..ceae00c 100644 --- a/src/RGPSegment2D.cpp +++ b/src/RGPSegment2D.cpp @@ -2,14 +2,37 @@ // Constructors -RGPSegment2D::RGPSegment2D(RGPPoint2D p1, RGPPoint2D p2) : point1(p1), point2(p2) {} +RGPSegment2D::RGPSegment2D(RGPPoint2D p1, RGPPoint2D p2) + : point1(p1 < p2 ? p1 : p2), point2(p1 < p2 ? p2 : p1) {} RGPSegment2D::~RGPSegment2D() {} // Methods -bool RGPSegment2D::operator==(const RGPSegment2D &rhs) {} -bool RGPSegment2D::operator!=(const RGPSegment2D &rhs) {} +bool RGPSegment2D::operator==(const RGPSegment2D &rhs) { + if (point1 == rhs.point1 && point2 == rhs.point2) + return true; + else + return false; +} +bool RGPSegment2D::operator!=(const RGPSegment2D &rhs) { + if (point1 == rhs.point1 && point2 == rhs.point2) + return false; + else + return true; +} bool RGPSegment2D::operator<(const RGPSegment2D &rhs) {} bool RGPSegment2D::operator<=(const RGPSegment2D &rhs) {} bool RGPSegment2D::operator>(const RGPSegment2D &rhs) {} bool RGPSegment2D::operator>=(const RGPSegment2D &rhs) {} + +std::ostream &operator<<(std::ostream &os, const RGPSegment2D p) { + os << p.point1 << "," << p.point2; + return os; +} + +std::istream &operator>>(std::istream &is, const RGPSegment2D p) { + // TODO: Check for invalid conditions + char c; + is >> p.point1 >> c >> p.point2; + return is; +} From 163328f431e6790d0dceaf24d21faaaf9e5d5139 Mon Sep 17 00:00:00 2001 From: kotaprabhakar Date: Tue, 13 Nov 2018 01:15:11 -0500 Subject: [PATCH 07/95] Removed comment --- src/RGPHalfSegment2D.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RGPHalfSegment2D.cpp b/src/RGPHalfSegment2D.cpp index b04dd26..361ca89 100644 --- a/src/RGPHalfSegment2D.cpp +++ b/src/RGPHalfSegment2D.cpp @@ -24,7 +24,6 @@ bool RGPHalfSegment2D::operator!=(const RGPHalfSegment2D &rhs) { return !((*this) == rhs); } bool RGPHalfSegment2D::operator<(const RGPHalfSegment2D &rhs) { - // TODO: When both half segments are collinear if (dominantPoint < rhs.dominantPoint || (dominantPoint == rhs.dominantPoint && isLeftFlag == false && rhs.isLeftFlag == true) || From 6d72bbf670bd6f9927a12d663f8866e2bd907dc2 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Sun, 18 Nov 2018 01:37:58 -0500 Subject: [PATCH 08/95] Added Line2D files --- include/Line2D.h | 7 +- include/Line2DForProgrammer.h | 35 +++++++ src/Line2D.cpp | 56 +++++++---- src/Line2DForProgrammer.cpp | 181 ++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 26 deletions(-) create mode 100644 include/Line2DForProgrammer.h create mode 100644 src/Line2DForProgrammer.cpp diff --git a/include/Line2D.h b/include/Line2D.h index 49ba4b2..a88f9a9 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -9,7 +9,6 @@ class Line2D{ public: // Constructors - Line2D(); Line2D(std::vector listOfSegments); Line2D(std::string listOfLine2DString); Line2D(std::ifstream& file); // Send in file for constructor @@ -29,10 +28,8 @@ class Line2D{ RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index private: - class Line2DImpl; - - // Fields - Line2DImpl *impl; + struct Line2DUserStore; + Line2DUserStore *impl; }; #endif //LINE2D diff --git a/include/Line2DForProgrammer.h b/include/Line2DForProgrammer.h new file mode 100644 index 0000000..75b56a3 --- /dev/null +++ b/include/Line2DForProgrammer.h @@ -0,0 +1,35 @@ +#ifndef LINE2DFORPROGRAMMER_H +#define LINE2DFORPROGRAMMER_H + +#include "Number.h" +#include "RGP.h" +#include +#include + +class Line2DForProgrammer{ +public: + // Constructors + Line2DForProgrammer(std::vector listOfSegments); + Line2DForProgrammer(std::string listOfLine2DString); + Line2DForProgrammer(std::ifstream& file); // Send in file for constructor + ~Line2DForProgrammer(); + + // Methods + std::string getLineString(); // Get the line as human readable ASCII string + static bool isEmptyLine(); + static bool isValidLine(); + int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed + std::vector getBoundingBox(); + bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds + bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(int index, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(int index); // Removes a RGPSegment2D at specified index + RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index + +private: + struct Line2DImplStore; + Line2DImplStore *impl; +}; + +#endif //LINE2D \ No newline at end of file diff --git a/src/Line2D.cpp b/src/Line2D.cpp index b4add0a..c705f1f 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -1,81 +1,95 @@ #include "Line2D.h" +#include "Line2DForProgrammer.h" -class Line2D::Line2DImpl {}; +struct Line2D::Line2DUserStore { + Line2DForProgrammer *poi; -Line2D::Line2D() -{ - // Emtpy -} + Line2DUserStore(std::vector listOfSegments) { + poi = new Line2DForProgrammer(listOfSegments); + } + + Line2DUserStore(std::string listOfLine2DString) { + poi = new Line2DForProgrammer(listOfLine2DString); + } + + Line2DUserStore(std::ifstream& file) { + poi = new Line2DForProgrammer(file); + } + + ~Line2DUserStore() + { + poi = nullptr; + } +}; Line2D::Line2D(std::vector listOfSegments) { - // Emtpy + impl = new Line2DUserStore(listOfSegments); } Line2D::Line2D(std::string listOfLine2DString) { - // Emtpy + impl = new Line2DUserStore(listOfLine2DString); } Line2D::Line2D(std::ifstream& file) // Send in file for constructor { - // Emtpy + impl = new Line2DUserStore(file); } Line2D::~Line2D() { - // Emtpy + impl = nullptr; } - // Methods std::string Line2D::getLineString() // Get the line as human readable ASCII string { - // Emtpy + return impl->poi->getLineString(); } // static bool Line2D::isEmptyLine() { - // Emtpy + return impl->poi->isEmptyLine(); } int Line2D::Line2D::getNumberOfSegments() { - // Emtpy + return impl->poi->getNumberOfSegments(); } std::vector Line2D::getBoundingBox() { - // Emtpy + return impl->poi->getBoundingBox(); } bool Line2D::add(RGPSegment2D rgp2d) { - // Emtpy + return impl->poi->add(rgp2d); } bool Line2D::remove(int index) { - // Emtpy + return impl->poi->remove(index); } bool update(int index, RGPSegment2D rgps2d) { - // Emtpy + return impl->poi->update(index, rgps2d); } bool Line2D::operator==(const Line2D &l2d) { - // Emtpy + return impl->poi->operator==(&l2d); } bool Line2D::operator!=(const Line2D &l2d) { - // Emtpy + return impl->poi->operator!=(&l2d); } RGPSegment2D Line2D::operator[](int index) { - // Emtpy -} + return impl->poi->operator[](index); +} \ No newline at end of file diff --git a/src/Line2DForProgrammer.cpp b/src/Line2DForProgrammer.cpp new file mode 100644 index 0000000..6bb17d4 --- /dev/null +++ b/src/Line2DForProgrammer.cpp @@ -0,0 +1,181 @@ +#include "Line2D.h" +#include "Line2DForProgrammer.h" +#include + +struct Line2DForProgrammer::Line2DImplStore { + // data + std::vector vectorOfSegments; + + // constructors + Line2DImplStore(std::vector listOfSegments) + { + vectorOfSegments = listOfSegments; + } + + Line2DImplStore(std::string listOfLine2DString) + { + //TODO + vectorOfSegments = parseStringToVectorOfLines(listOfLine2DString); + } + + Line2DImplStore(std::ifstream& file) + { + std::string inputString; + if(file.is_open()) + { + std::stringstream strBuffer; + strBuffer << file.rdbuf(); + inputString = strBuffer; + } + else + { + throw std::exception("Error while reading the file"); + } + + //TODO + vectorOfSegments = parseStringToVectorOfLines(inputString); + } +}; + +Line2DForProgrammer::Line2DForProgrammer(std::vector listOfSegments) +{ + impl = new Line2DImplStore(listOfSegments); +} + +Line2DForProgrammer::Line2DForProgrammer(std::string listOfLine2DString) +{ + impl = new Line2DImplStore(listOfLine2DString); +} + +Line2DForProgrammer::Line2DForProgrammer(std::ifstream& file) // Send in file for constructor +{ + impl = new Line2DImplStore(file); +} + +Line2DForProgrammer::~Line2DForProgrammer() +{ + impl = nullptr; +} + +// Methods +std::string Line2DForProgrammer::getLineString() // Get the line as human readable ASCII string +{ + std::string resultString; + if(!isEmptyPoint()) + { + resultString += "("; + for (RGPHalfSegment2D rgpLine : impl->vectorOfSegments) + { + std::ostringstream stream; + stream << rgpLine; + std::string str = stream.str(); + + resultString += str; + resultString += ","; + } + resultString += ")"; + } + + return resultString; +} + +// static +bool Line2DForProgrammer::isEmptyLine() +{ + return impl->vectorOfSegments.empty(); +} + +int Line2DForProgrammer::Line2DForProgrammer::getNumberOfSegments() +{ + return impl->vectorOfSegments.size(); +} + +std::vector Line2DForProgrammer::getBoundingBox() +{ + //TODO + //Call convex hull implementation + + return NULL; +} + +bool Line2DForProgrammer::add(RGPSegment2D rgp2d) +{ + try + { + int i = 0; + while(rgp2d > impl->vectorOfSegments[i]) + i++; + impl->vectorOfSegments.insert(impl->vectorOfSegments.begin()+i, rgp2d) + } + catch(exception& e) + { + return false; + } + return true; +} + +bool Line2DForProgrammer::remove(int index) +{ + try + { + impl->vectorOfSegments.erase(index); + } + catch(exception& e) + { + return false; + } + return true; +} + +bool update(int index, RGPSegment2D rgps2d) +{ + try + { + vectorOfSegments.erase(index); + add(rgps2d); + } + catch(exception& e) + { + return false; + } + return true; +} + +bool Line2DForProgrammer::operator==(const Line2D &l2d) +{ + int i = 0; + if(impl->vectorOfSegments.size() != l2d->poi->impl->vectorOfSegments.size()){ + return false; + } + + while(i < l2d->poi->impl->vectorOfSegments.size()) + { + if(impl->vectorOfSegments[i] != l2d->poi->impl->vectorOfSegments[i]) + return false; + else + i++; + } + return true; +} + +bool Line2DForProgrammer::operator!=(const Line2D &l2d) +{ + int i = 0; + if(impl->vectorOfSegments.size() != l2d->poi->impl->vectorOfSegments.size()){ + return true; + } + + while(i < l2d->poi->impl->vectorOfSegments.size()) + { + if(impl->vectorOfSegments[i] != l2d->poi->impl->vectorOfSegments[i]) + return true; + else + i++; + } + return false; +} + +RGPSegment2D Line2DForProgrammer::operator[](int index) +{ + return impl->vectorOfSegments[index]; +} From 8435ced14b97fdb2543d04721718e432f23a727a Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:36 -0500 Subject: [PATCH 09/95] Update Point2D.h --- include/Point2D.h | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/include/Point2D.h b/include/Point2D.h index bda2895..e5501a4 100644 --- a/include/Point2D.h +++ b/include/Point2D.h @@ -11,33 +11,25 @@ class Point2D{ public: - // Fields - // Constructors - Point2D(); - Point2D(std::vector listOfPoints); // Create the Point2D as a vector of RGPPoint2Ds Point2D(std::ifstream& file); // Take input from a file, convert the data into a Point2D Point2D(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D ~Point2D(); // Methods std::string getPointString(); // Get the point as human readable ASCII string - static bool isEmptyPoint(); // Checks if the Point2D object is empty - static bool isValidPoint(); // Checks if the Point2D object is empty + bool isEmptyPoint(); // Checks if the Point2D object is empty + bool isValidPoint(); // Checks if the Point2D object is empty + int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + bool operator==(const Point2D &p2d); // Override of operator == to check equality of two Point2Ds bool operator!=(const Point2D &p2d); // Override of operator != to check inequality of two Point2Ds - int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + std::vector getBoundingBox(); - bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object - bool update(int index, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index - bool remove(int index); // Removes a RGPPoint2D at specified index - RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index - - struct Point2DStruct; - Point2DStruct *getStruct(); - - // Fields - Point2DStruct *impl; + +private: + struct Point2DStore; + Point2DStore *handle; }; #endif //POINT2D_H From 3931cf29086427dab0c209787cfd5bb1c3438c7c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:40 -0500 Subject: [PATCH 10/95] Create Point2DForProgrammer.h --- include/Point2DForProgrammer.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 include/Point2DForProgrammer.h diff --git a/include/Point2DForProgrammer.h b/include/Point2DForProgrammer.h new file mode 100644 index 0000000..c802873 --- /dev/null +++ b/include/Point2DForProgrammer.h @@ -0,0 +1,30 @@ +// PUBLIC HEADER FILE + +#ifndef POINT2DFORPROGRAMMER_H +#define POINT2DFORPROGRAMMER_H + +#include "Number.h" +#include "RGP.h" +#include +#include +#include + +class Point2DForProgrammer{ +public: + // Constructors + Point2DForProgrammer(std::ifstream& file); // Take input from a file, convert the data into a Point2DForProgrammer + Point2DForProgrammer(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2DForProgrammer + ~Point2DForProgrammer(); + + // Methods + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2DForProgrammer object + bool update(int index, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(int index); // Removes a RGPPoint2D at specified index + //RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index + +private: + struct Point2DProgrammerStore; + Point2DProgrammerStore *handle; +}; + +#endif //POINT2D_H From a56bc33c501b97eea1b551929909769c81796706 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:43 -0500 Subject: [PATCH 11/95] Update Point2DImpl.h --- include/Point2DImpl.h | 47 +++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h index f953e59..60ad66f 100644 --- a/include/Point2DImpl.h +++ b/include/Point2DImpl.h @@ -1,23 +1,40 @@ -// PRIVATE HEADER FILE - #ifndef POINT2DIMPL_H #define POINT2DIMPL_H -#include "Number.h" -#include "RGP.h" -#include "Point2D.h" -#include #include -#include +#include "RGPPoint2D.h" +#include "RGPSegment2D.h" + +class Point2DImpl +{ + public: + Point2DImpl(std::vector pointVector); + Point2DImpl(std::ifstream& file); // Take input from a file, convert the data into a Point2D + Point2DImpl(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D + ~Point2DImpl(); + + // Methods + std::string getPointString(); // Get the point as human readable ASCII string + bool isEmptyPoint(); // Checks if the Point2D object is empty + bool isValidPoint(); // Checks if the Point2D object is empty + int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + std::vector getBoundingBox(); + + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object + bool update(std::vector::iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(std::vector::iterator it); // Removes a RGPPoint2D at specified index -class Point2DImpl : public Point2D{ -private: - struct Point2DStruct - { - std::vector points; - }; + bool operator==(const Point2DImpl &p2d); // Override of operator == to check equality of two Point2Ds + bool operator!=(const Point2DImpl &p2d); // Override of operator != to check inequality of two Point2Ds + RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index + //Point2DImpl operator=(const Point2DImpl &p2dImpl) - Point2DStruct mystruct; + private: + struct Point2DImplStore; + Point2DImplStore *handle; + void pointSort(std::vector &bar); + void mergeSort(std::vector &left, std::vector &right, std::vector &bars); + bool parseStringToVectorOfPoints(std::string st); }; -#endif //POINT2DIMPL_H \ No newline at end of file +#endif //POINT2DIMPL_H From 413c4aad50c4ab044f20b6a4a450b11543327666 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:46 -0500 Subject: [PATCH 12/95] Delete Line2D.cpp --- src/Line2D.cpp | 95 -------------------------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 src/Line2D.cpp diff --git a/src/Line2D.cpp b/src/Line2D.cpp deleted file mode 100644 index c705f1f..0000000 --- a/src/Line2D.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "Line2D.h" -#include "Line2DForProgrammer.h" - -struct Line2D::Line2DUserStore { - Line2DForProgrammer *poi; - - Line2DUserStore(std::vector listOfSegments) { - poi = new Line2DForProgrammer(listOfSegments); - } - - Line2DUserStore(std::string listOfLine2DString) { - poi = new Line2DForProgrammer(listOfLine2DString); - } - - Line2DUserStore(std::ifstream& file) { - poi = new Line2DForProgrammer(file); - } - - ~Line2DUserStore() - { - poi = nullptr; - } -}; - -Line2D::Line2D(std::vector listOfSegments) -{ - impl = new Line2DUserStore(listOfSegments); -} - -Line2D::Line2D(std::string listOfLine2DString) -{ - impl = new Line2DUserStore(listOfLine2DString); -} - -Line2D::Line2D(std::ifstream& file) // Send in file for constructor -{ - impl = new Line2DUserStore(file); -} - -Line2D::~Line2D() -{ - impl = nullptr; -} - -// Methods -std::string Line2D::getLineString() // Get the line as human readable ASCII string -{ - return impl->poi->getLineString(); -} - -// static -bool Line2D::isEmptyLine() -{ - return impl->poi->isEmptyLine(); -} - -int Line2D::Line2D::getNumberOfSegments() -{ - return impl->poi->getNumberOfSegments(); -} - -std::vector Line2D::getBoundingBox() -{ - return impl->poi->getBoundingBox(); -} - -bool Line2D::add(RGPSegment2D rgp2d) -{ - return impl->poi->add(rgp2d); -} - -bool Line2D::remove(int index) -{ - return impl->poi->remove(index); -} - -bool update(int index, RGPSegment2D rgps2d) -{ - return impl->poi->update(index, rgps2d); -} - -bool Line2D::operator==(const Line2D &l2d) -{ - return impl->poi->operator==(&l2d); -} - -bool Line2D::operator!=(const Line2D &l2d) -{ - return impl->poi->operator!=(&l2d); -} - -RGPSegment2D Line2D::operator[](int index) -{ - return impl->poi->operator[](index); -} \ No newline at end of file From f34256c780ae6491c4d6365dcd26f06b916f6838 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:50 -0500 Subject: [PATCH 13/95] Delete Line2DForProgrammer.cpp --- src/Line2DForProgrammer.cpp | 181 ------------------------------------ 1 file changed, 181 deletions(-) delete mode 100644 src/Line2DForProgrammer.cpp diff --git a/src/Line2DForProgrammer.cpp b/src/Line2DForProgrammer.cpp deleted file mode 100644 index 6bb17d4..0000000 --- a/src/Line2DForProgrammer.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "Line2D.h" -#include "Line2DForProgrammer.h" -#include - -struct Line2DForProgrammer::Line2DImplStore { - // data - std::vector vectorOfSegments; - - // constructors - Line2DImplStore(std::vector listOfSegments) - { - vectorOfSegments = listOfSegments; - } - - Line2DImplStore(std::string listOfLine2DString) - { - //TODO - vectorOfSegments = parseStringToVectorOfLines(listOfLine2DString); - } - - Line2DImplStore(std::ifstream& file) - { - std::string inputString; - if(file.is_open()) - { - std::stringstream strBuffer; - strBuffer << file.rdbuf(); - inputString = strBuffer; - } - else - { - throw std::exception("Error while reading the file"); - } - - //TODO - vectorOfSegments = parseStringToVectorOfLines(inputString); - } -}; - -Line2DForProgrammer::Line2DForProgrammer(std::vector listOfSegments) -{ - impl = new Line2DImplStore(listOfSegments); -} - -Line2DForProgrammer::Line2DForProgrammer(std::string listOfLine2DString) -{ - impl = new Line2DImplStore(listOfLine2DString); -} - -Line2DForProgrammer::Line2DForProgrammer(std::ifstream& file) // Send in file for constructor -{ - impl = new Line2DImplStore(file); -} - -Line2DForProgrammer::~Line2DForProgrammer() -{ - impl = nullptr; -} - -// Methods -std::string Line2DForProgrammer::getLineString() // Get the line as human readable ASCII string -{ - std::string resultString; - if(!isEmptyPoint()) - { - resultString += "("; - for (RGPHalfSegment2D rgpLine : impl->vectorOfSegments) - { - std::ostringstream stream; - stream << rgpLine; - std::string str = stream.str(); - - resultString += str; - resultString += ","; - } - resultString += ")"; - } - - return resultString; -} - -// static -bool Line2DForProgrammer::isEmptyLine() -{ - return impl->vectorOfSegments.empty(); -} - -int Line2DForProgrammer::Line2DForProgrammer::getNumberOfSegments() -{ - return impl->vectorOfSegments.size(); -} - -std::vector Line2DForProgrammer::getBoundingBox() -{ - //TODO - //Call convex hull implementation - - return NULL; -} - -bool Line2DForProgrammer::add(RGPSegment2D rgp2d) -{ - try - { - int i = 0; - while(rgp2d > impl->vectorOfSegments[i]) - i++; - impl->vectorOfSegments.insert(impl->vectorOfSegments.begin()+i, rgp2d) - } - catch(exception& e) - { - return false; - } - return true; -} - -bool Line2DForProgrammer::remove(int index) -{ - try - { - impl->vectorOfSegments.erase(index); - } - catch(exception& e) - { - return false; - } - return true; -} - -bool update(int index, RGPSegment2D rgps2d) -{ - try - { - vectorOfSegments.erase(index); - add(rgps2d); - } - catch(exception& e) - { - return false; - } - return true; -} - -bool Line2DForProgrammer::operator==(const Line2D &l2d) -{ - int i = 0; - if(impl->vectorOfSegments.size() != l2d->poi->impl->vectorOfSegments.size()){ - return false; - } - - while(i < l2d->poi->impl->vectorOfSegments.size()) - { - if(impl->vectorOfSegments[i] != l2d->poi->impl->vectorOfSegments[i]) - return false; - else - i++; - } - return true; -} - -bool Line2DForProgrammer::operator!=(const Line2D &l2d) -{ - int i = 0; - if(impl->vectorOfSegments.size() != l2d->poi->impl->vectorOfSegments.size()){ - return true; - } - - while(i < l2d->poi->impl->vectorOfSegments.size()) - { - if(impl->vectorOfSegments[i] != l2d->poi->impl->vectorOfSegments[i]) - return true; - else - i++; - } - return false; -} - -RGPSegment2D Line2DForProgrammer::operator[](int index) -{ - return impl->vectorOfSegments[index]; -} From cdb166e294154a3b901512c4a0fdcd1beb6f5b6c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:53 -0500 Subject: [PATCH 14/95] Update Point2D.cpp --- src/Point2D.cpp | 76 ++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index 897ca5d..bc5f824 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -1,91 +1,69 @@ -// PRIVATE SOURCE FILE - #include "Point2D.h" #include "Point2DImpl.h" -//class Point2D::Point2DImpl {}; - -Point2D::Point2DStruct *getStruct() +struct Point2D::Point2DStore { - // return someObject->mystruct; -} + Point2DImpl *implPointer; -Point2D::Point2D() -{ - // Will NOT be used. Never create Point2D object without points. -} + Point2DStore(std::string pointsString) + { + implPointer = new Point2DImpl(pointsString); + } -Point2D::Point2D(std::vector listOfPoints) -{ - // 1) Takes in listOfPoints - // 2) gets '.points' vector from struct (call *getStruct()) - // 3) re-assign struct vector to listOfPoints -} + Point2DStore(std::ifstream& file) + { + implPointer = new Point2DImpl(file); + } +}; Point2D::Point2D(std::ifstream& file) { - // Emtpy + handle = new Point2DStore(file); } Point2D::Point2D(std::string listOfPoint2DString) { - // Takes in listOfPoint2DString and converts to vector - // and assigns vector to vector in struct + handle = new Point2DStore(listOfPoint2DString); } Point2D::~Point2D() { - // Assign vector in struct = null + delete handle->implPointer; + delete handle; } -std::string getPointString() // Get the point as human readable ASCII string +std::string Point2D::getPointString() { - // Emtpy + return handle->implPointer->getPointString(); } -// static bool Point2D::isEmptyPoint() { - // Emtpy -} - -bool Point2D::operator==(const Point2D &p2d) -{ - // Emtpy + return handle->implPointer->isEmptyPoint(); } -bool Point2D::operator!=(const Point2D &p2d) -{ - // Emtpy -} - -RGPPoint2D Point2D::operator[](int index) +bool Point2D::isValidPoint() { - // Emtpy + return handle->implPointer->isValidPoint(); } int Point2D::getNumberOfPoints() { - // Emtpy + return handle->implPointer->getNumberOfPoints(); } -std::vector Point2D::getBoundingBox() -{ - // Emtpy -} - -bool Point2D::add(RGPPoint2D rgpp2d) +bool Point2D::operator==(const Point2D &p2d) { - // Emtpy + //TODO } -bool Point2D::update(int index, RGPPoint2D rgpp2d) +bool Point2D::operator!=(const Point2D &p2d) { - // Emtpy + //TODO } -bool Point2D::remove(int index) +std::vector Point2D::getBoundingBox() { - // Emtpy + return handle->implPointer->getBoundingBox(); } From 91b07dd4fca772b43af8041774da99883e5c0918 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:56 -0500 Subject: [PATCH 15/95] Create Point2DForProgrammer.cpp --- src/Point2DForProgrammer.cpp | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/Point2DForProgrammer.cpp diff --git a/src/Point2DForProgrammer.cpp b/src/Point2DForProgrammer.cpp new file mode 100644 index 0000000..70537eb --- /dev/null +++ b/src/Point2DForProgrammer.cpp @@ -0,0 +1,51 @@ +#include "Point2DForProgrammer.h" +#include "Point2DImpl.h" + +struct Point2DForProgrammer::Point2DProgrammerStore +{ + Point2DImpl *implPointer; + + Point2DProgrammerStore(std::string pointsString) + { + implPointer = new Point2DImpl(pointsString); + } + + Point2DProgrammerStore(std::ifstream& file) + { + implPointer = new Point2DImpl(file); + } +}; + +Point2DForProgrammer::Point2DForProgrammer(std::ifstream& file) +{ + handle = new Point2DProgrammerStore(file); +} + +Point2DForProgrammer::Point2DForProgrammer(std::string listOfPoint2DString) +{ + handle = new Point2DProgrammerStore(listOfPoint2DString); +} + +Point2DForProgrammer::~Point2DForProgrammer() +{ + delete handle->implPointer; + delete handle; +} + +// Adds a new RGPPoint2D to the existing Point2D object +bool Point2DForProgrammer::add(RGPPoint2D rgpp2d) +{ + //TODO +} + +// Updates RGPPoint2D existing at specified index +bool Point2DForProgrammer::update(int index, RGPPoint2D rgpp2d) +{ + //TODO +} + +// Removes a RGPPoint2D at specified index +bool Point2DForProgrammer::remove(int index) +{ + //TODO +} From 7c568f5cbc6918c0e1198615a3e6fe9e4f0e143f Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Mon, 19 Nov 2018 23:01:59 -0500 Subject: [PATCH 16/95] Create Point2DImpl.cpp --- src/Point2DImpl.cpp | 297 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 src/Point2DImpl.cpp diff --git a/src/Point2DImpl.cpp b/src/Point2DImpl.cpp new file mode 100644 index 0000000..1d71955 --- /dev/null +++ b/src/Point2DImpl.cpp @@ -0,0 +1,297 @@ +#include "Point2DImpl.h" +#include "RGPPoint2D.h" +#include"Number.h" + +struct Point2DImpl::Point2DImplStore +{ + std::vector vectorOfPoints; +}; + +//Constructors +Point2DImpl::Point2DImpl(std::vector listOfPoints) +{ + handle = new Point2DImplStore; + handle->vectorOfPoints = listOfPoints; +} + +Point2DImpl::Point2DImpl(std::ifstream& file) +{ + /*std::string inputString; + if(file.is_open()) + { + std::stringstream strBuffer; + strBuffer << file.rdbuf(); + inputString = strBuffer; + } + else + { + throw std::exception("Error while reading the file"); + } + + //TODO + vectorOfPoints = parseStringToVectorOfPoints(inputString); + */ +} + +Point2DImpl::Point2DImpl(std::string listOfPoint2DString) +{ + //TODO + std::cout<< "inside" << "\n"; + parseStringToVectorOfPoints(listOfPoint2DString); +} + +Point2DImpl::~Point2DImpl() +{ + //TODO + //default; +} + +bool Point2DImpl::isEmptyPoint() +{ + return handle->vectorOfPoints.empty(); +} + +// Get the point as human readable ASCII string +std::string Point2DImpl::getPointString() +{ + std::string resultString = "test"; + /* + bool p = isEmptyPoint(); + if(p==false) + { + resultString += "("; + for (RGPPoint2D rgpPoint : vectorOfPoints) + { + std::ostringstream stream; + stream << rgpPoint; + std::string str = stream.str(); + + resultString += str; + resultString += ","; + } + resultString += ")"; + } + */ + return resultString; +} + + +bool Point2DImpl::isValidPoint() +{ + bool validity = false; + if(!handle->vectorOfPoints.empty()) + { + //Check for validity + //TODO + } + + return validity; +} + +int Point2DImpl::getNumberOfPoints() +{ + return handle->vectorOfPoints.size(); +} + +std::vector Point2DImpl::getBoundingBox() +{ + //TODO + //Call convex hull implementation + + //return NULL; +} + +bool Point2DImpl::operator==(const Point2DImpl &p2d) +{ + int i=0; + while(i< p2d.handle->vectorOfPoints.size()) + { + if(handle->vectorOfPoints[i] != p2d.handle->vectorOfPoints[i]) + return false; + else + i++; + } + if(handle->vectorOfPoints.size() == p2d.handle->vectorOfPoints.size()) + return true; + else + return false; +} + +bool Point2DImpl::operator!=(const Point2DImpl &p2d) +{ + int i=0; + if(handle->vectorOfPoints.size() != p2d.handle->vectorOfPoints.size()) + return true; + while(i< p2d.handle->vectorOfPoints.size()) + { + if(handle->vectorOfPoints[i] != p2d.handle->vectorOfPoints[i]) + return true; + else + i++; + } + return false; +} + +RGPPoint2D Point2DImpl::operator[](int index) +{ + return handle->vectorOfPoints[index]; +} +/* +Point2DImpl Point2DImpl::operator=(const Point2D &p2d) +{ + // Emtpy +}*/ + +bool Point2DImpl::add(RGPPoint2D rgpp2d) +{ + try + { + if(handle->vectorOfPoints.empty()) { + handle->vectorOfPoints.push_back(rgpp2d); + } + + int i=0; + while(rgpp2d > handle->vectorOfPoints[i]) + i++; + handle->vectorOfPoints.insert(handle->vectorOfPoints.begin()+i, rgpp2d); + } + catch(int e) + { + return false; + } + return true; +} + +bool Point2DImpl::update(std::vector::iterator it, RGPPoint2D rgpp2d) +{ + try + { + int index = distance(handle->vectorOfPoints.begin(), it); + handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); + add(rgpp2d); + } + catch(int e) + { + return false; + } + return true; +} + +bool Point2DImpl::remove(std::vector::iterator it) +{ + try + { + int index = distance(handle->vectorOfPoints.begin(), it); + handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); + } + catch(int e) + { + return false; + } + return true; +} + + +void Point2DImpl::pointSort(std::vector &bar) +{ + if (bar.size() <= 1) + return; + + int mid = bar.size() / 2; + std::vector l; + std::vector r; + + for (size_t j = 0; j < mid;j++) + l.push_back(bar[j]); + for (size_t j = 0; j < (bar.size()) - mid; j++) + r.push_back(bar[mid + j]); + + pointSort(l); + pointSort(r); + mergeSort(l, r, bar); +} + + +void Point2DImpl::mergeSort(std::vector &left, std::vector &right, std::vector &bars) +{ + int nL = left.size(); + int nR = right.size(); + int i = 0, j = 0, k = 0; + + while (j < nL && k < nR) + { + if (left[j] <= + right[k]) { + bars[i] = left[j]; + j++; + } + else { + bars[i] = right[k]; + k++; + } + i++; + } + while (j < nL) { + bars[i] = left[j]; + j++; i++; + } + while (k < nR) { + bars[i] = right[k]; + k++; i++; + } +} + +bool Point2DImpl::parseStringToVectorOfPoints(std::string st) +{ + int pos; + std::string num1; + std::string s =st; + std::string delimeter = ","; + s.erase(0,1); + s.erase(s.length()-1,1); + std::cout << s << "\n"; + pos = s.find(delimeter); + std::cout << pos << "\n"; + try{ + while(pos!= std::string::npos) + { + std::string a = s.substr(0, pos); + std::cout << a << "\n"; + if(a.length()==2) + { + try + { + if(a[0]=='(') + { + num1 = a[1]; + } + else if(a[1]==')') + { + std::string temp = a[0]+""; + std::cout << temp << "\t" << num1 << "\n"; + Number q(temp); + Number p(num1); + RGPPoint2D poi(p,q); + add(poi); + } + else + return false; + } + catch(int e){ + return false; + } + } + else + { + return false; + } + s.erase(0, pos + delimeter.length()); + pos = s.find(delimeter); + + } + } + catch(int e){ + return false; + + } +} \ No newline at end of file From 99205df136f9c6cafee0eaf4e1c6e4fa80d26aa0 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Tue, 20 Nov 2018 03:41:12 -0500 Subject: [PATCH 17/95] All Line2D header files added --- include/Line2D.h | 13 ++++------- include/Line2DForProgrammer.h | 21 ++++++----------- include/Line2DImpl.h | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 include/Line2DImpl.h diff --git a/include/Line2D.h b/include/Line2D.h index a88f9a9..e6e16a7 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -9,7 +9,6 @@ class Line2D{ public: // Constructors - Line2D(std::vector listOfSegments); Line2D(std::string listOfLine2DString); Line2D(std::ifstream& file); // Send in file for constructor ~Line2D(); @@ -19,17 +18,15 @@ class Line2D{ static bool isEmptyLine(); static bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - std::vector getBoundingBox(); + bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds - bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(int index, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(int index); // Removes a RGPSegment2D at specified index - RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index + std::vector getBoundingBox(); + private: - struct Line2DUserStore; - Line2DUserStore *impl; + struct Line2DStore; + Line2DStore *handle; }; #endif //LINE2D diff --git a/include/Line2DForProgrammer.h b/include/Line2DForProgrammer.h index 75b56a3..0b37bce 100644 --- a/include/Line2DForProgrammer.h +++ b/include/Line2DForProgrammer.h @@ -3,33 +3,26 @@ #include "Number.h" #include "RGP.h" +#include "RGPSegment2D.h" #include #include +#include class Line2DForProgrammer{ public: // Constructors - Line2DForProgrammer(std::vector listOfSegments); Line2DForProgrammer(std::string listOfLine2DString); Line2DForProgrammer(std::ifstream& file); // Send in file for constructor ~Line2DForProgrammer(); // Methods - std::string getLineString(); // Get the line as human readable ASCII string - static bool isEmptyLine(); - static bool isValidLine(); - int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - std::vector getBoundingBox(); - bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds - bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds - bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(int index, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(int index); // Removes a RGPSegment2D at specified index - RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index private: - struct Line2DImplStore; - Line2DImplStore *impl; + struct Line2DProgrammerStore; + Line2DProgrammerStore *handle; }; #endif //LINE2D \ No newline at end of file diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h new file mode 100644 index 0000000..7b5e5ea --- /dev/null +++ b/include/Line2DImpl.h @@ -0,0 +1,43 @@ +#ifndef LINE2DIMPL_H +#define LINE2DIMPL_H + +#include "RGP.h" +#include "RGPSegment2D.h" +#include "RGPHalfSegment2D.h" +#include +#include +#include + +class Line2DImpl +{ + public: + // Constructors + Line2DImpl(std::vector listOfSegments); + Line2DImpl(std::string listOfLine2DString); + Line2DImpl(std::ifstream& file); // Send in file for constructor + ~Line2DImpl(); + + // Methods + std::string getLineString(); // Get the line as human readable ASCII string + static bool isEmptyLine(); + static bool isValidLine(); + int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed + std::vector getBoundingBox(); + + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index + + bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds + bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds + RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index + + private: + struct Line2DImplStore; + Line2DImplStore *handle; + void lineSort(std::vector &bar); + void mergeSort(std::vector &left, std::vector &right, std::vector &bars); + bool parseStringToVectorOfLines(std::string st); +}; + +#endif //POINT2DIMPL_H \ No newline at end of file From de6bab5751f308f6ef9ece4d9767e8e59cbb2409 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Tue, 20 Nov 2018 04:10:45 -0500 Subject: [PATCH 18/95] Fixed compile Line2D.h errors --- include/Line2D.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Line2D.h b/include/Line2D.h index e6e16a7..6d2982b 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -15,8 +15,8 @@ class Line2D{ // Methods std::string getLineString(); // Get the line as human readable ASCII string - static bool isEmptyLine(); - static bool isValidLine(); + bool isEmptyLine(); + bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds From c389215424296e3cc44b5a819a2209b96dbad2c2 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Tue, 20 Nov 2018 04:54:14 -0500 Subject: [PATCH 19/95] Updated Line2DImpl.h parameter of operator!=(),operator==() --- include/Line2DImpl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 7b5e5ea..356b347 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -19,17 +19,17 @@ class Line2DImpl // Methods std::string getLineString(); // Get the line as human readable ASCII string - static bool isEmptyLine(); - static bool isValidLine(); + bool isEmptyLine(); + bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed std::vector getBoundingBox(); - bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index + bool add(RGPHalfSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(std::vector::iterator it, RGPHalfSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index - bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds - bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds + bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds + bool operator!=(const Line2DImpl &l2d); // Override of operator != to check inequality of two Line2Ds RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index private: From 9a6fba1c127815f572b94778a78fb75227191751 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Tue, 20 Nov 2018 04:54:43 -0500 Subject: [PATCH 20/95] Added Line2D cpp files --- src/Line2D.cpp | 66 ++++++++ src/Line2DForProgrammer.cpp | 49 ++++++ src/Line2DImpl.cpp | 307 ++++++++++++++++++++++++++++++++++++ 3 files changed, 422 insertions(+) create mode 100644 src/Line2D.cpp create mode 100644 src/Line2DForProgrammer.cpp create mode 100644 src/Line2DImpl.cpp diff --git a/src/Line2D.cpp b/src/Line2D.cpp new file mode 100644 index 0000000..57e0f90 --- /dev/null +++ b/src/Line2D.cpp @@ -0,0 +1,66 @@ +#include "../include/Line2D.h" +#include "../include/Line2DImpl.h" + +struct Line2D::Line2DStore { + Line2DImpl *implPointer; + + Line2DStore(std::string linesString) + { + implPointer = new Line2DImpl(linesString); + } + + Line2DStore(std::ifstream& file) + { + implPointer = new Line2DImpl(file); + } +}; + +Line2D::Line2D(std::string listOfLine2DString) +{ + handle = new Line2DStore(listOfLine2DString); +} + +Line2D::Line2D(std::ifstream& file) // Send in file for constructor +{ + handle = new Line2DStore(file); +} + +Line2D::~Line2D() +{ + delete handle->implPointer; + delete handle; +} + +// Methods +std::string Line2D::getLineString() // Get the line as human readable ASCII string +{ + return handle->implPointer->getLineString(); +} + +// static +bool Line2D::isEmptyLine() +{ + return handle->implPointer->isEmptyLine(); +} + +int Line2D::Line2D::getNumberOfSegments() +{ + return handle->implPointer->getNumberOfSegments(); +} + +bool Line2D::operator==(const Line2D &l2d) +{ + // TODO + //return handle->implPointer->operator==(&l2d); +} + +bool Line2D::operator!=(const Line2D &l2d) +{ + // TODO + //return handle->implPointer->operator!=(&l2d); +} + +std::vector Line2D::getBoundingBox() +{ + return handle->implPointer->getBoundingBox(); +} \ No newline at end of file diff --git a/src/Line2DForProgrammer.cpp b/src/Line2DForProgrammer.cpp new file mode 100644 index 0000000..08c01b1 --- /dev/null +++ b/src/Line2DForProgrammer.cpp @@ -0,0 +1,49 @@ +#include "../include/Line2D.h" +#include "../include/Line2DImpl.h" +#include "../include/Line2DForProgrammer.h" + +struct Line2DForProgrammer::Line2DProgrammerStore +{ + Line2DImpl *implPointer; + + Line2DProgrammerStore(std::string linesString) + { + implPointer = new Line2DImpl(linesString); + } + + Line2DProgrammerStore(std::ifstream& file) + { + implPointer = new Line2DImpl(file); + } +}; + +Line2DForProgrammer::Line2DForProgrammer(std::string listOfLine2DString) +{ + handle = new Line2DProgrammerStore(listOfLine2DString); +} + +Line2DForProgrammer::Line2DForProgrammer(std::ifstream& file) // Send in file for constructor +{ + handle = new Line2DProgrammerStore(file); +} + +Line2DForProgrammer::~Line2DForProgrammer() +{ + delete handle->implPointer; + delete handle; +} + +bool Line2DForProgrammer::add(RGPSegment2D rgpSeg2d) +{ + //TODO +} + +bool Line2DForProgrammer::remove(std::vector::iterator it) +{ + //TODO +} + +bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d) +{ + //TODO +} diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp new file mode 100644 index 0000000..8e25206 --- /dev/null +++ b/src/Line2DImpl.cpp @@ -0,0 +1,307 @@ +#include "../include/Line2D.h" +#include "../include/Line2DImpl.h" +#include +#include +#include +#include + +struct Line2DImpl::Line2DImplStore { + std::vector vectorOfSegments; +}; + +Line2DImpl::Line2DImpl(std::vector listOfSegments) +{ + handle = new Line2DImplStore; + handle->vectorOfSegments = listOfSegments; +} + +Line2DImpl::Line2DImpl(std::string listOfLine2DString) +{ + handle = new Line2DImplStore; + + //TODO: parseStringToVectorOfLines() needs to be updated + //handle->vectorOfSegments = parseStringToVectorOfLines(listOfLine2DString); +} + +Line2DImpl::Line2DImpl(std::ifstream& file) // Send in file for constructor +{ + handle = new Line2DImplStore; + + std::string inputString; + if(file.is_open()) + { + std::stringstream strBuffer; + strBuffer << file.rdbuf(); + inputString = strBuffer.str(); + } + else + { + throw std::runtime_error("Error while reading the file"); + } + + //TODO: parseStringToVectorOfLines() needs to be updated + //handle->vectorOfSegments = parseStringToVectorOfLines(inputString); +} + +Line2DImpl::~Line2DImpl() +{ + // TODO + // delete handle->vectorOfSegments; + // delete handle; +} + +// Methods +std::string Line2DImpl::getLineString() // Get the line as human readable ASCII string +{ + /*std::string resultString; + if(!isEmptyLine()) + { + resultString += "("; + for (RGPHalfSegment2D rgpLine : handle->vectorOfSegments) + { + std::ostringstream stream; + stream << rgpLine; + std::string str = stream.str(); + + resultString += str; + resultString += ","; + } + resultString += ")"; + } + + return resultString;*/ +} + +bool Line2DImpl::isEmptyLine() +{ + return handle->vectorOfSegments.empty(); +} + +bool Line2DImpl::isValidLine() +{ + bool validity = false; + if(!handle->vectorOfSegments.empty()) + { + //Check for validity + //TODO + } + + return validity; +} + +int Line2DImpl::Line2DImpl::getNumberOfSegments() +{ + return handle->vectorOfSegments.size(); +} + +std::vector Line2DImpl::getBoundingBox() +{ + //TODO + //Call convex hull implementation + //return NULL; +} + +bool Line2DImpl::add(RGPHalfSegment2D rgpSeg2d) +{ + try + { + if(isEmptyLine()){ + handle->vectorOfSegments.push_back(rgpSeg2d); + } + else{ + int i = 0; + // TODO: fix error with operator > comparison + //while(rgpSeg2d > handle->vectorOfSegments[i]){i++;} + handle->vectorOfSegments.insert(handle->vectorOfSegments.begin()+i, rgpSeg2d); + } + } + catch(int e) + { + return false; + } + return true; +} + +bool Line2DImpl::update(std::vector::iterator it, RGPHalfSegment2D rgpSeg2d) +{ + try + { + if(isEmptyLine()){ + return false; + } + else{ + int index = distance(handle->vectorOfSegments.begin(), it); + handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); + add(rgpSeg2d); + } + } + catch(int e) + { + return false; + } + return true; +} + +bool Line2DImpl::remove(std::vector::iterator it) +{ + try + { + if(isEmptyLine()){ + return false; + } + else{ + int index = distance(handle->vectorOfSegments.begin(), it); + handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); + } + } + catch(int e) + { + return false; + } + return true; +} + +bool Line2DImpl::operator==(const Line2DImpl &l2d) +{ + int i = 0; + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()){ + return false; + } + + while(i < l2d.handle->vectorOfSegments.size()) + { + if(handle->vectorOfSegments[i] != l2d.handle->vectorOfSegments[i]) + return false; + else + i++; + } + return true; +} + +bool Line2DImpl::operator!=(const Line2DImpl &l2d) +{ + int i = 0; + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()){ + return true; + } + + while(i < l2d.handle->vectorOfSegments.size()) + { + if(handle->vectorOfSegments[i] != l2d.handle->vectorOfSegments[i]) + return true; + else + i++; + } + return false; +} + +RGPSegment2D Line2DImpl::operator[](int index) +{ + // TODO: returned data type is NOT correct + //return handle->vectorOfSegments[index]; +} + +void Line2DImpl::lineSort(std::vector &bar) +{ + if (bar.size() <= 1) + return; + + int mid = bar.size() / 2; + std::vector l; + std::vector r; + + for (size_t j = 0; j < mid;j++) + l.push_back(bar[j]); + for (size_t j = 0; j < (bar.size()) - mid; j++) + r.push_back(bar[mid + j]); + + lineSort(l); + lineSort(r); + mergeSort(l, r, bar); +} + + +void Line2DImpl::mergeSort(std::vector &left, std::vector &right, std::vector &bars) +{ + int nL = left.size(); + int nR = right.size(); + int i = 0, j = 0, k = 0; + + while (j < nL && k < nR) + { + if (left[j] <= + right[k]) { + bars[i] = left[j]; + j++; + } + else { + bars[i] = right[k]; + k++; + } + i++; + } + while (j < nL) { + bars[i] = left[j]; + j++; i++; + } + while (k < nR) { + bars[i] = right[k]; + k++; i++; + } +} + +bool Line2DImpl::parseStringToVectorOfLines(std::string st) +{ + int pos; + std::string num1; + std::string s =st; + std::string delimeter = ","; + s.erase(0,1); + s.erase(s.length()-1,1); + std::cout << s << "\n"; + pos = s.find(delimeter); + std::cout << pos << "\n"; + try{ + while(pos!= std::string::npos) + { + std::string a = s.substr(0, pos); + std::cout << a << "\n"; + if(a.length()==2) + { + try + { + if(a[0]=='(') + { + num1 = a[1]; + } + else if(a[1]==')') + { + std::string temp = a[0]+""; + std::cout << temp << "\t" << num1 << "\n"; + // TODO: modify for line2d NOT point2d + /*Number q(temp); + Number p(num1); + RGPHalfSegment2D poi(p,q); + add(poi);*/ + } + else + return false; + } + catch(int e){ + return false; + } + } + else + { + return false; + } + s.erase(0, pos + delimeter.length()); + pos = s.find(delimeter); + + } + } + catch(int e){ + return false; + + } +} \ No newline at end of file From f1981c5085b4bf9a2812352a32dc75675e6e9c4f Mon Sep 17 00:00:00 2001 From: kotaprabhakar Date: Tue, 20 Nov 2018 11:19:57 -0500 Subject: [PATCH 21/95] Intersection of Line Segments --- include/RGPOperations2D.h | 39 ++++++++++++++++++++--------------- include/RGPSegment2D.h | 1 + src/RGPOperations.cpp | 43 ++++++++++++++++++++++++++++++++++++++- src/RGPSegment2D.cpp | 30 +++++++++++++++++++++++---- 4 files changed, 92 insertions(+), 21 deletions(-) diff --git a/include/RGPOperations2D.h b/include/RGPOperations2D.h index bf899ae..ba60007 100644 --- a/include/RGPOperations2D.h +++ b/include/RGPOperations2D.h @@ -10,31 +10,38 @@ #ifdef __has_include // Check for standard library -# if __has_include() -# include - using std::optional; +#if __has_include() +#include +using std::optional; // Check for exprimental version (bug fix for Xcode on macOS) -# elif __has_include() -# include - using std::experimental::optional; +#elif __has_include() +#include +using std::experimental::optional; // Not found -# else -# error "Missing " -# endif +#else +#error "Missing " +#endif #endif - +#include "RGPHalfSegment2D.h" #include "RGPPoint2D.h" #include "RGPSegment2D.h" -#include "RGPHalfSegment2D.h" -class RGPOperations2D -{ +#define COLLINEAR 1 +#define CLOCKWISE 2 +#define COUNTERCLOCKWISE 3 + +class RGPOperations2D { +private: + // Helper Function + static int orientation(RGPPoint2D point1, RGPPoint2D point2, + RGPPoint2D point3); + static RGPPoint2D intersection(RGPSegment2D s1, RGPSegment2D s2); + public: - static optional intersectionOf(RGPSegment2D s1, - RGPSegment2D s2); + static optional intersectionOf(RGPSegment2D s1, RGPSegment2D s2); }; -#endif //RGPOPERATIONS2D_H +#endif // RGPOPERATIONS2D_H diff --git a/include/RGPSegment2D.h b/include/RGPSegment2D.h index 95ffac7..55cd0c9 100644 --- a/include/RGPSegment2D.h +++ b/include/RGPSegment2D.h @@ -26,6 +26,7 @@ class RGPSegment2D { bool operator<=(const RGPSegment2D &rhs); bool operator>(const RGPSegment2D &rhs); bool operator>=(const RGPSegment2D &rhs); + bool contains(const RGPPoint2D p); // Allows ouptut of an RGPSegment2D in the format of "(x1,y1),(x2,y2)" friend std::ostream &operator<<(std::ostream &os, const RGPSegment2D p); diff --git a/src/RGPOperations.cpp b/src/RGPOperations.cpp index 5716224..31e64ea 100644 --- a/src/RGPOperations.cpp +++ b/src/RGPOperations.cpp @@ -1,4 +1,45 @@ #include "../include/RGPOperations2D.h" +int RGPOperations2D::orientation(RGPPoint2D point1, RGPPoint2D point2, + RGPPoint2D point3) { + Number x = (point2.y - point1.y) * (point3.x - point2.x) - + (point3.y - point2.y) * (point2.x - point1.x); + Number zero("0"); + if (x == zero) + return COLLINEAR; + else if (x > zero) + return CLOCKWISE; + else + return COUNTERCLOCKWISE; +} + +RGPPoint2D RGPOperations2D::intersection(RGPSegment2D s1, RGPSegment2D s2) { + Number x1 = s1.point1.x, y1 = s1.point1.y, x2 = s1.point2.x, y2 = s1.point2.y, + x3 = s2.point1.x, y3 = s2.point1.y, x4 = s2.point2.x, y4 = s2.point2.y, + resX, resY, denom; + denom = (x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1); + resX = ((x2 * y1 - x1 * y2) * (x4 - x3) - (x4 * y3 - x3 * y4) * (x2 - x1)) / + denom; + resY = ((x2 * y1 - x1 * y2) * (y4 - y3) - (x4 * y3 - x3 * y4) * (y2 - y1)) / + denom; + RGPPoint2D intersectPoint(resX, resY); + return intersectPoint; +} + optional RGPOperations2D::intersectionOf(RGPSegment2D s1, - RGPSegment2D s2) {} + RGPSegment2D s2) { + int orientation1 = orientation(s1.point1, s1.point2, s2.point1); + int orientation2 = orientation(s1.point1, s1.point2, s2.point2); + int orientation3 = orientation(s2.point1, s2.point2, s1.point1); + int orientation4 = orientation(s2.point1, s2.point2, s1.point2); + + if ((orientation1 != orientation2 && orientation3 != orientation4) || + (orientation1 == COLLINEAR && s1.contains(s2.point1)) || + (orientation2 == COLLINEAR && s1.contains(s2.point2)) || + (orientation3 == COLLINEAR && s2.contains(s1.point1)) || + (orientation4 == COLLINEAR && s2.contains(s1.point2))) { + return {intersection(s1, s2)}; + } + + return std::nullopt; +} diff --git a/src/RGPSegment2D.cpp b/src/RGPSegment2D.cpp index ceae00c..7eb16ee 100644 --- a/src/RGPSegment2D.cpp +++ b/src/RGPSegment2D.cpp @@ -20,10 +20,32 @@ bool RGPSegment2D::operator!=(const RGPSegment2D &rhs) { else return true; } -bool RGPSegment2D::operator<(const RGPSegment2D &rhs) {} -bool RGPSegment2D::operator<=(const RGPSegment2D &rhs) {} -bool RGPSegment2D::operator>(const RGPSegment2D &rhs) {} -bool RGPSegment2D::operator>=(const RGPSegment2D &rhs) {} +bool RGPSegment2D::operator<(const RGPSegment2D &rhs) { + if (point1 < rhs.point1 && point2 < rhs.point1) + return true; + return false; +} +bool RGPSegment2D::operator<=(const RGPSegment2D &rhs) { + if ((*this) < rhs || (*this) == rhs) + return true; + return false; +} +bool RGPSegment2D::operator>(const RGPSegment2D &rhs) { + return !((*this) <= rhs); +} +bool RGPSegment2D::operator>=(const RGPSegment2D &rhs) { + return !((*this) < rhs); +} + +bool RGPSegment2D::contains(const RGPPoint2D p) { + if (p.x <= std::max(point1.x, point2.x) && + p.x >= std::min(point1.x, point2.x) && + p.y <= std::max(point1.y, point2.y) && + p.y >= std::min(point1.y, point2.y)) { + return true; + } + return false; +} std::ostream &operator<<(std::ostream &os, const RGPSegment2D p) { os << p.point1 << "," << p.point2; From 5e49220c22a5f517d1a3e2c8ba39da0e38e7c969 Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Mon, 26 Nov 2018 16:34:44 -0500 Subject: [PATCH 22/95] Implement sqrt using long division --- include/Number.h | 3 + src/Number.cpp | 304 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 230 insertions(+), 77 deletions(-) diff --git a/include/Number.h b/include/Number.h index ffeb40f..fe96e7a 100644 --- a/include/Number.h +++ b/include/Number.h @@ -37,6 +37,9 @@ class Number bool operator==(const Number &n) const; bool operator!=(const Number &n) const; Number &sqrt() const; + Number &sqrt(size_t digits) const; + + std::string to_string(size_t digits) const; // Overriding the output and input operator friend std::ostream &operator<<(std::ostream &os, const Number &n); diff --git a/src/Number.cpp b/src/Number.cpp index 4f6a2c7..6f14626 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -1,129 +1,279 @@ #include "../include/Number.h" -#include "gmpxx.h" +#include +#include +#include -struct Number::NumberImpl { -mpq_class num; +struct Number::NumberImpl +{ + mpq_class num; }; // Constructors // Default number value is 0 -Number::Number() { - p = new NumberImpl; - mpq_class temp; - p->num = temp; +Number::Number() +{ + p = new NumberImpl; + mpq_class temp; + p->num = temp; } // The string will be converted to a rational number -Number::Number(std::string number) { - p = new NumberImpl; - mpq_class temp(number, 10); - p->num = temp; +Number::Number(std::string number) +{ + std::string denom = "/1"; + std::regex decimal("^[0-9]+(\\.[0-9]+)?$"); + + if (!std::regex_match(number, decimal)) + { + throw std::invalid_argument("Argument should be a decimal number!"); + } + + size_t dec_point_pos = number.find('.'); + if (dec_point_pos != std::string::npos) + { + denom.append(number.length() - dec_point_pos - 1, '0'); + number.replace(dec_point_pos, 1, ""); + } + + p = new NumberImpl; + mpq_class temp(number + denom, 10); + p->num = temp; } // Destructor -Number::~Number() { - delete p; +Number::~Number() +{ + delete p; } // Override arithmetic operators -Number &Number::operator=(const Number &n) { - p->num = n.p->num; - return *this; +Number &Number::operator=(const Number &n) +{ + p->num = n.p->num; + return *this; } -Number &Number::operator+(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num + n.p->num; - return *ret; +Number &Number::operator+(const Number &n) const +{ + Number *ret = new Number(); + ret->p->num = p->num + n.p->num; + return *ret; } -Number &Number::operator+=(const Number &n) { - p->num = p->num + n.p->num; - return *this; +Number &Number::operator+=(const Number &n) +{ + p->num = p->num + n.p->num; + return *this; } -Number &Number::operator-(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num - n.p->num; - return *ret; +Number &Number::operator-(const Number &n) const +{ + Number *ret = new Number(); + ret->p->num = p->num - n.p->num; + return *ret; } -Number &Number::operator-=(const Number &n) { - p->num = p->num - n.p->num; - return *this; +Number &Number::operator-=(const Number &n) +{ + p->num = p->num - n.p->num; + return *this; } -Number &Number::operator*(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num * n.p->num; - return *ret; +Number &Number::operator*(const Number &n) const +{ + Number *ret = new Number(); + ret->p->num = p->num * n.p->num; + return *ret; } -Number &Number::operator*=(const Number &n) { - p->num = p->num *= n.p->num; - return *this; +Number &Number::operator*=(const Number &n) +{ + p->num = p->num *= n.p->num; + return *this; } -Number &Number::operator/(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num / n.p->num; - return *ret; +Number &Number::operator/(const Number &n) const +{ + Number *ret = new Number(); + ret->p->num = p->num / n.p->num; + return *ret; } -Number &Number::operator/=(const Number &n) { - p->num = p->num /= n.p->num; - return *this; +Number &Number::operator/=(const Number &n) +{ + p->num = p->num /= n.p->num; + return *this; } -Number &Number::operator^(const int n) const { - Number *ret = new Number(); - mpz_pow_ui(ret->p->num.get_num_mpz_t(), p->num.get_num_mpz_t(), (unsigned long) n); - mpz_pow_ui(ret->p->num.get_den_mpz_t(), p->num.get_den_mpz_t(), (unsigned long) n); - ret->p->num.canonicalize(); - return *ret; +Number &Number::operator^(const int n) const +{ + Number *ret = new Number(); + mpz_pow_ui(ret->p->num.get_num_mpz_t(), p->num.get_num_mpz_t(), + (unsigned long)n); + mpz_pow_ui(ret->p->num.get_den_mpz_t(), p->num.get_den_mpz_t(), + (unsigned long)n); + ret->p->num.canonicalize(); + return *ret; } // Override comparison operators -bool Number::operator<(const Number &n) const { - return p->num < n.p->num; +bool Number::operator<(const Number &n) const +{ + return p->num < n.p->num; } -bool Number::operator<=(const Number &n) const { - return p->num <= n.p->num; +bool Number::operator<=(const Number &n) const +{ + return p->num <= n.p->num; } -bool Number::operator>(const Number &n) const { - return p->num > n.p->num; +bool Number::operator>(const Number &n) const +{ + return p->num > n.p->num; } -bool Number::operator>=(const Number &n) const { - return p->num >= n.p->num; +bool Number::operator>=(const Number &n) const +{ + return p->num >= n.p->num; } -bool Number::operator==(const Number &n) const { - return p->num == n.p->num; +bool Number::operator==(const Number &n) const +{ + return p->num == n.p->num; } -bool Number::operator!=(const Number &n) const { - return p->num != n.p->num; +bool Number::operator!=(const Number &n) const +{ + return p->num != n.p->num; } -Number &Number::sqrt() const { - // TODO: Temporary implementation, limited precision - Number *ret = new Number(); - mpf_class float_num(p->num); - mpf_sqrt(float_num.get_mpf_t(), float_num.get_mpf_t()); - ret->p->num = mpq_class(float_num); - return *ret; +Number &Number::sqrt() const +{ + // TODO: Temporary implementation, limited precision + Number *ret = new Number(); + mpf_class float_num(p->num); + mpf_sqrt(float_num.get_mpf_t(), float_num.get_mpf_t()); + ret->p->num = mpq_class(float_num); + return *ret; +} + +Number &Number::sqrt(size_t digits) const +{ + mpz_class den_mpz = p->num.get_den(); + std::string num = p->num.get_num().get_str(); + std::string den = p->num.get_den().get_str(); + size_t num_int_len = num.find('.'); + if (num_int_len == std::string::npos) + { + num_int_len = num.length(); + } + + std::string curr_div; + std::string quotient; + for (int i = 0; i < num_int_len; i++) + { + curr_div += num.at(i); + mpz_class curr_div_mpz(curr_div); + if (curr_div_mpz > den_mpz) + { + mpz_class quotient_digit = curr_div_mpz / den_mpz; + mpz_class remainder = curr_div_mpz % den_mpz; + quotient += quotient_digit.get_str(); + curr_div = remainder.get_str(); + } + else + { + quotient += '0'; + } + } + + quotient += '.'; + size_t long_div_digits = digits * 2; + + while (long_div_digits > 0) + { + curr_div += '0'; + mpz_class curr_div_mpz(curr_div); + if (curr_div_mpz > den_mpz) + { + mpz_class quotient_digit = curr_div_mpz / den_mpz; + mpz_class remainder = curr_div_mpz % den_mpz; + quotient += quotient_digit.get_str(); + curr_div = remainder.get_str(); + } + else + { + quotient += '0'; + } + long_div_digits--; + } + + size_t non_zero_idx = quotient.find_first_not_of('0'); + if (quotient[non_zero_idx] == '.') + { + non_zero_idx--; + } + quotient.erase(0, non_zero_idx); + + std::string full_divisor(quotient); + size_t quot_int_len = quotient.find('.'); + full_divisor.replace(quot_int_len, 1, ""); + + if (quot_int_len == std::string::npos) + { + quot_int_len = quotient.length(); + } + + mpz_class curr_divisor; + std::string curr_dividend; + std::string square_root; + if (quot_int_len % 2 != 0) + { + full_divisor = '0' + full_divisor; + quot_int_len++; + } + + for (int i = 0; i < digits + quot_int_len / 2; i++) + { + curr_dividend += full_divisor.substr(i * 2, 2); + for (int j = 0; j < 10; j++) + { + mpz_class curr_dividend_mpz(curr_dividend); + mpz_class temp_divisor = curr_divisor * 10 + j + 1; + if (temp_divisor * (j + 1) > curr_dividend_mpz) + { + curr_dividend_mpz -= (curr_divisor * 10 + j) * j; + curr_divisor = curr_divisor * 10 + 2 * j; + curr_dividend = curr_dividend_mpz.get_str(); + square_root += std::to_string(j); + break; + } + } + } + + square_root.insert(quot_int_len / 2, "."); + Number *ret = new Number(square_root); + return *ret; +} + +std::string Number::to_string(size_t digits) const +{ + size_t max_len = mpz_sizeinbase(p->num.get_num_mpz_t(), 10) + digits + 2; + char *buf = (char *)malloc(sizeof(char) * max_len); + gmp_snprintf(buf, max_len, "%.*Ff", digits, mpf_class(p->num, digits * 4)); + std::string ret(buf); + delete buf; + return ret; } // Overriding the output and input operator -std::ostream &operator<<(std::ostream &os, const Number &n) { - // TODO: Support arbitrary precision - os << n.p->num.get_d(); - return os; -} -std::istream &operator>>(std::istream &is, Number &n) { - is >> n.p->num; - return is; +std::ostream &operator<<(std::ostream &os, const Number &n) +{ + os << n.p->num.get_d(); + return os; +} +std::istream &operator>>(std::istream &is, Number &n) +{ + is >> n.p->num; + return is; } From 27566bb345d413120f9e2dde75807ad1a355e883 Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Thu, 29 Nov 2018 14:10:25 -0500 Subject: [PATCH 23/95] Removing pointers from implementation --- include/Number.h | 27 +++++++++-------- src/Number.cpp | 78 ++++++++++++++++++++++++++---------------------- 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/include/Number.h b/include/Number.h index fe96e7a..08649ec 100644 --- a/include/Number.h +++ b/include/Number.h @@ -11,6 +11,9 @@ class Number // Default number value is 0 Number(); + // Copy constructor + Number(const Number &n); + // The string will be converted to a rational number Number(std::string number); @@ -18,16 +21,16 @@ class Number ~Number(); // Override arithmetic operators - Number &operator=(const Number &n); - Number &operator+(const Number &n) const; - Number &operator+=(const Number &n); - Number &operator-(const Number &n) const; - Number &operator-=(const Number &n); - Number &operator*(const Number &n) const; - Number &operator*=(const Number &n); - Number &operator/(const Number &n) const; - Number &operator/=(const Number &n); - Number &operator^(const int n) const; + Number operator=(const Number &n); + Number operator+(const Number &n) const; + Number operator+=(const Number &n); + Number operator-(const Number &n) const; + Number operator-=(const Number &n); + Number operator*(const Number &n) const; + Number operator*=(const Number &n); + Number operator/(const Number &n) const; + Number operator/=(const Number &n); + Number operator^(const int n) const; // Override comparison operators bool operator<(const Number &n) const; @@ -36,8 +39,8 @@ class Number bool operator>=(const Number &n) const; bool operator==(const Number &n) const; bool operator!=(const Number &n) const; - Number &sqrt() const; - Number &sqrt(size_t digits) const; + Number sqrt() const; + Number sqrt(size_t digits) const; std::string to_string(size_t digits) const; diff --git a/src/Number.cpp b/src/Number.cpp index 6f14626..e0bd0fc 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -17,6 +17,13 @@ Number::Number() p->num = temp; } +// Copy constructor +Number::Number(const Number &n) +{ + p = new NumberImpl; + p->num = n.p->num; +} + // The string will be converted to a rational number Number::Number(std::string number) { @@ -47,73 +54,73 @@ Number::~Number() } // Override arithmetic operators -Number &Number::operator=(const Number &n) +Number Number::operator=(const Number &n) { p->num = n.p->num; return *this; } -Number &Number::operator+(const Number &n) const +Number Number::operator+(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num + n.p->num; - return *ret; + Number ret; + ret.p->num = p->num + n.p->num; + return ret; } -Number &Number::operator+=(const Number &n) +Number Number::operator+=(const Number &n) { p->num = p->num + n.p->num; return *this; } -Number &Number::operator-(const Number &n) const +Number Number::operator-(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num - n.p->num; - return *ret; + Number ret; + ret.p->num = p->num - n.p->num; + return ret; } -Number &Number::operator-=(const Number &n) +Number Number::operator-=(const Number &n) { p->num = p->num - n.p->num; return *this; } -Number &Number::operator*(const Number &n) const +Number Number::operator*(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num * n.p->num; - return *ret; + Number ret; + ret.p->num = p->num * n.p->num; + return ret; } -Number &Number::operator*=(const Number &n) +Number Number::operator*=(const Number &n) { p->num = p->num *= n.p->num; return *this; } -Number &Number::operator/(const Number &n) const +Number Number::operator/(const Number &n) const { - Number *ret = new Number(); - ret->p->num = p->num / n.p->num; - return *ret; + Number ret; + ret.p->num = p->num / n.p->num; + return ret; } -Number &Number::operator/=(const Number &n) +Number Number::operator/=(const Number &n) { p->num = p->num /= n.p->num; return *this; } -Number &Number::operator^(const int n) const +Number Number::operator^(const int n) const { - Number *ret = new Number(); - mpz_pow_ui(ret->p->num.get_num_mpz_t(), p->num.get_num_mpz_t(), + Number ret; + mpz_pow_ui(ret.p->num.get_num_mpz_t(), p->num.get_num_mpz_t(), (unsigned long)n); - mpz_pow_ui(ret->p->num.get_den_mpz_t(), p->num.get_den_mpz_t(), + mpz_pow_ui(ret.p->num.get_den_mpz_t(), p->num.get_den_mpz_t(), (unsigned long)n); - ret->p->num.canonicalize(); - return *ret; + ret.p->num.canonicalize(); + return ret; } // Override comparison operators @@ -147,17 +154,16 @@ bool Number::operator!=(const Number &n) const return p->num != n.p->num; } -Number &Number::sqrt() const +Number Number::sqrt() const { - // TODO: Temporary implementation, limited precision - Number *ret = new Number(); + Number ret; mpf_class float_num(p->num); mpf_sqrt(float_num.get_mpf_t(), float_num.get_mpf_t()); - ret->p->num = mpq_class(float_num); - return *ret; + ret.p->num = mpq_class(float_num); + return ret; } -Number &Number::sqrt(size_t digits) const +Number Number::sqrt(size_t digits) const { mpz_class den_mpz = p->num.get_den(); std::string num = p->num.get_num().get_str(); @@ -252,15 +258,15 @@ Number &Number::sqrt(size_t digits) const } square_root.insert(quot_int_len / 2, "."); - Number *ret = new Number(square_root); - return *ret; + Number ret(square_root); + return ret; } std::string Number::to_string(size_t digits) const { size_t max_len = mpz_sizeinbase(p->num.get_num_mpz_t(), 10) + digits + 2; char *buf = (char *)malloc(sizeof(char) * max_len); - gmp_snprintf(buf, max_len, "%.*Ff", digits, mpf_class(p->num, digits * 4)); + gmp_snprintf(buf, max_len, "%.*Ff", digits, mpf_class(p->num, digits * 4).get_mpf_t()); std::string ret(buf); delete buf; return ret; From 796d869e13aafd20b8398d2ff5ce1fd591fb5726 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Thu, 29 Nov 2018 17:13:58 -0500 Subject: [PATCH 24/95] Updated Line2DImpl, outline for parse() function --- src/Line2DImpl.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 8e25206..a35d64f 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -279,10 +279,23 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) std::string temp = a[0]+""; std::cout << temp << "\t" << num1 << "\n"; // TODO: modify for line2d NOT point2d - /*Number q(temp); - Number p(num1); - RGPHalfSegment2D poi(p,q); - add(poi);*/ + + /* + + Number q1(temp); + Number p1(num1); + + Number q2(temp); + Number p2(num1); + + RGPPoint2D poi1(p1,q1); + RGPPoint2D poi2(p2,q2); + + RGPSegment2D seg(poi1,poi2); + RGPHalfSegment2D halfseg(seg,poi); // choose dominant point + add(halfseg); + + */ } else return false; From c0f20d52c4e1a61a84a678c7e7e89eb5a2c03320 Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Thu, 29 Nov 2018 20:22:14 -0500 Subject: [PATCH 25/95] Added instructions for local compilation --- README.md | 3 ++- makefile | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d26a762..3dfbb1c 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ cd PostGRES_ext wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz tar -xf gmp-6.1.2.tar.xz cd gmp-6.1.2 -./configure +./configure --prefix=$HOME/.local --enable-cxx make +make install cd .. # Build PostGRES_ext make clean diff --git a/makefile b/makefile index 89a1fd0..0d0d6f5 100644 --- a/makefile +++ b/makefile @@ -5,14 +5,15 @@ CC := g++ CFLAGS := -std=c++17 -g LDFLAGS := -lgmpxx -lgmp TARGET := postgres_ext -INC := -I include/ +INC := -I include/ -I$(HOME)/.local/include +LIB := -L$(HOME)/.local/lib SRCS := $(wildcard $(SRC_DIR)/*.cpp postgres_ext.cpp) OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRCS)) all: $(TARGET) $(TARGET): $(OBJS) - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + $(CC) $(CFLAGS) $(LIB) -o $@ $^ $(LDFLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(CC) $(CFLAGS) -o $@ -c $< $(INC) clean: From 924d7e8170159c4ea88b0fe7c4fba0199a02393a Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Sun, 2 Dec 2018 21:57:32 -0500 Subject: [PATCH 26/95] Using long div for to_string, fixed operator>>, unit tests --- src/Number.cpp | 105 ++++++++++--------- test/NumberTest.cpp | 242 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+), 54 deletions(-) create mode 100644 test/NumberTest.cpp diff --git a/src/Number.cpp b/src/Number.cpp index e0bd0fc..8fcb13f 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -164,6 +164,50 @@ Number Number::sqrt() const } Number Number::sqrt(size_t digits) const +{ + std::string quotient = to_string(digits * 2); + std::string full_divisor(quotient); + size_t quot_int_len = quotient.find('.'); + full_divisor.replace(quot_int_len, 1, ""); + + if (quot_int_len == std::string::npos) + { + quot_int_len = quotient.length(); + } + + mpz_class curr_divisor; + std::string curr_dividend; + std::string square_root; + if (quot_int_len % 2 != 0) + { + full_divisor = '0' + full_divisor; + quot_int_len++; + } + + for (int i = 0; i < digits + quot_int_len / 2; i++) + { + curr_dividend += full_divisor.substr(i * 2, 2); + for (int j = 0; j < 10; j++) + { + mpz_class curr_dividend_mpz(curr_dividend); + mpz_class temp_divisor = curr_divisor * 10 + j + 1; + if (temp_divisor * (j + 1) > curr_dividend_mpz) + { + curr_dividend_mpz -= (curr_divisor * 10 + j) * j; + curr_divisor = curr_divisor * 10 + 2 * j; + curr_dividend = curr_dividend_mpz.get_str(); + square_root += std::to_string(j); + break; + } + } + } + + square_root.insert(quot_int_len / 2, "."); + Number ret(square_root); + return ret; +} + +std::string Number::to_string(size_t digits) const { mpz_class den_mpz = p->num.get_den(); std::string num = p->num.get_num().get_str(); @@ -194,9 +238,8 @@ Number Number::sqrt(size_t digits) const } quotient += '.'; - size_t long_div_digits = digits * 2; - while (long_div_digits > 0) + while (digits > 0) { curr_div += '0'; mpz_class curr_div_mpz(curr_div); @@ -211,7 +254,7 @@ Number Number::sqrt(size_t digits) const { quotient += '0'; } - long_div_digits--; + digits--; } size_t non_zero_idx = quotient.find_first_not_of('0'); @@ -220,56 +263,7 @@ Number Number::sqrt(size_t digits) const non_zero_idx--; } quotient.erase(0, non_zero_idx); - - std::string full_divisor(quotient); - size_t quot_int_len = quotient.find('.'); - full_divisor.replace(quot_int_len, 1, ""); - - if (quot_int_len == std::string::npos) - { - quot_int_len = quotient.length(); - } - - mpz_class curr_divisor; - std::string curr_dividend; - std::string square_root; - if (quot_int_len % 2 != 0) - { - full_divisor = '0' + full_divisor; - quot_int_len++; - } - - for (int i = 0; i < digits + quot_int_len / 2; i++) - { - curr_dividend += full_divisor.substr(i * 2, 2); - for (int j = 0; j < 10; j++) - { - mpz_class curr_dividend_mpz(curr_dividend); - mpz_class temp_divisor = curr_divisor * 10 + j + 1; - if (temp_divisor * (j + 1) > curr_dividend_mpz) - { - curr_dividend_mpz -= (curr_divisor * 10 + j) * j; - curr_divisor = curr_divisor * 10 + 2 * j; - curr_dividend = curr_dividend_mpz.get_str(); - square_root += std::to_string(j); - break; - } - } - } - - square_root.insert(quot_int_len / 2, "."); - Number ret(square_root); - return ret; -} - -std::string Number::to_string(size_t digits) const -{ - size_t max_len = mpz_sizeinbase(p->num.get_num_mpz_t(), 10) + digits + 2; - char *buf = (char *)malloc(sizeof(char) * max_len); - gmp_snprintf(buf, max_len, "%.*Ff", digits, mpf_class(p->num, digits * 4).get_mpf_t()); - std::string ret(buf); - delete buf; - return ret; + return quotient; } // Overriding the output and input operator @@ -280,6 +274,9 @@ std::ostream &operator<<(std::ostream &os, const Number &n) } std::istream &operator>>(std::istream &is, Number &n) { - is >> n.p->num; + std::string input; + getline(is, input); + Number temp(input); + n.p->num = temp.p->num; return is; } diff --git a/test/NumberTest.cpp b/test/NumberTest.cpp new file mode 100644 index 0000000..d54fda9 --- /dev/null +++ b/test/NumberTest.cpp @@ -0,0 +1,242 @@ +#include "Number.h" +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE NumberTest +#include +#include +#include + +BOOST_AUTO_TEST_CASE(init_out) +{ + boost::test_tools::output_test_stream out; + Number a; + out << a; + BOOST_REQUIRE(out.is_equal("0")); +} + +BOOST_AUTO_TEST_CASE(init_string) +{ + boost::test_tools::output_test_stream out; + Number a("500"); + out << a; + BOOST_REQUIRE(out.is_equal("500")); +} + +BOOST_AUTO_TEST_CASE(init_to_string) +{ + Number a("500.7293203823820"); + BOOST_REQUIRE(a.to_string(13) == "500.7293203823820"); +} + +BOOST_AUTO_TEST_CASE(to_string_truncate) +{ + Number a("500.7293203823820"); + BOOST_CHECK_EQUAL(a.to_string(10), "500.7293203823"); +} + +BOOST_AUTO_TEST_CASE(to_string_expand) +{ + Number a("500.7293203823820"); + BOOST_CHECK_EQUAL(a.to_string(15), "500.729320382382000"); +} + +BOOST_AUTO_TEST_CASE(malformed_number) +{ + BOOST_CHECK_THROW(Number a("7 - 99"), std::invalid_argument); + BOOST_CHECK_THROW(Number a("5/3"), std::invalid_argument); + BOOST_CHECK_THROW(Number a("1.45e+14"), std::invalid_argument); + BOOST_CHECK_THROW(Number a("500.729.789"), std::invalid_argument); + BOOST_CHECK_THROW(Number a("500.729abc"), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(assignment) +{ + Number a("65.378"); + Number b; + b = a; + BOOST_CHECK_EQUAL(b.to_string(3), "65.378"); +} + +BOOST_AUTO_TEST_CASE(addition) +{ + Number a("678.56"); + Number b("0.678965"); + Number c; + c = a + b; + BOOST_CHECK_EQUAL(c.to_string(6), "679.238965"); +} + +BOOST_AUTO_TEST_CASE(add_assign) +{ + Number a("678.56"); + Number b("0.678965"); + a += b; + BOOST_CHECK_EQUAL(a.to_string(6), "679.238965"); +} + +BOOST_AUTO_TEST_CASE(subtraction) +{ + Number a("678.56"); + Number b("0.678965"); + Number c; + c = a - b; + BOOST_CHECK_EQUAL(c.to_string(6), "677.881035"); +} + +BOOST_AUTO_TEST_CASE(sub_assign) +{ + Number a("678.56"); + Number b("0.678965"); + a -= b; + BOOST_CHECK_EQUAL(a.to_string(6), "677.881035"); +} + +BOOST_AUTO_TEST_CASE(multiplication) +{ + Number a("78.563"); + Number b("25.87601"); + Number c; + c = a * b; + BOOST_CHECK_EQUAL(c.to_string(8), "2032.89697363"); +} + +BOOST_AUTO_TEST_CASE(mult_assign) +{ + Number a("78.563"); + Number b("25.87601"); + a *= b; + BOOST_CHECK_EQUAL(a.to_string(8), "2032.89697363"); +} + +BOOST_AUTO_TEST_CASE(division) +{ + Number a("78.563"); + Number b("25.87601"); + Number c; + c = a / b; + BOOST_CHECK_EQUAL(c.to_string(20), "3.03613269588317518813"); +} + +BOOST_AUTO_TEST_CASE(div_assign) +{ + Number a("78.563"); + Number b("25.87601"); + a /= b; + BOOST_CHECK_EQUAL(a.to_string(20), "3.03613269588317518813"); +} + +BOOST_AUTO_TEST_CASE(exponentiation) +{ + Number a("78.563"); + int b = 3; + Number c; + c = a ^ b; + BOOST_CHECK_EQUAL(c.to_string(4), "484902.2251"); +} + +BOOST_AUTO_TEST_CASE(less_than) +{ + Number a("56.78"); + Number b("67.78"); + Number c("45.78"); + Number d("56.78"); + BOOST_CHECK_EQUAL(a < b, true); + BOOST_CHECK_EQUAL(a < c, false); + BOOST_CHECK_EQUAL(a < d, false); +} + +BOOST_AUTO_TEST_CASE(less_than_equal) +{ + Number a("56.78"); + Number b("67.78"); + Number c("45.78"); + Number d("56.78"); + BOOST_CHECK_EQUAL(a <= b, true); + BOOST_CHECK_EQUAL(a <= c, false); + BOOST_CHECK_EQUAL(a <= d, true); +} + +BOOST_AUTO_TEST_CASE(greater_than) +{ + Number a("56.78"); + Number b("67.78"); + Number c("45.78"); + Number d("56.78"); + BOOST_CHECK_EQUAL(a > b, false); + BOOST_CHECK_EQUAL(a > c, true); + BOOST_CHECK_EQUAL(a > d, false); +} + +BOOST_AUTO_TEST_CASE(greater_than_equal) +{ + Number a("56.78"); + Number b("67.78"); + Number c("45.78"); + Number d("56.78"); + BOOST_CHECK_EQUAL(a >= b, false); + BOOST_CHECK_EQUAL(a >= c, true); + BOOST_CHECK_EQUAL(a >= d, true); +} + +BOOST_AUTO_TEST_CASE(equal) +{ + Number a("56.78"); + Number b("67.78"); + Number c("56.78"); + BOOST_CHECK_EQUAL(a == a, true); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a == c, true); +} + +BOOST_AUTO_TEST_CASE(not_equal) +{ + Number a("56.78"); + Number b("67.78"); + Number c("56.78"); + BOOST_CHECK_EQUAL(a != a, false); + BOOST_CHECK_EQUAL(a != b, true); + BOOST_CHECK_EQUAL(a != c, false); +} + +BOOST_AUTO_TEST_CASE(sqrt_approx) +{ + Number a("5"); + a = a.sqrt(); + double sqrt5 = 2.236068; + double result = std::stod(a.to_string(6)); + BOOST_CHECK_CLOSE(result, sqrt5, 0.0001); +} + +BOOST_AUTO_TEST_CASE(sqrt_digits) +{ + Number a("5"); + a = a.sqrt(98); + std::string oeis_a002163 = "2.23606797749978969640917366873127623544" + "0618359611525724270897245410520925637804" + "89941441440837878227"; + BOOST_CHECK_EQUAL(a.to_string(98), oeis_a002163); +} + +BOOST_AUTO_TEST_CASE(input_stream) +{ + Number a; + std::stringstream ss; + ss << "5.6789"; + ss >> a; + BOOST_CHECK_EQUAL(a.to_string(4), "5.6789"); +} + +BOOST_AUTO_TEST_CASE(malformed_input) +{ + Number a; + std::stringstream ss; + ss << "7 - 99\n"; + BOOST_CHECK_THROW(ss >> a, std::invalid_argument); + ss << "5/3\n"; + BOOST_CHECK_THROW(ss >> a, std::invalid_argument); + ss << "1.45e+14\n "; + BOOST_CHECK_THROW(ss >> a, std::invalid_argument); + ss << "500.729.789\n"; + BOOST_CHECK_THROW(ss >> a, std::invalid_argument); + ss << "500.729abc\n"; + BOOST_CHECK_THROW(ss >> a, std::invalid_argument); +} \ No newline at end of file From 85079db0b552637fa799989b661922803724497e Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Sun, 2 Dec 2018 22:11:11 -0500 Subject: [PATCH 27/95] Makefile for NumberTest --- makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/makefile b/makefile index 0d0d6f5..3607826 100644 --- a/makefile +++ b/makefile @@ -1,9 +1,11 @@ SRC_DIR := ./src +TST_DIR := ./test INC_DIR := ./include OBJ_DIR := ./obj CC := g++ CFLAGS := -std=c++17 -g LDFLAGS := -lgmpxx -lgmp +LDFLAGS_TST := -lgmpxx -lgmp -lboost_unit_test_framework TARGET := postgres_ext INC := -I include/ -I$(HOME)/.local/include LIB := -L$(HOME)/.local/lib @@ -16,6 +18,10 @@ $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(LIB) -o $@ $^ $(LDFLAGS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(CC) $(CFLAGS) -o $@ -c $< $(INC) +test: $(TST_DIR)/NumberTest +$(TST_DIR)/NumberTest: $(OBJ_DIR)/Number.o $(TST_DIR)/NumberTest.cpp + $(CC) $(CFLAGS) $(LIB) -o $@ $^ $(INC) $(LDFLAGS_TST) + ./$(TST_DIR)/NumberTest clean: rm -rf $(TARGET) $(OBJ_DIR)/*.o From b4c518b130815af804c243dadbdc54b544de91b8 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Mon, 3 Dec 2018 16:36:52 -0500 Subject: [PATCH 28/95] Updated parse() function and added iterator stuff --- include/Line2DImpl.h | 5 +- src/Line2DImpl.cpp | 141 ++++++++++++++++++++++++++++++++----------- 2 files changed, 110 insertions(+), 36 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 356b347..19ba3b6 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -31,7 +31,10 @@ class Line2DImpl bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2DImpl &l2d); // Override of operator != to check inequality of two Line2Ds RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index - + + std::vector::iterator begin(); + std::vector::iterator end(); + private: struct Line2DImplStore; Line2DImplStore *handle; diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index a35d64f..05e4fd5 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -1,5 +1,8 @@ +#include "../include/Number.h" #include "../include/Line2D.h" #include "../include/Line2DImpl.h" +#include "../include/RGPSegment2D.h" +#include "../include/RGPHalfSegment2D.h" #include #include #include @@ -9,6 +12,38 @@ struct Line2DImpl::Line2DImplStore { std::vector vectorOfSegments; }; +/*class MyIterator +{ + public: + MyIterator(RGPHalfSegment2D *ptr1) + { + ptr = ptr1; + } + RGPHalfSegment2D operator*() + { + return *ptr; + } + RGPHalfSegment2D next() + { + ptr++; + return *ptr; + } + private: + RGPHalfSegment2D *ptr; +}; + +std::vector::iterator Line2DImpl::begin() +{ + return (&(handle->vectorOfSegments[0])); +} + +std::vector::iterator Line2DImpl::end() +{ + int t = handle->vectorOfSegments.size(); + return (&(handle->vectorOfSegments[t-1])); +}*/ + +//Constructors Line2DImpl::Line2DImpl(std::vector listOfSegments) { handle = new Line2DImplStore; @@ -19,11 +54,11 @@ Line2DImpl::Line2DImpl(std::string listOfLine2DString) { handle = new Line2DImplStore; - //TODO: parseStringToVectorOfLines() needs to be updated + //TODO: parseStringToVectorOfLines() return type needs to be updated //handle->vectorOfSegments = parseStringToVectorOfLines(listOfLine2DString); } -Line2DImpl::Line2DImpl(std::ifstream& file) // Send in file for constructor +Line2DImpl::Line2DImpl(std::ifstream& file) { handle = new Line2DImplStore; @@ -252,53 +287,89 @@ void Line2DImpl::mergeSort(std::vector &left, std::vectorvectorOfSegments" + // at any instance before we return false + + int pos,fl = 0; // fl unused + std::string num1,num2,num3,num4; + std::string s = st; std::string delimeter = ","; - s.erase(0,1); - s.erase(s.length()-1,1); - std::cout << s << "\n"; - pos = s.find(delimeter); - std::cout << pos << "\n"; + int flag = 0; + + //std::vector nums; // unused + try{ - while(pos!= std::string::npos) + s.erase(0,1); + s.erase(s.length()-1,1); + s.append(","); + std::cout << s << "\n"; + pos = s.find(delimeter); + std::cout << pos << "\n"; + std::string a = ""; + + while(pos != std::string::npos) // npos ..? (last delimeter??) { - std::string a = s.substr(0, pos); - std::cout << a << "\n"; - if(a.length()==2) + if(flag == 0){ + s.erase(0,1); // delete starting '(' + } + else if(flag == 3){ + s.erase(pos-1,pos); // delete ending ')' + flag=-1; + } + + if(flag == -1){ + a = s.substr(0, pos-1); + } + else{ + a = s.substr(0, pos); + } + + if(a.length() == 2) { try { - if(a[0]=='(') + if(a[0]=='(' && flag == 0) { num1 = a[1]; } - else if(a[1]==')') + else if(a[1]==')' && flag == 1) { - std::string temp = a[0]+""; - std::cout << temp << "\t" << num1 << "\n"; - // TODO: modify for line2d NOT point2d - - /* + num2 = a[0]; + } + else if(a[0]=='(' && flag == 2) + { + num3 = a[1]; + } + else if(a[1]==')' && flag == -1) + { + num4 = a[0]; + + std::cout<<"num1 and num2 is "<vectorOfSegments.push_back(halfseg); } - else + else{ return false; + } } catch(int e){ return false; @@ -309,12 +380,12 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) return false; } s.erase(0, pos + delimeter.length()); + std::cout <<"string s is"<< s << "\n"; pos = s.find(delimeter); - + flag++; } } catch(int e){ return false; - } } \ No newline at end of file From 0cb33be9581fc550b95f2b75e34d2d7ab7cef056 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Mon, 3 Dec 2018 19:14:49 -0500 Subject: [PATCH 29/95] Minor update to Line2DImpl.cpp --- src/Line2DImpl.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 05e4fd5..032f998 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -1,8 +1,5 @@ -#include "../include/Number.h" #include "../include/Line2D.h" #include "../include/Line2DImpl.h" -#include "../include/RGPSegment2D.h" -#include "../include/RGPHalfSegment2D.h" #include #include #include @@ -12,7 +9,7 @@ struct Line2DImpl::Line2DImplStore { std::vector vectorOfSegments; }; -/*class MyIterator +class MyIterator { public: MyIterator(RGPHalfSegment2D *ptr1) @@ -32,7 +29,7 @@ struct Line2DImpl::Line2DImplStore { RGPHalfSegment2D *ptr; }; -std::vector::iterator Line2DImpl::begin() +/*std::vector::iterator Line2DImpl::begin() { return (&(handle->vectorOfSegments[0])); } From 487d06f8105ecb255a74783c78e231b3b2b5a08c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Thu, 6 Dec 2018 17:21:11 -0500 Subject: [PATCH 30/95] Add files via upload From 60cd244c66c8d6a2f194a5f530f585f3941f3cce Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Thu, 6 Dec 2018 17:23:51 -0500 Subject: [PATCH 31/95] Add files via upload From 39632573a2f3e1b97075991940628a03a35d3553 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Thu, 6 Dec 2018 21:07:43 -0500 Subject: [PATCH 32/95] Updated Line2DImpl with correct iterator stuff --- include/Line2DImpl.h | 34 ++++++++--- src/Line2DImpl.cpp | 141 ++++++++++++++++++++++++++++--------------- 2 files changed, 118 insertions(+), 57 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 19ba3b6..960d3ee 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -1,12 +1,12 @@ #ifndef LINE2DIMPL_H #define LINE2DIMPL_H +#include +#include + #include "RGP.h" #include "RGPSegment2D.h" #include "RGPHalfSegment2D.h" -#include -#include -#include class Line2DImpl { @@ -17,24 +17,38 @@ class Line2DImpl Line2DImpl(std::ifstream& file); // Send in file for constructor ~Line2DImpl(); + class iterator + { + public: + iterator(RGPHalfSegment2D*); + RGPHalfSegment2D operator*(); + RGPHalfSegment2D operator++(int); + RGPHalfSegment2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPHalfSegment2D *ptr; + }; + + iterator begin(); + iterator end(); + // Methods std::string getLineString(); // Get the line as human readable ASCII string + void printAllLines(); bool isEmptyLine(); bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - std::vector getBoundingBox(); + Line2DImpl getBoundingBox(); bool add(RGPHalfSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(std::vector::iterator it, RGPHalfSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index + bool update(iterator it, RGPHalfSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(iterator it); // Removes a RGPSegment2D at specified index bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2DImpl &l2d); // Override of operator != to check inequality of two Line2Ds - RGPSegment2D operator[](int index); // Retrieves a RGPSegment2D at specified index + Line2DImpl operator[](int index); // Retrieves a RGPSegment2D at specified index + Line2DImpl operator=(const Line2DImpl &l2dImpl); - std::vector::iterator begin(); - std::vector::iterator end(); - private: struct Line2DImplStore; Line2DImplStore *handle; diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 032f998..1962619 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -7,38 +7,58 @@ struct Line2DImpl::Line2DImplStore { std::vector vectorOfSegments; + std::vector boundingBox; }; -class MyIterator +Line2DImpl::iterator::iterator(RGPHalfSegment2D *ptr1) { - public: - MyIterator(RGPHalfSegment2D *ptr1) - { - ptr = ptr1; - } - RGPHalfSegment2D operator*() - { - return *ptr; - } - RGPHalfSegment2D next() - { - ptr++; - return *ptr; - } - private: - RGPHalfSegment2D *ptr; -}; + ptr = ptr1; +} + +RGPHalfSegment2D Line2DImpl::iterator::operator*() +{ + return *ptr; +} + +RGPHalfSegment2D Line2DImpl::iterator::operator++(int junk) +{ + RGPHalfSegment2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr; +} + +RGPHalfSegment2D Line2DImpl::iterator::operator++() +{ + ptr++; + return *ptr; +} + +bool Line2DImpl::iterator::operator!=(const iterator &it) +{ + if(it.ptr==ptr) + return false; + return true; +} -/*std::vector::iterator Line2DImpl::begin() +bool Line2DImpl::iterator::operator==(const iterator &it) { - return (&(handle->vectorOfSegments[0])); + if(it.ptr!=ptr) + return false; + return true; +} + +Line2DImpl::iterator Line2DImpl::begin() +{ + RGPHalfSegment2D *ptr = &(handle->vectorOfSegments[0]); + return iterator(ptr); } -std::vector::iterator Line2DImpl::end() +Line2DImpl::iterator Line2DImpl::end() { int t = handle->vectorOfSegments.size(); - return (&(handle->vectorOfSegments[t-1])); -}*/ + return (iterator(&(handle->vectorOfSegments[t-1]))); +} //Constructors Line2DImpl::Line2DImpl(std::vector listOfSegments) @@ -51,8 +71,10 @@ Line2DImpl::Line2DImpl(std::string listOfLine2DString) { handle = new Line2DImplStore; - //TODO: parseStringToVectorOfLines() return type needs to be updated - //handle->vectorOfSegments = parseStringToVectorOfLines(listOfLine2DString); + if(parseStringToVectorOfLines(listOfLine2DString)) + std::cout << "success" << std::endl; + else + std::cout << "failed" << std::endl; } Line2DImpl::Line2DImpl(std::ifstream& file) @@ -71,8 +93,10 @@ Line2DImpl::Line2DImpl(std::ifstream& file) throw std::runtime_error("Error while reading the file"); } - //TODO: parseStringToVectorOfLines() needs to be updated - //handle->vectorOfSegments = parseStringToVectorOfLines(inputString); + if(parseStringToVectorOfLines(inputString)) + std::cout << "success" << std::endl; + else + std::cout << "failed" << std::endl; } Line2DImpl::~Line2DImpl() @@ -104,6 +128,15 @@ std::string Line2DImpl::getLineString() // Get the line as human readable ASCII return resultString;*/ } +void Line2DImpl::printAllLines() +{ + /*std::cout<<"("; + std::vector x = handle->vectorOfSegments; + for(auto i = x.begin(); i!=x.end(); i++) + std::cout<<*i; + std::cout<<")";*/ +} + bool Line2DImpl::isEmptyLine() { return handle->vectorOfSegments.empty(); @@ -126,11 +159,12 @@ int Line2DImpl::Line2DImpl::getNumberOfSegments() return handle->vectorOfSegments.size(); } -std::vector Line2DImpl::getBoundingBox() +Line2DImpl Line2DImpl::getBoundingBox() { - //TODO - //Call convex hull implementation - //return NULL; + std::vector box; + box = handle->boundingBox; + Line2DImpl pt(box); + return pt; } bool Line2DImpl::add(RGPHalfSegment2D rgpSeg2d) @@ -154,7 +188,7 @@ bool Line2DImpl::add(RGPHalfSegment2D rgpSeg2d) return true; } -bool Line2DImpl::update(std::vector::iterator it, RGPHalfSegment2D rgpSeg2d) +bool Line2DImpl::update(Line2DImpl::iterator it, RGPHalfSegment2D rgpSeg2d) { try { @@ -162,9 +196,10 @@ bool Line2DImpl::update(std::vector::iterator it, RGPHalfSegme return false; } else{ - int index = distance(handle->vectorOfSegments.begin(), it); + int index = it.ptr - &(handle->vectorOfSegments[0]); handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); add(rgpSeg2d); + lineSort(handle->vectorOfSegments); } } catch(int e) @@ -174,7 +209,7 @@ bool Line2DImpl::update(std::vector::iterator it, RGPHalfSegme return true; } -bool Line2DImpl::remove(std::vector::iterator it) +bool Line2DImpl::remove(Line2DImpl::iterator it) { try { @@ -182,7 +217,7 @@ bool Line2DImpl::remove(std::vector::iterator it) return false; } else{ - int index = distance(handle->vectorOfSegments.begin(), it); + int index = it.ptr - &(handle->vectorOfSegments[0]); handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); } } @@ -227,10 +262,18 @@ bool Line2DImpl::operator!=(const Line2DImpl &l2d) return false; } -RGPSegment2D Line2DImpl::operator[](int index) +Line2DImpl Line2DImpl::operator[](int index) { - // TODO: returned data type is NOT correct - //return handle->vectorOfSegments[index]; + std::vector t; + t.push_back(handle->vectorOfSegments[index]); + Line2DImpl temp(t); + return temp; +} + +Line2DImpl Line2DImpl::operator=(const Line2DImpl &l2d) +{ + handle->vectorOfSegments.clear(); + handle->vectorOfSegments = l2d.handle->vectorOfSegments; } void Line2DImpl::lineSort(std::vector &bar) @@ -286,20 +329,15 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) { // line2ed format // (((a1,b1),(c1,d1)),((a2,b2),(c2,d2)),((a3,b3),(c3,d3)),((a4,b4),(c4,d4))) - // ((a1,b1),(c1,d1)),((a2,b2),(c2,d2)),((a3,b3),(c3,d3)),((a4,b4),(c4,d4)) - + // point2d format // ((a,b),(c,d),(e,f)) - - // should we reset "handle->vectorOfSegments" - // at any instance before we return false - - int pos,fl = 0; // fl unused + + int pos,flag = 0; std::string num1,num2,num3,num4; std::string s = st; std::string delimeter = ","; - int flag = 0; - + //std::vector nums; // unused try{ @@ -362,18 +400,27 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) RGPSegment2D seg(*point1,*point2); RGPHalfSegment2D halfseg(seg, *point1); // how to decide dominant point (2nd param)? + // Could dominant point be decided based on initial inputted format?? + // ex: (((non-dominant),(dominant)),(non-dominant),(dominant),...) + handle->vectorOfSegments.push_back(halfseg); } else{ + // should we reset vectorOfSegments for any possible changes that + // may have already happened with push_back() before returning false..? return false; } } catch(int e){ + // should we reset vectorOfSegments for any possible changes that + // may have already happened with push_back() before returning false..? return false; } } else { + // should we reset vectorOfSegments for any possible changes that + // may have already happened with push_back() before returning false..? return false; } s.erase(0, pos + delimeter.length()); From f3c340543dd5acd98b2142f75700d56eb827078d Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Thu, 6 Dec 2018 22:05:31 -0500 Subject: [PATCH 33/95] Support negative number in constructor and sqrt --- src/Number.cpp | 20 +++++++++++++++++++- test/NumberTest.cpp | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Number.cpp b/src/Number.cpp index 8fcb13f..db0ba4f 100644 --- a/src/Number.cpp +++ b/src/Number.cpp @@ -28,7 +28,7 @@ Number::Number(const Number &n) Number::Number(std::string number) { std::string denom = "/1"; - std::regex decimal("^[0-9]+(\\.[0-9]+)?$"); + std::regex decimal("^-?[0-9]+(\\.[0-9]+)?$"); if (!std::regex_match(number, decimal)) { @@ -166,6 +166,11 @@ Number Number::sqrt() const Number Number::sqrt(size_t digits) const { std::string quotient = to_string(digits * 2); + if (quotient[0] == '-') + { + throw std::runtime_error("Square root of a negative number is not supported!"); + } + std::string full_divisor(quotient); size_t quot_int_len = quotient.find('.'); full_divisor.replace(quot_int_len, 1, ""); @@ -212,6 +217,12 @@ std::string Number::to_string(size_t digits) const mpz_class den_mpz = p->num.get_den(); std::string num = p->num.get_num().get_str(); std::string den = p->num.get_den().get_str(); + bool is_negative = num[0] == '-'; + if (is_negative) + { + num.erase(0, 1); + } + size_t num_int_len = num.find('.'); if (num_int_len == std::string::npos) { @@ -262,7 +273,14 @@ std::string Number::to_string(size_t digits) const { non_zero_idx--; } + quotient.erase(0, non_zero_idx); + + if (is_negative) + { + quotient.insert(0, 1, '-'); + } + return quotient; } diff --git a/test/NumberTest.cpp b/test/NumberTest.cpp index d54fda9..a7e9552 100644 --- a/test/NumberTest.cpp +++ b/test/NumberTest.cpp @@ -21,6 +21,14 @@ BOOST_AUTO_TEST_CASE(init_string) BOOST_REQUIRE(out.is_equal("500")); } +BOOST_AUTO_TEST_CASE(init_negative) +{ + boost::test_tools::output_test_stream out; + Number a("-400"); + out << a; + BOOST_REQUIRE(out.is_equal("-400")); +} + BOOST_AUTO_TEST_CASE(init_to_string) { Number a("500.7293203823820"); @@ -39,6 +47,12 @@ BOOST_AUTO_TEST_CASE(to_string_expand) BOOST_CHECK_EQUAL(a.to_string(15), "500.729320382382000"); } +BOOST_AUTO_TEST_CASE(init_negative_decimal) +{ + Number a("-4.87654"); + BOOST_CHECK_EQUAL(a.to_string(5), "-4.87654"); +} + BOOST_AUTO_TEST_CASE(malformed_number) { BOOST_CHECK_THROW(Number a("7 - 99"), std::invalid_argument); @@ -216,6 +230,12 @@ BOOST_AUTO_TEST_CASE(sqrt_digits) BOOST_CHECK_EQUAL(a.to_string(98), oeis_a002163); } +BOOST_AUTO_TEST_CASE(sqrt_digits_neg) +{ + Number a("-5"); + BOOST_CHECK_THROW(a.sqrt(2), std::runtime_error); +} + BOOST_AUTO_TEST_CASE(input_stream) { Number a; From 1e1ed6b70dc27a04baef56dcfdee69817855e0a5 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Thu, 6 Dec 2018 22:59:53 -0500 Subject: [PATCH 34/95] slight update to parse() --- src/Line2DImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 1962619..e7c5149 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -366,7 +366,7 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) a = s.substr(0, pos); } - if(a.length() == 2) + if(a.length() >= 2) { try { From 9435ea6b5f885cf485b26716d380eb782243ef45 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 01:49:33 -0500 Subject: [PATCH 35/95] Updated parse() function. Still needs testing that actual values are being updated to vector properly --- src/Line2DImpl.cpp | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index e7c5149..118c897 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -330,9 +330,6 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) // line2ed format // (((a1,b1),(c1,d1)),((a2,b2),(c2,d2)),((a3,b3),(c3,d3)),((a4,b4),(c4,d4))) - // point2d format - // ((a,b),(c,d),(e,f)) - int pos,flag = 0; std::string num1,num2,num3,num4; std::string s = st; @@ -340,54 +337,62 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) //std::vector nums; // unused + // QUESTION: + // should we reset vectorOfSegments for any possible changes that + // may have already happened with push_back() before returning false..? + // for instance data could be pushed but, then additional data is then + // formatted incorrectly, possibly corrupting vectorOfSegments ..? + try{ s.erase(0,1); s.erase(s.length()-1,1); s.append(","); std::cout << s << "\n"; pos = s.find(delimeter); - std::cout << pos << "\n"; std::string a = ""; - - while(pos != std::string::npos) // npos ..? (last delimeter??) + + while(pos != std::string::npos) { if(flag == 0){ s.erase(0,1); // delete starting '(' } else if(flag == 3){ - s.erase(pos-1,pos); // delete ending ')' + s.erase(pos-1,1); // delete ending ')' flag=-1; } - if(flag == -1){ + if(flag == 0){ + a = s.substr(0, pos); + } + else if(flag == -1){ a = s.substr(0, pos-1); } else{ - a = s.substr(0, pos); + a = s.substr(0, pos+1); } - + if(a.length() >= 2) { try { if(a[0]=='(' && flag == 0) { - num1 = a[1]; + num1 = a.substr(1,a.length()-2); } - else if(a[1]==')' && flag == 1) + else if(!(a.substr(a.length()-2,1)).compare(")") && flag == 1) { - num2 = a[0]; + num2 = a.substr(0,a.length()-2); } else if(a[0]=='(' && flag == 2) { - num3 = a[1]; + num3 = a.substr(1,a.length()-2); } - else if(a[1]==')' && flag == -1) + else if(!(a.substr(a.length()-1,1)).compare(")") && flag == -1) { - num4 = a[0]; + num4 = a.substr(0,a.length()-1); - std::cout<<"num1 and num2 is "<vectorOfSegments.push_back(halfseg); } else{ - // should we reset vectorOfSegments for any possible changes that - // may have already happened with push_back() before returning false..? return false; } } catch(int e){ - // should we reset vectorOfSegments for any possible changes that - // may have already happened with push_back() before returning false..? return false; } } else { - // should we reset vectorOfSegments for any possible changes that - // may have already happened with push_back() before returning false..? return false; } - s.erase(0, pos + delimeter.length()); + + if(flag < 1){ + s.erase(0, pos); + } + else{ + s.erase(0, pos + delimeter.length()); + } std::cout <<"string s is"<< s << "\n"; pos = s.find(delimeter); flag++; } + return true; } catch(int e){ return false; From 710bfa98adbb45b3c100a572637ea5f65056387d Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 20:16:54 -0500 Subject: [PATCH 36/95] Update destructor --- src/Line2DImpl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 118c897..8b5b01c 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -102,8 +102,11 @@ Line2DImpl::Line2DImpl(std::ifstream& file) Line2DImpl::~Line2DImpl() { // TODO - // delete handle->vectorOfSegments; - // delete handle; + if(!isEmptyLine()){ + // delete handle->vectorOfSegments; + // delete handle->boundingBox; + // delete handle; + } } // Methods From 86c5bb7bbb17b307dfd5088aa4be5e54d407a15b Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 20:29:26 -0500 Subject: [PATCH 37/95] Added doc defining Line2D functions --- Line2D.docx | Bin 0 -> 17438 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Line2D.docx diff --git a/Line2D.docx b/Line2D.docx new file mode 100644 index 0000000000000000000000000000000000000000..c050b0b8031bc8fb8dccb7ee88ee238e49063c13 GIT binary patch literal 17438 zcmeIagLfdy);=6(Vp|j2wl%SxiEZ1qZQHhOn-g z_F6P9mKI<0K!C_{0DwO8|KIiha0@gfj+^zxS# ziV`*y7mHuscE;w+O<Y!g?eB2_0i4cvKGK@nBD9M~$rNgQLsc`tVE(5 zK>%4EV2f(k6gWb%e^x$gafVM)&_r)coaep6HHJumzJ4}1bnDp6PdP?XxJN}!4()q;PK%wLS}X&nrG3CWN??-B%(4{^8wCAa zrV0tCB1P^+)`v<|hz9V_8{|l9XRfbtIdDEptw_2sw~t$7U8&A~$WytFE5l5%OPTOG zN;1&yN74a^0e*BHT>ScP!R)eGDOkt)u$7LaAaf)Ehpz8Z=N8h!@<&W;c&7D1-q`Nl z9OjPSz#rgcv$O8-V=Jb4@D?=Gd^zGKoj+24qJ5I>;{zB#_CGWhHx{$`>hp>8r$Rz~ zYV3DALkoLanm^?KY3l#O>iM^Sy&|snQ&XY&uKa)b&vweK^`hrX)9TNxqpyO0(GZtJ zT3<0+e*eX_vI3-aqANN+Hy=OaW}hMAxRaoDjhUnb6V?f_^sL>l@!H`6kQmreNbj;_ zvj?4i_+a#Fj8L3>%s*TWC2SfKEcPiRWwHn9fI{fupcu-OfP8vEpQt`R%T{UmF~y59 zCzXD2$xKYc9lVTNxGM;!Z3@E+(ulV{4+7b2AQ)x$^=QT_cW>=1*OO*7x3ed(AOP$Y5u=I!EhpxAHG#$t~yxtexcoH}Wkvbln%yH)^A|B7K zNJ6GuD!BO{6@fAw)IvzSFntCtOE353kFzGZ8SzA4<V2A{6f&p*s7wtp89IGZh>{iH;2ntBLGn?ILaw#YKgyy z8B>P_FV+}Ta2ed7YrEzpHpdayg%{TmWpEzca47w=&A%8!D#t#iF2&|)Ea)PoCf)V{ z!H2Q0|BMdu8JdoB4KXNSbP^Y_w}dl571l{)X5AKZMhrHI>_p9cBJNV}ZMglXz?~Jn z*Uwt)-n5Et^gXH(-L4y!e1u~HsT;YJO<|V~T1NH=U+ISV7~ScR!HJ zGyz!=BjGeU08YtMwZ7;5 zP8yLK^TjA${WeLC4O{qnI2nf#Q}{&Dp$W}@owDK}BDsQPb>BGE$@Qw3E;o)a&1F_D zRZ+6^xb8lSkW-j=8|f94*#PaO$rAnH zh8IuWnm7y;3(PiCmC2TwZIQw)>viGj17-VQ=1Q?|gyCtb_BG1NS4KH7rWtl z-=}E3iDq}gV1*IBvR?(gA#*pxZ~;H^Rt4qL9d%O;Rs>CX0^!OncH&862{8@@mAN`~ zV@|4Gkfjy142K3Du)~-|&hJoRav)}kmv0*_K3-IIz%wr=c($#!{NzncPqzSGP zmj(u55|b6N`-x3bVk43O3(rP~>C2kup?ee$rmh4%EUzeB(N&-%Wve(zA5e9*c#4J7 zMZ!Uq0=I#DN~Jg>zMG?RTO@)|agPIhN>P4lUY6??MSMm}wN;NerH7GmN4o9$W7TvjZ}&-5u$_fV+%hMWLGris z6?e>@U9&uQhgYj{8nii-bD?CqJ?x{$A>@ z*&~u1APgnwRm6Ux2Wqb*JJV(;myd2Cldv9u`*P?7CJ-Vq8>OlzpjY$r>ZnxsExk{E z+`0GA*&4OaiUYZhS`>`6B#l2_a=ABiad3@sx7u15G@eP56WA^0OBUd&(N1Uwp0FP^ zuJhG3kF#k=0eeJkuuVl*DSO{t*@WJ%Tgx?Mm#tJ$8oRDOYZCPk?Qx5nKp5d z%smb>UcJ?lW7me!kR!fW#Zl-uXwF0he!gHu4D8kL;#BqOuQDC2lc&5XjM`NX(&kRv zr0;G;e>z%uzMx4A1qtw341diy(1NAA6=ItKSF~BjA!N=)T?8<)WiBqGSZ$z2TlP|} zi&Zy!dCiuGvMAOjsD~#1aK-+v;FOb1+r<*}4EM)edaiD1z0LyvPN~TQjU&s1C@vSb zjvgb_N?8NQ|6;oWzLtk$Syv$EuyMW|oq((nw~gFgaIyvvI+=_uGklcAiOUS%54Swd z&-0e^?o${F&W?1h;9zekHw*_9P(7wS+AX#jz8Px`uUER|OSX4>c{oN#M*zEsR9>Z# z%juc^by(9;p2sj;$V$4~Qj(^z1?5Fh5pS^DYz{8t}h$ts(=qTkKBc`dPGIQ1p_MNMGvgz z91ALBY$(vW2?k|Nu4z>}g}xj(0hT4B@_NK;B+B} zEZHI7EQj&o*B9`0$8Gxn_GV7R$?kvH^^U`jIfd}nN*XgNAJRB7S{mdO)n<1}_Q%)# z{2o@+!;tidRsNu%$5y2aGlbQ`)4b<{;}bksm|*C z^qCyeF1*6>S+0@sJlx>oIAL!=$XZl!?&{2D4OuVjtc(MZ&RLZdb2Rh^jH~h9djQH! zR55}|>jHJU?RT38XL4O|%7HkjB8=RAp6Q5}BX7jPNDtIv(!nJOlSRrV%&1^sGZ0IF zwB3=IL*6nUCxCa)V6UMg9c+1T@T!$}utS?GeY)(M$U3}l1l>tACB~PSy1X z|4QZ^uRmrQYYC8c#b4uN5W) z-+A)u)eZv%|JhJ6d{9AFcA8O#(xNitcB2Z9mZK_3(m_@fPUH$==D#SJ%6#fF?P$|~ zTYJ?rwb~C2V?nlMrPi=N9*o_=UH5VRv%fdmu1FY{e)M~0bakH|)wUUY_Re(?UPO#= zgFXw+7Dp+@7jtc}pxMT7)f`3lP@1{B zPc94O68yocN&D4+&AcL@0Rb+F0i9*&i(`W2+~F)pOP*fQr5JPb=;eENi%Vof)UG!x zHcTk19unwoP#hLZ!TursnLSRNtVBhDTtXp6MUD6tklYPC9g66e4lI1Lxa9nD&X#_A zVz6c-oaw-c4)F(z%9|NOoXIm+heTto0V45K)I=tle(w{9&#wi>hZY(sd`xq?6>97E zVmfV^oJX6ggoNkG$+6ruPPGa@X%I`PzL&4a+(m83($ud_9Zj;Q?)ZGv>x{}F=e2Bo z!RfGNDt0gkzQ})e=Ep~q(5Kn$kdb^;pe=J3S9i6?tk$u3%?0J`(9_FS|8nMVWTN=~ zH9h`^SsiIcKzEF`xQntx)=B1>wY7`cDA*i z7T7##Ko(kZm9?AGkrQ@M6`*bl4IH+wu-Qu1CQ|s3F$Y*!hRmL6$Hl;qfqp}S5?*s- z%x;Txvt+my6#lwdwo`ZXy!7qoJc_5CUF;<&io1EN;%s{k@5+B<3A|2B(jfcVr$dS8 z-0l5}O@!OG6MqSsJ+hvt1xK#57FQn<&dGD&SB%uPR$3x|2N}X&fvf5fCT95N@t{Uo zuUO;@pNxk4*ap8_a&;fDt=77)R(0EA7B<7#U=_tkUjN*dd2OoSFel#Kq0UmQMuIiD zDv&hk)+(NaT-F?A>L$I4V;CPz5Y=GO_}W~XK}L;0E?S)pt>lGcJgfgK{A*mme(9R` z(|r4H1MlNojsWJT>DLMZ0Dukf1@KP;?;l=}zngjg@`wO_`Yu0n|G#}zBuq+w`tAa* z#5x2Uoc9X&_)DZ|zm%$cf!i5M$Jzx%V@?Uzu(+(KCq!e9iPitw}YMM?^OuhGWM9mK0VoZuuA7rhB3 z>W98UBfg98X8P{@UJWoXl+ z0|7Q4Whn{p0=Ou?B7ycko7iFBha#-y#2SX5eqnbEzotBw6tXbU>c|UxakizMoxuz8 zXX3Akhbw*p{a@T78J5Hi`gE-2K>`3Eep2R7ZW&oyJ6Kse7~22gJy=Luw@ask54z%< zch+&Z3WM|HK#WVM2;ND)c=i(Ujb^0|3oCb1$qq<=7 z3)2+8I`yE>Q_m)K;$ZX+#*n`Up?S)(0fFEK@#CRrMWpE(E5RX01Nka(&pBY9MA+Bc z7Szb3MH32p&go&7CQEl@@5s{w#-}c1sJbj*O@w+;FM{-ht-KM_+O>lh@tV^Up;Z%7 z0V#>@$hpz$Mzu<+Arw*z)5w(y+s(*ubTV?A-UVxv&j`L*6Pb%kOa)YO52vBPLy=Fg zsAvV=)-t7RG{tO+N}s#TR+WF6g_`e+SxZu6(LMNwcze^~LpRZ(zPvj^*m(-j^t->Z zDv7b{u3LVV%w&MDqOb6&^Q{0+nDEdQYKS07U4ti(V)xVZOKL={-s+dCnBBHoJeL}l zMm4KGq^Xu7K)1$cgWL;%&av6r!_lD++?wESeDK|qIq02<90g~`_XSJ5 zGzfL^M&`egod+#Z5gO{gGDce+U$R78p-u)xuWd#UAZz*y6V*e%WL$v=U;5z;ZT2gi zcn}vReyOgqCACJcl$lJhLS0y1`lzqXkzdhFaP;?h=cIX0t$8|oesiZwf5+2hKid+; z=WwMf|KB6xP3_=X;3sP{K3V&3mzSZH!QV(bYPJ3cX+d9Lfv#X1)tmxX_|J%ht%T=z z00d{7;B5iL)qbu!n^>A2fYsTR!KsVA;~57r>T7Lx-1KqMS=x~+leOH$4ud4B(Ku1w zogMwM2<6fb9TCF^)yO4eJU06EJnxvu5DW3iSpa-Vb@Da=cXOq%+FbX4akjEEFHXO8 z^Dtre+bMLg*G_g;LQ(<-@T+AA8@xXzwkMA0I8!O#xetAjdmgp>#UGqyfA>oklw||_ zk^1(O0h;neIt;ZMV3K3Uq0WoV#x!JzU=|?Zk+djE_WV#blcwr8 z#W@t}PA~)05w>{GKx^d&nwL?B9vvJ93Flixa7oaTRMnwjR2EW`h^16Ci)DFHD|Rj_ zZtQApgybIjP`9Hr9Zjtvovt+k9T0%5pH@=Y^`L+ud8GbvorMIh-Ec;M5Om)thg`CFP3nRi3g9;A|05K_AlG&l1(OqieN*qy;R|>g!Msm7Nns}BKJ9O?iSZ?s5K~Mxv z3cH?0$#{zn@**V&!;^|5d;j9~vs>zP23p`vzqkGzNB?^k?`@-yjQ-^8`zL4N|25K@ z80s1r+R^_p&UPeiTd&c<4{wuRc!#`6XKn|S$U4fhG$fl^c>AQIBQ8c!ugBbMU&X=a zNT>uV;=nVU#YW=PGOK*!Lph>x(#vv$cM%N-orAoA0%UHt(uSSU;GWI0^b zEl!MB#!SUbI+$hRFhD&0%cPWmm`#Nbj}${Lh$kCkYB2^t#%2Mu6_^h`_sl_VYq11g zrHtdNH~bexN3mYIIm+I^ele?LCR~x5wgMCMQU&P_jU9nGAQDyqTfLp)H9hHtdFdzs zs?bq9`=oSWx{I2@m<|`roG%^HAeV(INJA;%2@JHBAqK;yx~C(xdC+$FkeLTJ3%ed5UA+{Tq!PM@uGMTw96KWHYI(xeg5+Hv6{t4fO9|_uwNx_vWPbs(kukHc3gXB z?>Ho9^zMAKH98a4AC<;ch@EaE$G1f_GTpl?-hHZdaLO<1knUawDi{fN#dgFy)=&jv zMZv;yf~d%V%eQ<_A=>qnq=JoXBx30HhU3WU{Ir^qwSUNT04(O)^rV?NoU=VX*l`8T zqFWK1$j~+59aeq7X9l4<2s%w@PAuHvm3dW8`u48<%&H-O5fT4}(pRtHQCEUz^nf#w z&{zN&Ma+`M*tV%GQpBPZ*>7Hk*2MY~jaDhxep}1!^2ff?w2HY{+NPi>fEsi@ZDJ8r zp|9uFYu7E_jmC12Ky9vvG%12?W86~%8YIo|lKP%a8VT$7ZazNC{r zH3q>6HsPDIaiIs_?stMfOmw-fYDIlP0sZ0mvKK@s1ldb${54zMOnOe9p2xy7St24y zhmEjz`*BXRF>`zhCkw%5~0=DwcN&HF_&-&qBzQZ++nsJKX(#P`>Q__Wb>{kpHaRxH_BH{r=ao_pi4Bpes9vlwiCVbf_Z^ z9w)0>bQTje0KA*Wc(xGuQ3;25*&GmZ3@Ep+gutGjzGQVfZYvG@IIt&uU>!`|#_(Iw zPnw8O*XqbvJ={Yk(Y9w+kJZSZ^N@rx!fB5L7TQn5UA zXF9=5hb|wu+d`y>k`2rRFA0WjMtIV}5W{iNZW$ggfz#A>yqD`scYgGEfP^dx8LG4;LduVTJ35(g`@>1y}e?Z|M>Kq>@D>)Gl~_ zS%6Lj)O4(6);=*YE0FJ7%x#Qs!PnFG4pg@m8TmrFi1y&3Wz+9{WjDlkxCK74^O)p2 z@IKYV&bOfY6)FW7L@9`R(=TNAT~Y{#l$xb^Olm?fy*0N(?rwm{)f}`z?)3?;`oR}+ ze-TcGdS$-U`Mf7ykwbXYpuUT|&r+Ega9{uC1dZ8~NybXAMU-l$KJBog=y`jYN%-iw zB96V>V2T2xeMGdxpl(l?7f7A^cvgL{ub2l(;G|1awu91Pm2l@gI+(76Q{CiOj43L= zeQSm<6#JZIFyk|5?5tOSQH`WhHGEj%sVo~KNsi52zw)M;-_$-gi?nF@;-bA2JRbvA zaGyCdtYMm@DAwdT;FfylW#9|{S(s0pCmv$!pd_LrROq4EH8s)Qlyso*dS71Q0$Sb7 zcZuqrgCAe-#Wo)0Mc}RA=kyPX6}=8N6&@X8=_f6hsn*RYtBUtc{e@^YBoSNbB6e<8 zuz3u>H!~(<-X)MXnKEhM^)FL|TKoV@OW{63pVHg}XC`DiYe9M%1(|dKdkGj*3<(k+ z#u+WlM8%0n(Hp8GW{q<1NcC|Gf{$rm4?(YU1O{w6fqNSU2=aHq00>cY@V zs74p(s7s@ym&uK<>bQa}b|t#6e-tzIObrrrldfdgLyur*IZ40Ux-(VL5?hrdI_t6> zha)FsjG(?n_H2;V=jbj)+6*`8V6S52-J04j%YHJ@e7PRDAVgz|s`>SFso^L(+IjRy z)zEcYC$Z>qQgd1Rpe;{h?+2PdlzLMNzZ89w?6`=OS+Oeok0gy?qgfo=wdP)T^iiO3z;JPkXABUpm(W>B1uR%Cf7t1MprQYCWv0hnu%Hhs)((H$nyti_UiH zP?xSQ%NzHcA7KH@;d-zHWm{ZVJk*?ov5i>~MPjpSE&_S5ZfBcz9~eZeIoDwWo)U`!J%#w65cp)>og_wRl2@ z2}^CX_QIA8Sa{&s-(Bv{Xz?CGiN5)!VFLSxj2&OZ-iGa8wvuI2Y42+r&wSB_ zC*So`HN-Bsx7Gguot@u8t9i5$k^(&(nJquc0=Fi#`3@fdO1(XV0E?|q<1s`yx^4m_ zNC+3fg-M{+Nz%aWAh-+^&SM+gQb*9bwWPV@2ztrqAqt-t`%v||?&<+5e4A;{vPKGn z0BQiMh;27C59{-~m!8-Mxq!49Q#MDest5x7%CibNk>e5}w4Pw#zy57=_x{^YumoH> zYyvy*F}+|=8f1iWFtnbe8+8b6jLx`^UM0vtvad33;V?&KhhcBzS>C?<&I(8lWlSOW zM)UR>^2xM3Q!dhlL5Bl1)=0yPW!CIE^7>%9Jf?)r9Yk6M>iplc;WB-rz#xNi)L8ds z2tcVvwVXRC9ZSSudo^dT478K8HA>0oPK|DmaNkA%<()abeFHi;nTSYL8*MDF8d9es zI`Sr|QT)Qs+5$8^n)9H4tVO}--6|@qji{yGM z{%E933(JP#1aQ0pKhItO?xE^ds35UaDws&)m}6&yx4u}|XtIkY?-I^;>~y6I%L zvqx$>AQJNCS8v?XX%GWp@`amWg;|Ph7QdyImn%Gn^zijL5~!3EuMw*%t7xUf>1eYO z-gzEkdDYKYjSVKx4^8V?3(eUJ>D;OV@+S)2ieXAxWV~BS}YOF#ED1!L3j zqEtRUE!O|GWqCR~vB97L0BoHA06zCo|KT;XcW|}%hs*FhQ^I+@4Pp3^yLj7IwA?9n z#F~_6xpmm-eC=o`)Y^d6JS2c>fhhN8SCrQiFec$E48Ltpsmdl%Qpq#mz=XHY?rrn- z_jop!Lp2%$H;%PmEsT&Zm}6oE(Z%_}ujO#rBK+DlOnSAF&nL%`NBP^`Z}+s_of$s{ zH70KP0O#I_AY?>u^Heh;hF#f?AjWyeKxGz(QYR3VOQKiz*>qPGTA$#@40<8yQEJJy zhTJ(hMe{M^?{i01B?I2dp~nM?18eb&xs-)c5AAD5u+}8-*1{+9gh>Rmj?9YVTlR=0 z3nV5k0Re~!CJbnd2Spnh9iySYrCwd8bjP`XvJC(}0PK(eQp%Oz!nyS6Kh;_@WK5Rb%o%|`P|^}f5YJ$zE8XcrVJ&@^}w zvTD!k(L_{GKi9Cy`Kk5!x_$w8a!g<;5}oh<1CbMquluw6lcVS4-5IZKQm(`(7+%nbc?77tJfww1?7disC;s z2wPoPa@KFGINwq#3cg+~&h)x7J3MK_;B=}84u2+#AI(N|-jiWMnf9s^;dL2(+9LO5 z3DfrBvC{Tu5YzT!Ak+3`fztNBI4}((44Xs|N+M(k1XYnW_<3$4Tx@P!*azS_zb5Pq zZ}I>?**24U@LoQ=T@G(%P5o+FuW!b4cCQ<wv4j(D|I|MzXi<-Ax3yH!q01Fp}2w?XcHyg z=|(XSepyngi67Th;vz|SU7;RNs-|K#+C%iDdY;7)^!=FHSm+bib3HmiDqvuY9dtDw zBFsX}ktPLZn6o~MOnJ8Dd+}x)pNW<~6Q=#c7uv|R;y)kC^qW6w+rw2)^UwWX=@FvI z6`*`}=cPO+m|FBP+$UD_aF6rnE>zvKYcDd!kEvUVQ|6P1${af(VxbzB38;hNjxi&@ zX-eS6b|i5T_)@#}6FZeBjk@_dNhwTAj+xFQVw~hEkEn z^K&MB_3J)6sBj_`KGe9ka~W2y*sWWe_*Sr49t+YLVfZ8zA5^`K%B5hqI z#F9&Koh9A=j*R#4;C_WoXN(wZj2Ai7!>4?;Q%rM?jcda`OsglvUKa%^I1VoeCnp$I z594JUMNW5wdM>mng_13xuD&n(OdFXYNU{#9ij}3*$2cHKsb3r5GbVK+;M3~Ak9>iR zQEq6LoVx2oWT>RsBjG#MU!dRBYwwd|e@4rWbCjwldlj}3N*Jt75E@=mMvAJ{>~^wD zPi>9Yw?VtqL%nH@Ak1Qa7_}@vJrH-)7&3a4Vs*oLcq73*5~fR~jeb~9$rqb7D1BG`Sa~i>8SWB*f$;z^cGA1d>65nM5Mc7;(VyaIz zo7!jVq!^>wllN!K1wDnG0-c?mg4@|xjF;^N$9z<2(h!d=V+=9uX-D zasnX{OmYQ2pV$BfAyG68L!hj^enFA<2!JI2$Nf(Ph0s5;xm8_c9%>5&A~(q515qo6 z@IftBpn-ouS=$eQyzu-)@cjK53c-v(;FmwL5-aLl5-W=FL;dSkxdzOyK*$SQfxw49 zAb7a~kbhR~UoZNjKJfot#Y2N#fLsCh4B6byXj%M0(UKUyf7k6FkUx?EkQ1GM)qWNw z`=0#Uvf)GfQ-0PI<-==sTN&s5d{^SS$i<^5bEjSX%XYX8&4I#<+x~7>DeDXW02AsQ zcAis)a&zlp+?R#WX*{$|=ckoBUpTF@t3bLVNx-+9YGSq`yBU<5CStN1*fxUACXn(e z|EhCy4L{TC9Lf_+Ef%!Gl9Mm!&V?A`F3Y-GiIvp$Yy(>CYYYK|8;PmZf^0on&npaE z&<=K64Ls-U(xT&M5`ejs*wlTs=`$!vGb&OXL4C((Osu)pj~fA9Rt`wA?+$v`QI7dD zxK82n;;eC_`Tzc0Q*;FAvaFULeH(3BqE>p0ME=mew>rIv|{SKX~D>C zRRxjps`QsapP7mEv|%FFRN=DWbJD+m-nLc|OvoY;6s>I_39rjl|+ z8x7Rll_gMn>(%|b%sisXlPro`Av`;eNbVf-(|vA=k^G%2umT@yus(~|Y+N`r^UiJi ze8YYjadElrqWr%_-1=gRS?T0I#QW%~)U_RRmHMf}zl2>orV4dq>tDicC*XYG>5sdP zZJ(l5E3!OkP4hoQM%9p#MCQMR)#qCaS^h)(R*AVv1_Y33pEM#WN}#r*L9KcZ?V4RU zQV%i4tnsH*Q9w79VOsO6iaE;^)``+>G&9kA{qaioh`iIWbc~XamtXR%n+A2;)D9qBnFAKI~R-ZbX z=P#~a35c4CW=kPEN6DcaSHXH!CAL=vm+{WGxJ{?N?2|+y?-Y6st1QkRCn}LO{_-3C zNnP$mjdqzm8k?Hf(&A2T3zI_RMUyEC)o9E;TT0E0a zJ!oCim%*W6(^DgUypHu=!I0Hmp_?loQ>18yx1q$>$)V1)t6B{08~OS}E-_b~=5Y!g z@A_(M#|mdlMRDTGy$eO06r}72Yxn$fll%{XLpPc?MHzr4>xl4V-sg_*TBk)?YPUV+ zkLSskI8?lB-`kc+bps5m_GSudCv|GTEayQNi*%TCu)ItrSz)U!ZbQtUYG)mkI;jlp zRZg8tbn;3Ge(|Qs&Kkh16+x9r3FenRTOA+nqFGc4tgEimMN znGDW`dJ2E@pCrspngP+n1MIlxUcuWfSI8GqRSA$MX@AST03JB62r^>8M`~Xyw%#!F zzTVRoAQ|--4M?SSIvxNQYWhLRj)^Mo!>Xv!UG-!A%+7`ql=Q;DkRYkpN^^h=q zq9}=Wp6t9T@S{P~7aqrF3cqmz*R7Qv(#lRDbMhtpIKV?qxHfCJ#(Un0<3nfxa{_v1 z)0A-bu9AGamy%@`Vn zxqZMHl~%_@U1IGlff0ByKEygPzQogxAQ3&`XV;kb=p~C)Zt1MEl=9}Xw!S3u?YYP@ zH#U@#K|Jn1{MG)NYnB1SSF6h&ICcO^|4{R1`39FzD58Y!&ETFfaUEi+5sY;%%+!_pRRBm2D;D<+ zw913usEW$h`~c^jw3?n_N!D*Un6T_f%XMrv;0U`Je2ZX$f+ zV`&r6{ltmw`dm(7lpAn!IfV%UeGG?x=lEXKcS z?sw~rx6DzIghjc>ATW^B$yv3?y*McA$^z);sPH=&{~GBGW5pKCQHRFX88&+vL8s)g zYIabx>(EkEZq6nt4C$PE)Rj*{3ltV6lIA!h6eXG>26s2g2Ud~hq9pY7NCtMb3tCsf zCSSqKB%6&sp0GZ3u?NQ0q!TK<=4%Rst*<|kK{g1KbDR-j4(fV*RQ67 zEmRD5ZEDZxnR)hKbBRp_P=E9oGuPXlD0&wk%XfPvmB_^G=fGEw}yOVu>&Gh2DCv%1jE_j!rQ<8z(H zNP*=taBa&a^b{#4c+xK(qsJgC;rCKIcx7?35OtoU9We;Q!O^TKsq8DFM-6cVdj`*F z#GNork%RkW&0-)Chvd*2Ycr$=$Y_lw|hSV&w#!Y`_>Oe$(yX` zKX#yS0OWV$oC6B2o%5Fv*@UbE8Z>l$IR(FT5)ZQ`;7ePLg6^Z#B}knk(H~d~Ja(C+GI9P|#Uw5!bz5;r3uRdFi)34XTqAdQYq zmx%!T!Q-%HoQa!bz0WfFr@qKK(l%s-EbbfInqsG6UxdaMO+>g^%?l zM4H6Zwy%T2^!)T#`F-AiHCJ9Z9Iftq_>;_Mzy3ob0D-7KS3m#zTLgc0|KG&__%ea4 z#D5m>pGTwrh6SkmRI|Swl>Qy~`KSL z+XDUf5`JHM{#C*(+doS%`ux1czgMEal1^|Hl{PFr!k1)PJQvV-nt&ora literal 0 HcmV?d00001 From d16237b842a6660c53eb8945317a176ebc2b95e3 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 20:54:10 -0500 Subject: [PATCH 38/95] Updated bb function in Line2D --- include/Line2D.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Line2D.h b/include/Line2D.h index 6d2982b..3cfc260 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -22,7 +22,7 @@ class Line2D{ bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds - std::vector getBoundingBox(); + Line2D getBoundingBox(); private: struct Line2DStore; From 13daa28273f72c5d679944adf20c14f2aea2bd51 Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 20:56:31 -0500 Subject: [PATCH 39/95] Updated bb function --- include/Line2D.h | 2 +- src/Line2D.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Line2D.h b/include/Line2D.h index 3cfc260..8bd6f93 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -22,7 +22,7 @@ class Line2D{ bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds - Line2D getBoundingBox(); + Line2DImpl getBoundingBox(); private: struct Line2DStore; diff --git a/src/Line2D.cpp b/src/Line2D.cpp index 57e0f90..4360f3a 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -60,7 +60,7 @@ bool Line2D::operator!=(const Line2D &l2d) //return handle->implPointer->operator!=(&l2d); } -std::vector Line2D::getBoundingBox() +Line2DImpl Line2D::getBoundingBox() { return handle->implPointer->getBoundingBox(); } \ No newline at end of file From dee3aca5fb0aa5c444a97be6cb139a281ce5058d Mon Sep 17 00:00:00 2001 From: Kyler Clegg Date: Fri, 7 Dec 2018 20:59:32 -0500 Subject: [PATCH 40/95] Updated #include --- include/Line2D.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/Line2D.h b/include/Line2D.h index 8bd6f93..35392fc 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -1,8 +1,9 @@ #ifndef LINE2D_H #define LINE2D_H -#include "Number.h" #include "RGP.h" +#include "Number.h" +#include "Line2DImpl.h" #include #include From f434814bafe28048eadac85e9df8aeeaa5e9ccf9 Mon Sep 17 00:00:00 2001 From: kadarisai <31567088+kadarisai@users.noreply.github.com> Date: Fri, 7 Dec 2018 21:30:51 -0500 Subject: [PATCH 41/95] Add files via upload Complete impl files --- src/Line2DImpl.cpp | 120 +++++++++++++++++--------- src/Line2DImpl.h | 61 +++++++++++++ src/Point2DImpl.cpp | 204 +++++++++++++++++++++++++++++++++++--------- src/Point2DImpl.h | 55 ++++++++++++ 4 files changed, 360 insertions(+), 80 deletions(-) create mode 100644 src/Line2DImpl.h create mode 100644 src/Point2DImpl.h diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 8b5b01c..644d31a 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -7,7 +7,7 @@ struct Line2DImpl::Line2DImplStore { std::vector vectorOfSegments; - std::vector boundingBox; + std::vector boundingBox; }; Line2DImpl::iterator::iterator(RGPHalfSegment2D *ptr1) @@ -25,7 +25,7 @@ RGPHalfSegment2D Line2DImpl::iterator::operator++(int junk) RGPHalfSegment2D *ptr1; ptr1 = ptr; ptr++; - return *ptr; + return *ptr1; } RGPHalfSegment2D Line2DImpl::iterator::operator++() @@ -60,11 +60,23 @@ Line2DImpl::iterator Line2DImpl::end() return (iterator(&(handle->vectorOfSegments[t-1]))); } +Line2DImpl::Line2DImpl() +{ + handle = new Line2DImplStore(); +} //Constructors -Line2DImpl::Line2DImpl(std::vector listOfSegments) + +Line2DImpl::Line2DImpl(std::vector listOfSegments) { handle = new Line2DImplStore; - handle->vectorOfSegments = listOfSegments; + std::vector halfSegments; + for(auto it = listOfSegments.begin(); it!=listOfSegments.end();it++) + { + halfSegments.push_back(RGPHalfSegment2D(*it,(*it).point1)); + halfSegments.push_back(RGPHalfSegment2D(*it,(*it).point2)); + } + lineSort(halfSegments); + handle->vectorOfSegments = halfSegments; } Line2DImpl::Line2DImpl(std::string listOfLine2DString) @@ -102,11 +114,8 @@ Line2DImpl::Line2DImpl(std::ifstream& file) Line2DImpl::~Line2DImpl() { // TODO - if(!isEmptyLine()){ - // delete handle->vectorOfSegments; - // delete handle->boundingBox; - // delete handle; - } + // delete handle->vectorOfSegments; + // delete handle; } // Methods @@ -133,11 +142,11 @@ std::string Line2DImpl::getLineString() // Get the line as human readable ASCII void Line2DImpl::printAllLines() { - /*std::cout<<"("; + std::cout<<"("; std::vector x = handle->vectorOfSegments; for(auto i = x.begin(); i!=x.end(); i++) - std::cout<<*i; - std::cout<<")";*/ + std::cout<<(*i).segment; + std::cout<<")"; } bool Line2DImpl::isEmptyLine() @@ -164,24 +173,37 @@ int Line2DImpl::Line2DImpl::getNumberOfSegments() Line2DImpl Line2DImpl::getBoundingBox() { - std::vector box; - box = handle->boundingBox; - Line2DImpl pt(box); + std::vector halfSegments; + halfSegments = handle->vectorOfSegments; + RGPPoint2D p1(halfSegments[0].segment.point1.x,halfSegments[0].segment.point1.y); + RGPPoint2D p2(halfSegments[halfSegments.size()-1].segment.point2.x,halfSegments[halfSegments.size()-1].segment.point2.y); + auto maxy = halfSegments[0].segment.point2.y; + for(auto it = halfSegments.begin();it!= halfSegments.end();it++) + { + if(maxy<(*it).segment.point1.y) + maxy = (*it).segment.point1.y; + if(maxy<(*it).segment.point2.y) + maxy = (*it).segment.point2.y; + } + RGPSegment2D seg(p1,RGPPoint2D(p2.x,maxy)); + handle->boundingBox.push_back(seg); + Line2DImpl pt(handle->boundingBox); return pt; } -bool Line2DImpl::add(RGPHalfSegment2D rgpSeg2d) +bool Line2DImpl::add(RGPSegment2D rgpSeg2d) { try { + if(isEmptyLine()){ - handle->vectorOfSegments.push_back(rgpSeg2d); + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); } else{ - int i = 0; - // TODO: fix error with operator > comparison - //while(rgpSeg2d > handle->vectorOfSegments[i]){i++;} - handle->vectorOfSegments.insert(handle->vectorOfSegments.begin()+i, rgpSeg2d); + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); + lineSort(handle->vectorOfSegments); } } catch(int e) @@ -191,7 +213,7 @@ bool Line2DImpl::add(RGPHalfSegment2D rgpSeg2d) return true; } -bool Line2DImpl::update(Line2DImpl::iterator it, RGPHalfSegment2D rgpSeg2d) +bool Line2DImpl::update(Line2DImpl::iterator it, RGPSegment2D rgpSeg2d) { try { @@ -199,9 +221,16 @@ bool Line2DImpl::update(Line2DImpl::iterator it, RGPHalfSegment2D rgpSeg2d) return false; } else{ - int index = it.ptr - &(handle->vectorOfSegments[0]); - handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); - add(rgpSeg2d); + for(std::vector::iterator i = handle->vectorOfSegments.begin(); i!= handle->vectorOfSegments.end() ; i++) + { + if((*i).segment == (*it).segment) + { + int index = it.ptr - &(handle->vectorOfSegments[0]); + handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); + } + } + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); + handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); lineSort(handle->vectorOfSegments); } } @@ -220,8 +249,14 @@ bool Line2DImpl::remove(Line2DImpl::iterator it) return false; } else{ - int index = it.ptr - &(handle->vectorOfSegments[0]); - handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); + for(std::vector::iterator i = handle->vectorOfSegments.begin(); i!= handle->vectorOfSegments.end() ; i++) + { + if((*i).segment == (*it).segment) + { + int index = it.ptr - &(handle->vectorOfSegments[0]); + handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); + } + } } } catch(int e) @@ -234,14 +269,17 @@ bool Line2DImpl::remove(Line2DImpl::iterator it) bool Line2DImpl::operator==(const Line2DImpl &l2d) { int i = 0; - if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()){ + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()) + { return false; } while(i < l2d.handle->vectorOfSegments.size()) { if(handle->vectorOfSegments[i] != l2d.handle->vectorOfSegments[i]) + { return false; + } else i++; } @@ -251,7 +289,8 @@ bool Line2DImpl::operator==(const Line2DImpl &l2d) bool Line2DImpl::operator!=(const Line2DImpl &l2d) { int i = 0; - if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()){ + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()) + { return true; } @@ -267,8 +306,8 @@ bool Line2DImpl::operator!=(const Line2DImpl &l2d) Line2DImpl Line2DImpl::operator[](int index) { - std::vector t; - t.push_back(handle->vectorOfSegments[index]); + std::vector t; + t.push_back(handle->vectorOfSegments[index].segment); Line2DImpl temp(t); return temp; } @@ -337,7 +376,8 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) std::string num1,num2,num3,num4; std::string s = st; std::string delimeter = ","; - + std::vector segments; + std::vector halfSegments; //std::vector nums; // unused // QUESTION: @@ -397,21 +437,17 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) std::cout<<"num1 and num2 is "<vectorOfSegments.push_back(halfseg); + } else{ return false; @@ -436,6 +472,8 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) pos = s.find(delimeter); flag++; } + lineSort(halfSegments); + handle->vectorOfSegments = halfSegments; return true; } catch(int e){ diff --git a/src/Line2DImpl.h b/src/Line2DImpl.h new file mode 100644 index 0000000..60b2f71 --- /dev/null +++ b/src/Line2DImpl.h @@ -0,0 +1,61 @@ +#ifndef LINE2DIMPL_H +#define LINE2DIMPL_H + +#include +#include + +#include "RGP.h" +#include "RGPSegment2D.h" +#include "RGPHalfSegment2D.h" + +class Line2DImpl +{ + public: + // Constructors + Line2DImpl(); + Line2DImpl(std::vector listOfSegments); + Line2DImpl(std::string listOfLine2DString); + Line2DImpl(std::ifstream& file); // Send in file for constructor + ~Line2DImpl(); + + class iterator + { + public: + iterator(RGPHalfSegment2D*); + RGPHalfSegment2D operator*(); + RGPHalfSegment2D operator++(int); + RGPHalfSegment2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPHalfSegment2D *ptr; + }; + + iterator begin(); + iterator end(); + + // Methods + std::string getLineString(); // Get the line as human readable ASCII string + void printAllLines(); + bool isEmptyLine(); + bool isValidLine(); + int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed + Line2DImpl getBoundingBox(); + + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(iterator it); // Removes a RGPSegment2D at specified index + + bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds + bool operator!=(const Line2DImpl &l2d); // Override of operator != to check inequality of two Line2Ds + Line2DImpl operator[](int index); // Retrieves a RGPSegment2D at specified index + Line2DImpl operator=(const Line2DImpl &l2dImpl); + + private: + struct Line2DImplStore; + Line2DImplStore *handle; + void lineSort(std::vector &bar); + void mergeSort(std::vector &left, std::vector &right, std::vector &bars); + bool parseStringToVectorOfLines(std::string st); +}; + +#endif //POINT2DIMPL_H \ No newline at end of file diff --git a/src/Point2DImpl.cpp b/src/Point2DImpl.cpp index 1d71955..fe13a25 100644 --- a/src/Point2DImpl.cpp +++ b/src/Point2DImpl.cpp @@ -1,12 +1,64 @@ #include "Point2DImpl.h" #include "RGPPoint2D.h" -#include"Number.h" +#include +#include + struct Point2DImpl::Point2DImplStore { std::vector vectorOfPoints; + std::vector boundingBox; }; +Point2DImpl::iterator::iterator(RGPPoint2D *ptr1) +{ + ptr = ptr1; +} + +RGPPoint2D Point2DImpl::iterator::operator*() +{ + return *ptr; +} + +RGPPoint2D Point2DImpl::iterator::operator++(int junk) +{ + RGPPoint2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +RGPPoint2D Point2DImpl::iterator::operator++() +{ + ptr++; + return *ptr; +} + +bool Point2DImpl::iterator::operator!=(const iterator &it) +{ + if(it.ptr==ptr) + return false; + return true; +} +bool Point2DImpl::iterator::operator==(const iterator &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +Point2DImpl::iterator Point2DImpl::begin() +{ + RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); + return iterator(ptr); +} + +Point2DImpl::iterator Point2DImpl::end() +{ + int t = handle->vectorOfPoints.size(); + return (iterator(&(handle->vectorOfPoints[t-1]))); +} + //Constructors Point2DImpl::Point2DImpl(std::vector listOfPoints) { @@ -14,6 +66,11 @@ Point2DImpl::Point2DImpl(std::vector listOfPoints) handle->vectorOfPoints = listOfPoints; } +Point2DImpl::Point2DImpl() +{ + handle = new Point2DImplStore; +} + Point2DImpl::Point2DImpl(std::ifstream& file) { /*std::string inputString; @@ -35,9 +92,16 @@ Point2DImpl::Point2DImpl(std::ifstream& file) Point2DImpl::Point2DImpl(std::string listOfPoint2DString) { - //TODO + handle = new Point2DImplStore; std::cout<< "inside" << "\n"; - parseStringToVectorOfPoints(listOfPoint2DString); + if(parseStringToVectorOfPoints(listOfPoint2DString)) + { + std::cout<<"All points are added successfully"< x = handle->vectorOfPoints; + for(auto i = x.begin(); i!=x.end(); i++) + std::cout<<*i; + std::cout<<")"; +} bool Point2DImpl::isValidPoint() { @@ -93,12 +165,12 @@ int Point2DImpl::getNumberOfPoints() return handle->vectorOfPoints.size(); } -std::vector Point2DImpl::getBoundingBox() +Point2DImpl Point2DImpl::getBoundingBox() { - //TODO - //Call convex hull implementation - - //return NULL; + std::vector box; + box = handle->boundingBox; + Point2DImpl pt(box); + return pt; } bool Point2DImpl::operator==(const Point2DImpl &p2d) @@ -132,28 +204,38 @@ bool Point2DImpl::operator!=(const Point2DImpl &p2d) return false; } -RGPPoint2D Point2DImpl::operator[](int index) +Point2DImpl Point2DImpl::operator[](int index) { - return handle->vectorOfPoints[index]; + std::vector t; + t.push_back(handle->vectorOfPoints[index]); + Point2DImpl temp(t); + return temp; } -/* -Point2DImpl Point2DImpl::operator=(const Point2D &p2d) + +Point2DImpl Point2DImpl::operator=(const Point2DImpl &p2d) { - // Emtpy -}*/ + handle->vectorOfPoints.clear(); + handle->vectorOfPoints = p2d.handle->vectorOfPoints; +} bool Point2DImpl::add(RGPPoint2D rgpp2d) { + + //handle->vectorOfPoints.push_back(rgpp2d); try { if(handle->vectorOfPoints.empty()) { handle->vectorOfPoints.push_back(rgpp2d); + return true; } int i=0; - while(rgpp2d > handle->vectorOfPoints[i]) - i++; - handle->vectorOfPoints.insert(handle->vectorOfPoints.begin()+i, rgpp2d); + while(rgpp2d > handle->vectorOfPoints[i] && i < handle->vectorOfPoints.size()) + i++; + if(i==handle->vectorOfPoints.size()) + handle->vectorOfPoints.push_back(rgpp2d); + else + handle->vectorOfPoints.insert(handle->vectorOfPoints.begin()+i, rgpp2d); } catch(int e) { @@ -162,13 +244,21 @@ bool Point2DImpl::add(RGPPoint2D rgpp2d) return true; } -bool Point2DImpl::update(std::vector::iterator it, RGPPoint2D rgpp2d) +bool Point2DImpl::update(Point2DImpl::iterator it, RGPPoint2D rgpp2d) { try { - int index = distance(handle->vectorOfPoints.begin(), it); - handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); - add(rgpp2d); + if(isEmptyPoint()) + { + return false; + } + else + { + int index = it.ptr - &(handle->vectorOfPoints[0]); + handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); + add(rgpp2d); + pointSort(handle->vectorOfPoints); + } } catch(int e) { @@ -177,12 +267,19 @@ bool Point2DImpl::update(std::vector::iterator it, RGPPoint2D rgpp2d return true; } -bool Point2DImpl::remove(std::vector::iterator it) +bool Point2DImpl::remove(Point2DImpl::iterator it) { try { - int index = distance(handle->vectorOfPoints.begin(), it); - handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); + if(isEmptyPoint()) + { + return false; + } + else + { + int index = it.ptr - &(handle->vectorOfPoints[0]); + handle->vectorOfPoints.erase(handle->vectorOfPoints.begin()+index); + } } catch(int e) { @@ -191,7 +288,6 @@ bool Point2DImpl::remove(std::vector::iterator it) return true; } - void Point2DImpl::pointSort(std::vector &bar) { if (bar.size() <= 1) @@ -243,12 +339,15 @@ void Point2DImpl::mergeSort(std::vector &left, std::vector points; + int pos,fl=0; + std::string num1,num2; std::string s =st; + std::vector nums; std::string delimeter = ","; s.erase(0,1); s.erase(s.length()-1,1); + s.append(","); std::cout << s << "\n"; pos = s.find(delimeter); std::cout << pos << "\n"; @@ -256,23 +355,33 @@ bool Point2DImpl::parseStringToVectorOfPoints(std::string st) while(pos!= std::string::npos) { std::string a = s.substr(0, pos); - std::cout << a << "\n"; - if(a.length()==2) + if(a.length()>=2) { try { if(a[0]=='(') { - num1 = a[1]; + std::string temp = ""; + int i =1; + while(((a[i]<='9'&&a[i]>='0')||a[i]=='.'||a[i]=='-')&&i='0')||a[i]=='.'||a[i]=='-')&&i boundPoints; + boundPoints.push_back(points[0]); + auto maxy = points[0].y; + std::cout<<"bound box \n"; + for(auto it = points.begin(); it!=points.end() ;it++) + { + if((*it).y > maxy) + maxy=(*it).y; } -} \ No newline at end of file + RGPPoint2D pt(points[points.size() - 1].x,maxy); + boundPoints.push_back(pt); + + std::cout<vectorOfPoints = points; + handle->boundingBox = boundPoints; + +} diff --git a/src/Point2DImpl.h b/src/Point2DImpl.h new file mode 100644 index 0000000..aeac56f --- /dev/null +++ b/src/Point2DImpl.h @@ -0,0 +1,55 @@ +#ifndef POINT2DIMPL_H +#define POINT2DIMPL_H + +#include +#include "RGPPoint2D.h" +#include "RGPSegment2D.h" + +class Point2DImpl +{ + public: + Point2DImpl(std::vector pointVector); + Point2DImpl(); + Point2DImpl(std::ifstream& file); // Take input from a file, convert the data into a Point2D + Point2DImpl(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D + ~Point2DImpl(); + class iterator + { + public: + iterator(RGPPoint2D*); + RGPPoint2D operator*(); + RGPPoint2D operator++(int); + RGPPoint2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPPoint2D *ptr; + }; + + // Methods + std::string getPointString(); // Get the point as human readable ASCII string + void printAllPoints(); + bool isEmptyPoint(); // Checks if the Point2D object is empty + bool isValidPoint(); // Checks if the Point2D object is empty + int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + iterator begin(); + iterator end(); + Point2DImpl getBoundingBox(); + + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object + bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(iterator it); // Removes a RGPPoint2D at specified index + + bool operator==(const Point2DImpl &p2d); // Override of operator == to check equality of two Point2Ds + bool operator!=(const Point2DImpl &p2d); // Override of operator != to check inequality of two Point2Ds + Point2DImpl operator[](int index); // Retrieves a RGPPoint2D at specified index + Point2DImpl operator=(const Point2DImpl &p2dImpl); + + private: + struct Point2DImplStore; + Point2DImplStore *handle; + void pointSort(std::vector &bar); + void mergeSort(std::vector &left, std::vector &right, std::vector &bars); + bool parseStringToVectorOfPoints(std::string st); +}; + +#endif //POINT2DIMPL_H From fdf711c3f45753ed5c3120ab32dfd62c8560100f Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 21:52:06 -0500 Subject: [PATCH 42/95] Add files via upload --- src/Region2D.cpp | 190 +++++++++---------- src/Region2DImpl.cpp | 424 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 519 insertions(+), 95 deletions(-) create mode 100644 src/Region2DImpl.cpp diff --git a/src/Region2D.cpp b/src/Region2D.cpp index 2eb2e50..e0b7187 100644 --- a/src/Region2D.cpp +++ b/src/Region2D.cpp @@ -1,95 +1,95 @@ -#include "Region2D.h" - -class Region2D::Region2DImpl {}; - -Region2D::Region2D() -{ - // Emtpy -} - -Region2D::Region2D(std::vector> listOfRegions) -{ - // Emtpy -} - -Region2D::Region2D(std::string listOfRegion2DString) -{ - // Emtpy -} - -Region2D::Region2D(std::ifstream& file) -{ - // Emtpy -} - -Region2D::~Region2D() -{ - // Emtpy -} - -std::string Region2D::getRegionString() // Get the region as human readable ASCII string -{ - // Emtpy -} - -Number Region2D::area() -{ - // Emtpy -} - -// static -bool Region2D::isEmptyRegion(Region2D region) -{ - // Emtpy -} - -int Region2D::getNumberOfFaces() -{ - // Emtpy -} - -std::vector Region2D::getBoundingBox() -{ - // Emtpy -} - -bool Region2D::addFace(std::vector) -{ - // Emtpy -} - -bool Region2D::update(int index, std::vector) -{ - // Emtpy -} - -bool Region2D::remove(int index) -{ - // Emtpy -} - -bool Region2D::operator==(const Region2D &p2d) -{ - // Emtpy -} - -bool Region2D::operator!=(const Region2D &p2d) -{ - // Emtpy -} - -std::vector Region2D::operator[](int index) -{ - // Empty -} - -template std::vector getCycle(T it) -{ - // Emtpy -} - -template std::vector getFace(T it) -{ - // Emtpy -} - +#include "Region2D.h" + +class Region2D::Region2DImpl {}; + +Region2D::Region2D() +{ + // Emtpy +} + +Region2D::Region2D(std::vector> listOfRegions) +{ + // Emtpy +} + +Region2D::Region2D(std::string listOfRegion2DString) +{ + // Emtpy +} + +Region2D::Region2D(std::ifstream& file) +{ + // Emtpy +} + +Region2D::~Region2D() +{ + // Emtpy +} + +std::string Region2D::getRegionString() // Get the region as human readable ASCII string +{ + // Emtpy +} + +Number Region2D::area() +{ + // Emtpy +} + +// static +bool Region2D::isEmptyRegion(Region2D region) +{ + // Emtpy +} + +int Region2D::getNumberOfFaces() +{ + // Emtpy +} + +std::vector Region2D::getBoundingBox() +{ + // Emtpy +} + +bool Region2D::addFace(std::vector) +{ + // Emtpy +} + +bool Region2D::update(int index, std::vector) +{ + // Emtpy +} + +bool Region2D::remove(int index) +{ + // Emtpy +} + +bool Region2D::operator==(const Region2D &p2d) +{ + // Emtpy +} + +bool Region2D::operator!=(const Region2D &p2d) +{ + // Emtpy +} + +std::vector Region2D::operator[](int index) +{ + // Empty +} + +template std::vector getCycle(T it) +{ + // Emtpy +} + +template std::vector getFace(T it) +{ + // Emtpy +} + diff --git a/src/Region2DImpl.cpp b/src/Region2DImpl.cpp new file mode 100644 index 0000000..75c002a --- /dev/null +++ b/src/Region2DImpl.cpp @@ -0,0 +1,424 @@ +#include "Region2DImpl.h" +#include + +struct Region2DImpl::Region2DImplStore +{ + std::vector sortedVectorOfSegments; + std::vector vectorOfAnnHalfSegments; + std::vector> vectorOfFaces; + std::vector> vectorOfHoles; + std::map faceToHoleRelationMap; + Number areaOfRegion; + + //std::vector outerCycle; +}; + +//Constructors + +Region2DImpl::Region2DImpl() +{ + +} + +Region2DImpl::Region2DImpl(std::vector listOfRegions) +{ + handle = new Region2DImplStore; + handle->vectorOfAnnHalfSegments = listOfRegions; +} + +Region2DImpl::Region2DImpl(std::string listOfRegion2DString) +{ + handle = new Region2DImplStore; + bool result = parseWDR(listOfRegion2DString); + if(result == true) + { + // check areas if adding upto positive Number + std::vector faceAreas; + std::vector holeAreas; + + Number tfaceArea("0"); + for(int i=0; ivectorOfFaces.size(); i++) + { + Number area = getAreaOfCycle(handle->vectorOfFaces[i]); + if(area <= Number("0")) + { + //TODO Throw exception + } + faceAreas.push_back(area); + tfaceArea = tfaceArea + area; + } + Number tholeArea("0"); + for(int i=0; ivectorOfHoles.size(); i++) + { + Number area = getAreaOfCycle(handle->vectorOfHoles[i]); + if(area <= Number("0")) + { + //TODO Throw exception + } + holeAreas.push_back(area); + tholeArea = tholeArea + area; + } + handle->areaOfRegion = tfaceArea - tholeArea; + + if(handle->areaOfRegion <= Number("0")) + { + //TODO throw exception + } + + // Check if all holes are contained in their respective faces + std::map::iterator itr; + int faceIndex = 0; + int holeIndex = 0; + for (itr = handle->faceToHoleRelationMap.begin(); itr != handle->faceToHoleRelationMap.end(); ++itr) { + Number fArea = faceAreas[faceIndex]; + Number hArea("0"); + for(int i=holeIndex; isecond; i++) + { + hArea = hArea + holeAreas[i]; + } + + if(fArea - hArea <= Number("0")) + { + //TODO throw exeption + + } + + faceIndex++; + holeIndex = holeIndex + itr->second; + } + + //Check if any 2 cycles are intersecting + + } + else + { + + } +} + +Number Region2DImpl::getAreaOfCycle(std::vector vectorOfSegments) +{ + Number area("0"); + Number xCoord[vectorOfSegments.size()/2]; + Number yCoord[vectorOfSegments.size()/2]; + int j =0; + for(int i=0; i faceToHoleMap; + if(inputString.length() < 2) + { + return false; + } + + std::string firstChar = inputString.substr(0,1); + std::string lastChar = inputString.substr(inputString.length()-1, inputString.length()); + if(firstChar != "[" || lastChar != "]") + { + return false; + } + + std::string notation = inputString.substr(1,3); + if(notation == "WCS") + { + return false; + } + + // formattedString = ((1 1,2 2),(1 1,2 2))& + std::string formattedString = inputString.substr(4); + formattedString.erase(formattedString.length()-1,1); + + std::string delimiter = "&"; + + int numOfFaces = 1; + int numOfHoles = 0; + + while(formattedString.length() > 0) + { + // ((1 1,2 2),(1 1,3 3)) = faceHoleSetString + int pos = formattedString.find(delimiter); + std::string faceHoleSetString = formattedString; + if(pos != -1) + { + faceHoleSetString = formattedString.substr(0,pos); + } + + // (1 1,2 2),(1 1,3 3) = partString + std::string partString = faceHoleSetString.substr(0,pos); + partString.erase(0,1); + partString.erase(partString.length()-1,1); + + // 1 1,2 2 = faceSegmentString + std::vector facePoints; + int faceClosingPoint = partString.find(")"); + std::string faceSegmentString = partString.substr(1,faceClosingPoint-1); + int faceSegmentStringLength = faceSegmentString.length(); + while(faceSegmentString.length() > 0) + { + int l = faceSegmentString.find(" "); + std::string coord1 = faceSegmentString.substr(0,l); + faceSegmentString.erase(0,l+1); + int r = faceSegmentString.find(","); + std::string coord2 = faceSegmentString.substr(0,r); + if(r == -1) + { + faceSegmentString.erase(0,faceSegmentString.length()); + } + else + { + faceSegmentString.erase(0,r+1); + } + facePoints.push_back(RGPPoint2D(Number(coord1), Number(coord2))); + } + if(facePoints[0] != facePoints[facePoints.size()-1]) + { + return false; + } + + std::vector emptyFaceVec; + handle->vectorOfFaces.push_back(emptyFaceVec); + + for(int i=0; ivectorOfFaces[numOfFaces-1].push_back(annHS); + handle->vectorOfFaces[numOfFaces-1].push_back(annHS2); + } + + std::vector> holePointVector; + std::string holesString = partString.substr(faceSegmentStringLength+3, partString.length()); + + while(holesString.find(")") != std::string::npos) + { + int holeClosingPoint = holesString.find(")"); + std::string holeSegmentString = holesString.substr(1,holeClosingPoint-1); + int holeSegmentStringLength = holeSegmentString.length(); + std::vector emptyVec; + std::vector emptyHoleVec; + holePointVector.push_back(emptyVec); + handle->vectorOfHoles.push_back(emptyHoleVec); + while(holeSegmentString.length() > 0) + { + int l = holeSegmentString.find(" "); + std::string coord1 = holeSegmentString.substr(0,l); + holeSegmentString.erase(0,l+1); + int r = holeSegmentString.find(","); + std::string coord2 = holeSegmentString.substr(0,r); + if(r == -1) + { + holeSegmentString.erase(0,holeSegmentString.length()); + } + else + { + holeSegmentString.erase(0,r+1); + } + + holePointVector[numOfHoles].push_back(RGPPoint2D(Number(coord1), Number(coord2))); + } + + std::vector hole = holePointVector[numOfHoles]; + if(hole[0] != hole[hole.size()-1]) + { + return false; + } + + for(int i=0; ivectorOfHoles[numOfHoles].push_back(annHS); + handle->vectorOfHoles[numOfHoles].push_back(annHS2); + } + + + holesString = holesString.substr(holeSegmentStringLength+2, holesString.length()); + if(holesString.length() != 0 && holesString.substr(0,1) == ",") + { + holesString.erase(0,1); + } + numOfHoles++; + } + + faceToHoleMap.insert(std::pair(numOfFaces,numOfHoles)); + numOfFaces++; + + int faceHoleSetStringLength = faceHoleSetString.length(); + if(pos != -1) + { + faceHoleSetStringLength++; + } + formattedString = formattedString.substr(faceHoleSetStringLength,formattedString.length()); + } + + std::map::iterator itr; + for (itr = faceToHoleMap.begin(); itr != faceToHoleMap.end(); ++itr) { + std::cout << '\t' << itr->first + << '\t' << itr->second << '\n'; + } + handle->faceToHoleRelationMap = faceToHoleMap; + return true; +} + +/* +std::vector Region2DImpl::constructRegion(std::string formattedInputString) +{ + // Parse the string into half segments + create a set of dp-array + std::map> mapOfDpToAnnHS; + + + // sort the annotated half segments + + // implement the algorithm + int numberOfHalfSegments = annHalfSegmentsVector.length; + int visitedHalfSegments = 0; + while(visitedHalfSegments != numberOfHalfSegments) + { + RGPAnnotatedHalfSegment2D annHalfSegment = handle->vectorOfAnnHalfSegments[visitedHalfSegments]; + if(annHalfSegment.isCycleComputed) + { + visitedHalfSegments++; + continue; + } + //TODO + // Find if this segment is a part of a outer cycle or hole cycle + annHalfSegment.isPartOfHole = computeCyclicStructure(); + + //NewCycle(h) + annHalfSegment.isCycleComputed = true; + std::vector newCycleSegments; + if(annHalfSegment.isPartOfHole) + { + annHalfSegment.insideIsAbove = false; + } + else + { + annHalfSegment.insideIsAbove = true; + } + newCycleSegments.push_back(annHalfSegment); + + //Visit(dp(h)) + annHalfSegment.isPointVisited = true; + + if(annHalfSegment.isPartOfHole) + { + //TODO + //Using sweep line status, retrieve halfsegment f from its owning outer cycle; + //Owns(h, f); + //Set cycle walk mode to use counter-clockwise adjacency; + } + else + { + //TODO Set cycle walk mode to use clockwise adjacency + } + + // Cycle walk + //1. Mark the other annotated hs to the current Cycle + RGPPoint2D otherDp = annHalfSegment.segment.point1; + + + visitedHalfSegments++; + } +} +*/ +Region2DImpl::Region2DImpl(std::ifstream& file) +{ + // Emtpy +} + +Region2DImpl::~Region2DImpl() +{ + // Emtpy +} + +std::string Region2DImpl::getRegionString() // Get the region as human readable ASCII string +{ + // Emtpy +} + +Number Region2DImpl::area() +{ + // Emtpy +} + +// static +bool Region2DImpl::isEmptyRegion(Region2DImpl region) +{ + // Emtpy +} + +int Region2DImpl::getNumberOfFaces() +{ + // Emtpy +} + +std::vector Region2DImpl::getBoundingBox() +{ + // Emtpy +} + +bool Region2DImpl::addFace(std::vector) +{ + // Emtpy +} + +bool Region2DImpl::update(int index, std::vector) +{ + // Emtpy +} + +bool Region2DImpl::remove(int index) +{ + // Emtpy +} + +bool Region2DImpl::operator==(const Region2DImpl &p2d) +{ + // Emtpy +} + +bool Region2DImpl::operator!=(const Region2DImpl &p2d) +{ + // Emtpy +} + +std::vector Region2DImpl::operator[](int index) +{ + // Empty +} + +template std::vector getCycle(T it) +{ + // Emtpy +} + +template std::vector getFace(T it) +{ + // Emtpy +} + From b990f84f3df1496677b7deba914d3f839b578c05 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 21:52:31 -0500 Subject: [PATCH 43/95] Add files via upload --- include/Region2D.h | 84 +++++++++++++++++++++--------------------- include/Region2DImpl.h | 43 +++++++++++++++++++++ 2 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 include/Region2DImpl.h diff --git a/include/Region2D.h b/include/Region2D.h index e70124b..d9fd653 100644 --- a/include/Region2D.h +++ b/include/Region2D.h @@ -1,42 +1,42 @@ -#ifndef REGION2D_H -#define REGION2D_H - -#include "Number.h" -#include "RGP.h" -#include -#include - -class Region2D -{ -public: - // Constructors - Region2D(); //Empty constructor - Region2D(std::vector> listOfRegions); - Region2D(std::string listOfRegion2DString); - Region2D(std::ifstream& file); // Send in file for constructor (possibly .txt) - ~Region2D(); - - // Methods - std::string getRegionString(); // Get the region as human readable ASCII string - Number area(); - static bool isEmptyRegion(Region2D region); - static bool isValidRegion(Region2D region); - int getNumberOfFaces(); - std::vector getBoundingBox(); - bool operator==(const Region2D &p2d); - bool operator!=(const Region2D &p2d); - std::vector getCycle(int index); - std::vector getFace(int index); - bool addFace(std::vector); - bool update(int index, std::vector); // Updates a whole region at specified index - bool remove(int index); // Removes a region at specified index - std::vector operator[](int index); // Retrieves a region at specified index - -private: - class Region2DImpl; - - // Fields - Region2DImpl *impl; -}; - -#endif // REGION2D_H +#ifndef REGION2D_H +#define REGION2D_H + +#include "Number.h" +#include "RGP.h" +#include +#include + +class Region2D +{ +public: + // Constructors + Region2D(); //Empty constructor + Region2D(std::vector> listOfRegions); + Region2D(std::string listOfRegion2DString); + Region2D(std::ifstream& file); // Send in file for constructor (possibly .txt) + ~Region2D(); + + // Methods + std::string getRegionString(); // Get the region as human readable ASCII string + Number area(); + static bool isEmptyRegion(Region2D region); + static bool isValidRegion(Region2D region); + int getNumberOfFaces(); + std::vector getBoundingBox(); + bool operator==(const Region2D &p2d); + bool operator!=(const Region2D &p2d); + std::vector getCycle(int index); + std::vector getFace(int index); + bool addFace(std::vector); + bool update(int index, std::vector); // Updates a whole region at specified index + bool remove(int index); // Removes a region at specified index + std::vector operator[](int index); // Retrieves a region at specified index + +private: + class Region2DImpl; + + // Fields + Region2DImpl *impl; +}; + +#endif // REGION2D_H diff --git a/include/Region2DImpl.h b/include/Region2DImpl.h new file mode 100644 index 0000000..5d2bed6 --- /dev/null +++ b/include/Region2DImpl.h @@ -0,0 +1,43 @@ +#ifndef Region2DImpl_H +#define Region2DImpl_H + +#include "Number.h" +#include "RGP.h" +#include +#include + +class Region2DImpl +{ +public: + // Constructors + Region2DImpl(std::vector listOfRegions); + Region2DImpl(); + Region2DImpl(std::string listOfRegion2DString); + Region2DImpl(std::ifstream& file); // Send in file for constructor (possibly .txt) + ~Region2DImpl(); + + // Methods + std::string getRegionString(); // Get the region as human readable ASCII string + Number area(); + bool isEmptyRegion(Region2DImpl region); + bool isValidRegion(Region2DImpl region); + int getNumberOfFaces(); + std::vector getBoundingBox(); + bool operator==(const Region2DImpl &p2d); + bool operator!=(const Region2DImpl &p2d); + std::vector getCycle(int index); + std::vector getFace(int index); + bool addFace(std::vector); + bool update(int index, std::vector); // Updates a whole region at specified index + bool remove(int index); // Removes a region at specified index + std::vector operator[](int index); // Retrieves a region at specified index + +private: + class Region2DImplStore; + bool parseWDR(std::string inputString); + Number getAreaOfCycle(std::vector vectorOfSegments); + Region2DImplStore *handle; + std::vector constructRegion(std::string formattedInputString); +}; + +#endif // Region2DImpl_H From 68a48516b8ba6857db7b8b8c421b74d5ad56efab Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:09:36 -0500 Subject: [PATCH 44/95] Delete Line2DImpl.h --- src/Line2DImpl.h | 61 ------------------------------------------------ 1 file changed, 61 deletions(-) delete mode 100644 src/Line2DImpl.h diff --git a/src/Line2DImpl.h b/src/Line2DImpl.h deleted file mode 100644 index 60b2f71..0000000 --- a/src/Line2DImpl.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef LINE2DIMPL_H -#define LINE2DIMPL_H - -#include -#include - -#include "RGP.h" -#include "RGPSegment2D.h" -#include "RGPHalfSegment2D.h" - -class Line2DImpl -{ - public: - // Constructors - Line2DImpl(); - Line2DImpl(std::vector listOfSegments); - Line2DImpl(std::string listOfLine2DString); - Line2DImpl(std::ifstream& file); // Send in file for constructor - ~Line2DImpl(); - - class iterator - { - public: - iterator(RGPHalfSegment2D*); - RGPHalfSegment2D operator*(); - RGPHalfSegment2D operator++(int); - RGPHalfSegment2D operator++(); - bool operator!=(const iterator&); - bool operator==(const iterator&); - RGPHalfSegment2D *ptr; - }; - - iterator begin(); - iterator end(); - - // Methods - std::string getLineString(); // Get the line as human readable ASCII string - void printAllLines(); - bool isEmptyLine(); - bool isValidLine(); - int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - Line2DImpl getBoundingBox(); - - bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(iterator it); // Removes a RGPSegment2D at specified index - - bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds - bool operator!=(const Line2DImpl &l2d); // Override of operator != to check inequality of two Line2Ds - Line2DImpl operator[](int index); // Retrieves a RGPSegment2D at specified index - Line2DImpl operator=(const Line2DImpl &l2dImpl); - - private: - struct Line2DImplStore; - Line2DImplStore *handle; - void lineSort(std::vector &bar); - void mergeSort(std::vector &left, std::vector &right, std::vector &bars); - bool parseStringToVectorOfLines(std::string st); -}; - -#endif //POINT2DIMPL_H \ No newline at end of file From a61cee339c9cd5eaa3df6dc646ac0d1e8946d670 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:09:49 -0500 Subject: [PATCH 45/95] Delete Point2DImpl.h --- src/Point2DImpl.h | 55 ----------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/Point2DImpl.h diff --git a/src/Point2DImpl.h b/src/Point2DImpl.h deleted file mode 100644 index aeac56f..0000000 --- a/src/Point2DImpl.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef POINT2DIMPL_H -#define POINT2DIMPL_H - -#include -#include "RGPPoint2D.h" -#include "RGPSegment2D.h" - -class Point2DImpl -{ - public: - Point2DImpl(std::vector pointVector); - Point2DImpl(); - Point2DImpl(std::ifstream& file); // Take input from a file, convert the data into a Point2D - Point2DImpl(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D - ~Point2DImpl(); - class iterator - { - public: - iterator(RGPPoint2D*); - RGPPoint2D operator*(); - RGPPoint2D operator++(int); - RGPPoint2D operator++(); - bool operator!=(const iterator&); - bool operator==(const iterator&); - RGPPoint2D *ptr; - }; - - // Methods - std::string getPointString(); // Get the point as human readable ASCII string - void printAllPoints(); - bool isEmptyPoint(); // Checks if the Point2D object is empty - bool isValidPoint(); // Checks if the Point2D object is empty - int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed - iterator begin(); - iterator end(); - Point2DImpl getBoundingBox(); - - bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object - bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index - bool remove(iterator it); // Removes a RGPPoint2D at specified index - - bool operator==(const Point2DImpl &p2d); // Override of operator == to check equality of two Point2Ds - bool operator!=(const Point2DImpl &p2d); // Override of operator != to check inequality of two Point2Ds - Point2DImpl operator[](int index); // Retrieves a RGPPoint2D at specified index - Point2DImpl operator=(const Point2DImpl &p2dImpl); - - private: - struct Point2DImplStore; - Point2DImplStore *handle; - void pointSort(std::vector &bar); - void mergeSort(std::vector &left, std::vector &right, std::vector &bars); - bool parseStringToVectorOfPoints(std::string st); -}; - -#endif //POINT2DIMPL_H From 57f14cdf4247128b8b686bbcc10b48e5aee0b9a6 Mon Sep 17 00:00:00 2001 From: kadarisai <31567088+kadarisai@users.noreply.github.com> Date: Fri, 7 Dec 2018 22:10:09 -0500 Subject: [PATCH 46/95] Add files via upload --- include/Line2DImpl.h | 7 ++++--- include/Point2DImpl.h | 25 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 960d3ee..60b2f71 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -12,7 +12,8 @@ class Line2DImpl { public: // Constructors - Line2DImpl(std::vector listOfSegments); + Line2DImpl(); + Line2DImpl(std::vector listOfSegments); Line2DImpl(std::string listOfLine2DString); Line2DImpl(std::ifstream& file); // Send in file for constructor ~Line2DImpl(); @@ -40,8 +41,8 @@ class Line2DImpl int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed Line2DImpl getBoundingBox(); - bool add(RGPHalfSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(iterator it, RGPHalfSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index bool remove(iterator it); // Removes a RGPSegment2D at specified index bool operator==(const Line2DImpl &l2d); // Override of operator == to check equality of two Line2Ds diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h index 60ad66f..aeac56f 100644 --- a/include/Point2DImpl.h +++ b/include/Point2DImpl.h @@ -9,25 +9,40 @@ class Point2DImpl { public: Point2DImpl(std::vector pointVector); + Point2DImpl(); Point2DImpl(std::ifstream& file); // Take input from a file, convert the data into a Point2D Point2DImpl(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D ~Point2DImpl(); + class iterator + { + public: + iterator(RGPPoint2D*); + RGPPoint2D operator*(); + RGPPoint2D operator++(int); + RGPPoint2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPPoint2D *ptr; + }; // Methods std::string getPointString(); // Get the point as human readable ASCII string + void printAllPoints(); bool isEmptyPoint(); // Checks if the Point2D object is empty bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed - std::vector getBoundingBox(); + iterator begin(); + iterator end(); + Point2DImpl getBoundingBox(); bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object - bool update(std::vector::iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index - bool remove(std::vector::iterator it); // Removes a RGPPoint2D at specified index + bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(iterator it); // Removes a RGPPoint2D at specified index bool operator==(const Point2DImpl &p2d); // Override of operator == to check equality of two Point2Ds bool operator!=(const Point2DImpl &p2d); // Override of operator != to check inequality of two Point2Ds - RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index - //Point2DImpl operator=(const Point2DImpl &p2dImpl) + Point2DImpl operator[](int index); // Retrieves a RGPPoint2D at specified index + Point2DImpl operator=(const Point2DImpl &p2dImpl); private: struct Point2DImplStore; From a1bb2bdcccffa546e0b14c2e565d0a7d900afeec Mon Sep 17 00:00:00 2001 From: kadarisai <31567088+kadarisai@users.noreply.github.com> Date: Fri, 7 Dec 2018 22:11:01 -0500 Subject: [PATCH 47/95] Add files via upload From e83c2045a4f7a7249fd06dbf976c61dde1c0caab Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:32 -0500 Subject: [PATCH 48/95] Update Line2D.cpp --- src/Line2D.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Line2D.cpp b/src/Line2D.cpp index 4360f3a..4eb1031 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -1,5 +1,5 @@ -#include "../include/Line2D.h" -#include "../include/Line2DImpl.h" +#include "Line2D.h" +#include "Line2DImpl.h" struct Line2D::Line2DStore { Line2DImpl *implPointer; From c9bd99fc3b8310c03367cfbbb893931a7a262751 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:37 -0500 Subject: [PATCH 49/95] Update Line2DForProgrammer.cpp --- src/Line2DForProgrammer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Line2DForProgrammer.cpp b/src/Line2DForProgrammer.cpp index 08c01b1..6600844 100644 --- a/src/Line2DForProgrammer.cpp +++ b/src/Line2DForProgrammer.cpp @@ -1,6 +1,6 @@ -#include "../include/Line2D.h" -#include "../include/Line2DImpl.h" -#include "../include/Line2DForProgrammer.h" +#include "Line2D.h" +#include "Line2DImpl.h" +#include "Line2DForProgrammer.h" struct Line2DForProgrammer::Line2DProgrammerStore { From 3caa6dafcceaea4590fab9b7bc6ba6084f8168b9 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:40 -0500 Subject: [PATCH 50/95] Update Line2DImpl.cpp --- src/Line2DImpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 644d31a..f895350 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -1,5 +1,5 @@ -#include "../include/Line2D.h" -#include "../include/Line2DImpl.h" +#include "Line2D.h" +#include "Line2DImpl.h" #include #include #include From 73c247a56796e8aa09a9717f02fb880ac19c05ed Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:44 -0500 Subject: [PATCH 51/95] Update Point2D.cpp --- src/Point2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index bc5f824..56b31d8 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -65,5 +65,5 @@ bool Point2D::operator!=(const Point2D &p2d) std::vector Point2D::getBoundingBox() { - return handle->implPointer->getBoundingBox(); + //return handle->implPointer->getBoundingBox(); } From 8aa4159010414aedc2b29d15f0104fa782864f5e Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:48 -0500 Subject: [PATCH 52/95] Update RGPHalfSegment2D.cpp --- src/RGPHalfSegment2D.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RGPHalfSegment2D.cpp b/src/RGPHalfSegment2D.cpp index 361ca89..4525995 100644 --- a/src/RGPHalfSegment2D.cpp +++ b/src/RGPHalfSegment2D.cpp @@ -9,7 +9,11 @@ RGPHalfSegment2D::RGPHalfSegment2D(RGPSegment2D s, RGPPoint2D dp) isLeftFlag = true; else isLeftFlag = false; - m = (s.point2.y - s.point1.y) / (s.point2.x - s.point2.x); + if(s.point2.x - s.point2.x != Number("0")) { + m = (s.point2.y - s.point1.y) / (s.point2.x - s.point2.x); + } else { + m = s.point2.x - s.point2.x; + } } RGPHalfSegment2D::~RGPHalfSegment2D() {} From a53ee7ff9849595d807fc314b63422a6a0a867db Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Fri, 7 Dec 2018 22:21:56 -0500 Subject: [PATCH 53/95] Update postgres_ext.cpp --- postgres_ext.cpp | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/postgres_ext.cpp b/postgres_ext.cpp index aef5bff..e8b2b12 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -6,12 +6,46 @@ #include "include/RGPPoint2D.h" #include "include/RGPSegment2D.h" #include "include/Region2D.h" +#include "include/Point2D.h" +#include "include/Region2DImpl.h" -int -main(void) +int main(void) { Number n; - Number a("5"); + Number b("5"); + //std::cout< Date: Sat, 8 Dec 2018 20:04:50 -0500 Subject: [PATCH 54/95] Updated report group2 --- Report_Group2.docx | Bin 0 -> 23413 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Report_Group2.docx diff --git a/Report_Group2.docx b/Report_Group2.docx new file mode 100644 index 0000000000000000000000000000000000000000..3d168ad6bbd652054e15265081fef399b5288eda GIT binary patch literal 23413 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 Date: Sat, 8 Dec 2018 20:56:25 -0500 Subject: [PATCH 55/95] Revert "Merge branch 'group4_fin' into Group2_November" This reverts commit eb5d8e53d68e735a26ff955cb1d62e9e91370225, reversing changes made to f29a72a0937aa8c1a666ad53d63c6704804f6bc1. --- include/AVLTree.h | 48 -- include/Evaluate.h | 34 - include/Explore.h | 26 - include/Line2DImpl.h | 2 +- include/Optional.h | 27 - include/PlaneSweep.h | 117 ---- include/PredicateEnum.h | 6 - include/RGPHalfSegment2D.h | 3 +- include/RGPPoint2D.h | 1 - include/RGPSegment2D.h | 1 - include/Region2DImpl.h | 2 +- include/Relationship2D.h | 77 --- include/STO.h | 10 - include/SpatialOperations.h | 27 - src/AVLTree.cpp | 202 ------ src/Evaluate.cpp | 1260 ----------------------------------- src/Explore.cpp | 663 ------------------ src/PlaneSweep.cpp | 268 -------- src/RGPHalfSegment2D.cpp | 1 + src/RGPPoint2D.cpp | 3 +- src/Region2DImpl.cpp | 3 +- src/Relationship2D.cpp | 678 ------------------- src/SpatialOperations.cpp | 122 ---- 23 files changed, 7 insertions(+), 3574 deletions(-) delete mode 100644 include/AVLTree.h delete mode 100644 include/Evaluate.h delete mode 100644 include/Explore.h delete mode 100644 include/Optional.h delete mode 100644 include/PlaneSweep.h delete mode 100644 include/PredicateEnum.h delete mode 100644 include/Relationship2D.h delete mode 100644 include/STO.h delete mode 100644 include/SpatialOperations.h delete mode 100644 src/AVLTree.cpp delete mode 100644 src/Evaluate.cpp delete mode 100644 src/Explore.cpp delete mode 100644 src/PlaneSweep.cpp delete mode 100644 src/Relationship2D.cpp delete mode 100644 src/SpatialOperations.cpp diff --git a/include/AVLTree.h b/include/AVLTree.h deleted file mode 100644 index 90ca847..0000000 --- a/include/AVLTree.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef AVLTree_H -#define AVLTree_H - -#include -#include - -/* AVL node */ -template -class AVLnode { -public: - T key; - int balance; - AVLnode *left, *right, *parent; - - AVLnode(T k, AVLnode *p) : key(k), balance(0), parent(p), - left(NULL), right(NULL) {} - - ~AVLnode() { - delete left; - delete right; - } -}; - -/* AVL tree */ -template -class AVLtree { -public: - AVLtree(void); - ~AVLtree(void); - bool insert(T key); - void deleteKey(const T key); - void printBalance(); - -private: - AVLnode *root; - - AVLnode* rotateLeft ( AVLnode *a ); - AVLnode* rotateRight ( AVLnode *a ); - AVLnode* rotateLeftThenRight ( AVLnode *n ); - AVLnode* rotateRightThenLeft ( AVLnode *n ); - void rebalance ( AVLnode *n ); - int height ( AVLnode *n ); - void setBalance ( AVLnode *n ); - void printBalance ( AVLnode *n ); - void clearNode ( AVLnode *n ); -}; - -#endif //AVLTree_H diff --git a/include/Evaluate.h b/include/Evaluate.h deleted file mode 100644 index 425e9cf..0000000 --- a/include/Evaluate.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef EVALUATE_H -#define EVALUATE_H - -#include "Point2DImpl.h" -#include "PredicateEnum.h" -#include "Line2DImpl.h" -#include "Region2DImpl.h" -#include - -class Evaluate { -public: - Evaluate(); - ~Evaluate(); - -// std::vector &featureVectorF, std::vector &featureVectorG - static bool validate( Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - static bool validate( Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - static bool validate( Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - static bool validate( Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - static bool validate( Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - static bool validate( Region2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate); - - static Predicate determine( Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - static Predicate determine( Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - static Predicate determine( Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - static Predicate determine( Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - static Predicate determine( Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - static Predicate determine( Region2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ); - -private: - std::vector >* IM; -}; - -#endif //EVALUATE_H diff --git a/include/Explore.h b/include/Explore.h deleted file mode 100644 index b352646..0000000 --- a/include/Explore.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef EXPLORE_H -#define EXPLORE_H - -#include "RGP.h" -#include "../include/Point2DImpl.h" -#include "Line2DImpl.h" -#include "Region2DImpl.h" -#include "PlaneSweep.h" -#include - -class Explore -{ -public: - Explore(); - ~Explore(); - - // F and G are spatial objects where F is of same or lower dimension then G - void explore(Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG); - void explore(Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG); - void explore(Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF); - void explore(Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG); - void explore(Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG); - void explore(Region2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG); -}; - -#endif diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index b1b6d41..60b2f71 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -58,4 +58,4 @@ class Line2DImpl bool parseStringToVectorOfLines(std::string st); }; -#endif //POINT2DIMPL_H +#endif //POINT2DIMPL_H \ No newline at end of file diff --git a/include/Optional.h b/include/Optional.h deleted file mode 100644 index 9f7f160..0000000 --- a/include/Optional.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef OPTIONAL_H -#define OPTIONAL_H - -// Optional definition -#ifdef __has_include - -// Check for standard library -# if __has_include() -# include - using std::optional; - using std::make_optional; - using std::nullopt; - -// Check for exprimental version (bug fix for Xcode on macOS) -# elif __has_include() -# include - using std::experimental::optional; - using std::experimental::make_optional; - using std::experimental::nullopt; - -// Not found -# else -# error "Missing " -# endif -#endif - -#endif //OPTIONAL_H diff --git a/include/PlaneSweep.h b/include/PlaneSweep.h deleted file mode 100644 index b84f895..0000000 --- a/include/PlaneSweep.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef PLANESWEEP_H -#define PLANESWEEP_H - -#include "RGP.h" -#include "AVLTree.h" -#include -#include -#include - -// Object - ObjectSelected -enum class ObjectSelected {OBJ_F, OBJ_G, BOTH, NONE}; -// Status - TraversalStatus -enum class TraversalStatus {END_OF_F, END_OF_G, END_OF_BOTH, END_OF_NONE}; - -// template -// class PointerWrapper{ -// -// PointerWrapper(typename std::vector::iterator dynamicIterator) { -// myIterator = dynamicIterator; -// } -// typename std::vector::iterator myIterator; -// -// bool operator>(const PointerWrapper &pw)const { -// return true; -// } -// }; - -template -class PlaneSweep { -public: - PlaneSweep(typename std::vector::iterator startIteratorF, typename std::vector::iterator endIteratorF, - typename std::vector::iterator startIteratorG, typename std::vector::iterator endIteratorG); - - PlaneSweep(const std::vector& seqF, const std::vector& seqG); - - ObjectSelected object; - TraversalStatus status; - - ~PlaneSweep(); - - void select_first(); - void select_next(); - - // Get event returns the element to which the logical pointer of a point - // or half segment sequence of an object points to - // typename std::vector::const_iterator getEventF(); - // typename std::vector::const_iterator getEventG(); - F getEventF(); - G getEventG(); - - // Checks whether a given point lies on/in any segment of the sweep line status - bool pointOnSegment(RGPPoint2D p); - bool pointInSegment(RGPPoint2D p); - - // Inserts/Removes a segment from the sweep line status when it's left/right half segment is encountered - void insert(RGPSegment2D s); - void remove(RGPSegment2D s); - - // Check if the dominant points of the given halfsegment and the next halfsegment - // (after the current index) of the indicated sequence are equal - bool lookAheadF(RGPHalfSegment2D h); - bool lookAheadG(RGPHalfSegment2D h); - - // Atribute - whether a segment is inside a region - // Returns the nearest annotated halfsegment, from the sweep line status, below a given point, if there is one - optional getAttributeOfSegmentBelow(RGPPoint2D p); - // Returns the overlap numbers of the predecessor to the given segment in the sweep line status - optional> getOverlapNumbersOfPredecessor(RGPSegment2D s); - // Returns the overlap numbers of the given segment in the sweep line status - optional> getOverlapNumbersOf(RGPSegment2D s); - -private: - // Stores event points - std::queue eventPointSchedule; - - // PointerWrapper() iteratorPtr; - // Holds the state of the intersection of the sweep line - - AVLtree sweepLineStatus; - //Sets an attribute for a segment in the sweep line status - void set_attr(AVLtree &sweepLineStatus, bool attribute); - //Gets an attribute from a segment in the sweep line status - bool get_attr(AVLtree &sweepLineStatus); - //Yields the attribute from the prdecessor of a segment in the sweepline status - bool get_pred_attr(AVLtree &sweepLineStatus, RGPHalfSegment2D segment); - //Checks for a segment in the sweepLineStatus to check if it hasa predecessor - bool pred_exists(AVLtree &sweepLineStatus, RGPHalfSegment2D segment); - //Checks for a neighbor segment - bool common_point_exists(AVLtree &sweepLineStatus, RGPHalfSegment2D segment); - //Tests whether such a segment exists - bool current_exists(AVLtree &sweepLineStatus); - //Stores left segment component into the segment sequence of the sweep line status - bool add_left(); - //Removes a segment component from the segment sequence of the sweep line status - bool del_right(); - //Returns new sweep line status - AVLtree new_sweep(); - - // template - // References to the spatial object sequences - const std::vector& staticSequenceF; - const std::vector& staticSequenceG; - std::vector dynamicSequenceF; - std::vector dynamicSequenceG; - typename std::vector::iterator staticIteratorF; - typename std::vector::iterator staticIteratorG; - // Iterators to check if we are at the end of vector - // typename std::vector::iterator startStaticIteratorF; - // typename std::vector::iterator startStaticIteratorG; - typename std::vector::iterator endStaticIteratorF; - typename std::vector::iterator endStaticIteratorG; - typename std::vector::iterator dynamicIteratorF; - typename std::vector::iterator dynamicIteratorG; - -}; - -#endif //PLANESWEEP diff --git a/include/PredicateEnum.h b/include/PredicateEnum.h deleted file mode 100644 index f849a68..0000000 --- a/include/PredicateEnum.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef POSTGRES_EXT_PREDICATEENUM_H -#define POSTGRES_EXT_PREDICATEENUM_H - -enum class Predicate { disjoint, meet, overlap, covers, contains, equal, inside, coveredBy }; - -#endif //POSTGRES_EXT_PREDICATEENUM_H diff --git a/include/RGPHalfSegment2D.h b/include/RGPHalfSegment2D.h index 99bfba5..7bfaa8f 100644 --- a/include/RGPHalfSegment2D.h +++ b/include/RGPHalfSegment2D.h @@ -1,9 +1,8 @@ #ifndef RGPHALFSEGMENT2D_H #define RGPHALFSEGMENT2D_H -#include "RGPSegment2D.h" #include "RGPPoint2D.h" -#include "Optional.h" +#include "RGPSegment2D.h" class RGPHalfSegment2D { public: diff --git a/include/RGPPoint2D.h b/include/RGPPoint2D.h index 08f1e2d..3303df8 100644 --- a/include/RGPPoint2D.h +++ b/include/RGPPoint2D.h @@ -6,7 +6,6 @@ #define RGPPOINT2D_H #include "Number.h" -#include "Optional.h" class RGPPoint2D { public: diff --git a/include/RGPSegment2D.h b/include/RGPSegment2D.h index 946bf3a..55cd0c9 100644 --- a/include/RGPSegment2D.h +++ b/include/RGPSegment2D.h @@ -6,7 +6,6 @@ #define RGPSEGMENT2D_H #include "RGPPoint2D.h" -#include "Optional.h" class RGPSegment2D { public: diff --git a/include/Region2DImpl.h b/include/Region2DImpl.h index 19aaa47..5d2bed6 100644 --- a/include/Region2DImpl.h +++ b/include/Region2DImpl.h @@ -40,4 +40,4 @@ class Region2DImpl std::vector constructRegion(std::string formattedInputString); }; -#endif // Region2DImpl_H \ No newline at end of file +#endif // Region2DImpl_H diff --git a/include/Relationship2D.h b/include/Relationship2D.h deleted file mode 100644 index 3e5fb13..0000000 --- a/include/Relationship2D.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef POSTGRES_EXT_RELATIONSHIP2D_H -#define POSTGRES_EXT_RELATIONSHIP2D_H - -#include "PredicateEnum.h" -#include "Point2D.h" -#include "Line2D.h" -#include "Region2D.h" - -class Relationship2D { - -public: - - Relationship2D(); - ~Relationship2D(); - - // Determine relationship - // Reference these from Evaluate.h - // enum PREDICATE { disjoint, meet, overlap, covers, contains, equal, inside, coveredBy }; - static Predicate determine(Point2D &leftOperand, Point2D &rightOperand); - static Predicate determine(Point2D &leftOperand, Line2D &rightOperand); - static Predicate determine(Point2D &leftOperand, Region2D &rightOperand); - static Predicate determine(Line2D &leftOperand, Line2D &rightOperand); - static Predicate determine(Line2D &leftOperand, Region2D &rightOperand); - static Predicate determine(Region2D &leftOperand, Region2D &rightOperand); - - // Disjoint - static bool disjoint(Point2D &leftOperand, Point2D &rightOperand); - static bool disjoint(Point2D &leftOperand, Line2D &rightOperand); - static bool disjoint(Point2D &leftOperand, Region2D &rightOperand); - static bool disjoint(Line2D &leftOperand, Line2D &rightOperand); - static bool disjoint(Line2D &leftOperand, Region2D &rightOperand); - static bool disjoint(Region2D &leftOperand, Region2D &rightOperand); - - // Meet - static bool meet(Point2D &leftOperand, Line2D &rightOperand); - static bool meet(Point2D &leftOperand, Region2D &rightOperand); - static bool meet(Line2D &leftOperand, Line2D &rightOperand); - static bool meet(Line2D &leftOperand, Region2D &rightOperand); - static bool meet(Region2D &leftOperand, Region2D &rightOperand); - - // Overlap - static bool overlap(Point2D &leftOperand, Point2D &rightOperand); - static bool overlap(Point2D &leftOperand, Line2D &rightOperand); - static bool overlap(Point2D &leftOperand, Region2D &rightOperand); - static bool overlap(Line2D &leftOperand, Line2D &rightOperand); - static bool overlap(Line2D &leftOperand, Region2D &rightOperand); - static bool overlap(Region2D &leftOperand, Region2D &rightOperand); - - // Equal - static bool equal(Point2D &leftOperand, Point2D &rightOperand); - static bool equal(Line2D &leftOperand, Line2D &rightOperand); - static bool equal(Region2D &leftOperand, Region2D &rightOperand); - - // Inside - static bool inside(Point2D &leftOperand, Point2D &rightOperand); - static bool inside(Point2D &leftOperand, Line2D &rightOperand); - static bool inside(Point2D &leftOperand, Region2D &rightOperand); - static bool inside(Line2D &leftOperand, Line2D &rightOperand); - static bool inside(Line2D &leftOperand, Region2D &rightOperand); - static bool inside(Region2D &leftOperand, Region2D &rightOperand); - - // Contains - static bool contains(Point2D &leftOperand, Point2D &rightOperand); - static bool contains(Line2D &leftOperand, Line2D &rightOperand); - static bool contains(Region2D &leftOperand, Region2D &rightOperand); - - // Covers - static bool covers(Line2D &leftOperand, Line2D &rightOperand); - static bool covers(Region2D &leftOperand, Region2D &rightOperand); - - // Covered by - static bool coveredBy(Line2D &leftOperand, Line2D &rightOperand); - static bool coveredBy(Line2D &leftOperand, Region2D &rightOperand); - static bool coveredBy(Region2D &leftOperand, Region2D &rightOperand); -}; - -#endif //POSTGRES_EXT_RELATIONSHIP2D_H diff --git a/include/STO.h b/include/STO.h deleted file mode 100644 index f040e69..0000000 --- a/include/STO.h +++ /dev/null @@ -1,10 +0,0 @@ -// Global include for complex spatial types - -#ifndef SPATIALTYPES_H -#define SPATIALTYPES_H - -#include "Point2D.h" -#include "Line2D.h" -#include "Region2D.h" - -#endif //SPATIALTYPES_H \ No newline at end of file diff --git a/include/SpatialOperations.h b/include/SpatialOperations.h deleted file mode 100644 index 1f36c45..0000000 --- a/include/SpatialOperations.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SPATIALOPERATIONS_H -#define SPATIALOPERATIONS_H - -#include "STO.h" - -class SpatialOperations{ -public: - SpatialOperations(); - ~SpatialOperations(); - - Point2D union(Point2D F, Point2D G); - Line2D union(Line2D F, Line2D G); - Region2D union(Region2D F, Region2D G); - - Point2D intersection(Point2D F, Point2D G); - Line2D intersection(Line2D F, Line2D G); - Region2D intersection(Region2D F, Region2D G); - Line2D intersection(Region2D F, Line2D G); - - Point2D difference(Point2D F, Point2D G); - Line2D difference(Line2D F, Line2D G); - Region2D difference(Region2D F, Region2D G); -private: - -}; - -#endif //SPATIALOPERATIONS_H diff --git a/src/AVLTree.cpp b/src/AVLTree.cpp deleted file mode 100644 index 74bbe26..0000000 --- a/src/AVLTree.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "AVLTree.h" - -/* AVL class definition */ -template -void AVLtree::rebalance(AVLnode *n) { - setBalance(n); - - if (n->balance == -2) { - if (height(n->left->left) >= height(n->left->right)) - n = rotateRight(n); - else - n = rotateLeftThenRight(n); - } - else if (n->balance == 2) { - if (height(n->right->right) >= height(n->right->left)) - n = rotateLeft(n); - else - n = rotateRightThenLeft(n); - } - - if (n->parent != NULL) { - rebalance(n->parent); - } - else { - root = n; - } -} - -template -AVLnode* AVLtree::rotateLeft(AVLnode *a) { - AVLnode *b = a->right; - b->parent = a->parent; - a->right = b->left; - - if (a->right != NULL) - a->right->parent = a; - - b->left = a; - a->parent = b; - - if (b->parent != NULL) { - if (b->parent->right == a) { - b->parent->right = b; - } - else { - b->parent->left = b; - } - } - - setBalance(a); - setBalance(b); - return b; -} - -template -AVLnode* AVLtree::rotateRight(AVLnode *a) { - AVLnode *b = a->left; - b->parent = a->parent; - a->left = b->right; - - if (a->left != NULL) - a->left->parent = a; - - b->right = a; - a->parent = b; - - if (b->parent != NULL) { - if (b->parent->right == a) { - b->parent->right = b; - } - else { - b->parent->left = b; - } - } - - setBalance(a); - setBalance(b); - return b; -} - -template -AVLnode* AVLtree::rotateLeftThenRight(AVLnode *n) { - n->left = rotateLeft(n->left); - return rotateRight(n); -} - -template -AVLnode* AVLtree::rotateRightThenLeft(AVLnode *n) { - n->right = rotateRight(n->right); - return rotateLeft(n); -} - -template -int AVLtree::height(AVLnode *n) { - if (n == NULL) - return -1; - return 1 + std::max(height(n->left), height(n->right)); -} - -template -void AVLtree::setBalance(AVLnode *n) { - n->balance = height(n->right) - height(n->left); -} - -template -void AVLtree::printBalance(AVLnode *n) { - if (n != NULL) { - printBalance(n->left); - std::cout << n->balance << " "; - printBalance(n->right); - } -} - -template -AVLtree::AVLtree(void) : root(NULL) {} - -template -AVLtree::~AVLtree(void) { - delete root; -} - -template -bool AVLtree::insert(T key) { - if (root == NULL) { - root = new AVLnode(key, NULL); - } - else { - AVLnode - *n = root, - *parent; - - while (true) { - if (n->key == key) - return false; - - parent = n; - - bool goLeft = n->key > key; - n = goLeft ? n->left : n->right; - - if (n == NULL) { - if (goLeft) { - parent->left = new AVLnode(key, parent); - } - else { - parent->right = new AVLnode(key, parent); - } - - rebalance(parent); - break; - } - } - } - - return true; -} - -template -void AVLtree::deleteKey(const T delKey) { - if (root == NULL) - return; - - AVLnode - *n = root, - *parent = root, - *delNode = NULL, - *child = root; - - while (child != NULL) { - parent = n; - n = child; - child = delKey >= n->key ? n->right : n->left; - if (delKey == n->key) - delNode = n; - } - - if (delNode != NULL) { - delNode->key = n->key; - - child = n->left != NULL ? n->left : n->right; - - if (root->key == delKey) { - root = child; - } - else { - if (parent->left == n) { - parent->left = child; - } - else { - parent->right = child; - } - - rebalance(parent); - } - } -} - -template -void AVLtree::printBalance() { - printBalance(root); - std::cout << std::endl; -} diff --git a/src/Evaluate.cpp b/src/Evaluate.cpp deleted file mode 100644 index 3102b92..0000000 --- a/src/Evaluate.cpp +++ /dev/null @@ -1,1260 +0,0 @@ -#include "Evaluate.h" -#include "PredicateEnum.h" - -Evaluate::Evaluate() {} - -Evaluate::~Evaluate() {} - -// ------------ Validate ----------------- - -bool Evaluate::validate( Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -bool Evaluate::validate( Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -bool Evaluate::validate( Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -bool Evaluate::validate( Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -bool Evaluate::validate( Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -bool Evaluate::validate( Region2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG, Predicate predicate) -{ - if( Evaluate::determine(spatialObj_F, spatialObj_G, featureVectorF, featureVectorG) == predicate ) { return true; } else { return false; } -} - -// ------------ Determine ----------------- - -Predicate Evaluate::determine( Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ) -{ - enum VectorFlag {poi_shared, poi_disjoint}; - - if ( featureVectorF[poi_disjoint] ) { // A0B- - if ( featureVectorF[poi_shared] ) { // A0B0, moved right - if ( featureVectorG[poi_disjoint] ) { // A-B0 - return Predicate::overlap; // 5 - } else { - return Predicate::contains; // 4 - } - } else { - return Predicate::disjoint; // 1 - } - } else { // A-B0, moved left - if ( featureVectorG[poi_disjoint] ) { // vg[poi_disjoint] - return Predicate::inside; // 3 - } else { - return Predicate::equal; // 2 - } - - } -} - -Predicate Evaluate::determine( Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ) -{ - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - if( featureVectorF[poi_on_interior] ) { // A0B0 - if( featureVectorF[poi_on_bound] ) { // A0&B (boundary B) - if( featureVectorF[poi_disjoint] ) { // A0B- - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::overlap; // 14 - } else { - return Predicate::overlap; //13 - } - } else { - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::inside; // 12 - } else { - return Predicate::inside; // 11 - } - } - } else { - if ( featureVectorF[poi_disjoint]) { // A0B- - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::overlap; // 9 - } else { - return Predicate::overlap; // 10 - } - } else { - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::inside; // 7 - } else { - return Predicate::inside; // 8 - } - } - } - } else { - if( featureVectorF[poi_on_bound] ) { // A0&B - if ( featureVectorF[poi_disjoint] ) { // A0B- - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::meet; // 6 - } else { - return Predicate::meet; // 5 - } - } else { - if ( featureVectorG[bound_poi_disjoint] ) { // A-&B - return Predicate::meet; // 4 - } else { - return Predicate::meet; // 3 - } - } - } else { // A-&B - if ( featureVectorG[bound_poi_disjoint] ) { - return Predicate::disjoint; // 2 - } else { - return Predicate::disjoint; // 1 - } - } - } -} - -Predicate Evaluate::determine( Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -{ - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - if ( featureVectorF[poi_inside] ) { // A0B0 - if ( featureVectorF[poi_on_bound] ) { // A0&B - if ( featureVectorF[poi_outside] ) { // A0B- - return Predicate::overlap; // 7 - } else { - return Predicate::inside; // 6 - } - } else { - if ( featureVectorF[poi_outside] ) { // A0B- - return Predicate::inside; // 4 - } else { - return Predicate::overlap; // 5 - } - } - } else { - if ( featureVectorF[poi_on_bound] ) { // A0&B - if ( featureVectorF[poi_outside] ) { //A0B- - return Predicate::meet; // 3 - } else { - return Predicate::meet; // 2 - } - } else { - return Predicate::disjoint; // 1 - } - } -} - -Predicate Evaluate::determine( Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ) -{ - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - if (featureVectorF[bound_shared]) - { - if (featureVectorG[bound_on_interior]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorF[bound_disjoint]) - { - if (featureVectorF[seg_unshared]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::equal; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::inside; - } - else - { - return Predicate::inside; - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::disjoint; - } - else - { - return Predicate::disjoint; - } - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::contains; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::disjoint; - } - else - { - return Predicate::disjoint; - } - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::contains; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_unshared]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_unshared]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorF[bound_disjoint]) - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - else - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::contains; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - else - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::contains; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorG[bound_on_interior]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorF[bound_disjoint]) - { - if (featureVectorF[seg_unshared]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::equal; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::coveredBy; - } - else - { - return Predicate::coveredBy; - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_unshared]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_unshared]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorF[bound_disjoint]) - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - else - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[interior_poi_shared]) - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - else - { - if (featureVectorF[bound_on_interior]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } -} - -Predicate Evaluate::determine( Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ) -{ - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - if (featureVectorF[bound_shared]) - { - if (featureVectorF[bound_inside]) - { - if (featureVectorF[seg_inside]) - { - if (featureVectorF[bound_disjoint]) - { - if (featureVectorF[seg_outside]) - { - if (featureVectorG[seg_unshared]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[poi_shared]) - { - return Predicate::disjoint; - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[poi_shared]) - { - return Predicate::disjoint; - } - else - { - if (featureVectorG[seg_unshared]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[poi_shared]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[seg_unshared]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[poi_shared]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorG[seg_unshared]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[seg_outside]) - { - return Predicate::inside; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorF[seg_shared] || featureVectorF[poi_shared]) - { - if (featureVectorF[bound_inside]) - { - if (featureVectorF[seg_inside]) - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[seg_outside]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_outside]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorF[seg_inside]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::meet; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::meet; - } - else - { - return Predicate::meet; - } - } - } - else - { - if (featureVectorF[bound_inside]) - { - if (featureVectorF[seg_outside]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[seg_outside]) - { - return Predicate::coveredBy; - } - else - { - if (featureVectorF[bound_disjoint]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } -} - -Predicate Evaluate::determine( Region2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG ) -{ - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - if (featureVectorG[one_two] || featureVectorG[two_one]) - { - if (featureVectorF[zero_one] || featureVectorF[one_zero]) - { - if (featureVectorF[zero_one] || featureVectorF[one_zero] || featureVectorF[one_one] || featureVectorG[one_two] || featureVectorG[two_one]) - { - if (featureVectorF[one_two] || featureVectorF[two_one]) - { - if (featureVectorF[one_two] || featureVectorF[two_one] || featureVectorF[one_one] || featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::equal; - } - else - { - return Predicate::coveredBy; - } - } - else - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_one] || featureVectorF[bound_poi_shared]) - { - return Predicate::inside; - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::coveredBy; - } - else - { - return Predicate::coveredBy; - } - } - } - } - else - { - if (featureVectorF[one_two] || featureVectorF[two_one]) - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_two] || featureVectorF[two_one] || featureVectorG[one_two] || featureVectorG[two_one]) - { - return Predicate::meet; - } - else - { - return Predicate::overlap; - } - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_two] || featureVectorF[two_one] || featureVectorG[one_two] || featureVectorG[two_one]) - { - return Predicate::meet; - } - else - { - if (featureVectorF[one_two] || featureVectorF[two_one]) - { - if (featureVectorF[one_two] || featureVectorF[two_one] || featureVectorF[one_one] || featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::covers; - } - else - { - return Predicate::overlap; - } - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_two] || featureVectorF[two_one] || featureVectorG[one_two] || featureVectorG[two_one]) - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_one] || featureVectorF[bound_poi_shared]) - { - return Predicate::disjoint; - } - else - { - return Predicate::meet; - } - } - else - { - if (featureVectorF[one_two] || featureVectorF[two_one]) - { - return Predicate::overlap; - } - else - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_one] || featureVectorF[bound_poi_shared]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - } - else - { - if (featureVectorF[one_two] || featureVectorF[two_one]) - { - if (featureVectorF[zero_one] || featureVectorF[one_zero]) - { - if (featureVectorF[one_two] || featureVectorF[two_one] || featureVectorF[one_one] || featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_one] || featureVectorF[bound_poi_shared]) - { - if (featureVectorF[one_two] || featureVectorF[two_one] || featureVectorF[one_one] || featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::contains; - } - else - { - return Predicate::overlap; - } - } - else - { - if (featureVectorF[one_two] || featureVectorF[two_one] || featureVectorF[one_one] || featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::covers; - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } - else - { - if (featureVectorF[zero_two] || featureVectorF[two_zero] || featureVectorF[one_one] || featureVectorF[bound_poi_shared]) - { - if (featureVectorF[zero_one] || featureVectorF[one_zero]) - { - return Predicate::overlap; - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - else - { - if (featureVectorF[zero_one] || featureVectorF[one_zero]) - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - else - { - if (featureVectorG[zero_one] || featureVectorG[one_zero]) - { - return Predicate::overlap; - } - else - { - return Predicate::overlap; - } - } - } - } - } -} diff --git a/src/Explore.cpp b/src/Explore.cpp deleted file mode 100644 index 49f7903..0000000 --- a/src/Explore.cpp +++ /dev/null @@ -1,663 +0,0 @@ -#include "Explore.h" - -// Point x Point -void Explore::explore(Point2DImpl &spatialObj_F, Point2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); - - sweep.select_first(); - - // Terminates when the end of an object is reached, or all flags are turned on - while (sweep.status == TraversalStatus::END_OF_NONE && !(featureVectorF[poi_disjoint] && featureVectorG[poi_disjoint] && featureVectorF[poi_shared])) - { - if (sweep.object == ObjectSelected::OBJ_F) - { - featureVectorF[poi_disjoint] = true; - } - else if (sweep.object == ObjectSelected::OBJ_G) - { - featureVectorG[poi_disjoint] = true; - } - else if (sweep.object == ObjectSelected::BOTH) - { - featureVectorF[poi_shared] = true; - } - - sweep.select_next(); - } - - if (sweep.status == TraversalStatus::END_OF_F) - { - featureVectorG[poi_disjoint] = true; - } - else if (sweep.status == TraversalStatus::END_OF_G) - { - featureVectorF[poi_disjoint] = true; - } - - return; -} - -// Point x Line -void Explore::explore(Point2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); - - optional lastDominantPoint = nullopt; // Empty point - - sweep.select_first(); - - while (sweep.status != TraversalStatus::END_OF_G && sweep.status != TraversalStatus::END_OF_BOTH && - !(featureVectorF[poi_disjoint] && featureVectorF[poi_on_interior] && featureVectorF[poi_on_bound] && featureVectorG[bound_poi_disjoint])) - { - if (sweep.object == ObjectSelected::OBJ_F) - { - RGPPoint2D p = sweep.getEventF(); - - if (sweep.pointInSegment(p)) - { - featureVectorF[poi_on_interior] = true; - } - else - { - featureVectorF[poi_disjoint] = true; - } - } - else if (sweep.object == ObjectSelected::OBJ_G) - { - RGPHalfSegment2D h = sweep.getEventG(); - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - sweep.remove(h.segment); - } - - optional dp = make_optional(h.dominantPoint); - - if (lastDominantPoint != dp) - { - lastDominantPoint = dp; - - if (!sweep.lookAheadG(h)) - { - featureVectorG[bound_poi_disjoint] = true; - } - } - } - else // BOTH - { - RGPHalfSegment2D h = sweep.getEventG(); - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - sweep.remove(h.segment); - } - - lastDominantPoint = make_optional(h.dominantPoint); - - if (sweep.lookAheadG(h)) - { - featureVectorF[poi_on_interior] = true; - } - else - { - featureVectorF[poi_on_bound] = true; - } - } - - sweep.select_next(); - } - - if (sweep.status == TraversalStatus::END_OF_G) - { - featureVectorF[poi_disjoint] = true; - } -} - -// Point x Region -void Explore::explore(Point2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); - - sweep.select_first(); - - while (sweep.status == TraversalStatus::END_OF_NONE && !(featureVectorF[poi_inside] && featureVectorF[poi_on_bound] && featureVectorF[poi_outside])) - { - if (sweep.object == ObjectSelected::OBJ_F) - { - RGPPoint2D p = sweep.getEventF(); - - if (sweep.pointOnSegment(p)) - { - featureVectorF[poi_on_bound] = true; - } - else - { - if (auto attr = sweep.getAttributeOfSegmentBelow(p)) - { - if (*attr) - { - featureVectorF[poi_inside] = true; - } - else - { - featureVectorF[poi_outside] = true; - } - } - else - { - featureVectorF[poi_outside] = true; - } - } - } - else - { - RGPAnnotatedHalfSegment2D ah = sweep.getEventG(); - - if (ah.dominantPoint == ah.segment.point1) // Left halfsegment - { - sweep.insert(ah.segment); - } - else // Right halfsegment - { - sweep.remove(ah.segment); - } - - if (sweep.object == ObjectSelected::BOTH) - { - featureVectorF[poi_on_bound] = true; - } - } - - sweep.select_next(); - } - - if (sweep.status == TraversalStatus::END_OF_G) - { - featureVectorF[poi_outside] = true; - } -} - -// Line x Line -void Explore::explore(Line2DImpl &spatialObj_F, Line2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); - - optional lastDominantPointF = nullopt; - optional lastDominantPointG = nullopt; - optional lastBoundaryPointF = nullopt; - optional lastBoundaryPointG = nullopt; - - sweep.select_first(); - - while (sweep.status != TraversalStatus::END_OF_BOTH && - !(featureVectorF[seg_shared] && featureVectorF[interior_poi_shared] && featureVectorF[seg_unshared] && - featureVectorF[bound_on_interior] && featureVectorF[bound_shared] && featureVectorF[bound_disjoint] && - featureVectorG[bound_disjoint] && featureVectorG[bound_on_interior] && featureVectorG[seg_unshared])) - { - if (sweep.object == ObjectSelected::OBJ_F) - { - RGPHalfSegment2D h = sweep.getEventF(); - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - sweep.remove(h.segment); - featureVectorF[seg_unshared] = true; - } - - optional dp = make_optional(h.dominantPoint); - - if (lastDominantPointF != dp) - { - lastDominantPointF = dp; - - if (!sweep.lookAheadF(h)) - { - lastBoundaryPointF = dp; - - if (lastBoundaryPointF == lastBoundaryPointG) - { - featureVectorF[bound_shared] = true; - } - else if (lastBoundaryPointF == lastDominantPointG) - { - featureVectorF[bound_on_interior] = true; - } - else if(!sweep.lookAheadG(h)) - { - featureVectorF[bound_disjoint] = true; - } - } - } - - if (dp != lastBoundaryPointF) - { - if (dp == lastBoundaryPointG) - { - featureVectorG[bound_on_interior] = true; - } - else if (dp == lastDominantPointG) - { - featureVectorF[interior_poi_shared] = true; - } - } - } - else if (sweep.object == ObjectSelected::OBJ_G) - { - RGPHalfSegment2D h = sweep.getEventG(); - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - sweep.remove(h.segment); - featureVectorG[seg_unshared] = true; - } - - optional dp = make_optional(h.dominantPoint); - - if (lastDominantPointG != dp) - { - lastDominantPointG = dp; - - if (!sweep.lookAheadG(h)) - { - lastBoundaryPointG = dp; - - if (lastBoundaryPointG == lastBoundaryPointF) - { - featureVectorG[bound_shared] = true; - } - else if (lastBoundaryPointG == lastDominantPointF) - { - featureVectorG[bound_on_interior] = true; - } - else if(!sweep.lookAheadF(h)) - { - featureVectorG[bound_disjoint] = true; - } - } - } - - if (dp != lastBoundaryPointG) - { - if (dp == lastBoundaryPointF) - { - featureVectorF[bound_on_interior] = true; - } - else if (dp == lastDominantPointF) - { - featureVectorG[interior_poi_shared] = true; - } - } - } - else // BOTH - { - RGPHalfSegment2D h = sweep.getEventF(); - featureVectorF[seg_shared] = true; - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - sweep.remove(h.segment); - } - - optional dp = make_optional(h.dominantPoint); - - if (lastDominantPointF != dp) - { - lastDominantPointF = dp; - - if (!sweep.lookAheadF(h)) - { - lastBoundaryPointF = dp; - } - } - - if (dp != lastDominantPointG) - { - lastDominantPointG = dp; - - if (!sweep.lookAheadG(h)) - { - lastBoundaryPointG = dp; - } - } - - if (lastBoundaryPointF == lastBoundaryPointG) - { - featureVectorF[bound_shared] = true; - } - else - { - if (lastBoundaryPointF == lastDominantPointG) - { - featureVectorF[bound_on_interior] = true; - } - - if (lastBoundaryPointG == lastDominantPointF) - { - featureVectorG[bound_on_interior] = true; - } - } - } - - if (sweep.status == TraversalStatus::END_OF_F) - { - featureVectorG[seg_unshared] = true; - } - else if (sweep.status == TraversalStatus::END_OF_G) - { - featureVectorF[seg_unshared] = true; - } - - sweep.select_next(); - } -} - -// Line x Region -void Explore::explore(Line2DImpl &spatialObj_F, Region2DImpl &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); - - optional lastDominantPointF = nullopt; - optional lastDominantPointG = nullopt; - optional lastBoundaryPointF = nullopt; - - sweep.select_first(); - - while (sweep.status != TraversalStatus::END_OF_F && sweep.status != TraversalStatus::END_OF_BOTH && - !(featureVectorF[seg_inside] && featureVectorF[seg_shared] && featureVectorF[seg_outside] && featureVectorF[poi_shared] && - featureVectorF[bound_inside] && featureVectorF[bound_shared] && featureVectorF[bound_disjoint] && featureVectorG[seg_unshared])) - { - if (sweep.object == ObjectSelected::OBJ_F) - { - RGPHalfSegment2D h = sweep.getEventF(); - - if (h.dominantPoint == h.segment.point1) // Left halfsegment - { - sweep.insert(h.segment); - } - else // Right halfsegment - { - if (auto overlapNums = sweep.getOverlapNumbersOfPredecessor(h.segment)) - { - auto [m,n] = *overlapNums; - - if (n == 1) - { - featureVectorF[seg_inside] = true; - } - else - { - featureVectorF[seg_outside] = true; - } - } - - sweep.remove(h.segment); - } - - optional dp = make_optional(h.dominantPoint); - - if (dp != lastDominantPointF) - { - lastDominantPointF = dp; - - if (!sweep.lookAheadF(h)) - { - lastBoundaryPointF = dp; - - if (lastBoundaryPointF == lastDominantPointG || sweep.lookAheadG(h)) - { - featureVectorF[bound_shared] = true; - } - else - { - if (auto overlapNums = sweep.getOverlapNumbersOfPredecessor(h.segment)) - { - auto [m,n] = *overlapNums; - - if (n == 1) - { - featureVectorF[bound_inside] = true; - } - else - { - featureVectorF[bound_disjoint] = true; - } - } - else - { - featureVectorF[bound_disjoint] = true; - } - } - } - } - - if (dp != lastBoundaryPointF && (dp == lastDominantPointG || sweep.lookAheadG(h))) - { - featureVectorF[poi_shared] = true; - } - } - else if (sweep.object == ObjectSelected::OBJ_G) - { - RGPAnnotatedHalfSegment2D ah = sweep.getEventG(); - - if (ah.dominantPoint == ah.segment.point1) // Left halfsegment - { - sweep.insert(ah.segment); - } - else // Right halfsegment - { - sweep.remove(ah.segment); - featureVectorG[seg_unshared] = true; - } - - optional dp = make_optional(ah.dominantPoint); - - if (dp != lastDominantPointG) - { - lastDominantPointG = dp; - } - } - else // BOTH - { - featureVectorF[seg_shared] = true; - - RGPAnnotatedHalfSegment2D ah = sweep.getEventG(); - - if (ah.dominantPoint == ah.segment.point1) // Left halfsegment - { - sweep.insert(ah.segment); - } - else // Right halfsegment - { - sweep.remove(ah.segment); - } - - optional dp = make_optional(ah.dominantPoint); - - if (dp != lastDominantPointF) - { - lastDominantPointF = dp; - - if (!sweep.lookAheadF(ah)) - { - featureVectorF[bound_shared] = true; - } - else - { - featureVectorF[poi_shared] = true; - } - } - - if (dp != lastDominantPointG) - { - lastDominantPointG = dp; - } - } - - if (sweep.status == TraversalStatus::END_OF_G) - { - featureVectorF[seg_outside] = true; - } - - sweep.select_next(); - } - - if (sweep.status == TraversalStatus::END_OF_F) - { - featureVectorG[seg_unshared] = true; - } -} - -//// Region x Region -//void Explore::explore(Region2D &spatialObj_F, Region2D &spatialObj_G, std::vector &featureVectorF, std::vector &featureVectorG) -//{ -// // Indicates what index in the bool vector represents what flag -// enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; -// -// PlaneSweep sweep(spatialObj_F.getSequence(), spatialObj_G.getSequence()); -// -// optional lastDominantPointF = nullopt; -// optional lastDominantPointG = nullopt; -// -// sweep.select_first(); -// -// while (sweep.status == TraversalStatus::END_OF_NONE && -// !(featureVectorF[zero_one] && featureVectorF[one_zero] && featureVectorF[one_two] && featureVectorF[two_one] && featureVectorF[zero_two] && featureVectorF[two_zero] && -// featureVectorF[one_one] && featureVectorF[bound_poi_shared] && featureVectorG[zero_one] && featureVectorG[one_zero] && featureVectorG[one_two] && featureVectorG[two_one])) -// { -// RGPAnnotatedHalfSegment2D ah; -// -// if (sweep.object == ObjectSelected::OBJ_F) -// { -// ah = sweep.getEventF(); -// lastDominantPointF = make_optional(ah.dominantPoint); -// } -// else if (sweep.object == ObjectSelected::OBJ_G) -// { -// ah = sweep.getEventG(); -// lastDominantPointG = make_optional(ah.dominantPoint); -// } -// else // BOTH -// { -// ah = sweep.getEventF() -// lastDominantPointF = make_optional(ah.dominantPoint); -// lastDominantPointG = make_optional(ah.dominantPoint); -// } -// -// if (lastDominantPointF == lastDominantPointG || sweep.lookAheadG(ah) || sweep.lookAheadF(ah)) -// { -// featureVectorF[bound_poi_shared] = true; -// } -// -// if (h.dominantPoint == h.segment.point2) // Right halfsegment -// { -// VectorFlag flag; -// -// if (auto overlapNums = sweep.getOverlapNumbersOf(ah.segment)) -// { -// auto [m,n] = *overlapNums; -// -// switch(m) -// { -// case 0: -// switch(n) -// { -// case 1: -// flag = zero_one; -// break; -// case 2: -// flag = zero_two; -// break; -// default:return; -// } -// break; -// case 1: -// switch(m) -// { -// case 0: -// flag = one_zero; -// break; -// case 1: -// flag = one_one; -// break; -// case 2: -// flag = one_two; -// break; -// default:return; -// } -// break; -// case 2: -// switch(m) -// { -// case 0: -// flag = two_zero; -// break; -// case 1: -// flag = two_one; -// break; -// default:return; -// } -// break; -// default:return; -// } -// } -// -// if (sweep.object == ObjectSelected::OBJ_F) -// { -// featureVectorF[flag] = true; -// } -// else if (sweep.object == ObjectSelected::OBJ_G) -// { -// featureVectorG[flag] = true; -// } -// else if (sweep.object == ObjectSelected::BOTH) -// { -// featureVectorF[flag] = true; -// featureVectorG[flag] = true; -// } -// -// sweep.remove(ah.segment); -// } -// else // Left halfsegment -// { -// sweep.insert(ah.segment); -// -// -// } -// } -//} diff --git a/src/PlaneSweep.cpp b/src/PlaneSweep.cpp deleted file mode 100644 index d8ef327..0000000 --- a/src/PlaneSweep.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "../include/PlaneSweep.h" - -//Constructors -template -PlaneSweep::PlaneSweep(typename std::vector::iterator startIteratorF, typename std::vector::iterator endIteratorF, - typename std::vector::iterator startIteratorG, typename std::vector::iterator endIteratorG) : - staticIteratorF(startIteratorF), endStaticIteratorF(endIteratorF), staticIteratorG(startIteratorG), endStaticIteratorG(endIteratorG) -{ - object = ObjectSelected::NONE; - status = TraversalStatus::END_OF_NONE; -} - -template -PlaneSweep::~PlaneSweep() -{ - //Empty -} - -template -void PlaneSweep::select_first() -{ - if (!staticSequenceF.empty()) - { - if (!staticSequenceG.empty()) - { - if ((*staticIteratorG) > (*staticIteratorF)) - { - object = ObjectSelected::OBJ_F; - } - else if ((*staticIteratorG) < (*staticIteratorF)) - { - object = ObjectSelected::OBJ_G; - } - else - { - object = ObjectSelected::BOTH; - } - status = TraversalStatus::END_OF_NONE; - } - else - { - status = TraversalStatus::END_OF_G; - } - } - else if (!staticSequenceG.empty()) - { - status = TraversalStatus::END_OF_F; - } - else - { - status = TraversalStatus::END_OF_BOTH; - } - return; -} - -template -void PlaneSweep::select_next() { - if (object == ObjectSelected::OBJ_F) - { - if (++staticIteratorF < endStaticIteratorF) - { - if (status != TraversalStatus::END_OF_G) - { - if ( (*staticIteratorG) > (*staticIteratorF)) - { - object = ObjectSelected::OBJ_F; - } - else if ((*staticIteratorG) < (*staticIteratorF)) - { - object = ObjectSelected::OBJ_G; - } - else - { - object = ObjectSelected::BOTH; - } - } - else - { - object = ObjectSelected::OBJ_F; - } - } - else - { - if (status == TraversalStatus::END_OF_G) - { - object = ObjectSelected::NONE; - status = TraversalStatus::END_OF_BOTH; - } - else - { - object = ObjectSelected::OBJ_G; - status = TraversalStatus::END_OF_F; - } - } - } - else if (object == ObjectSelected::OBJ_G) - { - if (++staticIteratorG < endStaticIteratorG) - { - if (status != TraversalStatus::END_OF_F) - { - if ((*staticIteratorG) > (*staticIteratorF)) - { - object = ObjectSelected::OBJ_F; - } - else if ((*staticIteratorG) < (*staticIteratorF)) - { - object = ObjectSelected::OBJ_G; - } - else - { - object = ObjectSelected::BOTH; - } - } - else - { - object = ObjectSelected::OBJ_G; - } - } - else - { - if (status == TraversalStatus::END_OF_F) - { - object = ObjectSelected::NONE; - status = TraversalStatus::END_OF_BOTH; - } - else - { - object = ObjectSelected::OBJ_F; - status = TraversalStatus::END_OF_G; - } - } - } - else if (object == ObjectSelected::BOTH) - { - ++staticIteratorF; - ++staticIteratorG; - - bool check_F = staticIteratorF < endStaticIteratorF; - bool check_G = staticIteratorG < endStaticIteratorG; - - if (check_F && check_G) - { - if ((*staticIteratorG) > (*staticIteratorF)) - { - object = ObjectSelected::OBJ_F; - } - else if ((*staticIteratorG) < (*staticIteratorF)) - { - object = ObjectSelected::OBJ_G; - } - else - { - object = ObjectSelected::BOTH; - } - } - else if (check_F) - { - object = ObjectSelected::OBJ_F; - status = TraversalStatus::END_OF_G; - } - else if (check_G) - { - object = ObjectSelected::OBJ_G; - status = TraversalStatus::END_OF_F; - } - else - { - object = ObjectSelected::NONE; - status = TraversalStatus::END_OF_BOTH; - } - } -} - -template -F PlaneSweep::getEventF() -{ - // Get event returns the element to which the logical pointer of a - // point or half segment sequence of an object points to - return *staticIteratorF; -} - -template -G PlaneSweep::getEventG() -{ - // Get event returns the element to which the logical pointer of a - // point or half segment sequence of an object points to - return *staticIteratorG; -} - -template -bool PlaneSweep::pointOnSegment(RGPPoint2D p) -{ - // Checks whether a given point lies on/in any segment of the sweep line status - -} - -template -bool PlaneSweep::pointInSegment(RGPPoint2D p) -{ - // Checks whether a given point lies on/in any segment of the sweep line status - - -} - -template -// Inserts/Removes a segment from the sweep line status when -// it's left/right half segment is encountered -void PlaneSweep::insert(RGPSegment2D s) -{ - sweepLineStatus.insert(s); -} - - -template -void PlaneSweep::remove(RGPSegment2D s) -{ - sweepLineStatus.deleteKey(s); -} - -template -bool PlaneSweep::lookAheadF(RGPHalfSegment2D h) -{ - // Check if the dominant points of the given halfsegment and the next - // halfsegment (after the current index) of the indicated sequence are equal - if (staticIteratorF == endStaticIteratorF) { - return (*++staticIteratorF) == h; - } else { - return false; - } -} - -template -bool PlaneSweep::lookAheadG(RGPHalfSegment2D h) -{ - // Check if the dominant points of the given halfsegment and the next - // halfsegment (after the current index) of the indicated sequence are equal - if (staticIteratorG == endStaticIteratorG) { - return (*++staticIteratorG) == h; - } else { - return false; - } -} - - -template -optional PlaneSweep::getAttributeOfSegmentBelow(RGPPoint2D p) -{ - // Returns the nearest annotated halfsegment, from the sweep line status, - // below a given point, if there is one - - // Loops through sweep line status, checking if the segment is classified as less than our RGPPoint2D - // Returns the first one that is true - -} - -template -optional> PlaneSweep::getOverlapNumbersOfPredecessor(RGPSegment2D s) -{ - // Returns the overlap numbers of the predecessor to the given segment in the sweep line status - -} - -template -optional> PlaneSweep::getOverlapNumbersOf(RGPSegment2D s) -{ - // Returns the overlap numbers of the given segment in the sweep line status -} diff --git a/src/RGPHalfSegment2D.cpp b/src/RGPHalfSegment2D.cpp index 9132069..4525995 100644 --- a/src/RGPHalfSegment2D.cpp +++ b/src/RGPHalfSegment2D.cpp @@ -66,5 +66,6 @@ RGPAnnotatedHalfSegment2D::RGPAnnotatedHalfSegment2D(RGPSegment2D s, bool regAbove) : RGPHalfSegment2D::RGPHalfSegment2D(s, dp) { this->insideIsAbove = regAbove; +} RGPAnnotatedHalfSegment2D::~RGPAnnotatedHalfSegment2D() {} diff --git a/src/RGPPoint2D.cpp b/src/RGPPoint2D.cpp index acb000d..2d94b6a 100644 --- a/src/RGPPoint2D.cpp +++ b/src/RGPPoint2D.cpp @@ -40,5 +40,4 @@ std::istream &operator>>(std::istream &is, RGPPoint2D p) { is >> p.y; is >> c; return is; -} - +} \ No newline at end of file diff --git a/src/Region2DImpl.cpp b/src/Region2DImpl.cpp index 6f33d45..75c002a 100644 --- a/src/Region2DImpl.cpp +++ b/src/Region2DImpl.cpp @@ -420,4 +420,5 @@ template std::vector getCycle(T it) template std::vector getFace(T it) { // Emtpy -} \ No newline at end of file +} + diff --git a/src/Relationship2D.cpp b/src/Relationship2D.cpp deleted file mode 100644 index df59083..0000000 --- a/src/Relationship2D.cpp +++ /dev/null @@ -1,678 +0,0 @@ -#include "PredicateEnum.h" -#include "Relationship2D.h" -#include "PlaneSweep.h" -#include "Explore.h" -#include "Evaluate.h" - -#include - -// ============================================================================= -// --------------------------- Determination ----------------------------------- -// ============================================================================= - -Predicate Relationship2D::determine(Point2D &leftOperand, Point2D &rightOperand) -{ - // Explore - explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -Predicate Relationship2D::determine(Point2D &leftOperand, Line2D &rightOperand) -{ - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -Predicate Relationship2D::determine(Point2D &leftOperand, Region2D &rightOperand) -{ - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -Predicate Relationship2D::determine(Line2D &leftOperand, Line2D &rightOperand) -{ - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -Predicate Relationship2D::determine(Line2D &leftOperand, Region2D &rightOperand) -{ - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -Predicate Relationship2D::determine(Region2D &leftOperand, Region2D &rightOperand) -{ - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::determine(leftOperand, rightOperand, leftFeature, rightFeature); -} - -// ============================================================================= -// --------------------------- Verification ------------------------------------ -// ============================================================================= - -// Disjoint -bool Relationship2D::disjoint(Point2D &leftOperand, Point2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - std::vector leftFeature(2, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !leftFeature[poi_shared] && leftFeature[poi_disjoint]; -} - -bool Relationship2D::disjoint(Point2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - std::vector leftFeature(3, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !leftFeature[poi_on_interior] && !leftFeature[poi_on_bound]; -} - -bool Relationship2D::disjoint(Point2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - std::vector leftFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !leftFeature[poi_inside] && !leftFeature[poi_on_bound]; -} - -bool Relationship2D::disjoint(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !(leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && - // !rightFeature[bound_on_interior] && - // leftFeature[seg_unshared] && - // !leftFeature[bound_on_interior] && - // !leftFeature[bound_shared]; -} - -bool Relationship2D::disjoint(Line2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - std::vector leftFeature(7, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !leftFeature[seg_inside] && - // !(leftFeature[seg_shared] || leftFeature[poi_shared]) && - // leftFeature[seg_outside] && - // !leftFeature[bound_inside] && - // !leftFeature[bound_shared]; -} - -bool Relationship2D::disjoint(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::disjoint); - - // return !(leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_two] || leftFeature[two_one] || rightFeature[one_two] || rightFeature[two_one]) && - // !(rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]) && - // (leftFeature[zero_one] || leftFeature[one_zero]) && - // (rightFeature[zero_one] || rightFeature[one_zero]); -} - -// Meet -bool Relationship2D::meet(Point2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - std::vector leftFeature(3, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::meet); - - // return !leftFeature[poi_on_interior] && leftFeature[poi_on_bound]; -} - -bool Relationship2D::meet(Point2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - std::vector leftFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::meet); - - // return !leftFeature[poi_inside] && leftFeature[poi_on_bound]; -} - -bool Relationship2D::meet(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::meet); - - // return !(leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && leftFeature[seg_unshared]; -} - -bool Relationship2D::meet(Line2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - std::vector leftFeature(7, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::meet); - - // return !leftFeature[seg_inside] && - // !leftFeature[seg_outside] && - // !leftFeature[bound_inside]; -} - -bool Relationship2D::meet(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::meet); - - // return !(leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_two] || leftFeature[two_one] || rightFeature[one_two] || rightFeature[two_one]) && - // !(rightFeature[one_two] || rightFeature[two_one]) && - // (leftFeature[zero_one] || leftFeature[one_zero] || leftFeature[one_one] || rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[one_two] || leftFeature[two_one]) && - // (leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]); -} - -// Overlap -bool Relationship2D::overlap(Point2D &leftOperand, Point2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - std::vector leftFeature(2, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return leftFeature[poi_shared] && leftFeature[poi_disjoint] && rightFeature[poi_disjoint]; -} - -bool Relationship2D::overlap(Point2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - std::vector leftFeature(3, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return leftFeature[poi_on_interior] && leftFeature[poi_disjoint]; -} - -bool Relationship2D::overlap(Point2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - std::vector leftFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return leftFeature[poi_inside] && leftFeature[poi_outside]; -} - -bool Relationship2D::overlap(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return (leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && rightFeature[seg_unshared]; -} - -bool Relationship2D::overlap(Line2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - std::vector leftFeature(7, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return leftFeature[seg_inside] && - // leftFeature[seg_outside]; -} - -bool Relationship2D::overlap(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::overlap); - - // return (leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_two] || leftFeature[two_one] || rightFeature[one_two] || rightFeature[two_one]) && - // (leftFeature[zero_one] || leftFeature[one_zero] || leftFeature[one_one] || rightFeature[one_two] || rightFeature[two_one]) && - // (leftFeature[one_two] || leftFeature[two_one] || leftFeature[one_one] || rightFeature[zero_one] || rightFeature[one_zero]); -} - -// Equal -bool Relationship2D::equal(Point2D &leftOperand, Point2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - std::vector leftFeature(2, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::equal); - - // return !leftFeature[poi_disjoint] && !rightFeature[poi_disjoint]; -} - -bool Relationship2D::equal(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::equal); - - // return !rightFeature[bound_on_interior] && - // !leftFeature[seg_unshared] && - // !leftFeature[bound_on_interior] && - // !leftFeature[bound_disjoint] && - // !rightFeature[seg_unshared]; -} - -bool Relationship2D::equal(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::equal); - - // return !(rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[zero_one] || leftFeature[one_zero] || leftFeature[one_one] || rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[one_two] || leftFeature[two_one]) && - // !(leftFeature[zero_one] || leftFeature[one_zero]) && - // !(leftFeature[one_two] || leftFeature[two_one] || leftFeature[one_one] || rightFeature[zero_one] || rightFeature[one_zero]); -} - -// Inside -bool Relationship2D::inside(Point2D &leftOperand, Point2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - std::vector leftFeature(2, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return !leftFeature[poi_disjoint] && rightFeature[poi_disjoint]; -} - -bool Relationship2D::inside(Point2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_disjoint, poi_on_interior, poi_on_bound, bound_poi_disjoint}; - - std::vector leftFeature(3, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return leftFeature[poi_on_interior] && !leftFeature[poi_disjoint]; -} - -bool Relationship2D::inside(Point2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_inside, poi_on_bound, poi_outside}; - - std::vector leftFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return leftFeature[poi_inside] && !leftFeature[poi_outside]; -} - -bool Relationship2D::inside(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return (leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && - // !rightFeature[bound_on_interior] && - // !leftFeature[seg_unshared] && - // !leftFeature[bound_shared] && - // !leftFeature[bound_disjoint] && - // rightFeature[seg_unshared]; -} - -bool Relationship2D::inside(Line2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - std::vector leftFeature(7, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return leftFeature[seg_inside] && - // !leftFeature[seg_outside] && - // !leftFeature[bound_shared]; -} - -bool Relationship2D::inside(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::inside); - - // return !(rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[zero_one] || leftFeature[one_zero] || leftFeature[one_one] || rightFeature[one_two] || rightFeature[two_one]) && - // (leftFeature[one_two] || leftFeature[two_one]) && - // !(leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]) && - // !(leftFeature[zero_one] || leftFeature[one_zero]); -} - -// Contains -bool Relationship2D::contains(Point2D &leftOperand, Point2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {poi_shared, poi_disjoint}; - - std::vector leftFeature(2, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::contains); - - // return leftFeature[poi_shared] && leftFeature[poi_disjoint] && !rightFeature[poi_disjoint]; -} - -bool Relationship2D::contains(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::contains); - - // return (leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && - // leftFeature[seg_unshared] && - // !leftFeature[bound_on_interior] && - // !leftFeature[bound_shared] && - // !rightFeature[seg_unshared]; -} - -bool Relationship2D::contains(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::contains); - - // return (rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[one_two] || leftFeature[two_one]) && - // !(leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]) && - // (leftFeature[zero_one] || leftFeature[one_zero]) && - // !(leftFeature[one_two] || leftFeature[two_one] || leftFeature[one_one] || rightFeature[zero_one] || rightFeature[one_zero]); -} - -// Covers -bool Relationship2D::covers(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::covers); - - // return (leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && - // leftFeature[seg_unshared] && - // !leftFeature[bound_on_interior] && - // leftFeature[bound_shared] && - // !rightFeature[seg_unshared]; -} - -bool Relationship2D::covers(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::covers); - - // return (leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_two] || leftFeature[two_one] || rightFeature[one_two] || rightFeature[two_one]) && - // !(leftFeature[one_two] || leftFeature[two_one]) && - // (leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]) && - // !(leftFeature[one_two] || leftFeature[two_one] || leftFeature[one_one] || rightFeature[zero_one] || rightFeature[one_zero]) && - // !(rightFeature[zero_one] || rightFeature[one_zero]); -} - -// CoveredBy -bool Relationship2D::coveredBy(Line2D &leftOperand, Line2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, bound_on_interior, bound_disjoint, seg_shared, interior_poi_shared, bound_shared}; - - std::vector leftFeature(6, false); - std::vector rightFeature(3, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::coveredBy); - - // return (leftFeature[seg_shared] || leftFeature[interior_poi_shared]) && - // !rightFeature[bound_on_interior] && - // !leftFeature[seg_unshared] && - // leftFeature[bound_shared] && - // !leftFeature[bound_disjoint] && - // rightFeature[seg_unshared]; -} - -bool Relationship2D::coveredBy(Line2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {seg_unshared, seg_inside, seg_shared, seg_outside, poi_shared, bound_inside, bound_shared, bound_disjoint}; - - std::vector leftFeature(7, false); - std::vector rightFeature(1, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::coveredBy); - - /* return leftFeature[seg_inside] && - !leftFeature[seg_outside] && - leftFeature[bound_shared]; */ -} - -bool Relationship2D::coveredBy(Region2D &leftOperand, Region2D &rightOperand) -{ - // Indicates what index in the bool vector represents what flag - enum VectorFlag {zero_one, one_zero, one_two, two_one, zero_two, two_zero, one_one, bound_poi_shared}; - - std::vector leftFeature(8, false); - std::vector rightFeature(4, false); - - // Explore - Explore::explore(leftOperand, rightOperand, leftFeature, rightFeature); - // Evaluate - return Evaluate::validate(leftOperand, rightOperand, leftFeature, rightFeature, Predicate::coveredBy); - - /* return !(rightFeature[one_two] || rightFeature[two_one]) && - !(leftFeature[zero_one] || leftFeature[one_zero] || leftFeature[one_one] || rightFeature[one_two] || rightFeature[two_one]) && - (leftFeature[zero_two] || leftFeature[two_zero] || leftFeature[one_one] || leftFeature[bound_poi_shared]) && - !(leftFeature[zero_one] || leftFeature[one_zero]) && - (leftFeature[one_two] || leftFeature[two_one] || leftFeature[one_one] || rightFeature[zero_one] || rightFeature[one_zero]); */ -} diff --git a/src/SpatialOperations.cpp b/src/SpatialOperations.cpp deleted file mode 100644 index d915148..0000000 --- a/src/SpatialOperations.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "SpatialOperations.h" - -SpatialOperations::SpatialOperations() -{ - // Emtpy -} - -SpatialOperations::~SpatialOperations() -{ - // Emtpy -} - -Point2D SpatialOperations::union(Point2D F, Point2D G) { - Point2D poi = new Point2D(); - // Point2D won't accept duplicate points being added - // Loop through both sets of points and add them to a new point object - for (int i = 0; i < F.getNumberOfPoints(); i++ ) { - poi.add( F[i] ); - } - - for (int i = 0; i < G.getNumberOfPoints(); i++ ) { - poi.add( G[i] ); - } - - return poi; -} - -Line2D SpatialOperations::union(Line2D F, Line2D G){ - Line2D line = new Line2D(); - // Add lines from F and G to new line object - for (int i = 0; i < F.getNumberOfSegments(); i++){ - line.add( F[i] ); - } - for (int i = 0; i < G.getNumberOfSegments(); i++){ - line.add( G[i] ); - } - return line; -} - -Region2D SpatialOperations::union(Region2D F, Region2D G){ - Region2D region = new Region2D(); - // Add regions from F and G to new region object - for (int i = 0; i < F.getNumberOfFaces(); i++){ - region.add( F[i] ); - } - for (int i = 0; i < G.getNumberOfFaces(); i++){ - region.add( G[i] ); - } - return region; -} - -Point2D SpatialOperations::intersection(Point2D F, Point2D G){ - Point2D poi = new Point2D(); - // Compare all points in F with all points in G - // Add to new point object if points are the same - for (int i = 0; i < F.getNumberOfPoints(); i++){ - for (int j = 0; j < G.getNumberOfPoints(); j++){ - if(F[i] == G[j]){ - poi.add( F[i] ); - } - } - } - return poi; -} - -Point2D SpatialOperations::difference(Point2D F, Point2D G){ - Point2D poi = new Point2D(); - // Add all points from F into new point object - // Remove all points from G from new point object - for (int i = 0; i < F.getNumberOfPoints(); i++){ - poi.add( F[i] ); - } - for (int i = 0; i < G.getNumberOfPoints(); i++){ - poi.remove( G[i] ); - } - return poi; -} - -Point2D union(Point2D F, Point2D G) { - //implemented - return new Point2D(); -} - -Line2D union(Line2D F, Line2D G) { - //implemented - return new Line2D(); -} - -Region2D union(Region2D F, Region2D G) { - //implemented - return new Region2D(); -} - -Point2D intersection(Point2D F, Point2D G) { - //implemented - return new Point2D(); -} - -Line2D intersection(Line2D F, Line2D G) { - return new Point2D(); -} - -Region2D intersection(Region2D F, Region2D G) { - return new Region2D(); -} - -Line2D intersection(Region2D F, Line2D G) { - return new Line2D(); -} - -Point2D difference(Point2D F, Point2D G) { - //implemented - return new Point2D(); -} - -Line2D difference(Line2D F, Line2D G) { - return new Line2D(); -} - -Region2D difference(Region2D F, Region2D G) { - return new Region2D(); -} From fe7dd16e70aed36a76302267ef66d0cfe6c3dfe8 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:13 -0500 Subject: [PATCH 56/95] Update Region2DImpl.cpp --- src/Region2DImpl.cpp | 512 +++++++++++++++++++++++++++++++------------ 1 file changed, 367 insertions(+), 145 deletions(-) diff --git a/src/Region2DImpl.cpp b/src/Region2DImpl.cpp index 75c002a..c483abb 100644 --- a/src/Region2DImpl.cpp +++ b/src/Region2DImpl.cpp @@ -3,99 +3,246 @@ struct Region2DImpl::Region2DImplStore { - std::vector sortedVectorOfSegments; std::vector vectorOfAnnHalfSegments; std::vector> vectorOfFaces; std::vector> vectorOfHoles; std::map faceToHoleRelationMap; + std::vector boundingBox; Number areaOfRegion; - - //std::vector outerCycle; }; //Constructors - -Region2DImpl::Region2DImpl() +Region2DImpl::Region2DImpl(std::string listOfRegion2DString) { - + handle = new Region2DImplStore; + bool result = parseWDR(listOfRegion2DString); + if(result == true) + { + bool isValid = validateRegion(); + if(isValid == false) + { + throw std::invalid_argument("Invalid Constructed Region"); + } + sortAnnotatedHS(handle->vectorOfAnnHalfSegments); + } + else + { + throw std::invalid_argument("Invalid Constructed Region"); + } } -Region2DImpl::Region2DImpl(std::vector listOfRegions) +void Region2DImpl::sortAnnotatedHS(std::vector vec) { - handle = new Region2DImplStore; - handle->vectorOfAnnHalfSegments = listOfRegions; + if(vec.size() < 1) + { + int mid = vec.size() / 2; + std::vector l; + std::vector r; + + for (size_t j = 0; j < mid; j++) + l.push_back(vec[j]); + for (size_t j = 0; j < (vec.size()) - mid; j++) + r.push_back(vec[mid + j]); + + sortAnnotatedHS(l); + sortAnnotatedHS(r); + mergeSort(l, r, vec); + } } -Region2DImpl::Region2DImpl(std::string listOfRegion2DString) +void Region2DImpl::mergeSort(std::vector &left, std::vector &right, std::vector &bars) +{ + int nL = left.size(); + int nR = right.size(); + int i = 0, j = 0, k = 0; + + while (j < nL && k < nR) + { + if (left[j] <= + right[k]) { + bars[i] = left[j]; + j++; + } + else { + bars[i] = right[k]; + k++; + } + i++; + } + while (j < nL) { + bars[i] = left[j]; + j++; i++; + } + while (k < nR) { + bars[i] = right[k]; + k++; i++; + } +} + +Number Region2DImpl::computeArea() { - handle = new Region2DImplStore; - bool result = parseWDR(listOfRegion2DString); - if(result == true) + Number tfaceArea("0"); + for(int i=0; ivectorOfFaces.size(); i++) + { + Number area = getAreaOfCycle(handle->vectorOfFaces[i]); + if(area <= Number("0")) + { + return Number("0"); + } + tfaceArea = tfaceArea + area; + } + Number tholeArea("0"); + for(int i=0; ivectorOfHoles.size(); i++) { - // check areas if adding upto positive Number - std::vector faceAreas; - std::vector holeAreas; + Number area = getAreaOfCycle(handle->vectorOfHoles[i]); + if(area <= Number("0")) + { + return Number("0"); + } + tholeArea = tholeArea + area; + } + handle->areaOfRegion = tfaceArea - tholeArea; + return handle->areaOfRegion; +} + +bool Region2DImpl::validateRegion() +{ + // check areas if adding upto positive Number + std::vector faceAreas; + std::vector holeAreas; - Number tfaceArea("0"); - for(int i=0; ivectorOfFaces.size(); i++) + Number tfaceArea("0"); + for(int i=0; ivectorOfFaces.size(); i++) + { + Number area = getAreaOfCycle(handle->vectorOfFaces[i]); + if(area <= Number("0")) { - Number area = getAreaOfCycle(handle->vectorOfFaces[i]); - if(area <= Number("0")) - { - //TODO Throw exception - } - faceAreas.push_back(area); - tfaceArea = tfaceArea + area; + return false; } - Number tholeArea("0"); - for(int i=0; ivectorOfHoles.size(); i++) + faceAreas.push_back(area); + tfaceArea = tfaceArea + area; + } + Number tholeArea("0"); + for(int i=0; ivectorOfHoles.size(); i++) + { + Number area = getAreaOfCycle(handle->vectorOfHoles[i]); + if(area <= Number("0")) { - Number area = getAreaOfCycle(handle->vectorOfHoles[i]); - if(area <= Number("0")) - { - //TODO Throw exception - } - holeAreas.push_back(area); - tholeArea = tholeArea + area; + return false; } - handle->areaOfRegion = tfaceArea - tholeArea; + holeAreas.push_back(area); + tholeArea = tholeArea + area; + } + handle->areaOfRegion = tfaceArea - tholeArea; - if(handle->areaOfRegion <= Number("0")) + if(handle->areaOfRegion <= Number("0")) + { + return false; + } + + // Check if all holes are contained in their respective faces + std::map::iterator itr; + int faceIndex = 0; + int holeIndex = 0; + for (itr = handle->faceToHoleRelationMap.begin(); itr != handle->faceToHoleRelationMap.end(); ++itr) { + Number fArea = faceAreas[faceIndex]; + Number hArea("0"); + for(int i=holeIndex; isecond; i++) + { + hArea = hArea + holeAreas[i]; + } + + if(fArea - hArea <= Number("0")) + { + return false; + } + + faceIndex++; + holeIndex = holeIndex + itr->second; + } + + std::vector allCyclesVec; + //Check if any 2 cycles are intersecting + for(int i=0; ivectorOfFaces.size(); i++) + { + for(int j=0; jvectorOfFaces[i].size(); j++) + { + allCyclesVec.push_back(handle->vectorOfFaces[i][j]); + } + } + for(int i=0; ivectorOfHoles.size(); i++) + { + for(int j=0; jvectorOfHoles[i].size(); j++) { - //TODO throw exception + allCyclesVec.push_back(handle->vectorOfHoles[i][j]); } + } + handle->vectorOfAnnHalfSegments = allCyclesVec; - // Check if all holes are contained in their respective faces - std::map::iterator itr; - int faceIndex = 0; - int holeIndex = 0; - for (itr = handle->faceToHoleRelationMap.begin(); itr != handle->faceToHoleRelationMap.end(); ++itr) { - Number fArea = faceAreas[faceIndex]; - Number hArea("0"); - for(int i=holeIndex; isecond; i++) + for(int i=0; isecond; - } +bool Region2DImpl::doSegmentsIntersect(RGPSegment2D a, RGPSegment2D b) +{ + RGPPoint2D a_p1 = a.point1; + RGPPoint2D a_p2 = a.point2; + RGPPoint2D b_p3 = b.point1; + RGPPoint2D b_p4 = b.point2; + + Number d1 = computeDirection(b_p3,b_p4,a_p1); + Number d2 = computeDirection(b_p3,b_p4,a_p2); + Number d3 = computeDirection(a_p1,a_p2,b_p3); + Number d4 = computeDirection(a_p1,a_p2,b_p4); + + Number zero("0"); + + if (((d1 > zero && d2 < zero) || (d1 < zero && d2 > zero)) && + ((d3 > zero && d4 < zero) || (d3 < zero && d4 > zero))) + { + return true; + } + else + { + return false; + } +} - //Check if any 2 cycles are intersecting +bool Region2DImpl::onSegment(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk) +{ + Number minX = (pi.x < pj.x) ? pi.x : pj.x; + Number maxX = (pi.x < pj.x) ? pj.x : pi.x; + Number minY = (pi.y < pj.y) ? pi.y : pj.y; + Number maxY = (pi.y < pj.y) ? pj.y : pi.y; + if((minX <= pk.x && pk.x <= maxX) && (minY <= pk.y && pk.y <= maxY)) + { + return true; } else { - + return false; } } +Number Region2DImpl::computeDirection(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk) +{ + Number g = (pk.x - pi.x)*(pj.y - pi.y) - (pj.x - pi.x)*(pk.y - pi.y); + return g; +} + Number Region2DImpl::getAreaOfCycle(std::vector vectorOfSegments) { Number area("0"); @@ -104,7 +251,6 @@ Number Region2DImpl::getAreaOfCycle(std::vector vecto int j =0; for(int i=0; i vecto } if(area < Number("0")) { - //area = area * Number("-1"); + area = area * Number("-1"); } - std::cout<<"area "<::iterator itr; - for (itr = faceToHoleMap.begin(); itr != faceToHoleMap.end(); ++itr) { - std::cout << '\t' << itr->first - << '\t' << itr->second << '\n'; - } + std::map::iterator itr; handle->faceToHoleRelationMap = faceToHoleMap; return true; } -/* -std::vector Region2DImpl::constructRegion(std::string formattedInputString) +Region2DImpl::~Region2DImpl() { - // Parse the string into half segments + create a set of dp-array - std::map> mapOfDpToAnnHS; - - - // sort the annotated half segments + delete handle; +} - // implement the algorithm - int numberOfHalfSegments = annHalfSegmentsVector.length; - int visitedHalfSegments = 0; - while(visitedHalfSegments != numberOfHalfSegments) - { - RGPAnnotatedHalfSegment2D annHalfSegment = handle->vectorOfAnnHalfSegments[visitedHalfSegments]; - if(annHalfSegment.isCycleComputed) - { - visitedHalfSegments++; - continue; - } - //TODO - // Find if this segment is a part of a outer cycle or hole cycle - annHalfSegment.isPartOfHole = computeCyclicStructure(); - - //NewCycle(h) - annHalfSegment.isCycleComputed = true; - std::vector newCycleSegments; - if(annHalfSegment.isPartOfHole) - { - annHalfSegment.insideIsAbove = false; - } - else - { - annHalfSegment.insideIsAbove = true; - } - newCycleSegments.push_back(annHalfSegment); +Number Region2DImpl::area() +{ + //TODO update region when faces are updated + return handle->areaOfRegion; +} - //Visit(dp(h)) - annHalfSegment.isPointVisited = true; +// static +bool Region2DImpl::isEmptyRegion() +{ + return handle->vectorOfFaces.empty(); +} - if(annHalfSegment.isPartOfHole) - { - //TODO - //Using sweep line status, retrieve halfsegment f from its owning outer cycle; - //Owns(h, f); - //Set cycle walk mode to use counter-clockwise adjacency; - } - else - { - //TODO Set cycle walk mode to use clockwise adjacency - } +int Region2DImpl::getNumberOfFaces() +{ + return handle->vectorOfFaces.size(); +} - // Cycle walk - //1. Mark the other annotated hs to the current Cycle - RGPPoint2D otherDp = annHalfSegment.segment.point1; - +int Region2DImpl::getNumberOfHoles() +{ + return handle->vectorOfHoles.size(); +} - visitedHalfSegments++; - } +RGPSegment2D Region2DImpl::getBoundingBox() +{ + //we are computing bounding box every time because it may change after adds, updates or removes + std::vector halfSegments; + halfSegments = handle->vectorOfAnnHalfSegments; + + //p1 is the first point of the bounding box segment + RGPPoint2D p1(halfSegments[0].segment.point1.x,halfSegments[0].segment.point1.y); + RGPPoint2D p2(halfSegments[halfSegments.size()-1].segment.point2.x,halfSegments[halfSegments.size()-1].segment.point2.y); + auto maxy = halfSegments[0].segment.point2.y; + + //iterate through the loop to find max y coordinate in the given lis of points + for(auto it = halfSegments.begin();it!= halfSegments.end();it++) + { + if(maxy<(*it).segment.point1.y) + maxy = (*it).segment.point1.y; + if(maxy<(*it).segment.point2.y) + maxy = (*it).segment.point2.y; + } + + //we make the next point taking the x of p2 and maxy found in the above loop + RGPSegment2D seg(p1,RGPPoint2D(p2.x,maxy)); + handle->boundingBox.push_back(seg); + //returing the diagonal that tells us the bounding box + return handle->boundingBox[0]; } -*/ -Region2DImpl::Region2DImpl(std::ifstream& file) + +bool Region2DImpl::addFace(std::vector) { // Emtpy } -Region2DImpl::~Region2DImpl() +bool Region2DImpl::update(int index, std::vector) { // Emtpy } -std::string Region2DImpl::getRegionString() // Get the region as human readable ASCII string +bool Region2DImpl::remove(int index) { // Emtpy } -Number Region2DImpl::area() +bool Region2DImpl::operator==(const Region2DImpl &p2d) { - // Emtpy + int i = 0; + if(handle->vectorOfAnnHalfSegments.size() != p2d.handle->vectorOfAnnHalfSegments.size()) + { + return false; + } + + while(i < p2d.handle->vectorOfAnnHalfSegments.size()) + { + if(handle->vectorOfAnnHalfSegments[i] != p2d.handle->vectorOfAnnHalfSegments[i]) + { + return false; + } + else + i++; + } + return true; } -// static -bool Region2DImpl::isEmptyRegion(Region2DImpl region) +bool Region2DImpl::operator!=(const Region2DImpl &p2d) { - // Emtpy + int i = 0; + if(handle->vectorOfAnnHalfSegments.size() != p2d.handle->vectorOfAnnHalfSegments.size()) + { + return true; + } + + while(i < p2d.handle->vectorOfAnnHalfSegments.size()) + { + if(handle->vectorOfAnnHalfSegments[i] != p2d.handle->vectorOfAnnHalfSegments[i]) + { + return true; + } + else + i++; + } + return false; } -int Region2DImpl::getNumberOfFaces() +template std::vector getCycle(T it) { // Emtpy } -std::vector Region2DImpl::getBoundingBox() +template std::vector getFace(T it) { // Emtpy } -bool Region2DImpl::addFace(std::vector) +Region2DImpl::iteratorforFaces::iteratorforFaces(std::vector *ptr1) { - // Emtpy + ptr = ptr1; } -bool Region2DImpl::update(int index, std::vector) +std::vector Region2DImpl::iteratorforFaces::operator*() { - // Emtpy + return *ptr; } -bool Region2DImpl::remove(int index) +std::vector Region2DImpl::iteratorforFaces::operator++(int junk) { - // Emtpy + std::vector *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; } -bool Region2DImpl::operator==(const Region2DImpl &p2d) +std::vector Region2DImpl::iteratorforFaces::operator++() { - // Emtpy + ptr++; + return *ptr; } -bool Region2DImpl::operator!=(const Region2DImpl &p2d) +bool Region2DImpl::iteratorforFaces::operator!=(const iteratorforFaces &it) { - // Emtpy + if(it.ptr==ptr) + return false; + return true; } -std::vector Region2DImpl::operator[](int index) +bool Region2DImpl::iteratorforFaces::operator==(const iteratorforFaces &it) { - // Empty + if(it.ptr!=ptr) + return false; + return true; } -template std::vector getCycle(T it) +Region2DImpl::iteratorforFaces Region2DImpl::beginFaces() { - // Emtpy + std::vector *ptr = &(handle->vectorOfFaces[0]); + return iteratorforFaces(ptr); } -template std::vector getFace(T it) +Region2DImpl::iteratorforFaces Region2DImpl::endFaces() { - // Emtpy + int t = handle->vectorOfFaces.size(); + return (iteratorforFaces(&(handle->vectorOfFaces[t-1]))); } +Region2DImpl::iteratorforHoles::iteratorforHoles(std::vector *ptr1) +{ + ptr = ptr1; +} + +std::vector Region2DImpl::iteratorforHoles::operator*() +{ + return *ptr; +} + +std::vector Region2DImpl::iteratorforHoles::operator++(int junk) +{ + std::vector *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +std::vector Region2DImpl::iteratorforHoles::operator++() +{ + ptr++; + return *ptr; +} + +bool Region2DImpl::iteratorforHoles::operator!=(const iteratorforHoles &it) +{ + if(it.ptr==ptr) + return false; + return true; +} + +bool Region2DImpl::iteratorforHoles::operator==(const iteratorforHoles &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +Region2DImpl::iteratorforHoles Region2DImpl::beginHoles() +{ + std::vector *ptr = &(handle->vectorOfHoles[0]); + return iteratorforHoles(ptr); +} + +Region2DImpl::iteratorforHoles Region2DImpl::endHoles() +{ + int t = handle->vectorOfHoles.size(); + return (iteratorforHoles(&(handle->vectorOfHoles[t-1]))); +} \ No newline at end of file From 1545a452de50eece082dee7004f998b1e357dfb5 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:19 -0500 Subject: [PATCH 57/95] Update Line2DImpl.h --- include/Line2DImpl.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 60b2f71..16fc5fe 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -12,12 +12,13 @@ class Line2DImpl { public: // Constructors - Line2DImpl(); - Line2DImpl(std::vector listOfSegments); - Line2DImpl(std::string listOfLine2DString); + Line2DImpl(); // no args + Line2DImpl(std::vector listOfSegments); //send in a vector of segments + Line2DImpl(std::string listOfLine2DString); // send in a string Line2DImpl(std::ifstream& file); // Send in file for constructor - ~Line2DImpl(); + ~Line2DImpl(); //destructor + //iterator to run through the list of half segments class iterator { public: @@ -30,16 +31,16 @@ class Line2DImpl RGPHalfSegment2D *ptr; }; - iterator begin(); - iterator end(); + iterator begin(); // return an iterator to the first element + iterator end(); // return an iterator to the last element // Methods std::string getLineString(); // Get the line as human readable ASCII string - void printAllLines(); - bool isEmptyLine(); + void printAllLines(); // print all half segments in the vector + bool isEmptyLine(); // checks if the line object is empty bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - Line2DImpl getBoundingBox(); + Line2DImpl getBoundingBox(); // find the bounding box diaginal bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index From 2d5b345e6dbe41ded2abd2dd5269e3a03b209972 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:23 -0500 Subject: [PATCH 58/95] Update Point2D.h --- include/Point2D.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/Point2D.h b/include/Point2D.h index e5501a4..f8cf40e 100644 --- a/include/Point2D.h +++ b/include/Point2D.h @@ -16,6 +16,26 @@ class Point2D{ Point2D(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D ~Point2D(); + class iterator + { + public: + iterator(RGPPoint2D*); + RGPPoint2D operator*(); + RGPPoint2D operator++(int); + RGPPoint2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPPoint2D *ptr; + }; + + iterator begin(); + iterator end(); + + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object + bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(iterator it); // Removes a RGPPoint2D at specified index + + // Methods std::string getPointString(); // Get the point as human readable ASCII string bool isEmptyPoint(); // Checks if the Point2D object is empty From 9c491ac0457bd91fa9d96aa79b2c16e99a6a504d Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:26 -0500 Subject: [PATCH 59/95] Update Point2DImpl.h --- include/Point2DImpl.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h index aeac56f..5b37ead 100644 --- a/include/Point2DImpl.h +++ b/include/Point2DImpl.h @@ -3,6 +3,7 @@ #include #include "RGPPoint2D.h" +#include "Line2DImpl.h" #include "RGPSegment2D.h" class Point2DImpl @@ -27,13 +28,13 @@ class Point2DImpl // Methods std::string getPointString(); // Get the point as human readable ASCII string - void printAllPoints(); + void printAllPoints(); // prints all the points in the object bool isEmptyPoint(); // Checks if the Point2D object is empty bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed - iterator begin(); - iterator end(); - Point2DImpl getBoundingBox(); + iterator begin(); //returns iterator to the first point + iterator end(); // return iterator to the last point + Line2DImpl getBoundingBox(); //returns the bounding box of the set od points bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index @@ -47,9 +48,9 @@ class Point2DImpl private: struct Point2DImplStore; Point2DImplStore *handle; - void pointSort(std::vector &bar); + void pointSort(std::vector &bar); // private methods for sort void mergeSort(std::vector &left, std::vector &right, std::vector &bars); - bool parseStringToVectorOfPoints(std::string st); + bool parseStringToVectorOfPoints(std::string st); // private method to parse }; #endif //POINT2DIMPL_H From 5a72a61adb3f2a4161a50f4fda555c8b29abc39b Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:29 -0500 Subject: [PATCH 60/95] Update Region2DImpl.h --- include/Region2DImpl.h | 52 ++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/include/Region2DImpl.h b/include/Region2DImpl.h index 5d2bed6..273688f 100644 --- a/include/Region2DImpl.h +++ b/include/Region2DImpl.h @@ -10,31 +10,59 @@ class Region2DImpl { public: // Constructors - Region2DImpl(std::vector listOfRegions); - Region2DImpl(); Region2DImpl(std::string listOfRegion2DString); - Region2DImpl(std::ifstream& file); // Send in file for constructor (possibly .txt) ~Region2DImpl(); + class iteratorforFaces + { + public: + iteratorforFaces(std::vector*); + std::vector operator*(); + std::vector operator++(int); + std::vector operator++(); + bool operator!=(const iteratorforFaces&); + bool operator==(const iteratorforFaces&); + std::vector *ptr; + }; + + class iteratorforHoles + { + public: + iteratorforHoles(std::vector*); + std::vector operator*(); + std::vector operator++(int); + std::vector operator++(); + bool operator!=(const iteratorforHoles&); + bool operator==(const iteratorforHoles&); + std::vector *ptr; + }; + + iteratorforHoles beginHoles(); + iteratorforHoles endHoles(); + iteratorforFaces beginFaces(); + iteratorforFaces endFaces(); + // Methods - std::string getRegionString(); // Get the region as human readable ASCII string Number area(); - bool isEmptyRegion(Region2DImpl region); - bool isValidRegion(Region2DImpl region); + bool isEmptyRegion(); int getNumberOfFaces(); - std::vector getBoundingBox(); + int getNumberOfHoles(); bool operator==(const Region2DImpl &p2d); bool operator!=(const Region2DImpl &p2d); - std::vector getCycle(int index); - std::vector getFace(int index); bool addFace(std::vector); - bool update(int index, std::vector); // Updates a whole region at specified index - bool remove(int index); // Removes a region at specified index - std::vector operator[](int index); // Retrieves a region at specified index + bool removeFace(int index); // Removes a region at specified index + RGPSegment2D getBoundingBox(); private: class Region2DImplStore; + Number computeArea(); + void sortAnnotatedHS(std::vector vec); + void mergeSort(std::vector &left, std::vector &right, std::vector &bars); bool parseWDR(std::string inputString); + Number computeDirection(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk); + bool doSegmentsIntersect(RGPSegment2D a, RGPSegment2D b); + bool onSegment(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk); + bool validateRegion(); Number getAreaOfCycle(std::vector vectorOfSegments); Region2DImplStore *handle; std::vector constructRegion(std::string formattedInputString); From 9ce9d772ec26467b7b75af60a66b7ac68ab9e71d Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:33 -0500 Subject: [PATCH 61/95] Update postgres_ext.cpp --- postgres_ext.cpp | 153 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 27 deletions(-) diff --git a/postgres_ext.cpp b/postgres_ext.cpp index e8b2b12..d0ec434 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -9,43 +9,142 @@ #include "include/Point2D.h" #include "include/Region2DImpl.h" +#include "include/Point2DImpl.h" +#include "include/Line2DImpl.h" + int main(void) { - Number n; - Number b("5"); - //std::cout< vec = *it; + std::cout< vec = *it; + std::cout< Date: Sun, 9 Dec 2018 04:39:36 -0500 Subject: [PATCH 62/95] Update Line2DImpl.cpp --- src/Line2DImpl.cpp | 112 ++++++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 31 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index f895350..c0da6a1 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -1,5 +1,5 @@ -#include "Line2D.h" -#include "Line2DImpl.h" +#include "../include/Line2D.h" +#include "../include/Line2DImpl.h" #include #include #include @@ -10,16 +10,19 @@ struct Line2DImpl::Line2DImplStore { std::vector boundingBox; }; +//constructor for Line2DImpl iterator Line2DImpl::iterator::iterator(RGPHalfSegment2D *ptr1) { ptr = ptr1; } +//overloading * to get output RGPHalfSegment2D Line2DImpl::iterator::operator*() { return *ptr; } +//operator overloading ++ (post) for incrementing the iterator RGPHalfSegment2D Line2DImpl::iterator::operator++(int junk) { RGPHalfSegment2D *ptr1; @@ -28,6 +31,7 @@ RGPHalfSegment2D Line2DImpl::iterator::operator++(int junk) return *ptr1; } +//operator overloading ++ (pre) for incrementing the iterator RGPHalfSegment2D Line2DImpl::iterator::operator++() { ptr++; @@ -41,6 +45,7 @@ bool Line2DImpl::iterator::operator!=(const iterator &it) return true; } +//overloading == to check if two iterators are equal bool Line2DImpl::iterator::operator==(const iterator &it) { if(it.ptr!=ptr) @@ -48,47 +53,65 @@ bool Line2DImpl::iterator::operator==(const iterator &it) return true; } +//Line2DImpl begin method, return an iterator to the first segment in the sorted order. Line2DImpl::iterator Line2DImpl::begin() { RGPHalfSegment2D *ptr = &(handle->vectorOfSegments[0]); return iterator(ptr); } +//Line2DImpl begin method, return an iterator to the last segment in the sorted order. Line2DImpl::iterator Line2DImpl::end() { int t = handle->vectorOfSegments.size(); return (iterator(&(handle->vectorOfSegments[t-1]))); } +//constructor without arguments, just initializes handle Line2DImpl::Line2DImpl() { handle = new Line2DImplStore(); } //Constructors +//constructor which takes in a vector of segments, converts them into half segments and stores it. Line2DImpl::Line2DImpl(std::vector listOfSegments) { + try{ handle = new Line2DImplStore; std::vector halfSegments; + //getting segments and converting them to half segments for(auto it = listOfSegments.begin(); it!=listOfSegments.end();it++) { halfSegments.push_back(RGPHalfSegment2D(*it,(*it).point1)); halfSegments.push_back(RGPHalfSegment2D(*it,(*it).point2)); } + //sorts all half segments to store a sorted array of segments lineSort(halfSegments); handle->vectorOfSegments = halfSegments; + } + catch(int e) + { + std::cout<<"failed"<vectorOfSegments.clear(); + } } +//constructor that takes in a string and creates our required segments Line2DImpl::Line2DImpl(std::string listOfLine2DString) { handle = new Line2DImplStore; + //pareses string, if successful prints success else prints failed. if(parseStringToVectorOfLines(listOfLine2DString)) std::cout << "success" << std::endl; - else + else{ + handle->vectorOfSegments.clear(); std::cout << "failed" << std::endl; + } } +//constructor to take in data from a file and create our segments Line2DImpl::Line2DImpl(std::ifstream& file) { handle = new Line2DImplStore; @@ -105,10 +128,13 @@ Line2DImpl::Line2DImpl(std::ifstream& file) throw std::runtime_error("Error while reading the file"); } + //same as the above constructor, makes it a string and parses it if(parseStringToVectorOfLines(inputString)) std::cout << "success" << std::endl; - else + else{ std::cout << "failed" << std::endl; + handle->vectorOfSegments.clear(); + } } Line2DImpl::~Line2DImpl() @@ -140,6 +166,7 @@ std::string Line2DImpl::getLineString() // Get the line as human readable ASCII return resultString;*/ } +//method to print all the segments in the object void Line2DImpl::printAllLines() { std::cout<<"("; @@ -149,6 +176,7 @@ void Line2DImpl::printAllLines() std::cout<<")"; } +//method to check if our object is empty or has data. bool Line2DImpl::isEmptyLine() { return handle->vectorOfSegments.empty(); @@ -166,18 +194,25 @@ bool Line2DImpl::isValidLine() return validity; } +//method to get total number of segments in out object int Line2DImpl::Line2DImpl::getNumberOfSegments() { - return handle->vectorOfSegments.size(); + return (handle->vectorOfSegments.size())/2; } +//method to find bounding box diagonal for the given list of segments Line2DImpl Line2DImpl::getBoundingBox() { + //we are computing bounding box every time because it may change after adds, updates or removes std::vector halfSegments; halfSegments = handle->vectorOfSegments; + + //p1 is the first point of the bounding box segment RGPPoint2D p1(halfSegments[0].segment.point1.x,halfSegments[0].segment.point1.y); RGPPoint2D p2(halfSegments[halfSegments.size()-1].segment.point2.x,halfSegments[halfSegments.size()-1].segment.point2.y); auto maxy = halfSegments[0].segment.point2.y; + + //iterate through the loop to find max y coordinate in the given lis of points for(auto it = halfSegments.begin();it!= halfSegments.end();it++) { if(maxy<(*it).segment.point1.y) @@ -185,22 +220,32 @@ Line2DImpl Line2DImpl::getBoundingBox() if(maxy<(*it).segment.point2.y) maxy = (*it).segment.point2.y; } + + //we make the next point taking the x of p2 and maxy found in the above loop RGPSegment2D seg(p1,RGPPoint2D(p2.x,maxy)); handle->boundingBox.push_back(seg); Line2DImpl pt(handle->boundingBox); + + //returing the diagonal that tells us the bounding box return pt; } +//method to add new segments to our list of segments bool Line2DImpl::add(RGPSegment2D rgpSeg2d) { try { - + + //check if the line object is empty if(isEmptyLine()){ + + //if empty pushback handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); } else{ + + //if not empty, add them and sort the segments in the object handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); lineSort(handle->vectorOfSegments); @@ -213,14 +258,18 @@ bool Line2DImpl::add(RGPSegment2D rgpSeg2d) return true; } +//method to update a segment in our current list of segments bool Line2DImpl::update(Line2DImpl::iterator it, RGPSegment2D rgpSeg2d) { try { if(isEmptyLine()){ + //check if empty and return false because we cannot update return false; } else{ + + //run through the list, find the segment to be updated and remove that segment for(std::vector::iterator i = handle->vectorOfSegments.begin(); i!= handle->vectorOfSegments.end() ; i++) { if((*i).segment == (*it).segment) @@ -229,6 +278,7 @@ bool Line2DImpl::update(Line2DImpl::iterator it, RGPSegment2D rgpSeg2d) handle->vectorOfSegments.erase(handle->vectorOfSegments.begin()+index); } } + //add the new segment and sort it handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point1)); handle->vectorOfSegments.push_back(RGPHalfSegment2D(rgpSeg2d,rgpSeg2d.point2)); lineSort(handle->vectorOfSegments); @@ -241,14 +291,19 @@ bool Line2DImpl::update(Line2DImpl::iterator it, RGPSegment2D rgpSeg2d) return true; } +//method to remove a segment using an iterator bool Line2DImpl::remove(Line2DImpl::iterator it) { try { if(isEmptyLine()){ + + //return false if the object is empty return false; } else{ + + //run a loop through the vector, find and remove the segment. for(std::vector::iterator i = handle->vectorOfSegments.begin(); i!= handle->vectorOfSegments.end() ; i++) { if((*i).segment == (*it).segment) @@ -266,6 +321,7 @@ bool Line2DImpl::remove(Line2DImpl::iterator it) return true; } +//overloading == operator for the Line2DImpl type bool Line2DImpl::operator==(const Line2DImpl &l2d) { int i = 0; @@ -286,6 +342,7 @@ bool Line2DImpl::operator==(const Line2DImpl &l2d) return true; } +//overloading != operator for the Line2DImpl type bool Line2DImpl::operator!=(const Line2DImpl &l2d) { int i = 0; @@ -304,6 +361,7 @@ bool Line2DImpl::operator!=(const Line2DImpl &l2d) return false; } +//overloading [] operator for the Line2DImpl type Line2DImpl Line2DImpl::operator[](int index) { std::vector t; @@ -312,12 +370,14 @@ Line2DImpl Line2DImpl::operator[](int index) return temp; } +//overloading = operator for the Line2DImpl type Line2DImpl Line2DImpl::operator=(const Line2DImpl &l2d) { handle->vectorOfSegments.clear(); handle->vectorOfSegments = l2d.handle->vectorOfSegments; } +//merge sort to sort our vector of halfsegments void Line2DImpl::lineSort(std::vector &bar) { if (bar.size() <= 1) @@ -367,6 +427,7 @@ void Line2DImpl::mergeSort(std::vector &left, std::vector segments; std::vector halfSegments; - //std::vector nums; // unused - - // QUESTION: - // should we reset vectorOfSegments for any possible changes that - // may have already happened with push_back() before returning false..? - // for instance data could be pushed but, then additional data is then - // formatted incorrectly, possibly corrupting vectorOfSegments ..? try{ + + //erase first and last (..*) and append a , s.erase(0,1); s.erase(s.length()-1,1); s.append(","); - std::cout << s << "\n"; - pos = s.find(delimeter); + pos = s.find(delimiter); std::string a = ""; + //keep finding the delimiter and get our required numbers while(pos != std::string::npos) { if(flag == 0){ @@ -418,6 +474,7 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) { try { + //find num1, num2, num3, num4 if(a[0]=='(' && flag == 0) { num1 = a.substr(1,a.length()-2); @@ -433,23 +490,15 @@ bool Line2DImpl::parseStringToVectorOfLines(std::string st) else if(!(a.substr(a.length()-1,1)).compare(")") && flag == -1) { num4 = a.substr(0,a.length()-1); - - std::cout<<"num1 and num2 is "<vectorOfSegments = halfSegments; return true; From 3a1499e237fa9d84b95d1fdf91d5cea54bfecc28 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:40 -0500 Subject: [PATCH 63/95] Update Point2D.cpp --- src/Point2D.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index 56b31d8..c749204 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -16,6 +16,57 @@ struct Point2D::Point2DStore } }; +/* +Point2DImpl::iterator::iterator(RGPPoint2D *ptr1) +{ + ptr = ptr1; +} + +RGPPoint2D Point2DImpl::iterator::operator*() +{ + return *ptr; +} + +RGPPoint2D Point2DImpl::iterator::operator++(int junk) +{ + RGPPoint2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +RGPPoint2D Point2DImpl::iterator::operator++() +{ + ptr++; + return *ptr; +} + +bool Point2DImpl::iterator::operator!=(const iterator &it) +{ + if(it.ptr==ptr) + return false; + return true; +} +bool Point2DImpl::iterator::operator==(const iterator &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +Point2DImpl::iterator Point2DImpl::begin() +{ + //auto it = handle->implPointer->begin(); + //RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); + //return iterator(&(*it)); +} + +Point2DImpl::iterator Point2DImpl::end() +{ + //int t = handle->vectorOfPoints.size(); + //return (iterator(&(handle->vectorOfPoints[t-1]))); +} +*/ Point2D::Point2D(std::ifstream& file) { handle = new Point2DStore(file); From c38444b27aff1aa7a982a09285ec078019bbf064 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:39:43 -0500 Subject: [PATCH 64/95] Update Point2DImpl.cpp --- src/Point2DImpl.cpp | 140 ++++++++++++++++++++++++++++++++------------ 1 file changed, 102 insertions(+), 38 deletions(-) diff --git a/src/Point2DImpl.cpp b/src/Point2DImpl.cpp index fe13a25..0d42732 100644 --- a/src/Point2DImpl.cpp +++ b/src/Point2DImpl.cpp @@ -1,25 +1,38 @@ #include "Point2DImpl.h" #include "RGPPoint2D.h" +#include "RGP.h" +#include "RGPSegment2D.h" +#include "RGPHalfSegment2D.h" +#include "Line2DImpl.h" #include #include +#include +#include +#include +#include - +//creates vectors to store points and bounding struct Point2DImpl::Point2DImplStore { std::vector vectorOfPoints; std::vector boundingBox; }; +//iterator to iterate through our data structure and return elements accordingly. +//constructor to the iterator, points iterator to a particular element of our data type. Point2DImpl::iterator::iterator(RGPPoint2D *ptr1) { ptr = ptr1; } +//overloading * operator to return the pointing element RGPPoint2D Point2DImpl::iterator::operator*() { return *ptr; } +//overloading ++ operator to move the iterator through our set of points +//this method is for postincrement RGPPoint2D Point2DImpl::iterator::operator++(int junk) { RGPPoint2D *ptr1; @@ -28,18 +41,23 @@ RGPPoint2D Point2DImpl::iterator::operator++(int junk) return *ptr1; } +//overloading ++ operator to move the iterator through our set of points +//this method is for preincrement RGPPoint2D Point2DImpl::iterator::operator++() { ptr++; return *ptr; } +//checks if both the iterators are not equal. bool Point2DImpl::iterator::operator!=(const iterator &it) { if(it.ptr==ptr) return false; return true; } + +//checks if both the iterators are equal. bool Point2DImpl::iterator::operator==(const iterator &it) { if(it.ptr!=ptr) @@ -47,12 +65,14 @@ bool Point2DImpl::iterator::operator==(const iterator &it) return true; } +//method for pointImpl, used mainly with iterators. returns iterator to the first point in the list of Points. Point2DImpl::iterator Point2DImpl::begin() { RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); return iterator(ptr); } +//method for pointImpl, used mainly with iterators. returns iterator to the last point in the list of Points. Point2DImpl::iterator Point2DImpl::end() { int t = handle->vectorOfPoints.size(); @@ -60,40 +80,48 @@ Point2DImpl::iterator Point2DImpl::end() } //Constructors +//constructor to initialise point with a vector of RGPPoints. Point2DImpl::Point2DImpl(std::vector listOfPoints) { handle = new Point2DImplStore; handle->vectorOfPoints = listOfPoints; } +//this constructor does not have any args. This just re initializes the handle. Point2DImpl::Point2DImpl() { handle = new Point2DImplStore; } +//constructor to read points from a file Point2DImpl::Point2DImpl(std::ifstream& file) { - /*std::string inputString; + std::string inputString; if(file.is_open()) { std::stringstream strBuffer; strBuffer << file.rdbuf(); - inputString = strBuffer; + inputString = strBuffer.str(); } else { - throw std::exception("Error while reading the file"); + throw std::runtime_error("Error while reading the file"); + } + + if(parseStringToVectorOfPoints(inputString)) + std::cout << "success" << std::endl; + else{ + std::cout << "failed" << std::endl; + handle->vectorOfPoints.clear(); } - - //TODO - vectorOfPoints = parseStringToVectorOfPoints(inputString); - */ } + +//This constructor creates a Point2DImpl object based on a passed in string of points. We follow a specific convention here. +//((a,b),(c,d)) Point2DImpl::Point2DImpl(std::string listOfPoint2DString) { handle = new Point2DImplStore; - std::cout<< "inside" << "\n"; if(parseStringToVectorOfPoints(listOfPoint2DString)) { std::cout<<"All points are added successfully"<vectorOfPoints.clear(); + } } @@ -110,6 +140,7 @@ Point2DImpl::~Point2DImpl() //default; } +//this method checks if the structure is empty bool Point2DImpl::isEmptyPoint() { return handle->vectorOfPoints.empty(); @@ -139,6 +170,7 @@ std::string Point2DImpl::getPointString() return resultString; } +//method to print all points in the Point2D object void Point2DImpl::printAllPoints() { std::cout<<"("; @@ -160,19 +192,45 @@ bool Point2DImpl::isValidPoint() return validity; } +//this method return total number of points in the Point2D object. int Point2DImpl::getNumberOfPoints() { return handle->vectorOfPoints.size(); } -Point2DImpl Point2DImpl::getBoundingBox() +//returns bounding box for the object +Line2DImpl Point2DImpl::getBoundingBox() { - std::vector box; - box = handle->boundingBox; - Point2DImpl pt(box); - return pt; + std::vector points; + std::vector boundPoints; + //get all the points in the object + points = handle->vectorOfPoints; + + //get the least point to get the first point for diagonal + boundPoints.push_back(points[0]); + + //get the maxy for the secound point + auto maxy = points[0].y; + for(auto it = points.begin(); it!=points.end() ;it++) + { + if((*it).y > maxy) + maxy=(*it).y; + } + //make the secound point from the set of points + RGPPoint2D pt(points[points.size() - 1].x,maxy); + //push back the secound point + boundPoints.push_back(pt); + + //create the diagonal + RGPSegment2D seg(boundPoints[0],boundPoints[1]); + std::vector segs; + + segs.push_back(seg); + Line2DImpl ln(segs); + return ln; } +//method checks if the both Point2D objects are equal bool Point2DImpl::operator==(const Point2DImpl &p2d) { int i=0; @@ -189,6 +247,7 @@ bool Point2DImpl::operator==(const Point2DImpl &p2d) return false; } +//method checks if the both Point2D objects are not equal bool Point2DImpl::operator!=(const Point2DImpl &p2d) { int i=0; @@ -204,6 +263,7 @@ bool Point2DImpl::operator!=(const Point2DImpl &p2d) return false; } +//returns the point at that particular index of the Point2D object Point2DImpl Point2DImpl::operator[](int index) { std::vector t; @@ -212,19 +272,21 @@ Point2DImpl Point2DImpl::operator[](int index) return temp; } +//assigns the object to the right to the object in the left. Point2DImpl Point2DImpl::operator=(const Point2DImpl &p2d) { handle->vectorOfPoints.clear(); handle->vectorOfPoints = p2d.handle->vectorOfPoints; } +//this method is used to add a new point to Point2D object bool Point2DImpl::add(RGPPoint2D rgpp2d) { - - //handle->vectorOfPoints.push_back(rgpp2d); try { - if(handle->vectorOfPoints.empty()) { + //check if the vector is empty + if(handle->vectorOfPoints.empty()) + { handle->vectorOfPoints.push_back(rgpp2d); return true; } @@ -244,6 +306,7 @@ bool Point2DImpl::add(RGPPoint2D rgpp2d) return true; } +//this method is used to update a point at a particular index bool Point2DImpl::update(Point2DImpl::iterator it, RGPPoint2D rgpp2d) { try @@ -267,6 +330,7 @@ bool Point2DImpl::update(Point2DImpl::iterator it, RGPPoint2D rgpp2d) return true; } +//removes a particular point in the vector of points bool Point2DImpl::remove(Point2DImpl::iterator it) { try @@ -288,6 +352,7 @@ bool Point2DImpl::remove(Point2DImpl::iterator it) return true; } +//merge sort imlementation to sort all points void Point2DImpl::pointSort(std::vector &bar) { if (bar.size() <= 1) @@ -337,6 +402,7 @@ void Point2DImpl::mergeSort(std::vector &left, std::vector points; @@ -344,13 +410,17 @@ bool Point2DImpl::parseStringToVectorOfPoints(std::string st) std::string num1,num2; std::string s =st; std::vector nums; + + //initialize the delimiter std::string delimeter = ","; + + //erase first and last (..*) s.erase(0,1); s.erase(s.length()-1,1); s.append(","); - std::cout << s << "\n"; + + //keep finding the substrings pos = s.find(delimeter); - std::cout << pos << "\n"; try{ while(pos!= std::string::npos) { @@ -361,6 +431,7 @@ bool Point2DImpl::parseStringToVectorOfPoints(std::string st) { if(a[0]=='(') { + //get the complete number and store it. std::string temp = ""; int i =1; while(((a[i]<='9'&&a[i]>='0')||a[i]=='.'||a[i]=='-')&&i='0')||a[i]=='.'||a[i]=='-')&&i boundPoints; - boundPoints.push_back(points[0]); - auto maxy = points[0].y; - std::cout<<"bound box \n"; - for(auto it = points.begin(); it!=points.end() ;it++) - { - if((*it).y > maxy) - maxy=(*it).y; - } - RGPPoint2D pt(points[points.size() - 1].x,maxy); - boundPoints.push_back(pt); - - std::cout<vectorOfPoints = points; - handle->boundingBox = boundPoints; - } From fa1f3393e4ce5657e5c5739e3122c4216e2dd6d0 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 04:41:10 -0500 Subject: [PATCH 65/95] Update Region2DImpl.cpp --- src/Region2DImpl.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Region2DImpl.cpp b/src/Region2DImpl.cpp index c483abb..0dc1536 100644 --- a/src/Region2DImpl.cpp +++ b/src/Region2DImpl.cpp @@ -485,12 +485,7 @@ bool Region2DImpl::addFace(std::vector) // Emtpy } -bool Region2DImpl::update(int index, std::vector) -{ - // Emtpy -} - -bool Region2DImpl::remove(int index) +bool Region2DImpl::removeFace(int index) { // Emtpy } From a08434cf63594bfd4600a67e329a2b159816ae8f Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 05:18:37 -0500 Subject: [PATCH 66/95] Update Region2DImpl.h --- include/Region2DImpl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Region2DImpl.h b/include/Region2DImpl.h index 273688f..eb7612d 100644 --- a/include/Region2DImpl.h +++ b/include/Region2DImpl.h @@ -61,7 +61,6 @@ class Region2DImpl bool parseWDR(std::string inputString); Number computeDirection(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk); bool doSegmentsIntersect(RGPSegment2D a, RGPSegment2D b); - bool onSegment(RGPPoint2D pi, RGPPoint2D pj, RGPPoint2D pk); bool validateRegion(); Number getAreaOfCycle(std::vector vectorOfSegments); Region2DImplStore *handle; From 7b45811c79211acb8d859ffec10b43e6c7c3b63a Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 05:18:40 -0500 Subject: [PATCH 67/95] Update Region2DImpl.cpp --- src/Region2DImpl.cpp | 90 ++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/src/Region2DImpl.cpp b/src/Region2DImpl.cpp index 0dc1536..e6bdf8d 100644 --- a/src/Region2DImpl.cpp +++ b/src/Region2DImpl.cpp @@ -31,11 +31,13 @@ Region2DImpl::Region2DImpl(std::string listOfRegion2DString) } } +// Sorts all the annotated half segments using mergeSort technique void Region2DImpl::sortAnnotatedHS(std::vector vec) { if(vec.size() < 1) { int mid = vec.size() / 2; + // Partition through midway for merge sort std::vector l; std::vector r; @@ -50,6 +52,7 @@ void Region2DImpl::sortAnnotatedHS(std::vector vec) } } +// merge sort internal function used for sorting the annotated half segments void Region2DImpl::mergeSort(std::vector &left, std::vector &right, std::vector &bars) { int nL = left.size(); @@ -79,8 +82,11 @@ void Region2DImpl::mergeSort(std::vector &left, std:: } } +// Computes the area of a region input +// This has been used to compute areas of individual cycles of a region Number Region2DImpl::computeArea() { + // compute area of all the faces Number tfaceArea("0"); for(int i=0; ivectorOfFaces.size(); i++) { @@ -91,6 +97,7 @@ Number Region2DImpl::computeArea() } tfaceArea = tfaceArea + area; } + // compute area of all the holes Number tholeArea("0"); for(int i=0; ivectorOfHoles.size(); i++) { @@ -105,6 +112,7 @@ Number Region2DImpl::computeArea() return handle->areaOfRegion; } +// Validates a region input according to the face and cycle information bool Region2DImpl::validateRegion() { // check areas if adding upto positive Number @@ -133,8 +141,9 @@ bool Region2DImpl::validateRegion() holeAreas.push_back(area); tholeArea = tholeArea + area; } - handle->areaOfRegion = tfaceArea - tholeArea; - + + // The total area of faces when subtracted by that of holes has to be a positive number + handle->areaOfRegion = tfaceArea - tholeArea; if(handle->areaOfRegion <= Number("0")) { return false; @@ -152,6 +161,7 @@ bool Region2DImpl::validateRegion() hArea = hArea + holeAreas[i]; } + // Check if the face area is more than that of all the holes inside it if(fArea - hArea <= Number("0")) { return false; @@ -179,6 +189,7 @@ bool Region2DImpl::validateRegion() } handle->vectorOfAnnHalfSegments = allCyclesVec; + // Check for intersection between any two segments of the region including all the faces and cycles for(int i=0; i vectorOfSegments) { Number area("0"); @@ -271,6 +268,7 @@ Number Region2DImpl::getAreaOfCycle(std::vector vecto } +// Parses the given input string and creates the vector of faces and cycles bool Region2DImpl::parseWDR(std::string inputString) { std::map faceToHoleMap; @@ -338,6 +336,7 @@ bool Region2DImpl::parseWDR(std::string inputString) } facePoints.push_back(RGPPoint2D(Number(coord1), Number(coord2))); } + // If start and end point of a cycle are not same, return false if(facePoints[0] != facePoints[facePoints.size()-1]) { return false; @@ -346,6 +345,7 @@ bool Region2DImpl::parseWDR(std::string inputString) std::vector emptyFaceVec; handle->vectorOfFaces.push_back(emptyFaceVec); + // Fill the currently parsed vector into the face vector of region for(int i=0; ivectorOfHoles[numOfHoles].push_back(annHS2); } - holesString = holesString.substr(holeSegmentStringLength+2, holesString.length()); if(holesString.length() != 0 && holesString.substr(0,1) == ",") { holesString.erase(0,1); } + // Keep track of number of holes being added numOfHoles++; } + // Maintain the relation of face to corresponding hole faceToHoleMap.insert(std::pair(numOfFaces,numOfHoles)); numOfFaces++; @@ -433,11 +436,9 @@ Region2DImpl::~Region2DImpl() Number Region2DImpl::area() { - //TODO update region when faces are updated return handle->areaOfRegion; } -// static bool Region2DImpl::isEmptyRegion() { return handle->vectorOfFaces.empty(); @@ -454,8 +455,7 @@ int Region2DImpl::getNumberOfHoles() } RGPSegment2D Region2DImpl::getBoundingBox() -{ - //we are computing bounding box every time because it may change after adds, updates or removes +{ std::vector halfSegments; halfSegments = handle->vectorOfAnnHalfSegments; @@ -480,24 +480,39 @@ RGPSegment2D Region2DImpl::getBoundingBox() return handle->boundingBox[0]; } -bool Region2DImpl::addFace(std::vector) +bool Region2DImpl::addFace(std::vector faceVec) { - // Emtpy -} - -bool Region2DImpl::removeFace(int index) -{ - // Emtpy + std::vector vecToAdd; + // Iterate and create annotated half segments + for(int i=0; ivectorOfAnnHalfSegments.push_back(a); + handle->vectorOfAnnHalfSegments.push_back(b); + } + handle->vectorOfFaces.push_back(vecToAdd); + handle->faceToHoleRelationMap.insert(std::pair(handle->vectorOfFaces.size()+1,0)); + + // Might throw exception as and when the validation fails + validateRegion(); + // Sort the newly added half segments as well + sortAnnotatedHS(handle->vectorOfAnnHalfSegments); } bool Region2DImpl::operator==(const Region2DImpl &p2d) { int i = 0; + //Check if size equal if(handle->vectorOfAnnHalfSegments.size() != p2d.handle->vectorOfAnnHalfSegments.size()) { return false; } + // Check iteratively if each segment is equal to other while(i < p2d.handle->vectorOfAnnHalfSegments.size()) { if(handle->vectorOfAnnHalfSegments[i] != p2d.handle->vectorOfAnnHalfSegments[i]) @@ -513,11 +528,13 @@ bool Region2DImpl::operator==(const Region2DImpl &p2d) bool Region2DImpl::operator!=(const Region2DImpl &p2d) { int i = 0; + //Check if size equal if(handle->vectorOfAnnHalfSegments.size() != p2d.handle->vectorOfAnnHalfSegments.size()) { return true; } + // Check iteratively if each segment is equal to other while(i < p2d.handle->vectorOfAnnHalfSegments.size()) { if(handle->vectorOfAnnHalfSegments[i] != p2d.handle->vectorOfAnnHalfSegments[i]) @@ -530,16 +547,7 @@ bool Region2DImpl::operator!=(const Region2DImpl &p2d) return false; } -template std::vector getCycle(T it) -{ - // Emtpy -} - -template std::vector getFace(T it) -{ - // Emtpy -} - +// Iterators for faces and hole cycles Region2DImpl::iteratorforFaces::iteratorforFaces(std::vector *ptr1) { ptr = ptr1; From baf608d95598b9896d4213b4c30241f29f7f0329 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:05:55 -0500 Subject: [PATCH 68/95] Update Point2D.h --- include/Point2D.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/include/Point2D.h b/include/Point2D.h index f8cf40e..a21f0f4 100644 --- a/include/Point2D.h +++ b/include/Point2D.h @@ -12,7 +12,6 @@ class Point2D{ public: // Constructors - Point2D(std::ifstream& file); // Take input from a file, convert the data into a Point2D Point2D(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D ~Point2D(); @@ -31,21 +30,19 @@ class Point2D{ iterator begin(); iterator end(); - bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object - bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index - bool remove(iterator it); // Removes a RGPPoint2D at specified index - - // Methods - std::string getPointString(); // Get the point as human readable ASCII string bool isEmptyPoint(); // Checks if the Point2D object is empty bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + void printAllPoints(); + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object + bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(iterator it); // Removes a RGPPoint2D at specified index + bool operator==(const Point2D &p2d); // Override of operator == to check equality of two Point2Ds bool operator!=(const Point2D &p2d); // Override of operator != to check inequality of two Point2Ds - - std::vector getBoundingBox(); + RGPSegment2D getBoundingBox(); private: struct Point2DStore; From c5fffd26dcc462206aa7a4e1d60b78523dc7ad83 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:05:59 -0500 Subject: [PATCH 69/95] Update Point2DImpl.h --- include/Point2DImpl.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h index 5b37ead..3861fdd 100644 --- a/include/Point2DImpl.h +++ b/include/Point2DImpl.h @@ -9,9 +9,9 @@ class Point2DImpl { public: - Point2DImpl(std::vector pointVector); Point2DImpl(); Point2DImpl(std::ifstream& file); // Take input from a file, convert the data into a Point2D + Point2DImpl(std::vector pointVector); Point2DImpl(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2D ~Point2DImpl(); class iterator @@ -32,9 +32,10 @@ class Point2DImpl bool isEmptyPoint(); // Checks if the Point2D object is empty bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed + std::vector getVectorOfPoints(); iterator begin(); //returns iterator to the first point iterator end(); // return iterator to the last point - Line2DImpl getBoundingBox(); //returns the bounding box of the set od points + RGPSegment2D getBoundingBox(); //returns the bounding box of the set od points bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index From 21ba6568c1a47bc8f3b9755cb67a7d3edb4a5d32 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:06:02 -0500 Subject: [PATCH 70/95] Update postgres_ext.cpp --- postgres_ext.cpp | 48 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/postgres_ext.cpp b/postgres_ext.cpp index d0ec434..eb0f28f 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -9,20 +9,20 @@ #include "include/Point2D.h" #include "include/Region2DImpl.h" -#include "include/Point2DImpl.h" +#include "include/Point2D.h" #include "include/Line2DImpl.h" int main(void) { //adding through strings. std::string str = "((333.33,22.22),(12,6),(3,4),(9,7),(4,5))"; - Point2DImpl x(str); + Point2D x(str); std::string str2 = "((9,7),(333.33,22.22),(3,4),(4,5),(12,6))"; - Point2DImpl y(str2); + Point2D y(str2); //adding through strings when input format is not correct. Checked all other cases as well std::string str3 = "((333.3322.22),(4,5),(3,4),(4,5))"; - Point2DImpl z(str3); + Point2D z(str3); //method to print all the points in our object @@ -51,61 +51,45 @@ int main(void) //get the total number of points in the object std::cout<<"total number of points in x are : "< Date: Sun, 9 Dec 2018 07:06:05 -0500 Subject: [PATCH 71/95] Update Point2D.cpp --- src/Point2D.cpp | 122 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index c749204..2d3fe1d 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -4,30 +4,33 @@ struct Point2D::Point2DStore { Point2DImpl *implPointer; + std::vector vectorOfPoints; Point2DStore(std::string pointsString) { implPointer = new Point2DImpl(pointsString); + vectorOfPoints = implPointer->getVectorOfPoints(); } - Point2DStore(std::ifstream& file) + Point2DStore(std::vector pointVector) { - implPointer = new Point2DImpl(file); + implPointer = new Point2DImpl(pointVector); + vectorOfPoints = implPointer->getVectorOfPoints(); } }; -/* -Point2DImpl::iterator::iterator(RGPPoint2D *ptr1) + +Point2D::iterator::iterator(RGPPoint2D *ptr1) { ptr = ptr1; } -RGPPoint2D Point2DImpl::iterator::operator*() +RGPPoint2D Point2D::iterator::operator*() { return *ptr; } -RGPPoint2D Point2DImpl::iterator::operator++(int junk) +RGPPoint2D Point2D::iterator::operator++(int junk) { RGPPoint2D *ptr1; ptr1 = ptr; @@ -35,43 +38,38 @@ RGPPoint2D Point2DImpl::iterator::operator++(int junk) return *ptr1; } -RGPPoint2D Point2DImpl::iterator::operator++() +RGPPoint2D Point2D::iterator::operator++() { ptr++; return *ptr; } -bool Point2DImpl::iterator::operator!=(const iterator &it) +bool Point2D::iterator::operator!=(const iterator &it) { if(it.ptr==ptr) return false; return true; } -bool Point2DImpl::iterator::operator==(const iterator &it) +bool Point2D::iterator::operator==(const iterator &it) { if(it.ptr!=ptr) return false; return true; } -Point2DImpl::iterator Point2DImpl::begin() +Point2D::iterator Point2D::begin() { - //auto it = handle->implPointer->begin(); - //RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); - //return iterator(&(*it)); + RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); + return iterator(ptr); } -Point2DImpl::iterator Point2DImpl::end() -{ - //int t = handle->vectorOfPoints.size(); - //return (iterator(&(handle->vectorOfPoints[t-1]))); -} -*/ -Point2D::Point2D(std::ifstream& file) +Point2D::iterator Point2D::end() { - handle = new Point2DStore(file); + int t = handle->vectorOfPoints.size(); + return (iterator(&(handle->vectorOfPoints[t-1]))); } + Point2D::Point2D(std::string listOfPoint2DString) { handle = new Point2DStore(listOfPoint2DString); @@ -83,15 +81,14 @@ Point2D::~Point2D() delete handle; } - -std::string Point2D::getPointString() +bool Point2D::isEmptyPoint() { - return handle->implPointer->getPointString(); + return handle->implPointer->isEmptyPoint(); } -bool Point2D::isEmptyPoint() +void Point2D::printAllPoints() { - return handle->implPointer->isEmptyPoint(); + handle->implPointer->isEmptyPoint(); } bool Point2D::isValidPoint() @@ -104,17 +101,82 @@ int Point2D::getNumberOfPoints() return handle->implPointer->getNumberOfPoints(); } + +//this method is used to add a new point to Point2D object +bool Point2D::add(RGPPoint2D rgpp2d) +{ + bool result = handle->implPointer->add(rgpp2d); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; +} + +//this method is used to update a point at a particular index +bool Point2D::update(Point2D::iterator it, RGPPoint2D rgpp2d) +{ + Point2DImpl::iterator newIt = handle->implPointer->begin(); + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->update(newIt, rgpp2d); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; +} + + +//removes a particular point in the vector of points +bool Point2D::remove(Point2D::iterator it) +{ + Point2DImpl::iterator newIt = handle->implPointer->begin(); + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->remove(newIt); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; +} + bool Point2D::operator==(const Point2D &p2d) { - //TODO + int i=0; + while(i< p2d.handle->vectorOfPoints.size()) + { + if(handle->vectorOfPoints[i] != p2d.handle->vectorOfPoints[i]) + return false; + else + i++; + } + if(handle->vectorOfPoints.size() == p2d.handle->vectorOfPoints.size()) + return true; + else + return false; } bool Point2D::operator!=(const Point2D &p2d) { - //TODO + int i=0; + if(handle->vectorOfPoints.size() != p2d.handle->vectorOfPoints.size()) + return true; + while(i< p2d.handle->vectorOfPoints.size()) + { + if(handle->vectorOfPoints[i] != p2d.handle->vectorOfPoints[i]) + return true; + else + i++; + } + return false; } -std::vector Point2D::getBoundingBox() +RGPSegment2D Point2D::getBoundingBox() { - //return handle->implPointer->getBoundingBox(); + return handle->implPointer->getBoundingBox(); } From 7dd670bcf1ab55e47408e8df055eddab4f2fc21c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:06:09 -0500 Subject: [PATCH 72/95] Update Point2DImpl.cpp --- src/Point2DImpl.cpp | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/src/Point2DImpl.cpp b/src/Point2DImpl.cpp index 0d42732..233a6dc 100644 --- a/src/Point2DImpl.cpp +++ b/src/Point2DImpl.cpp @@ -146,30 +146,6 @@ bool Point2DImpl::isEmptyPoint() return handle->vectorOfPoints.empty(); } -// Get the point as human readable ASCII string -std::string Point2DImpl::getPointString() -{ - std::string resultString = "test"; - /* - bool p = isEmptyPoint(); - if(p==false) - { - resultString += "("; - for (RGPPoint2D rgpPoint : vectorOfPoints) - { - std::ostringstream stream; - stream << rgpPoint; - std::string str = stream.str(); - - resultString += str; - resultString += ","; - } - resultString += ")"; - } - */ - return resultString; -} - //method to print all points in the Point2D object void Point2DImpl::printAllPoints() { @@ -199,7 +175,7 @@ int Point2DImpl::getNumberOfPoints() } //returns bounding box for the object -Line2DImpl Point2DImpl::getBoundingBox() +RGPSegment2D Point2DImpl::getBoundingBox() { std::vector points; std::vector boundPoints; @@ -227,7 +203,7 @@ Line2DImpl Point2DImpl::getBoundingBox() segs.push_back(seg); Line2DImpl ln(segs); - return ln; + return seg; } //method checks if the both Point2D objects are equal @@ -279,6 +255,11 @@ Point2DImpl Point2DImpl::operator=(const Point2DImpl &p2d) handle->vectorOfPoints = p2d.handle->vectorOfPoints; } +std::vector Point2DImpl::getVectorOfPoints() +{ + return handle->vectorOfPoints; +} + //this method is used to add a new point to Point2D object bool Point2DImpl::add(RGPPoint2D rgpp2d) { From 8d61fa2fcec8a39a85afd65ce2d859e912de90a2 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:18:04 -0500 Subject: [PATCH 73/95] Update postgres_ext.cpp --- postgres_ext.cpp | 127 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/postgres_ext.cpp b/postgres_ext.cpp index eb0f28f..59dd3b2 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -12,8 +12,13 @@ #include "include/Point2D.h" #include "include/Line2DImpl.h" +void callLine(); int main(void) { + //For point2D + std::cout<<"Point implementation from here : "< Date: Sun, 9 Dec 2018 07:45:22 -0500 Subject: [PATCH 74/95] Update Line2D.h --- include/Line2D.h | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/include/Line2D.h b/include/Line2D.h index 35392fc..8c8717c 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -11,11 +11,30 @@ class Line2D{ public: // Constructors Line2D(std::string listOfLine2DString); - Line2D(std::ifstream& file); // Send in file for constructor ~Line2D(); + //iterator to run through the list of half segments + class iterator + { + public: + iterator(RGPHalfSegment2D*); + RGPHalfSegment2D operator*(); + RGPHalfSegment2D operator++(int); + RGPHalfSegment2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPHalfSegment2D *ptr; + }; + + iterator begin(); // return an iterator to the first element + iterator end(); // return an iterator to the last element + + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D + bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(iterator it); // Removes a RGPSegment2D at specified index + // Methods - std::string getLineString(); // Get the line as human readable ASCII string + void printAllLines(); // print all half segments in the vector bool isEmptyLine(); bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed @@ -23,7 +42,7 @@ class Line2D{ bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds bool operator!=(const Line2D &l2d); // Override of operator != to check inequality of two Line2Ds - Line2DImpl getBoundingBox(); + RGPSegment2D getBoundingBox(); private: struct Line2DStore; From c168565878845c2dc84bf8f0de357e2c4d20d544 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:45:26 -0500 Subject: [PATCH 75/95] Update Line2DImpl.h --- include/Line2DImpl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 16fc5fe..d8d5a36 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -35,12 +35,12 @@ class Line2DImpl iterator end(); // return an iterator to the last element // Methods - std::string getLineString(); // Get the line as human readable ASCII string void printAllLines(); // print all half segments in the vector bool isEmptyLine(); // checks if the line object is empty bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed - Line2DImpl getBoundingBox(); // find the bounding box diaginal + RGPSegment2D getBoundingBox(); // find the bounding box diaginal + std::vector getVectorOfSegments(); bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index From b95c2c38a34943877a110b32046b101e7ac1a03e Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:45:30 -0500 Subject: [PATCH 76/95] Update postgres_ext.cpp --- postgres_ext.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/postgres_ext.cpp b/postgres_ext.cpp index 59dd3b2..125c4bb 100644 --- a/postgres_ext.cpp +++ b/postgres_ext.cpp @@ -10,7 +10,7 @@ #include "include/Region2DImpl.h" #include "include/Point2D.h" -#include "include/Line2DImpl.h" +#include "include/Line2D.h" void callLine(); int main(void) @@ -160,13 +160,13 @@ void callLine() //adding through strings. std::string str = "(((3,4),(2,2)),((6,2),(5,3)),((6,1),(7,9)),((8,4),(6,6)))"; - Line2DImpl ln(str); + Line2D ln(str); std::string str2 = "(((3,4),(2,2)),((6,2),(5,3)),((6,1),(7,9)),((8,4),(6,6)))"; - Line2DImpl ln2(str2); + Line2D ln2(str2); //adding through strings when input format is not correct std::string str3 = "(((3,4),(2,2)),((6,2),(5,3)),((6,1)(7,9)),((8,4),(6,6)))"; - Line2DImpl wrongInp(str3); + Line2D wrongInp(str3); //checking operator != std::cout<<"check if ln1!=ln2"< Date: Sun, 9 Dec 2018 07:45:33 -0500 Subject: [PATCH 77/95] Update Line2D.cpp --- src/Line2D.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 10 deletions(-) diff --git a/src/Line2D.cpp b/src/Line2D.cpp index 4eb1031..4aa2303 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -3,26 +3,124 @@ struct Line2D::Line2DStore { Line2DImpl *implPointer; + std::vector vectorOfSegments; Line2DStore(std::string linesString) { implPointer = new Line2DImpl(linesString); + vectorOfSegments = implPointer->getVectorOfSegments(); } Line2DStore(std::ifstream& file) { implPointer = new Line2DImpl(file); + vectorOfSegments = implPointer->getVectorOfSegments(); } }; -Line2D::Line2D(std::string listOfLine2DString) +//constructor for Line2D iterator +Line2D::iterator::iterator(RGPHalfSegment2D *ptr1) { - handle = new Line2DStore(listOfLine2DString); + ptr = ptr1; +} + +//overloading * to get output +RGPHalfSegment2D Line2D::iterator::operator*() +{ + return *ptr; +} + +//operator overloading ++ (post) for incrementing the iterator +RGPHalfSegment2D Line2D::iterator::operator++(int junk) +{ + RGPHalfSegment2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +//operator overloading ++ (pre) for incrementing the iterator +RGPHalfSegment2D Line2D::iterator::operator++() +{ + ptr++; + return *ptr; } -Line2D::Line2D(std::ifstream& file) // Send in file for constructor +bool Line2D::iterator::operator!=(const iterator &it) { - handle = new Line2DStore(file); + if(it.ptr==ptr) + return false; + return true; +} + +//overloading == to check if two iterators are equal +bool Line2D::iterator::operator==(const iterator &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +//Line2D begin method, return an iterator to the first segment in the sorted order. +Line2D::iterator Line2D::begin() +{ + RGPHalfSegment2D *ptr = &(handle->vectorOfSegments[0]); + return iterator(ptr); +} + +//Line2D begin method, return an iterator to the last segment in the sorted order. +Line2D::iterator Line2D::end() +{ + int t = handle->vectorOfSegments.size(); + return (iterator(&(handle->vectorOfSegments[t-1]))); +} + +//method to add new segments to our list of segments +bool Line2D::add(RGPSegment2D rgpSeg2d) +{ + bool res = handle->implPointer->add(rgpSeg2d); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return res; +} + +//method to update a segment in our current list of segments +bool Line2D::update(Line2D::iterator it, RGPSegment2D rgpSeg2d) +{ + Line2DImpl::iterator newIt = handle->implPointer->begin(); + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->update(newIt, rgpSeg2d); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return result; + +} + +//method to remove a segment using an iterator +bool Line2D::remove(Line2D::iterator it) +{ + Line2DImpl::iterator newIt = handle->implPointer->begin(); + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->remove(newIt); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return result; +} + +Line2D::Line2D(std::string listOfLine2DString) +{ + handle = new Line2DStore(listOfLine2DString); } Line2D::~Line2D() @@ -32,15 +130,14 @@ Line2D::~Line2D() } // Methods -std::string Line2D::getLineString() // Get the line as human readable ASCII string +bool Line2D::isEmptyLine() { - return handle->implPointer->getLineString(); + return handle->implPointer->isEmptyLine(); } -// static -bool Line2D::isEmptyLine() +void Line2D::printAllLines() { - return handle->implPointer->isEmptyLine(); + handle->implPointer->printAllLines(); } int Line2D::Line2D::getNumberOfSegments() @@ -60,7 +157,7 @@ bool Line2D::operator!=(const Line2D &l2d) //return handle->implPointer->operator!=(&l2d); } -Line2DImpl Line2D::getBoundingBox() +RGPSegment2D Line2D::getBoundingBox() { return handle->implPointer->getBoundingBox(); } \ No newline at end of file From c24f0e60d9f67d98cb4d60b2becb618773a2ea93 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:45:37 -0500 Subject: [PATCH 78/95] Update Line2DImpl.cpp --- src/Line2DImpl.cpp | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index c0da6a1..532aca6 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -145,26 +145,11 @@ Line2DImpl::~Line2DImpl() } // Methods -std::string Line2DImpl::getLineString() // Get the line as human readable ASCII string -{ - /*std::string resultString; - if(!isEmptyLine()) - { - resultString += "("; - for (RGPHalfSegment2D rgpLine : handle->vectorOfSegments) - { - std::ostringstream stream; - stream << rgpLine; - std::string str = stream.str(); - - resultString += str; - resultString += ","; - } - resultString += ")"; - } - return resultString;*/ -} +std::vector Line2DImpl::getVectorOfSegments() +{ + return handle->vectorOfSegments; +} //method to print all the segments in the object void Line2DImpl::printAllLines() @@ -201,7 +186,7 @@ int Line2DImpl::Line2DImpl::getNumberOfSegments() } //method to find bounding box diagonal for the given list of segments -Line2DImpl Line2DImpl::getBoundingBox() +RGPSegment2D Line2DImpl::getBoundingBox() { //we are computing bounding box every time because it may change after adds, updates or removes std::vector halfSegments; @@ -223,11 +208,9 @@ Line2DImpl Line2DImpl::getBoundingBox() //we make the next point taking the x of p2 and maxy found in the above loop RGPSegment2D seg(p1,RGPPoint2D(p2.x,maxy)); - handle->boundingBox.push_back(seg); - Line2DImpl pt(handle->boundingBox); //returing the diagonal that tells us the bounding box - return pt; + return seg; } //method to add new segments to our list of segments From ab939e918f84aea63017c094a3c76b506aa1688a Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:47:53 -0500 Subject: [PATCH 79/95] Update Point2DForProgrammer.h --- include/Point2DForProgrammer.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/include/Point2DForProgrammer.h b/include/Point2DForProgrammer.h index c802873..1a6416a 100644 --- a/include/Point2DForProgrammer.h +++ b/include/Point2DForProgrammer.h @@ -12,14 +12,31 @@ class Point2DForProgrammer{ public: // Constructors - Point2DForProgrammer(std::ifstream& file); // Take input from a file, convert the data into a Point2DForProgrammer + Point2DForProgrammer(std::vector); // Take input from a file, convert the data into a Point2DForProgrammer Point2DForProgrammer(std::string listOfPoint2DString); // Read the string as a vector of RGPPoint2D and form a Point2DForProgrammer ~Point2DForProgrammer(); + //iterator + class iterator + { + public: + iterator(RGPPoint2D*); + RGPPoint2D operator*(); + RGPPoint2D operator++(int); + RGPPoint2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPPoint2D *ptr; + }; + + iterator begin(); + iterator end(); + + // Methods - bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2DForProgrammer object - bool update(int index, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index - bool remove(int index); // Removes a RGPPoint2D at specified index + bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object + bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index + bool remove(iterator it); // Removes a RGPPoint2D at specified index //RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index private: From d92168995280fd719ceb386f05fa949b9f174838 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 07:47:56 -0500 Subject: [PATCH 80/95] Update Point2DForProgrammer.cpp --- src/Point2DForProgrammer.cpp | 95 ++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/src/Point2DForProgrammer.cpp b/src/Point2DForProgrammer.cpp index 70537eb..7939563 100644 --- a/src/Point2DForProgrammer.cpp +++ b/src/Point2DForProgrammer.cpp @@ -4,21 +4,74 @@ struct Point2DForProgrammer::Point2DProgrammerStore { Point2DImpl *implPointer; + std::vector vectorOfPoints; Point2DProgrammerStore(std::string pointsString) { implPointer = new Point2DImpl(pointsString); + vectorOfPoints = implPointer->getVectorOfPoints(); } - Point2DProgrammerStore(std::ifstream& file) + Point2DProgrammerStore(std::vector pointVector) { - implPointer = new Point2DImpl(file); + implPointer = new Point2DImpl(pointVector); + vectorOfPoints = implPointer->getVectorOfPoints(); } }; -Point2DForProgrammer::Point2DForProgrammer(std::ifstream& file) +Point2DForProgrammer::iterator::iterator(RGPPoint2D *ptr1) { - handle = new Point2DProgrammerStore(file); + ptr = ptr1; +} + +RGPPoint2D Point2DForProgrammer::iterator::operator*() +{ + return *ptr; +} + +RGPPoint2D Point2DForProgrammer::iterator::operator++(int junk) +{ + RGPPoint2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +RGPPoint2D Point2DForProgrammer::iterator::operator++() +{ + ptr++; + return *ptr; +} + +bool Point2DForProgrammer::iterator::operator!=(const iterator &it) +{ + if(it.ptr==ptr) + return false; + return true; +} +bool Point2DForProgrammer::iterator::operator==(const iterator &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +Point2DForProgrammer::iterator Point2DForProgrammer::begin() +{ + RGPPoint2D *ptr = &(handle->vectorOfPoints[0]); + return iterator(ptr); +} + +Point2DForProgrammer::iterator Point2DForProgrammer::end() +{ + int t = handle->vectorOfPoints.size(); + return (iterator(&(handle->vectorOfPoints[t-1]))); +} + + +Point2DForProgrammer::Point2DForProgrammer(std::vector pointVector) +{ + handle = new Point2DProgrammerStore(pointVector); } Point2DForProgrammer::Point2DForProgrammer(std::string listOfPoint2DString) @@ -35,17 +88,41 @@ Point2DForProgrammer::~Point2DForProgrammer() // Adds a new RGPPoint2D to the existing Point2D object bool Point2DForProgrammer::add(RGPPoint2D rgpp2d) { - //TODO + bool result = handle->implPointer->add(rgpp2d); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; } // Updates RGPPoint2D existing at specified index -bool Point2DForProgrammer::update(int index, RGPPoint2D rgpp2d) +bool Point2DForProgrammer::update(Point2DForProgrammer::iterator it, RGPPoint2D rgpp2d) { - //TODO + Point2DImpl::iterator newIt = handle->implPointer->begin(); + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->update(newIt, rgpp2d); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; } // Removes a RGPPoint2D at specified index -bool Point2DForProgrammer::remove(int index) +bool Point2DForProgrammer::remove(Point2DForProgrammer::iterator it) { - //TODO + Point2DImpl::iterator newIt = handle->implPointer->begin(); + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->remove(newIt); + handle->vectorOfPoints = handle->implPointer->getVectorOfPoints(); + return result; } From 667143bed47d93dff3e56ac026ff35f452ea1359 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:07 -0500 Subject: [PATCH 81/95] Update Line2D.h --- include/Line2D.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Line2D.h b/include/Line2D.h index 8c8717c..d3b14a8 100644 --- a/include/Line2D.h +++ b/include/Line2D.h @@ -36,7 +36,6 @@ class Line2D{ // Methods void printAllLines(); // print all half segments in the vector bool isEmptyLine(); - bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed bool operator==(const Line2D &l2d); // Override of operator == to check equality of two Line2Ds From f3df2e406e72a61aeaf251f98f14de2f504a5300 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:10 -0500 Subject: [PATCH 82/95] Update Line2DImpl.h --- include/Line2DImpl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index d8d5a36..368816c 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -37,7 +37,6 @@ class Line2DImpl // Methods void printAllLines(); // print all half segments in the vector bool isEmptyLine(); // checks if the line object is empty - bool isValidLine(); int getNumberOfSegments(); // Get the total number of RGPSegment2Ds listed RGPSegment2D getBoundingBox(); // find the bounding box diaginal std::vector getVectorOfSegments(); From 4eaca2ebc9077267411d1b71b048b2b1a08e3a1c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:13 -0500 Subject: [PATCH 83/95] Update Point2D.h --- include/Point2D.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Point2D.h b/include/Point2D.h index a21f0f4..96ea9b1 100644 --- a/include/Point2D.h +++ b/include/Point2D.h @@ -32,7 +32,6 @@ class Point2D{ // Methods bool isEmptyPoint(); // Checks if the Point2D object is empty - bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed void printAllPoints(); bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object From b4394b2d404c02e6499b2b6a0fb7ad6d34ef3a72 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:16 -0500 Subject: [PATCH 84/95] Update Point2DForProgrammer.h --- include/Point2DForProgrammer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Point2DForProgrammer.h b/include/Point2DForProgrammer.h index 1a6416a..25606e3 100644 --- a/include/Point2DForProgrammer.h +++ b/include/Point2DForProgrammer.h @@ -37,7 +37,6 @@ class Point2DForProgrammer{ bool add(RGPPoint2D rgpp2d); // Adds a new RGPPoint2D to the existing Point2D object bool update(iterator it, RGPPoint2D rgpp2d); // Updates RGPPoint2D existing at specified index bool remove(iterator it); // Removes a RGPPoint2D at specified index - //RGPPoint2D operator[](int index); // Retrieves a RGPPoint2D at specified index private: struct Point2DProgrammerStore; From 9e04e75697acdf80004552f011062e78118c0ef3 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:19 -0500 Subject: [PATCH 85/95] Update Point2DImpl.h --- include/Point2DImpl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/Point2DImpl.h b/include/Point2DImpl.h index 3861fdd..4c6e6bc 100644 --- a/include/Point2DImpl.h +++ b/include/Point2DImpl.h @@ -30,7 +30,6 @@ class Point2DImpl std::string getPointString(); // Get the point as human readable ASCII string void printAllPoints(); // prints all the points in the object bool isEmptyPoint(); // Checks if the Point2D object is empty - bool isValidPoint(); // Checks if the Point2D object is empty int getNumberOfPoints(); // Get the total number of RGPPoint2Ds listed std::vector getVectorOfPoints(); iterator begin(); //returns iterator to the first point From a48b1049332a6bbc1ebdc9a5205a339e110fb41d Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:26 -0500 Subject: [PATCH 86/95] Update Line2D.cpp --- src/Line2D.cpp | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Line2D.cpp b/src/Line2D.cpp index 4aa2303..9d7746f 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -3,6 +3,7 @@ struct Line2D::Line2DStore { Line2DImpl *implPointer; + // Maintains a dummy copy for iterator to work std::vector vectorOfSegments; Line2DStore(std::string linesString) @@ -87,7 +88,7 @@ bool Line2D::add(RGPSegment2D rgpSeg2d) bool Line2D::update(Line2D::iterator it, RGPSegment2D rgpSeg2d) { Line2DImpl::iterator newIt = handle->implPointer->begin(); - for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) { if(*it == *implit) { @@ -105,7 +106,7 @@ bool Line2D::update(Line2D::iterator it, RGPSegment2D rgpSeg2d) bool Line2D::remove(Line2D::iterator it) { Line2DImpl::iterator newIt = handle->implPointer->begin(); - for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) { if(*it == *implit) { @@ -147,14 +148,40 @@ int Line2D::Line2D::getNumberOfSegments() bool Line2D::operator==(const Line2D &l2d) { - // TODO - //return handle->implPointer->operator==(&l2d); + int i = 0; + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()) + { + return false; + } + + while(i < l2d.handle->vectorOfSegments.size()) + { + if(handle->vectorOfSegments[i] != l2d.handle->vectorOfSegments[i]) + { + return false; + } + else + i++; + } + return true; } bool Line2D::operator!=(const Line2D &l2d) { - // TODO - //return handle->implPointer->operator!=(&l2d); + int i = 0; + if(handle->vectorOfSegments.size() != l2d.handle->vectorOfSegments.size()) + { + return true; + } + + while(i < l2d.handle->vectorOfSegments.size()) + { + if(handle->vectorOfSegments[i] != l2d.handle->vectorOfSegments[i]) + return true; + else + i++; + } + return false; } RGPSegment2D Line2D::getBoundingBox() From 09e1744feb14ce484c2265c7e89bf9af82b3114d Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:29 -0500 Subject: [PATCH 87/95] Update Line2DImpl.cpp --- src/Line2DImpl.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 532aca6..6620dee 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -139,9 +139,7 @@ Line2DImpl::Line2DImpl(std::ifstream& file) Line2DImpl::~Line2DImpl() { - // TODO - // delete handle->vectorOfSegments; - // delete handle; + delete handle; } // Methods @@ -167,18 +165,6 @@ bool Line2DImpl::isEmptyLine() return handle->vectorOfSegments.empty(); } -bool Line2DImpl::isValidLine() -{ - bool validity = false; - if(!handle->vectorOfSegments.empty()) - { - //Check for validity - //TODO - } - - return validity; -} - //method to get total number of segments in out object int Line2DImpl::Line2DImpl::getNumberOfSegments() { From 5eb9c602bd0de6224a08a419341fdd911beed497 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:32 -0500 Subject: [PATCH 88/95] Update Point2D.cpp --- src/Point2D.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index 2d3fe1d..afdec83 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -4,6 +4,7 @@ struct Point2D::Point2DStore { Point2DImpl *implPointer; + // Maintains a dummy copy for iterator to work std::vector vectorOfPoints; Point2DStore(std::string pointsString) @@ -91,11 +92,6 @@ void Point2D::printAllPoints() handle->implPointer->isEmptyPoint(); } -bool Point2D::isValidPoint() -{ - return handle->implPointer->isValidPoint(); -} - int Point2D::getNumberOfPoints() { return handle->implPointer->getNumberOfPoints(); @@ -114,7 +110,7 @@ bool Point2D::add(RGPPoint2D rgpp2d) bool Point2D::update(Point2D::iterator it, RGPPoint2D rgpp2d) { Point2DImpl::iterator newIt = handle->implPointer->begin(); - for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) { if(*it == *implit) { @@ -132,7 +128,7 @@ bool Point2D::update(Point2D::iterator it, RGPPoint2D rgpp2d) bool Point2D::remove(Point2D::iterator it) { Point2DImpl::iterator newIt = handle->implPointer->begin(); - for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();++implit) + for(Point2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) { if(*it == *implit) { From 0ccc6059c84ef9f1026e3105f7e7a8e50f7ce3c5 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:35 -0500 Subject: [PATCH 89/95] Update Point2DForProgrammer.cpp --- src/Point2DForProgrammer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Point2DForProgrammer.cpp b/src/Point2DForProgrammer.cpp index 7939563..93e03f6 100644 --- a/src/Point2DForProgrammer.cpp +++ b/src/Point2DForProgrammer.cpp @@ -4,6 +4,7 @@ struct Point2DForProgrammer::Point2DProgrammerStore { Point2DImpl *implPointer; + // Maintains a dummy copy for iterator to work std::vector vectorOfPoints; Point2DProgrammerStore(std::string pointsString) From 92c506b7e8960ceaa552420715a92f4c8356bf9f Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:19:39 -0500 Subject: [PATCH 90/95] Update Point2DImpl.cpp --- src/Point2DImpl.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Point2DImpl.cpp b/src/Point2DImpl.cpp index 233a6dc..b85ca38 100644 --- a/src/Point2DImpl.cpp +++ b/src/Point2DImpl.cpp @@ -136,8 +136,7 @@ Point2DImpl::Point2DImpl(std::string listOfPoint2DString) Point2DImpl::~Point2DImpl() { - //TODO - //default; + delete handle; } //this method checks if the structure is empty @@ -156,18 +155,6 @@ void Point2DImpl::printAllPoints() std::cout<<")"; } -bool Point2DImpl::isValidPoint() -{ - bool validity = false; - if(!handle->vectorOfPoints.empty()) - { - //Check for validity - //TODO - } - - return validity; -} - //this method return total number of points in the Point2D object. int Point2DImpl::getNumberOfPoints() { From 17b7da65e2bb60ca531d41b80fea243cdd55c99c Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:21:46 -0500 Subject: [PATCH 91/95] Add files via upload --- ProjectReport_Group2.pdf | Bin 0 -> 308046 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ProjectReport_Group2.pdf diff --git a/ProjectReport_Group2.pdf b/ProjectReport_Group2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ca753320cbde9b0d23368ff88bba1b1e2af95d9d GIT binary patch literal 308046 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�Q2PO!+R5a+Yoqwh`o$5?4L07FJn$ z5s$(n$Woxbd$w&jtDY&6gAOu$9EHi!dCcex&KpdtN~uQ3pzI&CmB1^8)%;%elD*Qb zB7u#M;odO8udvdrg@qi}9zYIb!S1w`G|<2GRz~6Xzy@+?!g!*f7Ptm36h3N5K%us} z9cjLi6G_UAb{A2eVvTkdh`EKwC)%2cTW#w{&JZ+`Y|CVTmpBh7Ci!tB-JoLMBhpTH zR&W>;19%ySxYuMR%rcRJU9^vldhNB>bG^$1Q*nkXY zZA}#4z#Qd)Q21mL%}i0Va2%bPdyX|erV>gkAR>HqxIkbW@fK;R&AycIcmgiQH_Q17 zH)>?2jfTuFQzj9XT1U;sC*k56=z&9pj;n+-Ql*%-&(ukyvp8BX6oDIccT`$QVDrGX z<1KQxLUv(P7igWe2k^dVk()RjdrV3wD3i*mU-p7VnO*w0-y}GC@qWy>ut85%&cY)o z9(XdEHoR8)6bO&*@G8=&Euqd2p>3>1M-~5DhHYxopFyo}?a@|q(5gea{fF|G=`i22 z$L=b@z~N+gd&_UaqpDt$7%1*6ouzWplKBr480aLh9Za(z3UaLhu+EvyUe8Q9aYSEDQbBi>JG37Lmlc& z?y0BxWpq8lA>U6o(~=u4R40k=J!C7n^4Bx8{F}OQs`A-&7qp!\$OoXe;s^|u=f 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 z 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%0AvBzY}c?ee+vy^jbv<3(S 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 BxMTnT literal 0 HcmV?d00001 From 57df0c67b0b4661aeaa25eddac8e269a8f7e8b1f Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:26:31 -0500 Subject: [PATCH 92/95] Delete Report_Group2.docx --- Report_Group2.docx | Bin 23413 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Report_Group2.docx diff --git a/Report_Group2.docx b/Report_Group2.docx deleted file mode 100644 index 3d168ad6bbd652054e15265081fef399b5288eda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23413 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 Date: Sun, 9 Dec 2018 08:26:40 -0500 Subject: [PATCH 93/95] Delete Line2D.docx --- Line2D.docx | Bin 17438 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Line2D.docx diff --git a/Line2D.docx b/Line2D.docx deleted file mode 100644 index c050b0b8031bc8fb8dccb7ee88ee238e49063c13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17438 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 From e141c9c0f3803352ff474603ef04eb7a989c5571 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:36:58 -0500 Subject: [PATCH 94/95] Update Line2DForProgrammer.h --- include/Line2DForProgrammer.h | 23 +++++-- include/Line2DImpl.h | 1 - src/Line2D.cpp | 6 -- src/Line2DForProgrammer.cpp | 113 +++++++++++++++++++++++++++++----- src/Line2DImpl.cpp | 26 -------- 5 files changed, 115 insertions(+), 54 deletions(-) diff --git a/include/Line2DForProgrammer.h b/include/Line2DForProgrammer.h index 0b37bce..1efce24 100644 --- a/include/Line2DForProgrammer.h +++ b/include/Line2DForProgrammer.h @@ -15,11 +15,26 @@ class Line2DForProgrammer{ Line2DForProgrammer(std::ifstream& file); // Send in file for constructor ~Line2DForProgrammer(); - // Methods + //iterator to run through the list of half segments + class iterator + { + public: + iterator(RGPHalfSegment2D*); + RGPHalfSegment2D operator*(); + RGPHalfSegment2D operator++(int); + RGPHalfSegment2D operator++(); + bool operator!=(const iterator&); + bool operator==(const iterator&); + RGPHalfSegment2D *ptr; + }; + + iterator begin(); // return an iterator to the first element + iterator end(); // return an iterator to the last element + bool add(RGPSegment2D rgpSeg2d); // Adds a new RGPSegment2D - bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index - bool remove(std::vector::iterator it); // Removes a RGPSegment2D at specified index - + bool update(iterator it, RGPSegment2D rgpSeg2d); // Updates RGPSegment2D existing at specified index + bool remove(iterator it); // Removes a RGPSegment2D at specified index + private: struct Line2DProgrammerStore; Line2DProgrammerStore *handle; diff --git a/include/Line2DImpl.h b/include/Line2DImpl.h index 368816c..f461e9b 100644 --- a/include/Line2DImpl.h +++ b/include/Line2DImpl.h @@ -15,7 +15,6 @@ class Line2DImpl Line2DImpl(); // no args Line2DImpl(std::vector listOfSegments); //send in a vector of segments Line2DImpl(std::string listOfLine2DString); // send in a string - Line2DImpl(std::ifstream& file); // Send in file for constructor ~Line2DImpl(); //destructor //iterator to run through the list of half segments diff --git a/src/Line2D.cpp b/src/Line2D.cpp index 9d7746f..80dd34f 100644 --- a/src/Line2D.cpp +++ b/src/Line2D.cpp @@ -11,12 +11,6 @@ struct Line2D::Line2DStore { implPointer = new Line2DImpl(linesString); vectorOfSegments = implPointer->getVectorOfSegments(); } - - Line2DStore(std::ifstream& file) - { - implPointer = new Line2DImpl(file); - vectorOfSegments = implPointer->getVectorOfSegments(); - } }; //constructor for Line2D iterator diff --git a/src/Line2DForProgrammer.cpp b/src/Line2DForProgrammer.cpp index 6600844..49c405d 100644 --- a/src/Line2DForProgrammer.cpp +++ b/src/Line2DForProgrammer.cpp @@ -5,45 +5,124 @@ struct Line2DForProgrammer::Line2DProgrammerStore { Line2DImpl *implPointer; - + // Maintains a dummy copy for iterator to work + std::vector vectorOfSegments; Line2DProgrammerStore(std::string linesString) { implPointer = new Line2DImpl(linesString); - } + vectorOfSegments = implPointer->getVectorOfSegments(); - Line2DProgrammerStore(std::ifstream& file) - { - implPointer = new Line2DImpl(file); } }; -Line2DForProgrammer::Line2DForProgrammer(std::string listOfLine2DString) + +//constructor for Line2D iterator +Line2DForProgrammer::iterator::iterator(RGPHalfSegment2D *ptr1) { - handle = new Line2DProgrammerStore(listOfLine2DString); + ptr = ptr1; } -Line2DForProgrammer::Line2DForProgrammer(std::ifstream& file) // Send in file for constructor +//overloading * to get output +RGPHalfSegment2D Line2DForProgrammer::iterator::operator*() { - handle = new Line2DProgrammerStore(file); + return *ptr; } -Line2DForProgrammer::~Line2DForProgrammer() +//operator overloading ++ (post) for incrementing the iterator +RGPHalfSegment2D Line2DForProgrammer::iterator::operator++(int junk) { - delete handle->implPointer; - delete handle; + RGPHalfSegment2D *ptr1; + ptr1 = ptr; + ptr++; + return *ptr1; +} + +//operator overloading ++ (pre) for incrementing the iterator +RGPHalfSegment2D Line2DForProgrammer::iterator::operator++() +{ + ptr++; + return *ptr; +} + +bool Line2DForProgrammer::iterator::operator!=(const iterator &it) +{ + if(it.ptr==ptr) + return false; + return true; +} + +//overloading == to check if two iterators are equal +bool Line2DForProgrammer::iterator::operator==(const iterator &it) +{ + if(it.ptr!=ptr) + return false; + return true; +} + +//Line2D begin method, return an iterator to the first segment in the sorted order. +Line2DForProgrammer::iterator Line2DForProgrammer::begin() +{ + RGPHalfSegment2D *ptr = &(handle->vectorOfSegments[0]); + return iterator(ptr); } +//Line2D begin method, return an iterator to the last segment in the sorted order. +Line2DForProgrammer::iterator Line2DForProgrammer::end() +{ + int t = handle->vectorOfSegments.size(); + return (iterator(&(handle->vectorOfSegments[t-1]))); +} + +//method to add new segments to our list of segments bool Line2DForProgrammer::add(RGPSegment2D rgpSeg2d) { - //TODO + bool res = handle->implPointer->add(rgpSeg2d); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return res; +} + +//method to update a segment in our current list of segments +bool Line2DForProgrammer::update(Line2DForProgrammer::iterator it, RGPSegment2D rgpSeg2d) +{ + Line2DImpl::iterator newIt = handle->implPointer->begin(); + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->update(newIt, rgpSeg2d); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return result; + +} + +//method to remove a segment using an iterator +bool Line2DForProgrammer::remove(Line2DForProgrammer::iterator it) +{ + Line2DImpl::iterator newIt = handle->implPointer->begin(); + for(Line2DImpl::iterator implit = handle->implPointer->begin(); implit!= handle->implPointer->end();implit++) + { + if(*it == *implit) + { + newIt = implit; + break; + } + } + bool result = handle->implPointer->remove(newIt); + handle->vectorOfSegments = handle->implPointer->getVectorOfSegments(); + return result; } -bool Line2DForProgrammer::remove(std::vector::iterator it) +Line2DForProgrammer::Line2DForProgrammer(std::string listOfLine2DString) { - //TODO + handle = new Line2DProgrammerStore(listOfLine2DString); } -bool update(std::vector::iterator it, RGPSegment2D rgpSeg2d) +Line2DForProgrammer::~Line2DForProgrammer() { - //TODO + delete handle->implPointer; + delete handle; } diff --git a/src/Line2DImpl.cpp b/src/Line2DImpl.cpp index 6620dee..ac20931 100644 --- a/src/Line2DImpl.cpp +++ b/src/Line2DImpl.cpp @@ -111,32 +111,6 @@ Line2DImpl::Line2DImpl(std::string listOfLine2DString) } } -//constructor to take in data from a file and create our segments -Line2DImpl::Line2DImpl(std::ifstream& file) -{ - handle = new Line2DImplStore; - - std::string inputString; - if(file.is_open()) - { - std::stringstream strBuffer; - strBuffer << file.rdbuf(); - inputString = strBuffer.str(); - } - else - { - throw std::runtime_error("Error while reading the file"); - } - - //same as the above constructor, makes it a string and parses it - if(parseStringToVectorOfLines(inputString)) - std::cout << "success" << std::endl; - else{ - std::cout << "failed" << std::endl; - handle->vectorOfSegments.clear(); - } -} - Line2DImpl::~Line2DImpl() { delete handle; From f4cceed8264cbfc8db1c998c839ac2437f879165 Mon Sep 17 00:00:00 2001 From: Lokesh Surya Paluri Date: Sun, 9 Dec 2018 08:39:21 -0500 Subject: [PATCH 95/95] Update Point2D.cpp --- src/Point2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Point2D.cpp b/src/Point2D.cpp index afdec83..8fa1532 100644 --- a/src/Point2D.cpp +++ b/src/Point2D.cpp @@ -89,7 +89,7 @@ bool Point2D::isEmptyPoint() void Point2D::printAllPoints() { - handle->implPointer->isEmptyPoint(); + handle->implPointer->printAllPoints(); } int Point2D::getNumberOfPoints()