I've been working on this assignment for several days now and I am reaching my limits. What I have is a triangle (mesh) consisting of three vertices, A(50,50,0), B(100,100,0) and C(100,0,0). The lines connecting each point are drawn for me so I don't need to worry about that.

What I am tasked with is choosing one vertex and rotating the triangle about that vertex. I have Matrix4 Varaibles declared and one static Matrix4 varaible 'c' for when I click "draw" several times or just hold enter (this is a windows app btw) the triangle will rotate about its vertex.

What I can do, is rotate the entire triangle. What I need to do is rotate the triangle about its vertex. So lets see some code:

/* composition.cpp simple animation using a composition transformation matrix */ #include <stdio.h> #include <windows.h> #include "resource.h" // your path for this include may vary #include "GraphicsFramework.h" #include "gmath.h" const double DTOR2 = 0.01745329251994; // degrees to radians // Global variable to store the graphics framwork object GraphicsFramework* PGraphics; HWND HOutput = 0; // handle to the output control HWND HDialog = 0; // function to draw a line between two points void DrawLine(int x1, int y1, int x2, int y2, unsigned int color) { int dx, dy; // dy / dx is the slope int x, y; // loop and point variables // calculate changes in y and x between the points dy = y2 - y1; dx = x2 - x1; if (Abs(dy) > Abs(dx)) { // since there is a greater change in y than x we must // loop in y, calculate x and draw for (y=y1; y != y2; y += Sign(dy)) { x = x1 + (y - y1) * dx / dy; PGraphics->AddPoint(x, y, color); } } else { // since there is a greater (or equal) change in x than y we must // loop in x, calculate y and draw for (x=x1; x != x2; x += Sign(dx)) { y = y1 + (x - x1) * dy / dx; PGraphics->AddPoint(x, y, color); } } // draw the last pixel PGraphics->AddPoint(x2, y2, color); } void DrawStuff() { COLORREF green = RGB(0, 255, 0); // green color to draw with COLORREF red = RGB(0, 0, 255); // red color to draw with char str[32]; // string to store user input Vector3 pts[3]; // original data points Vector3 newPts[3]; // transformed points Vector3 translation; // 3D Coordinate varaible double angle; // rotation angle // this composite matrix need to remember its value between calls to this draw function // so it must be declared static or made a global variable static Matrix4 c; // composition matrix Matrix4 t, rz; // set up the original points for the triangle pts[0].set( 50, 50, 0); pts[1].set(100, 100, 0); pts[2].set(100, 0, 0); // clear the scene and add an axis PGraphics->ClearScene(RGB(0, 0, 0)); PGraphics->AddAxis(RGB(150, 150, 150), 10); // get the user input from the edit boxes and // convert string input to double GetDlgItemText(HDialog, IDC_EDIT_ANGLE, str, 32); angle = atof(str); // Translate the whole mesh so that the vertex, A(Ax, Ay, Az) is at the origin t.makeTranslationMatrix(-pts[0].x, -pts[0].y, -pts[0].z); rz.makeRotationMatrixZ(angle); // update the composite matrix //c = Multiply(Multiply(rz, t), c); c = Multiply(rz, c); // transform the original triangle points into the new points for drawing for (int i=0; i < 3; i++) { newPts[i] = Multiply(Multiply(c, pts[i]), t); // Get new set of coordinates } rz.makeRotationMatrixZ(angle); t.makeTranslationMatrix(newPts[0].x, newPts[0].y, newPts[0].z); // draw the triangle lines 0-1, 1-2, 2-0 DrawLine(newPts[0].x, newPts[0].y, newPts[1].x, newPts[1].y, green); DrawLine(newPts[1].x, newPts[1].y, newPts[2].x, newPts[2].y, green); DrawLine(newPts[2].x, newPts[2].y, newPts[0].x, newPts[0].y, green); // draw the points PGraphics->Draw(); } /* DialogProc this is the window event handler for the main dialog */ BOOL CALLBACK DialogProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: // dialog is initializing - store the picture box handle in a global variable for later HOutput = GetDlgItem(hwnd, IDC_PICTURE_OUTPUT); // instantiate and initialize our graphics framework object PGraphics = new GraphicsFramework(HOutput); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_BTN_DRAW: // draw button was pressed DrawStuff(); break; case IDC_BTN_CLEAR: // clear button was pressed so clear the scene and draw the empty scene PGraphics->ClearScene(RGB(0, 0, 0)); PGraphics->Draw(); break; case IDCANCEL: // user is quitting so release the GraphicsFramework object and quit delete PGraphics; PostQuitMessage(0); break; } } return FALSE; } // this is the main function that starts the application int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, char * cmdParam, int cmdShow) { // create the main window // store its handle in a global if needed HDialog = CreateDialog (GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc); // make the dialog visible ShowWindow(HDialog, SW_SHOW); // standard windows message loop MSG msg; int status; while ((status = GetMessage (&msg, 0, 0, 0)) != 0) { if (status == -1) return -1; // avoid processing messages for the dialog if (!IsDialogMessage (HDialog, & msg)) { TranslateMessage ( & msg ); DispatchMessage ( & msg ); } } return (int)(msg.wParam); }

