// AffineTransforms_v2.cpp : main project file.
//This tests the Transform class

#include "stdafx.h"
#include <iostream>
#include "Transform.h"

using namespace std;
using namespace System;

int main(array<System::String ^> ^args)
{        
   //Allow the user to set-up a Transform object
   //Obtain matrix requirements from user (we will use rotations about the z-axis)
   Console::WriteLine("Enter a z-axis rotation from 0 to +360 degrees (CCW rotation): ");
   double rotAngle;
// Retrieve a double
cin >> rotAngle;
   while(rotAngle < 0 || rotAngle > 360)
   {
           Console::WriteLine("Enter a z-axis rotation from 0 to +360 degrees (CCW rotation): ");
           cin >> rotAngle;
   }
   //Set-up rotation matrix
   int rotSense = 1;
   if(rotAngle >= 0) { rotSense = 1; } //CCW rotation - angle positive
   //if(rotAngle < 0) { rotSense = -1; } //CW rotation - angle negative, *** check this before use!
   array<double,2> ^ transformMatrix = { { Math::Cos(Math::PI*(rotAngle/180)),
rotSense*-Math::Sin(Math::PI*(rotAngle/180)) },
           { rotSense*Math::Sin(Math::PI*(rotAngle/180)), Math::Cos(Math::PI*(rotAngle/180)) } };
   
   //Obtain linear translation requirements from user
   Console::WriteLine("Now enter the x-axis translation: ");
   double x_trans;
   cin >> x_trans;
   Console::WriteLine("Now enter the y-axis translation: ");
   double y_trans;
   cin >> y_trans;
   //Set-up translation array to hold translation terms
   array<double> ^ deltaTerms = { x_trans,y_trans };
   //Initialise transform object
   Transform ^ myTransform = gcnew Transform(transformMatrix, deltaTerms);
   Console::WriteLine();

   //Obtain x from user
   Console::WriteLine("Enter the x coordinate of the point to transform: ");
double xCoord;
// Retrieve a double
cin >> xCoord;

   //Obtain y from user
   Console::WriteLine("Enter the y coordinate of the point to transform: ");
double yCoord;
// Retrieve a double
cin >> yCoord;

   //Transform coordinates
   myTransform->TransformCoords(xCoord,yCoord);
   //Output new coordinates
   double transformed_x = myTransform->TransformedCoords[0];
   double transformed_y = myTransform->TransformedCoords[1]; //stored for later use
   Console::WriteLine();
   Console::WriteLine("The new x,y coordinates are: {0},{1} ",
           transformed_x, transformed_y);
   Console::WriteLine();

   //Perform inverse transform
   myTransform->InverseTransform(transformed_x,transformed_y);
   //Output new (original!) coordinates
   Console::WriteLine("The inverse transform on these new coordinates is: {0},{1}",
           myTransform->TransformedCoords[0], myTransform->TransformedCoords[1]);
   Console::WriteLine("Which should hopefully be the coordinates you entered initially!");
   Console::WriteLine("(Within rounding errors that is...)");
   Console::WriteLine();

   //Test composite-transform operator+ overload        
   Console::WriteLine("Now to test the composite-transform: ");
   Console::WriteLine("We shall compose a 90 degree CCW rotation and translation of y + 1 with ");
   Console::WriteLine("a 180 degree CCW rotation and translation of x + 1: ");
   Console::WriteLine("i.e. first we rotate CCW 180 degrees, add (1,0), then ");
   Console::WriteLine("rotate CCW 90 degrees add (0,1)");
   Console::WriteLine();
   //e.g. starting with (1,2) we should get (2,1)
   //***This composition operator requires further testing

   //Obtain x from user
   Console::WriteLine("Enter the x coordinate of the point to transform: ");
double xCoord_2;
// Retrieve a double
cin >> xCoord_2;
   //Obtain y from user
   Console::WriteLine("Enter the y coordinate of the point to transform: ");
double yCoord_2;
// Retrieve a double
cin >> yCoord_2;

   //Initialise transform objects
   //First transform (lhs)
   rotSense = 1;
   rotAngle = 90;
   array<double,2> ^ transformMatrix_lhs = { { Math::Cos(Math::PI*(rotAngle/180)),
rotSense*-Math::Sin(Math::PI*(rotAngle/180)) },
           { rotSense*Math::Sin(Math::PI*(rotAngle/180)), Math::Cos(Math::PI*(rotAngle/180)) } };
   array<double> ^ delta_lhs = { 0,1 };
   //Second transform (rhs)
   rotSense = 1;
   rotAngle = 180;
   array<double,2> ^ transformMatrix_rhs = { { Math::Cos(Math::PI*(rotAngle/180)),
rotSense*-Math::Sin(Math::PI*(rotAngle/180)) },
           { rotSense*Math::Sin(Math::PI*(rotAngle/180)), Math::Cos(Math::PI*(rotAngle/180)) } };
   array<double> ^ delta_rhs = { 1,0 };        
   Transform ^ transform_lhs = gcnew Transform(transformMatrix_lhs, delta_lhs);
   Transform ^ transform_rhs = gcnew Transform(transformMatrix_rhs, delta_rhs);
   //Obtain composite transform
   Transform ^ transformComposite = transform_lhs + transform_rhs;
   //Transform coordinates
   transformComposite->TransformCoords(xCoord_2,yCoord_2);
   
   //Output new coordinates
   Console::WriteLine();
   Console::WriteLine("The composite transform on these new coordinates is: {0},{1}",
           transformComposite->TransformedCoords[0], transformComposite->TransformedCoords[1]);
   Console::WriteLine();

   Console::WriteLine("Press return to continue...");
   Console::Read();
return 0;
}
//Transform.h

