Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) PolarCoordinat

 

Technical facts

 

 

 

 

 

 

./CppPolarCoordinat/CppPolarCoordinat.pri

 

INCLUDEPATH += \
    ../../Classes/CppPolarCoordinat

SOURCES += \
    ../../Classes/CppPolarCoordinat/polarcoordinat.cpp

HEADERS  += \
    ../../Classes/CppPolarCoordinat/polarcoordinat.h

OTHER_FILES += \
    ../../Classes/CppPolarCoordinat/Licence.txt

 

 

 

 

 

./CppPolarCoordinat/polarcoordinat.h

 

#ifndef POLARCOORDINAT_H
#define POLARCOORDINAT_H

#include <cassert>
#include <cmath>

//#include "coordinat.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/units/base_units/angle/radian.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si/area.hpp>
#include <boost/units/systems/si/io.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include "trace.h"
#pragma GCC diagnostic pop

namespace ribi {

template <class Angle, class Length>
struct PolarCoordinat
{
  typedef boost::geometry::model::d2::point_xy<Length> Coordinat;
  explicit PolarCoordinat(const Angle& angle, const Length& length);
  explicit PolarCoordinat(const Length& x, const Length& y);

  ///Add a polar coordinat by putting the second's tail on the
  ///head of this PolarCoordinat
  PolarCoordinat& operator+=(const PolarCoordinat& pc);

  static const Angle CalcAngle(const Length& dx, const Length& dy);

  static const Length CalcLength(const Length& dx, const Length& dy);

  ///Get the angle of this polar coordinat
  ///0.0 pi rad = 12 o'clock
  ///0.5 pi rad =  3 o'clock
  ///1.0 pi rad =  6 o'clock
  ///1.5 pi rad =  9 o'clock
  const Angle& GetAngle() const { return m_angle; }

  ///Get the length of this coordinat, which equals its distance to the origin
  const Length& GetLength() const { return m_length; }

  void SetAngle(const Angle& angle) { m_angle = angle; }

  ///Test this class
  static void Test();


  ///Translate with a coordinat
  void Translate(const Coordinat& c);

  private:
  ///The angle
  ///0.0 pi rad = 12 o'clock
  ///0.5 pi rad =  3 o'clock
  ///1.0 pi rad =  6 o'clock
  ///1.5 pi rad =  9 o'clock
  Angle m_angle;

