/* this version introduces a new transformation matrix called ident, its transformation has no effect, points are left exactly as they are. it also performs two matrix multiplications rotz by roty and then the result by shrink, producing a single matrix that performs a small rotation around the z axis and a small rotation around the y axis and a small amount of shrinkage into one efficient operation. this call at the end of main animate(ident, rzysh, path, sizeof(path) / sizeof(path[0]), 360); takes two transformation matrices and a shape (path, a cube as before but you can change that). The third parameter is simply the number of points in the shape, and the fourth is again the number of animated steps to perform before stopping. It applies the first transformation (ident) once to the shape before starting, then animates by repeatedly applying the second transformation (rzysh) to the result. */ #include "library.h" const int winsize = 500; const int halfwinsize = winsize / 2; double matvecmul(const double m[4][4], const double v[4], const int i, const int p) { if (p == 4) return 0.0; return m[i][p] * v[p] + matvecmul(m, v, i, p + 1); } double matvecmul(const double m[4][4], const double v[4], const int i) { return matvecmul(m, v, i, 0); } double matmatmul(const double m1[4][4], const double m2[4][4], const int i, const int j, const int p) { if (p == 4) return 0.0; return m1[i][p] * m2[p][j] + matmatmul(m1, m2, i, j, p + 1); } double matmatmul(const double m1[4][4], const double m2[4][4], const int i, const int j) { return matmatmul(m1, m2, i, j, 0); } const double pi = acos(-1.0); double degrees(const double x) { return x * pi / 180.0; } void move_to(const double p[4]) { move_to(halfwinsize + p[0], halfwinsize - p[1]); } void draw_to(const double p[4]) { draw_to(halfwinsize + p[0], halfwinsize - p[1]); } void draw(const double m[4][4], const double p[][4], const int i, const int len) { if (i == len) return; const double newvec[4] = { matvecmul(m, p[i], 0), matvecmul(m, p[i], 1), matvecmul(m, p[i], 2), matvecmul(m, p[i], 3) }; if (i == 0) move_to(newvec); else draw_to(newvec); draw(m, p, i + 1, len); } void animate(const double m[4][4], const double mstep[4][4], const double p[][4], const int len, const int nsteps) { if (nsteps == 0) return; const int c = get_pen_color(); draw(m, p, 0, len); wait(0.01); set_pen_color(color::white); draw(m, p, 0, len); set_pen_color(c); const double newm[4][4] = { { matmatmul(m, mstep, 0, 0), matmatmul(m, mstep, 0, 1), matmatmul(m, mstep, 0, 2), matmatmul(m, mstep, 0, 3) }, { matmatmul(m, mstep, 1, 0), matmatmul(m, mstep, 1, 1), matmatmul(m, mstep, 1, 2), matmatmul(m, mstep, 1, 3) }, { matmatmul(m, mstep, 2, 0), matmatmul(m, mstep, 2, 1), matmatmul(m, mstep, 2, 2), matmatmul(m, mstep, 2, 3) }, { matmatmul(m, mstep, 3, 0), matmatmul(m, mstep, 3, 1), matmatmul(m, mstep, 3, 2), matmatmul(m, mstep, 3, 3) } }; animate(newm, mstep, p, len, nsteps - 1); } void main() { make_window(winsize, winsize); set_pen_width(3); const double rotz[4][4] = { { cos(degrees(1)), sin(degrees(1)), 0, 0 }, { -sin(degrees(1)), cos(degrees(1)), 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; const double roty[4][4] = { { cos(degrees(1)), 0, sin(degrees(1)), 0 }, { 0, 1, 0, 0 }, { -sin(degrees(1)), 0, cos(degrees(1)), 0 }, { 0, 0, 0, 1 } }; const double rotx[4][4] = { { 1, 0, 0, 0 }, { 0, cos(degrees(1)), sin(degrees(1)), 0 }, { 0, -sin(degrees(1)), cos(degrees(1)), 0 }, { 0, 0, 0, 1 } }; const double grow[4][4] = { { 1.01, 0, 0, 0 }, { 0, 1.01, 0, 0 }, { 0, 0, 1.01, 0 }, { 0, 0, 0, 1 } }; const double shrink[4][4] = { { 0.98, 0, 0, 0 }, { 0, 0.98, 0, 0 }, { 0, 0, 0.98, 0 }, { 0, 0, 0, 1 } }; const double movx[4][4] = { { 1, 0, 0, 0.5 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; const double movxy[4][4] = { { 1, 0, 0, 2 }, { 0, 1, 0, -2 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; const double rotzy[4][4] = { { matmatmul(rotz, roty, 0, 0), matmatmul(rotz, roty, 0, 1), matmatmul(rotz, roty, 0, 2), matmatmul(rotz, roty, 0, 3) }, { matmatmul(rotz, roty, 1, 0), matmatmul(rotz, roty, 1, 1), matmatmul(rotz, roty, 1, 2), matmatmul(rotz, roty, 1, 3) }, { matmatmul(rotz, roty, 2, 0), matmatmul(rotz, roty, 2, 1), matmatmul(rotz, roty, 2, 2), matmatmul(rotz, roty, 2, 3) }, { matmatmul(rotz, roty, 3, 0), matmatmul(rotz, roty, 3, 1), matmatmul(rotz, roty, 3, 2), matmatmul(rotz, roty, 3, 3) } }; const double rzysh[4][4] = { { matmatmul(rotzy, shrink, 0, 0), matmatmul(rotzy, shrink, 0, 1), matmatmul(rotzy, shrink, 0, 2), matmatmul(rotzy, shrink, 0, 3) }, { matmatmul(rotzy, shrink, 1, 0), matmatmul(rotzy, shrink, 1, 1), matmatmul(rotzy, shrink, 1, 2), matmatmul(rotzy, shrink, 1, 3) }, { matmatmul(rotzy, shrink, 2, 0), matmatmul(rotzy, shrink, 2, 1), matmatmul(rotzy, shrink, 2, 2), matmatmul(rotzy, shrink, 2, 3) }, { matmatmul(rotzy, shrink, 3, 0), matmatmul(rotzy, shrink, 3, 1), matmatmul(rotzy, shrink, 3, 2), matmatmul(rotzy, shrink, 3, 3) } }; const double ident[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; const double path[][4] = { { -100, -100, -100, 1 }, { -100, 100, -100, 1 }, { 100, 100, -100, 1 }, { 100, -100, -100, 1 }, { -100, -100, -100, 1 }, { -100, -100, 100, 1 }, { 100, -100, 100, 1 }, { 100, -100, -100, 1 }, { 100, -100, 100, 1 }, { 100, 100, 100, 1 }, { 100, 100, -100, 1 }, { -100, 100, -100, 1 }, { -100, 100, 100, 1 }, { -100, -100, 100, 1 }, { -100, 100, 100, 1 }, { 100, 100, 100, 1 } }; const double line[4] = { 0, 150, 150, 1 }; set_pen_color(color::red); animate(ident, rzysh, path, sizeof(path) / sizeof(path[0]), 360); }