/* this version differs only in that it multiplies four matrices (movxy, rotz, roty, shrink) into a single operation that moves points a little bit diagonally between the x and y axes, rotates a little around the z axis, rotates a little around the y axis, and shrinks it in one operation. Of course it doesn't shrink a point, it shrinks its distance from (x, y, z). It may appear that the movxy is not working, but that is because of the rotation. the movement in the x y direction happens, but the whole result is rotated around y which cancels some of the linear movement by swinging it back round the y axis. If we had a three dimensional monitor it would look right */ #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 mrotz[4][4] = { { matmatmul(movxy, rotz, 0, 0), matmatmul(movxy, rotz, 0, 1), matmatmul(movxy, rotz, 0, 2), matmatmul(movxy, rotz, 0, 3) }, { matmatmul(movxy, rotz, 1, 0), matmatmul(movxy, rotz, 1, 1), matmatmul(movxy, rotz, 1, 2), matmatmul(movxy, rotz, 1, 3) }, { matmatmul(movxy, rotz, 2, 0), matmatmul(movxy, rotz, 2, 1), matmatmul(movxy, rotz, 2, 2), matmatmul(movxy, rotz, 2, 3) }, { matmatmul(movxy, rotz, 3, 0), matmatmul(movxy, rotz, 3, 1), matmatmul(movxy, rotz, 3, 2), matmatmul(movxy, rotz, 3, 3) } }; const double mrtzy[4][4] = { { matmatmul(mrotz, roty, 0, 0), matmatmul(mrotz, roty, 0, 1), matmatmul(mrotz, roty, 0, 2), matmatmul(mrotz, roty, 0, 3) }, { matmatmul(mrotz, roty, 1, 0), matmatmul(mrotz, roty, 1, 1), matmatmul(mrotz, roty, 1, 2), matmatmul(mrotz, roty, 1, 3) }, { matmatmul(mrotz, roty, 2, 0), matmatmul(mrotz, roty, 2, 1), matmatmul(mrotz, roty, 2, 2), matmatmul(mrotz, roty, 2, 3) }, { matmatmul(mrotz, roty, 3, 0), matmatmul(mrotz, roty, 3, 1), matmatmul(mrotz, roty, 3, 2), matmatmul(mrotz, roty, 3, 3) } }; const double mrtsh[4][4] = { { matmatmul(mrtzy, shrink, 0, 0), matmatmul(mrtzy, shrink, 0, 1), matmatmul(mrtzy, shrink, 0, 2), matmatmul(mrtzy, shrink, 0, 3) }, { matmatmul(mrtzy, shrink, 1, 0), matmatmul(mrtzy, shrink, 1, 1), matmatmul(mrtzy, shrink, 1, 2), matmatmul(mrtzy, shrink, 1, 3) }, { matmatmul(mrtzy, shrink, 2, 0), matmatmul(mrtzy, shrink, 2, 1), matmatmul(mrtzy, shrink, 2, 2), matmatmul(mrtzy, shrink, 2, 3) }, { matmatmul(mrtzy, shrink, 3, 0), matmatmul(mrtzy, shrink, 3, 1), matmatmul(mrtzy, shrink, 3, 2), matmatmul(mrtzy, 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, mrtsh, path, sizeof(path) / sizeof(path[0]), 360); }