#ifndef R2_CONTOUR_H #define R2_CONTOUR_H 1 #include #include #include #include #include "R2Graph.h" using std::size_t; class R2Polyline: public std::vector { public: R2Polyline(size_t n = 0, const R2Point* vertices = nullptr): std::vector(n) { if (n > 0 && vertices != nullptr) { for (size_t i = 0; i < n; ++i) { (*this)[i] = vertices[i]; } } } R2Polyline(const std::vector& vertices): std::vector(vertices) { } R2Polyline(std::vector&& vertices): std::vector(vertices) { } R2Polyline& operator=(const std::vector& vertices) { static_cast&>(*this) = vertices; return *this; } R2Polyline& operator=(std::vector&& vertices) { static_cast&>(*this) = std::move(vertices); return *this; } R2Point centroid() const { R2Point c(0., 0.); for (size_t i = 0; i < size(); ++i) { c += (*this)[i]; } if (size() > 0) { c *= 1./double(size()); } return c; } double length() const { double l = 0.; for (size_t i = 0; i < size() - 1; ++i) { l += (*this)[i].distance((*this)[i + 1]); } return l; } }; class R2Contour: public R2Polyline { private: mutable double perim; mutable bool perimeter_calculated; mutable double signed_area; mutable bool signed_area_calculated; public: R2Contour(size_t n = 0, const R2Point* vertices = nullptr): R2Polyline(n, vertices), perim(0.), perimeter_calculated(false), signed_area(0.), signed_area_calculated(false) {} R2Contour(const R2Polyline& lineStrip): R2Polyline(lineStrip), perim(0.), perimeter_calculated(false), signed_area(0.), signed_area_calculated(false) {} R2Contour(R2Polyline&& lineStrip): R2Polyline(lineStrip), perim(0.), perimeter_calculated(false), signed_area(0.), signed_area_calculated(false) {} R2Contour(const std::vector& vertices): R2Polyline(vertices), perim(0.), perimeter_calculated(false), signed_area(0.), signed_area_calculated(false) {} R2Contour(std::vector&& vertices): R2Polyline(vertices), perim(0.), perimeter_calculated(false), signed_area(0.), signed_area_calculated(false) {} void invalidateParameters() const { perimeter_calculated = false; signed_area_calculated = false; } void push_back(const R2Point& p) { static_cast(*this).push_back(p); invalidateParameters(); } void push_back(R2Point&& p) { static_cast(*this).push_back(p); invalidateParameters(); } void pop_back() { static_cast(*this).pop_back(); invalidateParameters(); } void clear() { static_cast(*this).clear(); invalidateParameters(); } double perimeter() const { if (!perimeter_calculated) { perim = length(); if (size() > 1) perim += (*this)[0].distance((*this)[size() - 1]); perimeter_calculated = true; } return perim; } double signedArea() const { if (!signed_area_calculated) { signed_area = 0.; if (size() > 1) { R2Point c(0., 0.); for (size_t i = 0; i < size(); ++i) { size_t j = i + 1; if (j >= size()) j = 0; signed_area += R2Point::signed_area( c, (*this)[i], (*this)[j] ); } } signed_area_calculated = true; } return signed_area; } double area() const { return fabs(signedArea()); } }; std::ostream& operator<<(std::ostream& s, const R2Polyline& l); std::ostream& operator<<(std::ostream& s, const R2Contour& c); #endif