This section gives a very simple external module which displays an oscillating mesh. To try out this example, make a copy of the file example1.c (it is distributed with Geomview in the doc subdirectory) in your directory and compile it with the command
cc -o example1 example1.c -lm
Then put the line
(emodule-define "Example 1" "./example1")
in a file called .geomview in your current directory. Then invoke Geomview; it is important that you compile the example program, create the .geomview file, and invoke Geomview all in the same directory. You should see "Example 1" in the Modules browser of Geomview's Main panel; click on this entry in the browser to start the module. A surface should appear in your camera window and should begin oscillating. You can stop the module by clicking on the red "[1] Example 1" line in the Modules browser.
/* * example1.c: oscillating mesh * * 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 more details. * * This module creates an oscillating mesh. */ #include <math.h> #include <stdio.h> /* 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)); } main(argc, argv) char **argv; { int xdim, ydim; float xmin, xmax, ymin, ymax, dx, dy, t, dt; 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 */ /* Geomview setup. We begin by sending the command * (geometry example { : foo}) * to Geomview. This tells Geomview to create a geom called * "example" which is an instance of the handle "foo". */ printf("(geometry example { : foo })\n"); fflush(stdout); /* Loop until killed. */ for (t=0; ; t+=dt) { UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t); } } /* UpdateMesh sends one mesh iteration to Geomview. This consists of * a command of the form * (read geometry { define foo * MESH * ... * }) * where ... is the actual data of the mesh. This command tells * Geomview to make the value of the handle "foo" be the specified * mesh. */ 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 module begins by defining a function F(x,y,t)
that
specifies a time-varying surface. The purpose of the module is to
animate this surface over time.
The main program begins by defining some variables that specify the parameters with which the function is to be plotted.
The next bit of code in the main program prints the following line to standard output
(geometry example { : foo })
This tells Geomview to create a geom called example
which is an
instance of the handle foo
. Handles are a part of the
OOGL file format which allow you to name a piece of geometry whose value
can be specified elsewhere (and in this case updated many times); for
more information on handles, See OOGL File Formats. In this case,
example
is the title by which the user will see the object in
Geomview's object browser, and foo
is the internal name of the
handle that the object is a reference to.
We then do fflush(stdout)
to ensure that Geomview
receives this command immediately. In general, since pipes may be
buffered, an external module should do this whenever it wants to be
sure Geomview has actually received everything it has printed out.
The last thing in the main program is an infinite loop that cycles
through calls to the procedure UpdateMesh
with increasing
values of t
. UpdateMesh
sends Geomview a command
of the form
(read geometry { define foo MESH 24 24 ... })
where ...
is a long list of numbers. This command tells Geomview
to make the value of the handle foo
be the specified mesh. As
soon as Geomview receives this command, the geom being displayed
changes to reflect the new geometry.
The mesh is given in the format of an OOGL MESH. This begins with
the keyword MESH
. Next come two numbers that give the x and y
dimensions of the mesh; in this case they are both 24. This line is
followed by 24 lines, each containing 24 triples of numbers. Each of
these triples is a point on the surface. Then finally there is a line
with "})
" on it that ends the "{
" which began the
define
statement and the "(
" that began the command. For
more details on the format of MESH data, see MESH.
This module could be written without the use of handles by having it write out commands of the form
(geometry example { MESH 24 24 ... })
This first time Geomview receives a command of this form it would create
a geom called example
with the given MESH
data.
Subsequent (geometry example ...)
commands would cause
Geomview to replace the geometry of the geom example
with the new
MESH
data. If done in this way there would be no need to send
the initial (geometry example { : foo })
command as above. The
handle technique is useful, however, because it can be used in more
general situations where a handle represents only part of a complex
geom, allowing an external module to replace only that part without
having to retransmit the entire geom. For more information on handles,
see GCL. See References. See (hdefine ...)
. See (read ...)
.
The module loops through calls to UpdateMesh
which print out
commands of the above form one after the other as fast as possible.
The loop continues indefinitely; the module will terminate when the
user kills it by clicking on its instance line in the Modules
browser, or else when Geomview exits.
Sometimes when you terminate this module by clicking on its instance entry the Modules browser, Geomview will kill it while it is in the middle of sending a command to Geomview. Geomview will then receive only a piece of a command and will print out a cryptic but harmless error message about this. When a module has a user interface panel it can use a "Quit" button to provide a more graceful way for the user to terminate the module. See the next example.
You can run this module in a shell window without Geomview to see the commands it prints out. You will have to kill it with ctrl-C to get it to stop.