#include <cmath>
#include <QLineF>
#include "map.h"


#define SAMPLES 100
#define DELTA 1e-6

static void growLeft(const Coordinates &c, RectC &rect)
{
	if (c.lon() < rect.left())
		rect.setLeft(c.lon());
}

static void growRight(const Coordinates &c, RectC &rect)
{
	if (c.lon() > rect.right())
		rect.setRight(c.lon());
}

static void growTop(const Coordinates &c, RectC &rect)
{
	if (c.lat() > rect.top())
		rect.setTop(c.lat());
}

static void growBottom(const Coordinates &c, RectC &rect)
{
	if (c.lat() < rect.bottom())
		rect.setBottom(c.lat());
}

RectC Map::llBounds()
{
	QRectF b(bounds());
	double dx = b.width() / SAMPLES;
	double dy = b.height() / SAMPLES;

	Coordinates tl(xy2ll(b.topLeft()));
	Coordinates br(xy2ll(b.bottomRight()));
	RectC rect(tl, br);

	for (int i = 0; i <= SAMPLES; i++) {
		double x = b.left() + i * dx;
		growBottom(xy2ll(QPointF(x, b.bottom())), rect);
		growTop(xy2ll(QPointF(x, b.top())), rect);
	}

	for (int i = 0; i <= SAMPLES; i++) {
		double y = b.top() + i * dy;
		growLeft(xy2ll(QPointF(b.left(), y)), rect);
		growRight(xy2ll(QPointF(b.right(), y)), rect);
	}

	if (rect.right() <= -180.0 + DELTA)
		rect.setRight(180.0);
	if (rect.left() >= 180.0 - DELTA)
		rect.setLeft(-180.0);

	return rect;
}

qreal Map::resolution(const QRectF &rect)
{
	/* The haversine formula used in Coordinates::distanceTo() only gives
	   "half world" distances and shorter so we have to use only the center
	   "half rectangle" in case e.g. world map bounds are on the input */
	QRectF halfRect(QPointF(rect.left() + (rect.width() / 4.0),
	  rect.top() + (rect.height() / 4.0)),
	  QPointF(rect.right() - (rect.width() / 4.0),
	  rect.bottom() - (rect.height() / 4.0)));

	qreal cy = halfRect.center().y();
	QPointF cl(halfRect.left(), cy);
	QPointF cr(halfRect.right(), cy);

	qreal ds = xy2ll(cl).distanceTo(xy2ll(cr));
	qreal ps = QLineF(cl, cr).length();

	return ds/ps;
}
