| 198 | */ |
| 199 | template <typename RealType, typename Allocator> |
| 200 | class circular : public labeled_base<Allocator>, |
| 201 | public iterator_mixin<circular<RealType, Allocator>> { |
| 202 | using base_type = labeled_base<Allocator>; |
| 203 | |
| 204 | public: |
| 205 | using allocator_type = typename base_type::allocator_type; |
| 206 | using value_type = RealType; |
| 207 | using bin_type = interval_view<circular>; |
| 208 | |
| 209 | // two_pi can be found in boost/math, but it is defined here to reduce deps |
| 210 | static value_type two_pi() { return 6.283185307179586; } |
| 211 | |
| 212 | /** Constructor for n bins with an optional offset. |
| 213 | * |
| 214 | * \param n number of bins. |
| 215 | * \param phase starting phase. |
| 216 | * \param perimeter range after which value wraps around. |
| 217 | * \param label description of the axis. |
| 218 | */ |
| 219 | explicit circular(unsigned n, value_type phase = 0.0, value_type perimeter = two_pi(), |
| 220 | string_view label = {}, const allocator_type& a = allocator_type()) |
| 221 | : base_type(n, uoflow_type::off, label, a), phase_(phase), perimeter_(perimeter) {} |
| 222 | |
| 223 | circular() = default; |
| 224 | circular(const circular&) = default; |
| 225 | circular& operator=(const circular&) = default; |
| 226 | circular(circular&&) = default; |
| 227 | circular& operator=(circular&&) = default; |
| 228 | |
| 229 | /// Returns the bin index for the passed argument. |
| 230 | int index(value_type x) const noexcept { |
| 231 | const value_type z = (x - phase_) / perimeter_; |
| 232 | const int i = static_cast<int>(std::floor(z * base_type::size())) % base_type::size(); |
| 233 | return i + (i < 0) * base_type::size(); |
| 234 | } |
| 235 | |
| 236 | /// Returns lower edge of bin. |
| 237 | value_type lower(int i) const noexcept { |
| 238 | const value_type z = value_type(i) / base_type::size(); |
| 239 | return z * perimeter_ + phase_; |
| 240 | } |
| 241 | |
| 242 | bin_type operator[](int idx) const noexcept { return bin_type(idx, *this); } |
| 243 | |
| 244 | bool operator==(const circular& o) const noexcept { |
| 245 | return base_type::operator==(o) && phase_ == o.phase_ && perimeter_ == o.perimeter_; |
| 246 | } |
| 247 | |
| 248 | value_type perimeter() const { return perimeter_; } |
| 249 | value_type phase() const { return phase_; } |
| 250 | |
| 251 | private: |
| 252 | value_type phase_ = 0.0, perimeter_ = 1.0; |
| 253 | |
| 254 | friend class ::boost::serialization::access; |
| 255 | template <class Archive> |
| 256 | void serialize(Archive&, unsigned); |
| 257 | }; |
no outgoing calls