/*-----------------------------------------------------------------+ | 2DMAPS.C by Alex Matulich | | Iterating 2-D mapping functions using the mouse for initial x,y | | This program runs in 640x480 VGA mode ONLY! | +-----------------------------------------------------------------*/ /* This was written for the Lattice compiler. The only incompatibilities with other compilers should be the graphics functions. The following Lattice graphics functions are used: screen() switch to text or graphics modes get_gfx_status() used for determining horiz & vertical number of pixels scale_float_view() scale the screen to my own coordinates pset() plot a point of a certain color, in my coordinates line() draw a line (used here to draw boxes), in my coordinates cls() clear the screen (text or graphics) also, this code assumes printf() works in graphics mode as well as text. Under Lattice, compile like so: lc -ms -k0 -Os -Lgr 2dmaps mouse */ #include #include #include #include #include #include "mouse.h" /* these are needed to convert mouse coordinates to user coordinates */ double xres, yres, xmult, ymult, xoff, yoff, xmin, xmax, ymin, ymax; /* initial parameters for KAM torus and Henon attractor */ double kamangle = 1.3, henon_a = 1.4, henon_b = .3; void reset_graphparms(void); void mainmenu(void); void iterate(void (*)(double *, double *)); void prepare_iterate(void); void zoombox(int); void curs_pos(int, int); void gingerbreadman(double *, double *); void henonstrange(double *, double *); void KAMtorus(double *, double *); /*-----------------------------------------------------------------------*/ void main() { if (!resetmouse()) { /* check mouse driver */ printf("Mouse driver not installed."); exit(0); } setupmouse(); /* prepare the mouse pointer and travel limits */ if (!screen(4)) { printf("I can't get a graphics mode -- sorry!"); exit(0); } mainmenu(); screen(0); /* back to text mode */ resetmouse(); } /*-----------------------------------------------------------------------*/ void mainmenu() { short done=0; char buffer[BUFSIZ]; double ftmp; do { screen(0); /* back to text mode */ cls(); curs_pos(1,3); printf("MENU\n\n 1. Gingerbreadman\n 2. KAM torus\n 3. Henon's strange attractor\n"); printf("\n\nSelect 1,2,3 or ESC to exit.\n\n"); switch(getch()) { case '1': xmin=-6.; xmax=11.; ymin=-7.; ymax=12.; iterate(gingerbreadman); break; case '2': printf("Enter angle parameter for KAM torus (currently %g)\n", kamangle); gets(buffer); if ((ftmp = atof(buffer)) != 0.) kamangle = ftmp; xmin=ymin=-1.3; xmax=ymax=1.3; iterate(KAMtorus); break; case '3': printf("Enter parameter \"a\" for Henon attractor (currently %g)\n", henon_a); gets(buffer); if ((ftmp = atof(buffer)) != 0.) henon_a = ftmp; printf("Enter parameter \"b\" (currently %g)\n", henon_b); gets(buffer); if ((ftmp = atof(buffer)) != 0.) henon_b = ftmp; xmin=-1.5; xmax=1.5; ymin=-.7; ymax=.7; iterate(henonstrange); break; case 27: done=1; } } while(!done); } /*-----------------------------------------------------------------------*/ void iterate(void (*mapfunc)(double *, double *)) { short visible=0, xt,yt, oldxmouse, oldymouse, xmouse, ymouse, done = 0; double x=0., y=0.; prepare_iterate(); /* show some instructions and switch to graphics */ /* We must keep track of the mouse visibility because you can't plot on top of a visible mouse. Mouse is made visible if it moves, and it is made invisible after the button is clicked. */ mouse_status(&xmouse, &ymouse); /* get intitial position */ oldxmouse=xmouse; oldymouse=ymouse; while(!done) { /* loop until user presses ESC */ pset(x, y, 3); /* plot current position */ (*mapfunc)(&x, &y); /* map the current position to a new position */ if (kbhit()) /* see if user pressed ESC, Z, or O */ switch(getch()) { case 27: done=1; break; case 'z': /* user wants to zoom in */ case 'Z': if (!visible) { showmouse(); visible=1; } zoombox(1); oldxmouse = xmouse; oldymouse = ymouse; visible = 0; break; case 'o': /* user wants to zoom out */ case 'O': if (!visible) { showmouse(); visible=1; } zoombox(-1); oldxmouse = xmouse; oldymouse = ymouse; visible = 0; } /* check for mouse movement and button activity */ if (mouse_status(&xmouse, &ymouse) || xmouse != oldxmouse || ymouse != oldymouse) { if (!visible) { showmouse(); visible=1; } if (mouse_activity(LEFTBUTTON, &xmouse, &ymouse)) { x = (double)xmouse/xmult+xoff; /* convert mouse pixel position */ y = (double)ymouse/ymult+yoff; /* to a new x,y position */ if (visible) { hidemouse(); visible=0; } /* hide the mouse */ while(mouse_status(&xt, &yt)); /* wait for button release */ } oldxmouse=xmouse; /* update variables for movement detection */ oldymouse=ymouse; } } /* showmouse() and hidemouse() get stacked, so we must undo the stack */ if (visible) hidemouse(); } /*-----------------------------------------------------------------------*/ void prepare_iterate() /* display instructions and initialize stuff */ { cls(); curs_pos(1,5); printf("While iterating, at any time you may:\n\n"); printf("Click the mouse to set a new initial x,y\n"); printf("Type Z to zoom in, O to zoom out\n"); printf("ESC to return to the main menu\n\n\nPress any key to begin."); getch(); screen(4); /* switch to graphics mode */ reset_graphparms(); } /*-----------------------------------------------------------------------*/ void zoombox(int direction) /* zoom in or out */ { int oldxm, oldym, xm, ym, button; double xc, yc, oldminx, oldminy, oldmaxx, oldmaxy, minx, miny, maxx, maxy, scl; curs_pos(1,1); printf(direction>0 ? "Click where you want the center of the zoom box." : "Click where you want the center of the unzoom box."); while(!mouse_activity(LEFTBUTTON, &xm, &ym)); xc = xm; yc = ym; while(mouse_status(&oldxm, &oldym)); /* wait for button release */ curs_pos(1,1); printf("Now size the box and click the mouse when you are finished."); hidemouse(); oldxm = xm; oldym = ym; oldminx = (xc-fabs(xc-xm))/xmult+xoff; oldmaxx = (xc+fabs(xc-xm))/xmult+xoff; oldminy = (yc-fabs(yc-ym))/ymult+yoff; oldmaxy = (yc+fabs(yc-ym))/ymult+yoff; line(oldminx,oldminy,oldmaxx,oldmaxy, 7 | XOR_PEL, EMPTY_BOX); do { /* draw zoom box until user presses button */ button = mouse_status(&xm, &ym); if (xm != oldxm || ym != oldym) { line(oldminx, oldminy, oldmaxx, oldmaxy, 7 | XOR_PEL, EMPTY_BOX); minx = (xc-fabs(xc-xm))/xmult+xoff; maxx = (xc+fabs(xc-xm))/xmult+xoff; miny = (yc+fabs(yc-ym))/ymult+yoff; maxy = (yc-fabs(yc-ym))/ymult+yoff; line(minx, miny, maxx, maxy, 7 | XOR_PEL, EMPTY_BOX); oldxm = xm; oldym = ym; oldminx = minx; oldminy = miny; oldmaxx = maxx; oldmaxy = maxy; } } while(!button); if (direction > 0) { /* set new screen limits for zooming in */ xmin = minx; xmax = maxx; ymin = miny; ymax = maxy; } else { /* set new screen limits for zooming out */ scl = (xmax-xmin)/(maxx-minx); xmin -= scl*(minx-xmin); xmax += scl*(xmax-maxx); scl = (ymax-ymin)/(maxy-miny); ymin -= scl*(miny-ymin); ymax += scl*(ymax-maxy); } while (mouse_activity(LEFTBUTTON, &xm, &ym)); /* clear the mouse */ reset_graphparms(); /* re-scale the screen */ cls(); } /*-----------------------------------------------------------------------*/ void reset_graphparms() /* scale the screen to our own size */ { int xr, yr; get_gfx_status(GFX_N_PELS_WIDE, &xr); /* get x resolution */ get_gfx_status(GFX_N_PELS_HIGH, &yr); /* get y resolution */ xres = (double)xr; yres = (double)yr; scale_float_view(xmax-xmin, ymax-ymin, -xmin, -ymin, (xmax-xmin>0.)?1:-1, (ymax-ymin>0.)?-1:1); xmult = xres/(xmax-xmin); ymult = yres/(ymin-ymax); xoff = xmin; yoff = ymax; } /*-----------------------------------------------------------------------*/ void curs_pos(col, row) /* used to set the cursor position */ int col, row; /* this assumes 1,1 is the upper left corner */ { union REGS reg; reg.h.ah = 0x02; /* function 02 of interrupt 0x10 */ reg.h.dh = --row; /* ROM BIOS assumes 0,0 is the upper left corner */ reg.h.dl = --col; reg.h.bh = 0; /* page 0 */ int86(0x10, ®, ®); } /*-----------------------------------------------------------------------*/ /* mapping functions called by iterate() */ /*-----------------------------------------------------------------------*/ void gingerbreadman(double *x, double *y) { double oldx = *x; *x = 1. - *y + fabs(oldx); *y = oldx; } void KAMtorus(double *x, double *y) { double oldx = *x; *x = oldx * cos(kamangle) + (oldx*oldx - *y)*sin(kamangle); *y = oldx * sin(kamangle) - (oldx*oldx - *y)*cos(kamangle); } void henonstrange(double *x, double *y) { double oldx = *x; *x = 1. + *y - henon_a*oldx*oldx; *y = henon_b * oldx; }