#pragma once #include #include #include #include "boost/units/systems/angle/degrees.hpp" #include "boost/units/systems/si.hpp" template auto get(const Point &p); namespace bu = boost::units; namespace qty { using Length = bu::quantity; using Angle = bu::quantity; using Degree = bu::quantity; using Radian = bu::quantity; } // namespace qty template class GenericCircle { public: GenericCircle(); GenericCircle(NumberType rad, Point ori); // Property setters void setRadius(NumberType rad); void setOrigin(const Point &ori); // Property getters NumberType radius() const; const Point &origin() const; Point &origin(); private: NumberType _r; Point _origin; }; // Free functions. template void approximate(Circle &circ, long n, qty::Angle alpha1, qty::Angle alpha2, Container &c); template void approximate(Circle &circ, long n, Container &c); // Impl. template GenericCircle::GenericCircle() : _r(0), _origin(0, 0) {} template GenericCircle::GenericCircle(NumberType rad, Point ori) : _r(rad), _origin(ori) {} /*! * Returns a polygon with \a n corners which approximates the * circle. * * \sa Point */ template void GenericCircle::setRadius(NumberType rad) { if (rad >= 0) { this->_r = rad; } } template void GenericCircle::setOrigin(const Point &ori) { this->_origin = ori; } template NumberType GenericCircle::radius() const { return this->_r; } template const Point &GenericCircle::origin() const { return this->_origin; } template Point &GenericCircle::origin() { return this->_origin; } template void approximate(Circle &circ, long n, qty::Angle alpha1, qty::Angle alpha2, Container &c) { auto clipp = [](double angle) { while (angle < 0) { angle += 2 * M_PI; } while (angle > 2 * M_PI) { angle -= 2 * M_PI; } return angle; }; double a1 = clipp(alpha1.value()); double a2 = clipp(alpha2.value()); double angleDisc = 0; if (n > 0) { angleDisc = (a2 - a1) / (n - 1); } else { angleDisc = (a2 - a1) / (n + 1); n = n * (-1); } double a = a1; using Point = std::remove_cv_t>; auto x0 = get<0>(circ.origin()); auto y0 = get<1>(circ.origin()); auto r = circ.radius(); using NumberType = std::remove_cv_t>; while (n--) { auto x = NumberType(x0 + r * std::cos(a)); auto y = NumberType(y0 + r * std::sin(a)); c.push_back(Point(x, y)); a += angleDisc; } } template void approximate(Circle &circ, long n, Container &c) { using namespace bu; double angleDisc = 0; if (n > 0) { angleDisc = 2 * M_PI / (n - 1); } else { angleDisc = 2 * M_PI / (n + 1); n = n * (-1); } double a = 0; using Point = std::remove_cv_t>; auto x0 = get<0>(circ.origin()); auto y0 = get<1>(circ.origin()); auto r = circ.radius(); using NumberType = std::remove_cv_t>; while (n--) { auto x = NumberType(x0 + r * std::cos(a)); auto y = NumberType(y0 + r * std::sin(a)); c.push_back(Point(x, y)); a += angleDisc; } }