gmath.h

// gmath.h #ifndef GMATH_H #define GMATH_H #include <math.h> const double PI = 3.14159265359; const double DTOR = 0.01745329251994; // degrees to radians const double RTOD = 57.29577951308; // radians to degrees // function to get the absolute value of an integer int Abs(int x) { if (x < 0) return -x; else return x; } // function to get the sign (+1 or -1) of an integer int Sign(int x) { if (x < 0) return -1; else return 1; } // a 3D vector with a homogeneous coordinate // if not used set w = 1 class Vector3 { public: double x, y, z, w; // default constructor Vector3() { x = y = z = 0.0; w = 1.0; } // set this vector to a new value void set(double x, double y, double z, double w = 1.0) { this->x = x; this->y = y; this->z = z; this->w = w; } // set this vector to a new value void set(Vector3 v) { this->x = v.x; this->y = v.y; this->z = v.z; this->w = v.w; } // scale this vector uniformly void scale(double f) { this->x *= f; this->y *= f; this->z *= f; } // return squared length of this vector double squaredLength() { return x * x + y * y + z * z; } // return length of this vector double length() { return sqrt(x * x + y * y + z * z); } // normalize this vector void normalize() { double len = length(); scale(1/len); } }; Vector3 Add(Vector3 a, Vector3 B)/> { // addition - returns result = a + b Vector3 result; result.x = a.x + b.x; result.y = a.y + b.y; result.z = a.z + b.z; return result; } Vector3 Subtract(Vector3 a, Vector3 B)/>{ // subtraction - returns result = a - b Vector3 result; result.x = a.x - b.x; result.y = a.y - b.y; result.z = a.z - b.z; return result; } Vector3 CrossProduct(Vector3 a, Vector3 B)/> { // cross product - returns result = a X b Vector3 result; result.x = a.y * b.z - a.z * b.y; result.y = a.z * b.x - a.x * b.z; result.z = a.x * b.y - a.y * b.x; return result; } // return dot product of a & b double DotProduct(Vector3 a, Vector3 B)/> { return a.x * b.x + a.y * b.y + a.z * b.z; } // a 4x4 matrix class class Matrix4 { public: double m[4][4]; Matrix4(){ // default constructor set m = I m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } Matrix4(double m00, double m01, double m02, double m03, double m10, double m11, double m12, double m13, double m20, double m21, double m22, double m23, double m30, double m31, double m32, double m33) { m[0][0] = m00; m[0][1] = m01; m02 = m02; m03 = m03; m[1][0] = m10; m[1][1] = m11; m12 = m12; m13 = m13; m[2][0] = m20; m[2][1] = m21; m22 = m22; m23 = m23; m[3][0] = m30; m[3][1] = m31; m32 = m32; m33 = m33; } void makeIdMatrix() { // makes an identity matrix m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } void makeTranslationMatrix(double dx, double dy, double dz) { // makes a translation matrix m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = dx; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = dy; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = dz; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } void makeScaleMatrix(double sx, double sy, double sz){ // makes a scale matrix m[0][0] = sx; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = sy; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = sz; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } // makes rotation matrix about X-axis based on a given angle in degrees void makeRotationMatrixX(double angle) { double angleInRads = angle * DTOR; makeRotationMatrixX(sin(angleInRads), cos(angleInRads)); } void makeRotationMatrixX(double sinA, double cosA){ // makes rotation matrix about X-axis m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = cosA; m[1][2] = -sinA; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = sinA; m[2][2] = cosA; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } // makes rotation matrix about Y-axis based on a given angle in degrees void makeRotationMatrixY(double angle) { double angleInRads = angle * DTOR; makeRotationMatrixY(sin(angleInRads), cos(angleInRads)); } void makeRotationMatrixY(double sinA, double cosA){ // makes rotation matrix about Y-axis m[0][0] = cosA; m[0][1] = 0.0; m[0][2] = sinA; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = -sinA; m[2][1] = 0.0; m[2][2] = cosA; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } // makes rotation matrix about Z-axis based on a given angle in degrees void makeRotationMatrixZ(double angle) { double angleInRads = angle * DTOR; makeRotationMatrixZ(sin(angleInRads), cos(angleInRads)); } void makeRotationMatrixZ(double sinA, double cosA){ // makes rotation matrix about Z-axis m[0][0] = cosA; m[0][1] = -sinA; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = sinA; m[1][1] = cosA; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } }; // multiplies matrix m by vector a Vector3 Multiply(Matrix4 m, Vector3 a) { // returns result = m * a Vector3 result; result.x = m.m[0][0] * a.x + m.m[0][1] * a.y + m.m[0][2] * a.z + m.m[0][3] * a.w; result.y = m.m[1][0] * a.x + m.m[1][1] * a.y + m.m[1][2] * a.z + m.m[1][3] * a.w; result.z = m.m[2][0] * a.x + m.m[2][1] * a.y + m.m[2][2] * a.z + m.m[2][3] * a.w; result.w = m.m[3][0] * a.x + m.m[3][1] * a.y + m.m[3][2] * a.z + m.m[3][3] * a.w; return result; } // multiplies vector a by matrix m Vector3 Multiply(Vector3 a, Matrix4 m) { // returns result = a * m Vector3 result; result.x = a.x * m.m[0][0] + a.y * m.m[1][0] + a.z * m.m[2][0] + a.w * m.m[3][0]; result.y = a.x * m.m[0][1] + a.y * m.m[1][1] + a.z * m.m[2][1] + a.w * m.m[3][1]; result.z = a.x * m.m[0][2] + a.y * m.m[1][2] + a.z * m.m[2][2] + a.w * m.m[3][2]; result.w = a.x * m.m[0][3] + a.y * m.m[1][3] + a.z * m.m[2][3] + a.w * m.m[3][3]; return result; } // multiply x X y using loops Matrix4 Multiply(Matrix4 x, Matrix4 y) { int i, j, k; Matrix4 result; for(i=0; i < 4; i++) { for(j=0; j < 4; j++) { result.m[i][j] = 0.0; for(k=0; k < 4; k++) { result.m[i][j] += x.m[i][k] * y.m[k][j]; } } } return result; } #endif

Their are only three steps when trying to acheive rotating a triangle about its vertex:

1) translate the chosen vertex to the origin

we just put in negative values for the chosen vertex:

t.translateMatrix(-pts[0].x, -pts[0].y, -pts[0].z);

that should translate a vertex to the origin.

2) rotate about the origin

should consist of the function call:

rz.makeRotationMatrixZ(angle);

3) translate the vertex back to where it was before the rotation

t.translateMatrix(newPts[0].x, newPts[0].y, newPts[0].z);

this statement is being called immeidately following the for loop in the composition.cpp source.

I don't know why its not working, I have seriously tried on this..Maybe someone could help?