|
@@ -3,8 +3,9 @@
|
|
|
#include <cmath>
|
|
|
#include <vector>
|
|
|
#include <fstream>
|
|
|
-#define PI 3.14159265358979323846
|
|
|
+#include <iomanip>
|
|
|
|
|
|
+#define PI 3.14159265358979323846
|
|
|
|
|
|
template<class T>
|
|
|
class Point {
|
|
@@ -21,37 +22,37 @@ template<class T>
|
|
|
class GeometricFigure {
|
|
|
public:
|
|
|
/// <summary>
|
|
|
- /// Calculate area of the figure
|
|
|
+ /// Calculate the area of the figure
|
|
|
/// </summary>
|
|
|
/// <returns>The internal area of the figure</returns>
|
|
|
- virtual T calc_area() = 0;
|
|
|
+ virtual T calc_area() const = 0;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Calculate perimeter of the figure
|
|
|
+ /// Calculate the perimeter of the figure
|
|
|
/// </summary>
|
|
|
/// <returns>The external perimeter of the figure</returns>
|
|
|
- virtual T calc_perimeter() = 0;
|
|
|
-
|
|
|
+ virtual T calc_perimeter() const = 0;
|
|
|
+
|
|
|
/// <summary>
|
|
|
- /// Get name of the figure
|
|
|
+ /// Get the name of the figure
|
|
|
/// </summary>
|
|
|
- virtual void name() = 0;
|
|
|
+ virtual void name() const = 0;
|
|
|
|
|
|
- friend std::ostream& operator << (const std::ostream& out, const GeometricFigure& figure);
|
|
|
-};
|
|
|
+ friend std::ostream& operator<<(std::ostream& out, const GeometricFigure<T>& figure) {
|
|
|
+ figure.name();
|
|
|
+ out << " (perimeter: " << figure.calc_perimeter() << ", area: " << figure.calc_area() << ")";
|
|
|
+ return out;
|
|
|
+ }
|
|
|
|
|
|
-template<class T>
|
|
|
-std::ostream& operator << (const std::ostream& out, const GeometricFigure<T>& figure)
|
|
|
-{
|
|
|
- out << figure.name << " (perimeter: " << figure.calc_perimeter() << ", area: " << figure.calc_area();
|
|
|
- return out;
|
|
|
-}
|
|
|
+ virtual ~GeometricFigure() = default;
|
|
|
+};
|
|
|
|
|
|
/// <summary>
|
|
|
/// Represents a circle
|
|
|
/// </summary>
|
|
|
/// <typeparam name="T">Number value type</typeparam>
|
|
|
-template<class T> class Circle : public GeometricFigure<T> {
|
|
|
+template<class T>
|
|
|
+class Circle : public GeometricFigure<T> {
|
|
|
private:
|
|
|
Point<T> center;
|
|
|
T radius;
|
|
@@ -64,24 +65,24 @@ public:
|
|
|
/// <param name="r">Radius of the circle</param>
|
|
|
Circle(Point<T> c, T r) : center(c), radius(r) {}
|
|
|
|
|
|
- T calc_area() override;
|
|
|
- T calc_perimeter() override;
|
|
|
- void name() override;
|
|
|
+ T calc_area() const override;
|
|
|
+ T calc_perimeter() const override;
|
|
|
+ void name() const override;
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
|
-T Circle<T>::calc_area() {
|
|
|
+T Circle<T>::calc_area() const {
|
|
|
return PI * radius * radius;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Circle<T>::calc_perimeter() {
|
|
|
+T Circle<T>::calc_perimeter() const {
|
|
|
return 2 * PI * radius;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-void Circle<T>::name() {
|
|
|
- std::cout << "Circle" << std::endl;
|
|
|
+void Circle<T>::name() const {
|
|
|
+ std::cout << "Circle";
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -96,31 +97,32 @@ private:
|
|
|
|
|
|
public:
|
|
|
/// <summary>
|
|
|
- /// Create an ellipse by its center point and two dimension
|
|
|
+ /// Create an ellipse by its center point and two dimensions
|
|
|
/// </summary>
|
|
|
/// <param name="c">Center of the ellipse</param>
|
|
|
/// <param name="a">First dimension</param>
|
|
|
/// <param name="b">Second dimension</param>
|
|
|
Ellipse(Point<T> c, T a, T b) : center(c), a(a), b(b) {}
|
|
|
|
|
|
- T calc_area() override;
|
|
|
- T calc_perimeter() override;
|
|
|
- void name() override;
|
|
|
+ T calc_area() const override;
|
|
|
+ T calc_perimeter() const override;
|
|
|
+ void name() const override;
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
|
-T Ellipse<T>::calc_area() {
|
|
|
+T Ellipse<T>::calc_area() const {
|
|
|
return PI * a * b;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Ellipse<T>::calc_perimeter() {
|
|
|
- return PI * (3 * (a + b) - sqrt((3 * a + b) * (a + 3 * b)));
|
|
|
+T Ellipse<T>::calc_perimeter() const {
|
|
|
+ // Approximation of the perimeter of an ellipse
|
|
|
+ return PI * (3 * (a + b) - std::sqrt((3 * a + b) * (a + 3 * b)));
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-void Ellipse<T>::name() {
|
|
|
- std::cout << "Ellipse" << std::endl;
|
|
|
+void Ellipse<T>::name() const {
|
|
|
+ std::cout << "Ellipse";
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -132,6 +134,10 @@ class Triangle : public GeometricFigure<T> {
|
|
|
private:
|
|
|
Point<T> vertices[3];
|
|
|
|
|
|
+ T side_length(const Point<T>& p1, const Point<T>& p2) const {
|
|
|
+ return std::sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
|
|
|
+ }
|
|
|
+
|
|
|
public:
|
|
|
/// <summary>
|
|
|
/// Create a triangle by three points
|
|
@@ -141,31 +147,31 @@ public:
|
|
|
/// <param name="c">Point C</param>
|
|
|
Triangle(Point<T> a, Point<T> b, Point<T> c) : vertices{ a, b, c } {}
|
|
|
|
|
|
- T calc_area() override;
|
|
|
- T calc_perimeter() override;
|
|
|
- void name() override;
|
|
|
+ T calc_area() const override;
|
|
|
+ T calc_perimeter() const override;
|
|
|
+ void name() const override;
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
|
-T Triangle<T>::calc_area() {
|
|
|
- T a = sqrt((vertices[1].x - vertices[0].x) * (vertices[1].x - vertices[0].x) + (vertices[1].y - vertices[0].y) * (vertices[1].y - vertices[0].y));
|
|
|
- T b = sqrt((vertices[2].x - vertices[1].x) * (vertices[2].x - vertices[1].x) + (vertices[2].y - vertices[1].y) * (vertices[2].y - vertices[1].y));
|
|
|
- T c = sqrt((vertices[0].x - vertices[2].x) * (vertices[0].x - vertices[2].x) + (vertices[0].y - vertices[2].y) * (vertices[0].y - vertices[2].y));
|
|
|
+T Triangle<T>::calc_area() const {
|
|
|
+ T a = side_length(vertices[0], vertices[1]);
|
|
|
+ T b = side_length(vertices[1], vertices[2]);
|
|
|
+ T c = side_length(vertices[2], vertices[0]);
|
|
|
T s = (a + b + c) / 2;
|
|
|
- return sqrt(s * (s - a) * (s - b) * (s - c));
|
|
|
+ return std::sqrt(s * (s - a) * (s - b) * (s - c));
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Triangle<T>::calc_perimeter() {
|
|
|
- T a = sqrt((vertices[1].x - vertices[0].x) * (vertices[1].x - vertices[0].x) + (vertices[1].y - vertices[0].y) * (vertices[1].y - vertices[0].y));
|
|
|
- T b = sqrt((vertices[2].x - vertices[1].x) * (vertices[2].x - vertices[1].x) + (vertices[2].y - vertices[1].y) * (vertices[2].y - vertices[1].y));
|
|
|
- T c = sqrt((vertices[0].x - vertices[2].x) * (vertices[0].x - vertices[2].x) + (vertices[0].y - vertices[2].y) * (vertices[0].y - vertices[2].y));
|
|
|
+T Triangle<T>::calc_perimeter() const {
|
|
|
+ T a = side_length(vertices[0], vertices[1]);
|
|
|
+ T b = side_length(vertices[1], vertices[2]);
|
|
|
+ T c = side_length(vertices[2], vertices[0]);
|
|
|
return a + b + c;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-void Triangle<T>::name() {
|
|
|
- std::cout << "Triangle" << std::endl;
|
|
|
+void Triangle<T>::name() const {
|
|
|
+ std::cout << "Triangle";
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -177,6 +183,10 @@ class Rectangle : public GeometricFigure<T> {
|
|
|
private:
|
|
|
Point<T> vertices[4];
|
|
|
|
|
|
+ T side_length(const Point<T>& p1, const Point<T>& p2) const {
|
|
|
+ return std::sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
|
|
|
+ }
|
|
|
+
|
|
|
public:
|
|
|
/// <summary>
|
|
|
/// Create a rectangle by 4 points
|
|
@@ -187,28 +197,28 @@ public:
|
|
|
/// <param name="d">Top-right point</param>
|
|
|
Rectangle(Point<T> a, Point<T> b, Point<T> c, Point<T> d) : vertices{ a, b, c, d } {}
|
|
|
|
|
|
- T calc_area() override;
|
|
|
- T calc_perimeter() override;
|
|
|
- void name() override;
|
|
|
+ T calc_area() const override;
|
|
|
+ T calc_perimeter() const override;
|
|
|
+ void name() const override;
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
|
-T Rectangle<T>::calc_area() {
|
|
|
- T width = sqrt((vertices[1].x - vertices[0].x) * (vertices[1].x - vertices[0].x) + (vertices[1].y - vertices[0].y) * (vertices[1].y - vertices[0].y));
|
|
|
- T height = sqrt((vertices[2].x - vertices[1].x) * (vertices[2].x - vertices[1].x) + (vertices[2].y - vertices[1].y) * (vertices[2].y - vertices[1].y));
|
|
|
+T Rectangle<T>::calc_area() const {
|
|
|
+ T width = side_length(vertices[0], vertices[1]);
|
|
|
+ T height = side_length(vertices[1], vertices[2]);
|
|
|
return width * height;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Rectangle<T>::calc_perimeter() {
|
|
|
- T width = sqrt((vertices[1].x - vertices[0].x) * (vertices[1].x - vertices[0].x) + (vertices[1].y - vertices[0].y) * (vertices[1].y - vertices[0].y));
|
|
|
- T height = sqrt((vertices[2].x - vertices[1].x) * (vertices[2].x - vertices[1].x) + (vertices[2].y - vertices[1].y) * (vertices[2].y - vertices[1].y));
|
|
|
+T Rectangle<T>::calc_perimeter() const {
|
|
|
+ T width = side_length(vertices[0], vertices[1]);
|
|
|
+ T height = side_length(vertices[1], vertices[2]);
|
|
|
return 2 * (width + height);
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-void Rectangle<T>::name() {
|
|
|
- std::cout << "Rectangle" << std::endl;
|
|
|
+void Rectangle<T>::name() const {
|
|
|
+ std::cout << "Rectangle";
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -227,17 +237,16 @@ public:
|
|
|
/// <param name="filename">Path to the file</param>
|
|
|
Polygon(const std::string& filename);
|
|
|
|
|
|
- T calc_area() override;
|
|
|
- T calc_perimeter() override;
|
|
|
- void name() override;
|
|
|
+ T calc_area() const override;
|
|
|
+ T calc_perimeter() const override;
|
|
|
+ void name() const override;
|
|
|
};
|
|
|
|
|
|
template<class T>
|
|
|
Polygon<T>::Polygon(const std::string& filename) {
|
|
|
std::ifstream file(filename);
|
|
|
if (!file.is_open()) {
|
|
|
- std::cerr << "Error opening file" << std::endl;
|
|
|
- return;
|
|
|
+ throw std::runtime_error("Error opening file");
|
|
|
}
|
|
|
int numVertices;
|
|
|
file >> numVertices;
|
|
@@ -250,7 +259,7 @@ Polygon<T>::Polygon(const std::string& filename) {
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Polygon<T>::calc_area() {
|
|
|
+T Polygon<T>::calc_area() const {
|
|
|
T area = 0.0;
|
|
|
int n = vertices.size();
|
|
|
for (int i = 0; i < n; ++i) {
|
|
@@ -260,16 +269,16 @@ T Polygon<T>::calc_area() {
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-T Polygon<T>::calc_perimeter() {
|
|
|
+T Polygon<T>::calc_perimeter() const {
|
|
|
T perimeter = 0.0;
|
|
|
int n = vertices.size();
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
- perimeter += sqrt((vertices[(i + 1) % n].x - vertices[i].x) * (vertices[(i + 1) % n].x - vertices[i].x) + (vertices[(i + 1) % n].y - vertices[i].y) * (vertices[(i + 1) % n].y - vertices[i].y));
|
|
|
+ perimeter += std::sqrt((vertices[(i + 1) % n].x - vertices[i].x) * (vertices[(i + 1) % n].x - vertices[i].x) + (vertices[(i + 1) % n].y - vertices[i].y) * (vertices[(i + 1) % n].y - vertices[i].y));
|
|
|
}
|
|
|
return perimeter;
|
|
|
}
|
|
|
|
|
|
template<class T>
|
|
|
-void Polygon<T>::name() {
|
|
|
- std::cout << "Polygon" << std::endl;
|
|
|
-}
|
|
|
+void Polygon<T>::name() const {
|
|
|
+ std::cout << "Polygon";
|
|
|
+}
|