//==============================================================================
/*! \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 computing projections on tangent planes in each of the vertices
 */

#ifndef _OM_PROJECTOR_H_
#define _OM_PROJECTOR_H_

#include <OpenMesh\Core\Utils\Property.hh>
#include <OMToolkit\OMTransformationSolver.h>
#include <MDSTk/Module/mdsModule.h>
#include <Eigen\LU>
#include <OMToolkit\OMTriIterator.h>
#include <set>
#include <OMToolkit\OMTriBSPTree.h>
#include <OMToolkit\OMTriBSPTreeAABB.h>

namespace OMToolkit
{	
	/**
	 * Helper struct for saving rectangle coordinates
	 * @tparam Point Type of point to work with
	 */
	template <class Point>
	struct Rect
	{
		/**
		 * Lower left nearest point
		 */
		Point minimum;

		/**
		 * Upper right farrest point
		 */
		Point maximum;
	};

	/**
	 * Class computing projections on tangent planes in each of the vertices
	 * @tparam Mesh Type of mesh to work with
	 * @tparam Matrix Type of vertex matrix on a mesh
	 */
	template <class Mesh, class Matrix>
	class OMProjector
	{
		protected:
			/**
			 * Matrix typename
			 */
			typedef typename Matrix MatrixT;

			/**
			 * Matrix scalar typename
			 */
			typedef typename MatrixT::Scalar ScalarT;

			/**
			 * Mesh typename
			 */
			typedef typename Mesh MeshT;

			/**
			 * Mesh point typename (coordinate)
			 */
			typedef typename MeshT::Point PointT;

			/**
			 * Mesh vertex handle typename
			 */
			typedef typename MeshT::VertexHandle VertexHandleT;

			/**
			 * Mesh face handle typename
			 */
			typedef typename MeshT::FaceHandle FaceHandleT;

			/**
			 * Mesh normal typename (vector)
			 */
			typedef typename MeshT::Normal VectorT;

		public:
			/**
			 * Curvature direction flag
			 */
			static const int XDIR_CURVATURE = 0;

			/**
			 * Do not check X direction flag
			 */
			static const int XDIR_DO_NOT_CHECK = 2;

			/**
			 * Compute Z direction as real Z direction
			 */
			static const int ZDIR_Z = 0;

			/**
			 * Compute Z direction as projected curvature
			 */
			static const int ZDIR_CURVATURE = 2;

			/**
			 * Compute Z direction as sine of normals angle
			 */
			static const int ZDIR_NORMAL = 4;
			/**
			 * Constructor - initializes vital variables
			 * @param mesh Pointer to a mesh to work with
			 * @param propertyHandle Handle to a vertex MatrixT property
			 */
			OMProjector(MeshT *mesh, OpenMesh::VPropHandleT<MatrixT> propertyHandle);

			/**
			 * Method computes tangent rasters on all the vertices
			 * @param length Length of a square raster (real length in mesh space)
			 * @param resolution Number of pixels on MatrixT edge
			 * @param zDir Use ZDIR consts for choose which component will be used as Z direction
			 * @param xdirection Direction of X axis on MatrixT (for ex. Maximum curvature direction)
			 * @param lengthRelative If true, length is computed as % of median edges lengths, if not, length is static
			 * @return True, if computation ended successfully, false otherwise
			 */
			bool ComputeMatrices(ScalarT length, ScalarT resolution, int zDir = ZDIR_Z, bool lengthRelative = false, int xdirection = XDIR_CURVATURE);

		public:
			ScalarT m_length;
			/**
			 * Function rasterizes neighbourhood of a vertex into a raster given by transformation solver
			 * Result is saved in MatrixT property of a vertex
			 * @param solver Transformation solver with saved transformation MatrixT
			 * @param vertex Vertex on which we compute a tangent raster
			 */
			void rasterizeVertex(OMTransformationSolver<PointT> &solver, VertexHandleT vertex);

			/**
			 * Function rasterizes one triangle given by face handle on a MatrixT with use of transformation MatrixT
			 * @param solver OMTransformationSolver with saved transformation MatrixT
			 * @param face Face handle of a triangle
			 * @param MatrixT MatrixT on which we will rasterize a face
			 */
			inline void rasterizeOnMatrixT(OMTransformationSolver<PointT> &solver, FaceHandleT face, MatrixT &MatrixT);

			/**
			 * Current MatrixT rectangle (size)
			 */
			Rect<PointT> m_MatrixTDelim;

			/**
			 * Mesh with we do computations
			 */
			MeshT *m_mesh;

			/**
			 * Square MatrixT dimension (resolution)
			 */
			ScalarT m_resolution;


			/**
			 * Compute z from curvature
			 */
			int m_zDir;
			
			/**
			 * MatrixT property handle
			 */
			OpenMesh::VPropHandleT<MatrixT> m_propertyHandle;

			/**
			 * BSP Tree for Ray casting
			 */
			OMTriBSPTree tree;
	};
#include <OMToolkit\OMProjector.hxx>
}

#endif