This section gives a new version of the above module — one that includes a user interface panel for controlling the velocity of the oscillation. We use the FORMS library by Mark Overmars for the control panel. The FORMS library is a public domain user interface toolkit for IRISes; for more information See Forms.
To try out this example, make a copy of the file example2.c (distributed with Geomview in the doc subdirectory) in your directory and compile it with the command
cc -I/u/gcg/ngrap/include -o example2 example2.c \ -L/u/gcg/ngrap/lib/sgi -lforms -lfm_s -lgl_s -lm
You should
replace the string /u/gcg/ngrap above with the pathname of the
Geomview distribution directory on your system. (The forms library is
distributed with Geomview and the -I
and -L
options above
tell the compiler where to find it.)
Then put the line
(emodule-define "Example 2" "./example2")
in a file called .geomview in the current directory and invoke Geomview from that directory. Click on the "Example 2" entry in the Modules browser to invoke the module. A small control panel should appear. You can then control the velocity of the mesh oscillation by moving the slider.
/* * example2.c: oscillating mesh with FORMS control panel * * This example module is distributed with the Geomview manual. * If you are not reading this in the manual, see the "External * Modules" chapter of the manual for an explanation. * * This module creates an oscillating mesh and has a FORMS control * panel that lets you change the speed of the oscillation with a * slider. */ #include <math.h> #include <stdio.h> #include <sys/time.h> /* for struct timeval below */ #include "forms.h" /* for FORMS library */ FL_FORM *OurForm; FL_OBJECT *VelocitySlider; float dt; /* F is the function that we plot */ float F(x,y,t) float x,y,t; { float r = sqrt(x*x+y*y); return(sin(r + t)*sqrt(r)); } /* SetVelocity is the slider callback procedure; FORMS calls this * when the user moves the slider bar. */ void SetVelocity(FL_OBJECT *obj, long val) { dt = fl_get_slider_value(VelocitySlider); } /* Quit is the "Quit" button callback procedure; FORMS calls this * when the user clicks the "Quit" button. */ void Quit(FL_OBJECT *obj, long val) { exit(0); } /* create_form_OurForm() creates the FORMS panel by calling a bunch of * procedures in the FORMS library. This code was generated * automatically by the FORMS designer program; normally this code * would be in a separate file which you would not edit by hand. For * simplicity of this example, however, we include this code here. */ create_form_OurForm() { FL_OBJECT *obj; FL_FORM *form; OurForm = form = fl_bgn_form(FL_NO_BOX,380.0,120.0); obj = fl_add_box(FL_UP_BOX,0.0,0.0,380.0,120.0,""); VelocitySlider = obj = fl_add_valslider(FL_HOR_SLIDER,20.0,30.0, 340.0,40.0,"Velocity"); fl_set_object_lsize(obj,FL_LARGE_FONT); fl_set_object_align(obj,FL_ALIGN_TOP); fl_set_call_back(obj,SetVelocity,0); obj = fl_add_button(FL_NORMAL_BUTTON,290.0,75.0,70.0,35.0,"Quit"); fl_set_object_lsize(obj,FL_LARGE_FONT); fl_set_call_back(obj,Quit,0); fl_end_form(); } main(argc, argv) char **argv; { int xdim, ydim; float xmin, xmax, ymin, ymax, dx, dy, t; int fdmask; static struct timeval timeout = {0, 200000}; xmin = ymin = -5; /* Set x and y */ xmax = ymax = 5; /* plot ranges */ xdim = ydim = 24; /* Set x and y resolution */ dt = 0.1; /* Time increment is 0.1 */ /* Forms panel setup. */ foreground(); create_form_OurForm(); fl_set_slider_bounds(VelocitySlider, 0.0, 1.0); fl_set_slider_value(VelocitySlider, dt); fl_show_form(OurForm, FL_PLACE_SIZE, TRUE, "Example 2"); /* Geomview setup. */ printf("(geometry example { : foo })\n"); fflush(stdout); /* Loop until killed. */ for (t=0; ; t+=dt) { fdmask = (1 << fileno(stdin)) | (1 << qgetfd()); select(qgetfd()+1, &fdmask, NULL, NULL, &timeout); fl_check_forms(); UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t); } } /* UpdateMesh sends one mesh iteration to Geomview */ UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t) float xmin, xmax, ymin, ymax, t; int xdim, ydim; { int i,j; float x,y, dx,dy; dx = (xmax-xmin)/(xdim-1); dy = (ymax-ymin)/(ydim-1); printf("(read geometry { define foo \n"); printf("MESH\n"); printf("%1d %1d\n", xdim, ydim); for (j=0, y = ymin; j<ydim; ++j, y += dy) { for (i=0, x = xmin; i<xdim; ++i, x += dx) { printf("%f %f %f\t", x, y, F(x,y,t)); } printf("\n"); } printf("})\n"); fflush(stdout); }
The code begins by including some header files needed for the event loop
and the FORMS library. It then declares global variables for holding a
pointer to the slider FORMS object and the velocity dt
. These
are global because they are needed in the slider callback procedure
SetVelocity
, which forms calls every time the user moves the
slider bar. SetVelocity
sets dt
to be the new value of the
slider.
Quit
is the callback procedure for the Quit button;
it provides a graceful way for the user to terminate the program.
The procedure create_panel
calls a bunch of FORMS library
procedures to set up the control panel with slider and button. For more
information on using FORMS to create interface panels see the FORMS
documentation. In particular, FORMS comes with a graphical panel
designer that lets you design your panels interactively and generates
code like that in create_panel
.
This example's main program is similar to the previous example, but includes extra code to deal with setting up and managing the FORMS panel.
To set up the panel we call the GL procedure foreground
to cause
the process to run in the foreground. By default GL programs run in the
background, and for various reasons external modules that use FORMS
(which is based on GL) need to run in the foreground. We then call
create_panel
to create the panel and fl_set_slider_value
to set the initial value of the slider. The call to fl_show_form
causes the panel to appear on the screen.
The first three lines of the main loop, starting with
fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
check for and deal with events in the panel. The call to select
imposes a delay on each pass through the main loop. This call returns
either after a delay of 1/5 second or when the next GL event occurs, or
when data appears on standard input, whichever comes first. The
timeout
variable specifies the amount of time to wait on this
call; the first member (0 in this example) gives the number of seconds,
and the second member (200000 in this example) gives the number of
microseconds. Finally, fl_check_forms()
checks for and processes
any FORMS events that have happened; in this case this means calling
SetVelocity
if the user has moved the slider or calling
Quit
if the user has clicked on the Quit button.
The purpose of the delay in the loop is to keep the program from using excessive amounts of CPU time running around its main loop when there are no events to be processed. This is not so crucial in this example, and in fact may actually slow down the animation somewhat, but in general with external modules that have event loops it is important to do something like this because otherwise the module will needlessly take CPU cycles away from other running programs (such as Geomview!) even when it isn't doing anything.
The last line of the main loop in this example, the call to
UpdateMesh
, is the same as in the previous example.