#ifndef _PROJECTIVE_H_
#define _PROJECTIVE_H_
/**
 *
 *  \file projective.h
 *  \brief This is a header file for projective.c
 *
 *
 *  \ingroup corefiles
 *  \date Apr 13, 2009
 *  \author Alexander Pimenov
 *
 */
#ifdef __cplusplus
	extern "C" {
#endif

#include "matrix.h"
#include "geometry.h"


/**
 * \brief A projective transformation matrix
 *
 * \code
 * [ data[0]  data[1]  data[2] ]
 * [ data[3]  data[4]  data[5] ]
 * [ data[6]  data[7]  data[8] ]
 * \endcode
 *
 */
typedef struct projectiveTransform2D_TAG {
	double data[9]; /**< \brief matrix elements */
} projectiveTransform2D;

typedef struct affineTransform3D_tag {
	double data[16];
} affineTransform3D;


projectiveTransform2D getRotation2D(double alpha);
projectiveTransform2D getShift2D(double dx, double dy);
projectiveTransform2D getScale2D(double sx, double sy);
projectiveTransform2D getProjective2DRaw(
		double a11, double a12, double a13,
		double a21, double a22, double a23,
		double a31, double a32, double a33
		);
projectiveTransform2D getProjective2D(double px, double py);

affineTransform3D getRotation3DZ(double alpha);
affineTransform3D getRotation3DY(double alpha);
affineTransform3D getRotation3DX(double alpha);
void applyTransform3D (affineTransform3D *transform, double x, double y, double z, double *rx, double *ry, double *rz);


affineTransform3D getShift3D(double dx, double dy, double dz);
affineTransform3D getScale3D(double sx, double sy, double sz);

affineTransform3D affine3Dtranspose(affineTransform3D t);

projectiveTransform2D multiplyBy2D(projectiveTransform2D a, projectiveTransform2D b);
affineTransform3D multiplyBy3D(affineTransform3D a, affineTransform3D b);

void projective2Dprint(projectiveTransform2D *t);


double projective2Ddeterminant (projectiveTransform2D *t);
projectiveTransform2D projective2Dtranspose(projectiveTransform2D t);
projectiveTransform2D projective2Dinverse(projectiveTransform2D *t);

projectiveTransform2D projective2DCreateFromMatrix(Matrix *M);

projectiveTransform2D projective2DCreateFromRaw (double *data);


vector2Dd projective2DapplyToCartesian(projectiveTransform2D *t, vector2Dd input);
vector3Dd projective2Dapply(projectiveTransform2D *t, vector3Dd *input);




#ifdef __cplusplus
	} // 	extern "C"
#endif
#endif /* _PROJECTIVE_H_ */
