// //+---------------------------------------------------------------------+ //+ Program ATRACTOR.CPP 16/05/94 + //+ By Rafael GOMEZ {gomez@gosc.enst-bretagne.fr} (France) + //+ + //+ PLOTS A ROTATING Lorenz ATRACTOR IN 3D. + //+ + //+ Based on the program LORENZ.CPP + //+ By Ramiro Perez {RPEREZ@UTPVM1.BITNET}, (Panama) + //+ and Fausto A. A. Barbuto {BJ06@C53000.PETROBRAS.ANRJ.BR}, (Brazil). + //+ C++ 3.1 programme's creator: Fausto A. A. Barbuto, April 14, 1994. + //+ After a TURBO BASIC program by Ramiro Perez. + //+ + //+ You can rotate it with the numeric keyboard (NumLock = ON) + //+ Keys: (NumLock = ON) + //+ 4 and 6 rotate the atractor around the Y axis (azimuth). + //+ 2 and 8 change the elevation of the looking point + //+ (Rotation around the screen's X axis) + //+ 5 returns the azimuth and elevation to 0.0 + //+ - and + decrease or increase the step angle of the rotations. + //+ / and * decrease or increase the number of iterations. + //+ A or a turns on/of the reference axis + //+ SPACE turns on/off the repetition of the last command + //+ (with this you can have continuous rotation) + //+ < and > decrease or increase the integration interval dt + //+ Q or q Quit + //+ + //+ VGA 16 colours, 640x480 points version. + //+---------------------------------------------------------------------+ // #include #include #include #include #include #define centx 320 #define centy 240 #define axesx 35 #define axesy 440 #define longaxe 30 #define pi 3.141592654 #define twopi 6.283185307 #define halfpi 1.570796327 int get_cmd (int *); double bound (double); void update_param (int, double *, int *, int *, int *); void axe_x (); void axe_y (); void axe_z (); void draw_axes (); void print_info (int, int, double); static double azim, elev, fxx, fxz, fyx, fyy, fyz; void main() { int c, b, a, l, n, kb, cl, step, iter, axis = 1, rep = 0; double dt, xa[2], ya[2], za[2], x, y, z, x1, y1, z1, xd, yd; int graphdriver = VGA, graphmode = VGAHI; initgraph (&graphdriver,&graphmode,""); settextstyle (SMALL_FONT, HORIZ_DIR, 4); azim = 0.0; elev = 0.0; step = 9; iter = 1000; dt = 0.03; a = 5; b = 15; c = 1; do { cleardevice (); // // Start-up values for xa, ya and za. // xa[0] = 3.051522; ya[0] = 1.592542; za[0] = 15.62388; xa[1] = 3.051522; ya[1] = 1.582542; za[1] = 15.62388; fxx = cos(azim); fxz = -sin(azim); fyx = sin(elev)*fxz; fyy = cos(elev); fyz = -sin(elev)*fxx; for (n=1; n<=iter; n++) { for (l=0;l<=1;l++) { x = xa[l]; y = ya[l]; z = za[l]; x1 = x - a*x*dt + a*y*dt; y1 = y + b*x*dt - y*dt - z*x*dt; z1 = z - c*z*dt + x*y*dt; xa[l] = x1; ya[l] = y1; za[l] = z1; z1 -= 16.0; xd = 19.3*(x1*fxx + z1*fxz) + centx; yd = -11.0*(x1*fyx + y1*fyy + z1*fyz) + centy; putpixel((int)xd, (int)yd, (l==0) ? LIGHTBLUE : LIGHTGREEN); } } if (axis) draw_axes (); if (!rep) print_info (step, iter, dt); kb = get_cmd (&rep); update_param (kb, &dt, &step, &iter, &axis); } while (kb!='q' && kb!='Q'); closegraph (); } int get_cmd (int *rep) { static int lkb; int kb; if (*rep) { if (kbhit ()) kb = getch (); if (kb==' ') *rep = 0; else kb = lkb; } else { for ( ; !kbhit (); ); kb = getch (); if (kb==' ') { *rep = 1; kb = lkb; } else lkb = kb; } return (kb); } void axe_x () { int br, xd, yd; br = azim>=0.0 && azim<=pi || elev==halfpi || elev==3*halfpi; if (elev>halfpi && elev<3*halfpi) br = !br; setcolor (br ? CYAN : BLUE); xd = longaxe*fxx + axesx; yd = -longaxe*fyx + axesy; line (axesx, axesy, xd, yd); outtextxy (xd, yd, "X"); return; } void axe_y () { int xd, yd; setcolor ((elev<=pi) ? YELLOW : GREEN); xd = axesx; yd = -longaxe*fyy + axesy; line (axesx, axesy, xd, yd); outtextxy (xd + 2, yd, "Y"); return; } void axe_z () { int br, xd, yd; br = azim>=(3*halfpi) || azim<=halfpi || elev==halfpi || elev==3*halfpi; if (elev>halfpi && elev<3*halfpi) br = !br; setcolor (br ? LIGHTRED : RED); xd = longaxe*fxz + axesx; yd = -longaxe*fyz + axesy; line (axesx, axesy, xd, yd); outtextxy (xd, yd, "Z"); return; } void draw_axes () { int dr = 1, ord; //These if's are for line-hiding in the reference axis. //If you want more speed you can delete them. if (elev>=pi && elev<=twopi) { axe_y (); dr = 0; } ord = azim>=3*halfpi && azim<=twopi; if (elev>halfpi) ord = !ord; if (ord) { axe_x (); axe_z (); } else { axe_z (); axe_x (); } if (dr) axe_y (); return; } void print_info (int step, int iter, double dt) { char mess[100]; setcolor (WHITE); outtextxy (216, 5, "L O R E N Z A T R A C T O R"); sprintf (mess, "Elev= %4.0f deg Azim= %4.0f deg Step= %i deg Iterations= %i dt= %4.3f", elev*180/pi, azim*180/pi, step, iter, dt); outtextxy (80, 460, mess); return; } double bound (double angle) { double angb; if (angle>=twopi) angb = angle - twopi; else if (angle<0.0) angb = angle + twopi; else angb = angle; return (angb); } void update_param (int kb, double *dt, int *step, int *iter, int *axis) { double delta; delta = (*step)*pi/180.0; switch (kb) { case('4'): azim += delta; break; case('6'): azim -= delta; break; case('2'): elev += delta; break; case('8'): elev -= delta; break; case('5'): azim = 0.0; elev = 0.0; break; case('*'): (*iter) += 500; break; case('/'): if (*iter>500) (*iter) -= 500; break; case('+'): if (*step<90.0) (*step)++; break; case('-'): if (*step>0.0) (*step)--; break; case('>'): if (*dt<0.05) (*dt) += 0.005; break; case('<'): if (*dt>0.0) (*dt) -= 0.005; break; case('a'): case('A'): *axis = !(*axis); break; default: break; } azim = bound (azim); elev = bound (elev); return; }