//==============================================================================
/*! \file
 * OpenMesh Toolkit for mesh analysis    \n
 * Copyright (c) 2010 by Rostislav Hulik     \n
 *
 * Author:  Rostislav Hulik, rosta.hulik@gmail.com  \n
 * Date:    2010/11/21                          \n
 *
 * This file is part of software developed for support of Rostislav Hulik's dissertation thesis at dcgm-robotics@FIT group.
 *
 * This file 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 3 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 file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Description:
 * - Class computig transformation between mesh and raster which is positioned on a vertex and is tangent to surface
 */

#ifndef _OM_TRANSFORMATION_SOLVER_H_
#define _OM_TRANSFORMATION_SOLVER_H_

#include <Eigen/Geometry>

namespace OMToolkit
{
	using namespace Eigen;
	using namespace OpenMesh;

	/**
	 * Class computig transformation between mesh and raster which is positioned on a vertex and is tangent to surface
	 * @tparam vectorT Type of vectors used in this class
	 */
	template <class Vector>
	class OMTransformationSolver
	{
		protected:
			/**
			 * Vector type
			 */
			typedef typename Vector VectorT;

			/**
			 * Scalar component of a vector
			 */
			typedef typename Vector::value_type ScalarT;

			/**
			 * Vector type in eigen library
			 */
			typedef typename  Matrix<ScalarT, 3, 1, 2, 3, 1> VectorEigen;

		public:
			/**
			 * Constructor - computes desired transformation
			 * Produces transformation matrix, which projects mesh coordinates intu tangent raster coordinates
			 * Center vertex will be projected to a center of a matrix
			 * @param matrixLength Raster length - square raster edge length (real in mesh space)
			 * @param resolution Number of raster pixels (matrix dimensions) - matrix is squared
			 * @param normal Normal on spacified vertex (futire Z direction)
			 * @param direction Direction of future X direction (for example maximum curvature direction)
			 * @param origin Coordinates of a vertex
			 */
			OMTransformationSolver(ScalarT matrixLength, ScalarT resolution, VectorT normal, VectorT direction, VectorT origin);

			/**
			 * Transforms a mesh point (OpenMesh VecXX) to a raster
			 * @param point Point to be transformed
			 * @return Transformed point
			 */
			inline VectorT transformTo2D(VectorT point);

			/**
			 * Transforms a raster point (OpenMesh VecXX) to a mesh space
			 * @param point Point to be transformed
			 * @return Transformed point
			 */
			inline VectorT transformToMesh(VectorT point);

			/**
			 * Transforms a mesh vector (OpenMesh VecXX) to a raster
			 * @param point Vector to be transformed
			 * @return Transformed vector
			 */
			inline VectorT transformTo2DLinear(VectorT vector);

			/**
			 * Transforms a raster vector (OpenMesh VecXX) to a mesh space
			 * @param point Vector to be transformed
			 * @return Transformed vector
			 */
			inline VectorT transformToMeshLinear(VectorT vector);

			/**
			 * Function returns maximum coordinate of a associed matrix
			 * @returns Desired dimensions
			 */
			inline VectorT getMaxBounds();
			
			/**
			 * Function returns pixel width (in a mesh space)
			 */
			inline ScalarT getPixelSize();
			
			/**
			 * Function returns a signed angle (0..Pi) with use of a reference vector
			 * @param vec1 First vector
			 * @param vec2 Second vector
			 * @reference Reference vector (i.e. normal vector etc..)
			 * @return Signed angle of two vectors in interval 0..Pi
			 */
			static inline ScalarT vectorSignedAngle(VectorT& vec1, VectorT& vec2, VectorT reference);

			/**
			 * Function returns an unsigned angle (0..Pi)
			 * @param vec1 First vector
			 * @param vec2 Second vector
			 * @return Unsigned angle of two vectors in interval 0..Pi
			 */
			static inline ScalarT vectorAngle(VectorT& vec1, VectorT& vec2);

		protected:
			
			/**
			 * Transformation matrix from raster coordinates into mesh coordinates
			 */
			Transform<ScalarT, 3> m_2DToModel;

			/**
			 * Transformation matrix from mesh coordinates into raster coordinates
			 */
			Transform<ScalarT, 3> m_modelTo2D;

			/**
			 * Raster edge length in mesh space
			 */
			ScalarT m_matrixLength;

			/**
			 * Raster resolution - number of pixels on an edge
			 */
			ScalarT m_resolution;

			/**
			 * Pixel width in a mesh space
			 */
			ScalarT m_pixelSize;
	};

	#include <OMToolkit\OMTransformationSolver.hxx>
}

#endif