#pragma once

// Affine takes a 2x2 matrix of transform coefficients and a doublet (dx,dy) to initialise the transform
// An initialised instance can then return the transform of a point array (x,y)
// Currently 2D Cartesian coords are used
ref class Transform
{
public:
   //Constructors
   Transform(void);
   Transform(array<double,2> ^ coefficients, array<double> ^ delta);
   //Copy constructor
   Transform(const Transform ^ &copier);
   //Instance methods
   array<double> ^ TransformCoords(double x, double y);
   array<double> ^ TransformCoords(array<double> ^ aPoint);
   array<double> ^ InverseTransform(double x, double y);
   array<double> ^ InverseTransform(array<double> ^ aPoint);
   //Properties and indexers (accessors/mutators)
   //Coefficients of transformation matrix, M, 2x2 matrix assumed real
   property double MyCoefficients[int,int]
{
   double get(int i, int j) { return myCoefficients[i,j]; }        
   void set(int i, int j, double value) { myCoefficients[i,j] = value; }
}
   property array<double,2> ^ MyCoefficientMatrix
{
   array<double,2> ^ get() { return myCoefficients; }
   void set(array<double,2> ^ matrix) { myCoefficients = matrix; }
}
   //Delta terms (dx,dy) assumed real
   property double MyDelta[int]
   {
           double get(int i) { return myDelta[i]; }
           void set(int i, double value) { myDelta[i] = value; }
   }
   property array<double> ^ MyDeltaMatrix
   {
           array<double> ^ get() { return myDelta; }
           void set(array<double> ^ matrix) { myDelta = matrix; }
   }
   //Transformed point coordinates
   property double TransformedCoords[int]
   {
           double get(int i) { return transformedCoords[i]; }
           //void set(int i, double value) { transformedCoords[i] = value; }
   }
   property array<double> ^ MyTransformedCoords
   {
           array<double> ^ get() { return transformedCoords; }
   }
   //Transform composition operator
   static Transform ^ operator+ (Transform ^ lhs, Transform ^ rhs);

private:
   //Coefficients of transformation matrix, M, 2x2 matrix assumed real
   array<double,2> ^ myCoefficients;
   //Delta terms (dx,dy) assumed real
   array<double> ^ myDelta;        
   //Transformed point coordinates
   array<double> ^ transformedCoords;

   //Coefficients of inverse transform matrix
   array<double,2> ^ myInverseCoefficients;
   //Inverse transform delta terms
   array<double> ^ myInverseDelta;

};
//Transform.cpp

#include "StdAfx.h"
#include "Transform.h"


Transform::Transform(void)
{
}

Transform::Transform(array<double,2> ^ coefficients, array<double> ^ delta)
   {
           //Creates a new affine transform with specified matrix and delta terms
                   
           myCoefficients = gcnew array<double,2>(2,2);
           myDelta = gcnew array<double>(2);
           transformedCoords = gcnew array<double>(2);

           myCoefficients = coefficients;
           myDelta = delta;

           //Set up inverse transform
           myInverseCoefficients = gcnew array<double,2>(2,2);
           myInverseDelta = gcnew array<double>(2);

           //Set up inverse transform matrix
           //(m00m11 - m01m10)
           double divisor = ( (myCoefficients[0,0]*myCoefficients[1,1]) - (myCoefficients[0,1]*myCoefficients[1,0]) );
           //m00’ = m11 / (m00m11 - m01m10)
           myInverseCoefficients[0,0] = myCoefficients[1,1] / divisor;
           //m01’ = - m01 / (m00m11 - m01m10)
           myInverseCoefficients[0,1] = -myCoefficients[0,1] / divisor;
           //m10’ = - m10 / (m00m11 - m01m10)
           myInverseCoefficients[1,0] = -myCoefficients[1,0] / divisor;
           //m11’ = m00 / (m00m11 - m01m10)
           myInverseCoefficients[1,1] = myCoefficients[0,0] / divisor;

           //Set up inverse delta matrix
           //dx’ = - dx * m00’ - dy * m01’
           myInverseDelta[0] = -(myDelta[0]*myInverseCoefficients[0,0]) - (myDelta[1]*myInverseCoefficients[0,1]);
           //dy’ = - dx * m10’ - dy * m11’
           myInverseDelta[1] = -(myDelta[0]*myInverseCoefficients[1,0]) - (myDelta[1]*myInverseCoefficients[1,1]);
   }

