/*
    Scan Tailor - Interactive post-processing tool for scanned pages.
    Copyright (C) 2015  Joseph Artsimovich <joseph.artsimovich@gmail.com>

    This program 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.

    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TO_LINE_PROJECTOR_H_
#define TO_LINE_PROJECTOR_H_

#include "math_config.h"
#include "VecNT.h"
#include <QPointF>
#include <QLineF>

/**
 * \brief Projects points onto a line (not a line segment).
 *
 * Projecting means finding the point on a line that is closest
 * to the given point.
 */
class MATH_EXPORT ToLineProjector
{
public:
	/**
	 * \brief Initializes line projector.
	 *
	 * If line endpoints match, all points will
	 * be projected to that point.
	 */
	ToLineProjector(QLineF const& line);

	/**
	 * \brief Finds the projection point.
	 */
	QPointF projectionPoint(QPointF const& pt) const;

	/**
	 * \brief Equivalent to projectionPoint(pt) - pt.
	 */
	QPointF projectionVector(QPointF const& pt) const;

	/**
	 * Solves the equation of:\n
	 * line.p1() + x * (line.p2() - line.p1()) = p\n
	 * for x, where p would be the projection point.
	 * This function is faster than projectionPoint().
	 */
	double projectionScalar(QPointF const& pt) const;

	/**
	 * Returns the distance from \p pt to the projection point.
	 */
	double projectionDist(QPointF const& pt) const;

	/**
	 * Returns the squared distance from \p pt to the projection point.
	 * This function is faster than projectionDist().
	 */
	double projectionSqDist(QPointF const& pt) const;

	/**
	 * \see projectionScalar(), projectionPoint()
	 */
	QPointF projectionScalarToProjectionPoint(double scalar) const;
private:
	QPointF m_origin;
	QPointF m_vec;
	Vec2d m_mat;
};

#endif
