GenericCircle.h 3.78 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
#pragma once

#include <QObject>
#include <QPointF>

#include <cmath>

#include "boost/units/systems/angle/degrees.hpp"
#include "boost/units/systems/si.hpp"

11
template <int k, class Point> auto get(const Point &p);
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

namespace bu = boost::units;

namespace qty {
using Length = bu::quantity<bu::si::length>;
using Angle = bu::quantity<bu::si::plane_angle>;
using Degree = bu::quantity<bu::degree::plane_angle>;
using Radian = bu::quantity<bu::si::plane_angle>;
} // namespace qty

template <class NumberType, class Point> 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 <class Circle, class Container>
void approximate(Circle &circ, long n, qty::Angle alpha1, qty::Angle alpha2,
                 Container &c);
template <class Circle, class Container>
void approximate(Circle &circ, long n, Container &c);

// Impl.
template <class NumberType, class Point>
GenericCircle<NumberType, Point>::GenericCircle() : _r(0), _origin(0, 0) {}

template <class NumberType, class Point>
GenericCircle<NumberType, Point>::GenericCircle(NumberType rad, Point ori)
    : _r(rad), _origin(ori) {}

/*!
 * Returns a polygon with \a n corners which approximates the
 * circle.
 *
 * \sa Point
 */

template <class NumberType, class Point>
void GenericCircle<NumberType, Point>::setRadius(NumberType rad) {
  if (rad >= 0) {
    this->_r = rad;
  }
}

template <class NumberType, class Point>
void GenericCircle<NumberType, Point>::setOrigin(const Point &ori) {
  this->_origin = ori;
}

template <class NumberType, class Point>
NumberType GenericCircle<NumberType, Point>::radius() const {
  return this->_r;
}

template <class NumberType, class Point>
const Point &GenericCircle<NumberType, Point>::origin() const {
  return this->_origin;
}

template <class NumberType, class Point>
Point &GenericCircle<NumberType, Point>::origin() {
  return this->_origin;
}

template <class Circle, class Container>
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;
115 116
  using Point =
      std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
  auto x0 = get<0>(circ.origin());
  auto y0 = get<1>(circ.origin());
  auto r = circ.radius();
  using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>;
  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 <class Circle, class Container>
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;
142 143
  using Point =
      std::remove_cv_t<std::remove_reference_t<decltype(circ.origin())>>;
144 145 146 147 148 149 150 151 152 153 154
  auto x0 = get<0>(circ.origin());
  auto y0 = get<1>(circ.origin());
  auto r = circ.radius();
  using NumberType = std::remove_cv_t<std::remove_reference_t<decltype(x0)>>;
  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;
  }
}