//Copy constructor
Transform::Transform(const Transform ^ &copier)
   {
           myCoefficients = copier->myCoefficients;
           myDelta = copier->myDelta;        
           transformedCoords = copier->transformedCoords;        
           myInverseCoefficients = copier->myInverseCoefficients;        
           myInverseDelta = copier->myInverseDelta;
   }

//May require an equals method

array<double> ^ Transform::TransformCoords(double x, double y)
   {
           //Implements the object's affine transform to a pair of coordinates
           transformedCoords[0] = myCoefficients[0,0]*x + myCoefficients[0,1]*y + myDelta[0];
           transformedCoords[1] = myCoefficients[1,0]*x + myCoefficients[1,1]*y + myDelta[1];
           return transformedCoords;
   }

array<double> ^ Transform::TransformCoords(array<double> ^ aPoint)
   {
           //Implements the object's affine transform to a pair of coordinates
           transformedCoords[0] = myCoefficients[0,0]*aPoint[0] + myCoefficients[0,1]*aPoint[1] + myDelta[0];
           transformedCoords[1] = myCoefficients[1,0]*aPoint[0] + myCoefficients[1,1]*aPoint[1] + myDelta[1];
           return transformedCoords;
   }

array<double> ^ Transform::InverseTransform(double x, double y)
   {
           //Implements the object's inverse affine transform to a pair of coordinates
           transformedCoords[0] = myInverseCoefficients[0,0]*x + myInverseCoefficients[0,1]*y + myInverseDelta[0];
           transformedCoords[1] = myInverseCoefficients[1,0]*x + myInverseCoefficients[1,1]*y + myInverseDelta[1];
           return transformedCoords;
   }

array<double> ^ Transform::InverseTransform(array<double> ^ aPoint)
   {
           //Implements the object's inverse affine transform to a pair of coordinates
           transformedCoords[0] = myInverseCoefficients[0,0]*aPoint[0] + myInverseCoefficients[0,1]*aPoint[1] +
myInverseDelta[0];
           transformedCoords[1] = myInverseCoefficients[1,0]*aPoint[0] + myInverseCoefficients[1,1]*aPoint[1] +
myInverseDelta[1];
           return transformedCoords;
   }

Transform ^ Transform::operator+ (Transform ^ lhs, Transform ^ rhs)
   {
           //Allows affine transforms to be concatenated or composed

           array<double,2> ^ coefficients = gcnew array<double,2>(2,2);
           array<double> ^ delta = gcnew array<double>(2);
           //Initialise matrix of coefficients
           //M’ = M1M2, here I have multiplied out the cefficients manually
           //But it might be better to use a tried and tested library class that multiplies matrices
           coefficients[0,0] = lhs->MyCoefficients[0,0]*rhs->MyCoefficients[0,0] + lhs->MyCoefficients[0,1]*rhs-
>MyCoefficients[1,0];
           coefficients[0,1] = lhs->MyCoefficients[0,0]*rhs->MyCoefficients[0,1] + lhs->MyCoefficients[0,1]*rhs-
>MyCoefficients[1,1];
           coefficients[1,0] = lhs->MyCoefficients[1,0]*rhs->MyCoefficients[0,0] + lhs->MyCoefficients[1,1]*rhs-
>MyCoefficients[1,0];
           coefficients[1,1] = lhs->MyCoefficients[1,0]*rhs->MyCoefficients[0,1] + lhs->MyCoefficients[1,1]*rhs-
>MyCoefficients[1,1];
           
           //Initialise delta (translation) terms
           //d’ = d1 + M1d2
           delta[0] = lhs->MyDelta[0] + lhs->MyCoefficients[0,0]*rhs->MyDelta[0] + lhs->MyCoefficients[0,1]*rhs-
>MyDelta[1];
           delta[1] = lhs->MyDelta[1] + lhs->MyCoefficients[1,0]*rhs->MyDelta[0] + lhs->MyCoefficients[1,1]*rhs-
>MyDelta[1];

           //Return new Transform object which represents the inverse transform
           Transform ^ compoundTransform = gcnew Transform(coefficients, delta);
           return compoundTransform;
   }
The following code includes a transform class and the main function that tests the transform class. The
transform class carries out affine transformations on a point. In particular it allows the user to enter a
rotation about the z-axis (projecting perpendicular to the screen) and a translation in the x and y directions
and execute this transform on a mathematical point (x,y). It then reverses the transform and tests the effect
of a composite transform on a point.

This code was written in C++/CLI using VS 2010 express (a bit painful as this version of VS has no
intellisense support for C++).
Affine Transforms