/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2002-04-15
**  Copyright: 2002-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef RECT_H
#define RECT_H

#include <QGpCoreTools.h>

#include "QGpCoreMathDLLExport.h"
#include "Point.h"
#include "Point2D.h"
#include "Curve.h"

namespace QGpCoreMath {

class QGPCOREMATH_EXPORT Rect: public XMLClass
{
public:
  enum Area {AllRect,
             AboveAscDiag,
             BelowAscDiag,
             AboveDescDiag,
             BelowDescDiag};
  inline Rect();
  inline Rect(const Point2D& p1, const Point2D& p2);
  inline Rect(const Point& p1, const Point& p2);
  inline Rect(const QPoint& p1, const QPoint& p2);
  inline Rect(const QPointF& p1, const QPointF& p2);
  inline Rect(double nx1, double ny1, double nx2, double ny2);
  inline Rect(const QRect& o);
  inline Rect(const Rect& o);
  virtual ~Rect() {}

  virtual const QString& xml_tagName() const {return xmlRectTag;}
  static const QString xmlRectTag;

  void operator*=(double fac);
  void setLimits (double nx1, double ny1, double nx2, double ny2);
  bool includes (const Rect & r) const;
  bool includes (const Point & p) const;
  bool includes (const Point2D & p) const;
  bool includes (const Point2D & p, Area inArea) const;
  inline bool includes (const Point2D& p1, const Point2D& p2) const;
  bool includes (double x1, double y1, double x2, double y2) const;
  bool isNull() {return _x1==_x2 && _y1==_y2;}
  double x1() const {return _x1;}
  double y1() const {return _y1;}
  double x2() const {return _x2;}
  double y2() const {return _y2;}
  Point2D topLeft() const {return Point2D(_x1, _y1);}
  Point2D bottomRight() const {return Point2D(_x2, _y2);}
  double width() const {return _x2 -_x1;}
  double height() const {return _y2 -_y1;}
  double area() const {return width()*height();}
  void setX1(double nx1) {_x1=nx1;}
  void setY1(double ny1) {_y1=ny1;}
  void setX2(double nx2) {_x2=nx2;}
  void setY2(double ny2) {_y2=ny2;}
  void add(double x, double y);
  void add(const Point& p);
  void add(const Point2D& p);
  void add(const Rect& r);
  Rect intersect(const Rect& r) const;
  void intersect(Point2D &p1, Point2D &p2) const;
  void square();
  void enlarge(double dx, double dy, SamplingOptions xScale, SamplingOptions yScale);
  void enlarge(double ratio, SamplingOptions xScale, SamplingOptions yScale);
  void printDebug() const;
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
protected:
  double _x1, _y1, _x2, _y2;
};


inline Rect::Rect()
{
  setLimits(0,0,0,0);
}

inline Rect::Rect(const Rect &o)
{
  setLimits(o._x1, o._y1, o._x2, o._y2);
}

inline Rect::Rect(const QRect &o)
{
  setLimits(o.left(), o.top(), o.right(), o.bottom());
}

inline Rect::Rect(double nx1, double ny1, double nx2, double ny2)
{
  setLimits(nx1,ny1,nx2,ny2);
}

inline Rect::Rect(const Point2D& p1, const Point2D& p2)
{
  setLimits(p1.x(), p1.y(), p2.x(), p2.y());
}

inline Rect::Rect(const Point& p1, const Point& p2)
{
  setLimits(p1.x(), p1.y(), p2.x(), p2.y());
}

inline Rect::Rect(const QPoint& p1, const QPoint& p2)
{
  setLimits(p1.x(), p1.y(), p2.x(), p2.y());
}

inline Rect::Rect(const QPointF& p1, const QPointF& p2)
{
  setLimits(p1.x(), p1.y(), p2.x(), p2.y());
}

inline bool Rect::includes (const Point2D& p1, const Point2D& p2) const
{
  return includes(p1.x(), p1.y(), p2.x(), p2.y());
}

} // namespace QGpCoreMath

#endif // RECT_H
