/***************************************************************************
**
**  This file is part of ArrayCore.
**
**  ArrayCore is free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  ArrayCore is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2019-04-12
**  Copyright: 2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#ifndef WAVENUMBER_H
#define WAVENUMBER_H

#include <QGpCoreMath.h>

#include "ArrayCoreDLLExport.h"

namespace ArrayCore {

  class ARRAYCORE_EXPORT Wavenumber
  {
  public:
    inline Wavenumber();
    inline Wavenumber(const Point2D& p);
    inline Wavenumber(double r, const Angle& theta);
    inline Wavenumber(const Wavenumber& o);
    ~Wavenumber() {}

    inline void operator+=(const Point2D& o);
    inline void rotate(double angle);

    const Point2D& pos() const {return _pos;}
    inline void setPos(const Point2D& p);

    double radius() const {return _radius;}
    double cos() const {return _cos;}
    double sin() const {return _sin;}

    inline double angularManhatanDistance(const Wavenumber& o) const;
  private:
    inline void updatePolar();

    Point2D _pos;
    double _cos, _sin;
    double _radius;
  };

  inline Wavenumber::Wavenumber()
  {
    _radius=0.0;
  }

  inline Wavenumber::Wavenumber(const Point2D& p)
  {
    setPos(p);
  }

  inline Wavenumber::Wavenumber(double r, const Angle& theta)
  {
    _radius=r;
    _cos=theta.cos();
    _sin=theta.sin();
    _pos.setX(_radius*_cos);
    _pos.setY(_radius*_sin);
  }

  inline Wavenumber::Wavenumber(const Wavenumber& o)
  {
    _pos=o._pos;
    _cos=o._cos;
    _sin=o._sin;
    _radius=o._radius;
  }

  inline void Wavenumber::updatePolar()
  {
    _radius=_pos.length();
    if(_radius>0.0) {
      double f=1.0/_radius;
      _cos=f*_pos.x();
      _sin=f*_pos.y();
    } else {
      _cos=1.0;
      _sin=0.0;
    }
  }

  inline void Wavenumber::setPos(const Point2D& p)
  {
    _pos=p;
    updatePolar();
  }

  inline void Wavenumber::operator+=(const Point2D& o)
  {
    _pos+=o;
    updatePolar();
  }

  inline void Wavenumber::rotate(double dk)
  {
    _pos+=Point2D(-dk*_sin, dk*_cos);
    updatePolar();
  }

  inline double Wavenumber::angularManhatanDistance(const Wavenumber& o) const
  {
    return fabs(_cos-o._cos)+fabs(_sin-o._sin);
  }

} // namespace ArrayCore

#endif // WAVENUMBER_H