  Length m_length;

};

/*
template <class T, class U>
T CalculateSqrt(const U& x);
*/

template <class Angle,class Length>
boost::geometry::model::d2::point_xy<Length> ToCoordinat(const PolarCoordinat<Angle,Length>& c)
{
  return boost::geometry::model::d2::point_xy<Length>(
     std::sin(c.GetAngle().value()) * c.GetLength(),
    -std::cos(c.GetAngle().value()) * c.GetLength()
  );
}

template <class Angle, class Length>
PolarCoordinat<Angle,Length>::PolarCoordinat(const Angle& angle, const Length& length)
  : m_angle(angle), m_length(length)
{
  #ifndef NDEBUG
  Test();
  #endif
}

template <class Angle, class Length>
PolarCoordinat<Angle,Length>::PolarCoordinat(const Length& x, const Length& y)
  : m_angle(CalcAngle(x,y)), m_length(CalcLength(x,y))
{
  #ifndef NDEBUG
  Test();
  #endif
}

template <class Angle, class Length>
const Angle PolarCoordinat<Angle,Length>::CalcAngle(const Length& dx, const Length& dy)
{
  const double half_pi = boost::math::constants::half_pi<double>();
  return Angle(
    (half_pi + std::atan2(dy.value(),dx.value()))
    * boost::units::si::radians);
}


template <class Angle, class Length>
const Length PolarCoordinat<Angle,Length>::CalcLength(const Length& dx, const Length& dy)
{
  const double a { dx.value() };
  const double b { dy.value() };
  return std::sqrt((a*a)+(b*b)) * boost::units::si::meter;
}

template <class T>
bool IsAboutEqual(
  const boost::units::quantity<T>& lhs,
  const boost::units::quantity<T>& rhs,
  const boost::units::quantity<T>& max_error)
{
  return lhs < rhs
    ? lhs + max_error > rhs
    : rhs + max_error > lhs;
}

template <class Angle,class Length>
PolarCoordinat<Angle,Length> operator+(
  const PolarCoordinat<Angle,Length>& a,
  const PolarCoordinat<Angle,Length>& b
  )
{
  return PolarCoordinat<Angle,Length>(
    boost::geometry::get<0>(ToCoordinat(a)) + boost::geometry::get<0>(ToCoordinat(b)),
    boost::geometry::get<1>(ToCoordinat(a)) + boost::geometry::get<1>(ToCoordinat(b))
  );
}

template <class Angle, class Length>
void PolarCoordinat<Angle,Length>::Test()
{
  {
    static bool is_tested { false };
    if (is_tested) return;
    is_tested = true;
  }
  #ifdef SHOW_CALCANGLE_SERIES
  TRACE(CalcAngle(Length( 1.0 * meter),Length(-1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length( 1.0 * meter),Length( 0.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length( 1.0 * meter),Length( 1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length( 0.0 * meter),Length( 1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length(-1.0 * meter),Length( 1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length(-1.0 * meter),Length( 0.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length(-1.0 * meter),Length(-1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  TRACE(CalcAngle(Length( 0.0 * meter),Length(-1.0 * meter)) / Angle(boost::math::constants::pi<double>() * radian));
  #endif
  using boost::units::si::meter;
  using boost::units::si::micro;
  using boost::units::si::nano;
  using boost::units::si::radian;
  assert(IsAboutEqual(CalcAngle(Length( 1.0 * meter),Length(-1.0 * meter)),Angle( 0.25 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length( 1.0 * meter),Length( 0.0 * meter)),Angle( 0.50 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length( 1.0 * meter),Length( 1.0 * meter)),Angle( 0.75 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length( 0.0 * meter),Length( 1.0 * meter)),Angle( 1.00 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length(-1.0 * meter),Length( 1.0 * meter)),Angle( 1.25 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length(-1.0 * meter),Length( 0.0 * meter)),Angle( 1.50 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  assert(IsAboutEqual(CalcAngle(Length(-1.0 * meter),Length(-1.0 * meter)),Angle(-0.25 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
  {
    PolarCoordinat c(Length(1.0 * nano * meter),Length(-1.0 * meter));
    assert(IsAboutEqual(c.GetAngle(),Angle(1.0 * nano * radian),Angle(1.0 * nano * radian)));
    assert(IsAboutEqual(c.GetLength(),Length(1.0 * meter),Length(1.0 * nano * meter)));
  }
  {
    PolarCoordinat c(Length(1.0 * meter),Length(1.0 * meter));
    assert(IsAboutEqual(c.GetAngle(),Angle(0.75 * boost::math::constants::pi<double>() * radian),Angle(1.0 * nano * radian)));
    assert(IsAboutEqual(c.GetLength(),Length(std::sqrt(2.0) * meter),Length(1.0 * nano * meter)));
  }
  //Conversion to Coordinat
  using boost::geometry::get;
  {
    const PolarCoordinat<Angle,Length> p(
      Angle(0.0 * boost::math::constants::pi<double>() * radian),
      Length(1.0 * meter)
    );
    const Coordinat c(ToCoordinat(p));
    assert(get<0>(c) > Length(-1.0 * micro * meter));
    assert(get<0>(c) < Length( 1.0 * micro * meter));
    assert(get<1>(c) > Length(-1.00001 * meter));
    assert(get<1>(c) < Length(-0.99999 * meter));
  }
  {
    const PolarCoordinat<Angle,Length> p(Angle(0.5 * boost::math::constants::pi<double>() * radian),Length(1.0 * meter));
    const Coordinat c(ToCoordinat(p));
    assert(get<1>(c) > Length(-1.0 * micro * meter));
    assert(get<1>(c) < Length( 1.0 * micro * meter));
    assert(get<0>(c) > Length(0.99999 * meter));
    assert(get<0>(c) < Length(1.00001 * meter));
  }
  {
    const PolarCoordinat<Angle,Length> p(Angle(1.0 * boost::math::constants::pi<double>() * radian),Length(1.0 * meter));
    const Coordinat c(ToCoordinat(p));
    assert(get<0>(c) > Length(-1.0 * micro * meter));
    assert(get<0>(c) < Length( 1.0 * micro * meter));
    assert(get<1>(c) > Length(0.99999 * meter));
    assert(get<1>(c) < Length(1.00001 * meter));
  }
  {
    const PolarCoordinat<Angle,Length> p(Angle(1.5 * boost::math::constants::pi<double>() * radian),Length(1.0 * meter));
    const Coordinat c(ToCoordinat(p));
    assert(get<1>(c) > Length(-1.0 * micro * meter));
    assert(get<1>(c) < Length( 1.0 * micro * meter));
    assert(get<0>(c) > Length(-1.00001 * meter));
    assert(get<0>(c) < Length(-0.99999 * meter));
  }
  {
    const PolarCoordinat<Angle,Length> p(Angle(2.0 * boost::math::constants::pi<double>() * radian),Length(1.0 * meter));
    const Coordinat c(ToCoordinat(p));
    assert(get<0>(c) > Length(-1.0 * micro * meter));
    assert(get<0>(c) < Length( 1.0 * micro * meter));
    assert(get<1>(c) > Length(-1.00001 * meter));
    assert(get<1>(c) < Length(-0.99999 * meter));
  }
  //Translate
  {
    const PolarCoordinat<Angle,Length> c(Length(1.0 * meter),Length(1.0 * meter));
    PolarCoordinat<Angle,Length> d(c);
    d.Translate(Coordinat(Length(2.0 * meter),Length(2.0 * meter)));
    assert(IsAboutEqual(c.GetAngle(),d.GetAngle(),Angle(1.0 * nano * radian)));
  }
  {
    const PolarCoordinat<Angle,Length> c(Length(-1.0 * meter),Length(1.0 * meter));
    PolarCoordinat<Angle,Length> d(c);
    d.Translate(Coordinat(Length(-2.0 * meter),Length(2.0 * meter)));
    assert(IsAboutEqual(c.GetAngle(),d.GetAngle(),Angle(1.0 * nano * radian)));
  }
  {
    const PolarCoordinat<Angle,Length> c(Length( 3.0 * meter),Length( 4.0 * meter));
    const PolarCoordinat<Angle,Length> d(Length(-3.0 * meter),Length(-4.0 * meter));
    PolarCoordinat<Angle,Length> e(d);
    e.Translate(Coordinat(Length(6.0 * meter),Length(8.0 * meter)));
    assert(IsAboutEqual(c.GetAngle(),e.GetAngle(),Angle(1.0 * nano * radian)));
    assert(IsAboutEqual(c.GetLength(),e.GetLength(),Length(1.0 * nano * meter)));
  }
}

template <class Angle, class Length>
void PolarCoordinat<Angle,Length>::Translate(const Coordinat& c)
{
  using boost::geometry::get;
  const Coordinat this_coordinat(ToCoordinat(*this));
  const Coordinat delta_coordinat(
    get<0>(this_coordinat) + get<0>(c),
    get<1>(this_coordinat) + get<1>(c)
  );
  const PolarCoordinat<Angle,Length> new_coordinat(
    get<0>(delta_coordinat),
    get<1>(delta_coordinat)
  );
  m_angle = new_coordinat.GetAngle();
  m_length = new_coordinat.GetLength();
}

} //~namespace ribi

#endif // POLARCOORDINAT_H

 

 

 

 

 

./CppPolarCoordinat/polarcoordinat.cpp

 

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "polarcoordinat.h"
#pragma GCC diagnostic pop

/*
template<>
double CalculateSqrt<double,double>(const double& x)
{
  static_assert(
    !std::is_same<
      double,boost
      ::units::quantity<boost::units::si::length>>(),"");
  return std::sqrt(x);
}

template<>
boost::units::quantity<boost::units::si::length>
  CalculateSqrt<
    boost::units::quantity<boost::units::si::length>,
    boost::units::quantity<boost::units::si::area>
  >(
  const boost::units::quantity<boost::units::si::area>& x)
{
  return std::sqrt(x.value()) * boost::units::si::meter;
}
*/

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml