In this section most features of *surf* are explained.
Many of these features
can be invoked from the graphical user interface. All features can be
invoked through *surf*'s command language. Command language features
are only explained if not accessible through the GUI. For a complete
reference to the command language, have a look at the next section.

To draw a plane curve, enter the equation into *surf*'s text
window preceded by `curve=`

and followed by a semicolon.
Then press the button *draw curve*.
Some seconds later the curve will show up in the window titled
*color image*.
By default the curve is drawn inside the rectangle

-10.0 <= x,y <= 10.0and is clipped at a circle with radius 10.0. The x-axis is horizontal pointing to the right, the y-axis is vertical and points upwards. By default the image size is 200 x 200 pixels. The image size can be altered by setting

The view can be altered in the *position window*:
A different origin can be specified by setting
*origin x* and *origin x*.
A rotation with center at (0,0) can be specified by setting
*rotation about z-axis*. The curve may be scaled by setting
*scale factor x* and *scale factor y*.
The appearance of the curve can be altered in the *curve window*.

The clipping area can be specified in the *clip window*.
For a curve the only reasonable values are
*sphere* and *none*.

An arbitrary color can be given to the curve by setting
*curve red*,*curve green* and *curve blue*
to appropriate values in the *curve window*.
The curve width can be set by changing *curve width*.
A high value of *curve gamma* sharpens the curve, whereas a low
value blurs the curve.

To draw a surface, enter its equation into *surf*'s text window
preceded by `surface=`

and followed by a semicolon. Then press the button
*draw surface*.
Some more seconds later the surface will appear. By default, the surface
is calculated inside the cube

-10.0 <= x,y,z <= 10.0and clipped at a sphere of radius 10.0. The x-axis is horizontal pointing to the right, the y-axis is vertical and points upwards. The z-axis points to you. The spectator is located at (0,0,25) by default.

Changing the view can be done by altering the settings in the
*position window*. A different origin may be specified by setting
*origin x*, *origin y* and *origin z*.
To rotate the surface one can set *rotation about x-axis*,
*rotation about y-axis* and *rotation about z-axis*
to appropriate values.
Rotation is performed on the following order: y-axis, x-axis, z-axis.
To scale the surface set *scale factor x*, *scale factor y*
and *scale factor z* to desired
values. It is also possible to switch from central perspective to parallel
perspective.

Illumination and color can be altered in the *light window*.
The direction of the normal vector given by the gradient
of the surface equation defines one side of the surface which
is regarded as outside. You can specify a color for this
side by setting *surface red*, *surface green*
and *surface blue*. The other side of the surface
(inside) can be given a different color by specifying
*inside red*, *inside green* and *inside blue*.

Currently only the Phong illumination model is implemented. Therefore the intensity of the surface in one point consists of four components which are calculated separately:

- ambient light,
- diffuse light,
- reflected light and
- transmitted light.

These four light components are added with weights
*ambient*, *diffuse*, *reflected*
and *transmitted*.

The number of light sources is limited to nine. For every light source, the position, the color and the intensity can be specified.

The *clip window* allows to specify a different clipping area. Here the
center and radius of the clipping area may be specified. Additionally
a front and a back clipping plane may be specified.

To draw one or more hyperplane sections of an algebraic surface,
just specify the hyperplane by setting the global variable
`plane`

to its equation.
The section is drawn when the command `cut_with_plane`

is interpreted.
For example:

rot_x=0.3; // a nice rotation rot_y=0.2; surface=x^2*y^2+y^2*z^2+z^2*x^2-16*x*y*z; clear_screen; // draw the steiner roman surface draw_surface; curve_red=0; curve_green=255; curve_blue=0; curve_width=5; curve_gamma=1.2; plane=x+y+z; // draw a green hyperplane section cut_with_plane; plane=x+y+z+4.0; // draw another one cut_with_plane;

The color of the hyperplane section can be set by specifying

`curve_red`

, `curve_green`

and `curve_blue`

.
The width of the section is altered by setting `curve_width`

to any suitable value. A high value of `curve_gamma`

(eg. 10.0) makes the curve
look very pixelized, whereas a small value (eg. 1.0) makes the section
look blurred.

Multiple curves can be drawn in script files just by *NOT* clearing
the screen. This works fine for plane curves.
Just consider the following example:

do_background=yes; clear_screen; curve=y^2-x^2*(x-1); draw_curve; // draw a cubic do_background=no; curve=x; draw_curve; // draw y-axis curve=y; draw_curve; // draw y-axis

Not that every curve will be drawn just over all curves that have been draw so far.

Multiple surfaces can be drawn by specifying up to 9 surfaces
in the variables `surface`

, `surface2`

...
`surface9`

. Additionally it is possible to draw on every surface
any number of hyperplane sections.

rot_x=0.69; // a nice rotation rot_y=0.35; illumination=ambient_light + // specify illumination diffuse_light + // model reflected_light + transmitted_light; transparence=35; // set transparence for surface no 1 transparence2=35; // set transparence for surface no 2 surface=x^2+y^2+z^2-30; // first surface: a sphere surface2_red=255; // second surface: a red steiner surface surface2_green=0; surface2_blue=0; surface2=x^2*y^2+x^2*z^2+y^2*z^2-16*x*y*z; clear_screen; draw_surface; // draw the surface curve_width=5; curve_red=0; curve_green=255; curve_blue=0; plane=x+y+z-6.0; // draw a green hyperplane section surf_nr=1; // on the sphere cut_with_plane; curve_red=0; curve_green=255; curve_blue=255; plane=x+y+z+4.0; // draw a turquoise hyperplane section surf_nr=2; // on the steiner surface cut_with_plane;

Given a polynomial function `f(x,y)`

and a set of levels
`z1`

, ... ,`zn`

, **surf** can visualize the graph
`z=f(x,y)`

and all isoline for the levels
`z1`

, ... ,`zn`

as follows:

rot_x=-0.8; clear_screen; poly f=x^2+y^2; // graph of (x,y)->x^2+y^2 surface=z-f; draw_surface; // draw the graph curve_width=3; // width of isoline plane=z-1; cut_with_plane; // draw isoline f(x,y)=1 plane=z-2; cut_with_plane; // draw isoline f(x,y)=2 plane=z-3; cut_with_plane; // draw isoline f(x,y)=3 plane=z-4; cut_with_plane; // draw isoline f(x,y)=4 plane=z-5; cut_with_plane; // draw isoline f(x,y)=5 plane=z-6; cut_with_plane; // draw isoline f(x,y)=6 plane=z-7; cut_with_plane; // draw isoline f(x,y)=7 plane=z-8; cut_with_plane; // draw isoline f(x,y)=8 plane=z-9; cut_with_plane; // draw isoline f(x,y)=9

If however your function

`f`

is not polynomial, try to expand
calculate its Taylor series. Since the new root algorithms work fine
with polynomials of degree up to 30, you might approximate `f`

by its Taylor series. If your function is piecewise defined, better
use another program.

The *position* window provides an interface to adjust the
curve/surface position. You can set the 9 buttons into the
three modes *translate*, *rotate* and
*scale*.

If you try to draw a surface and give the equation to *surf*,
the resulting image normally does not look nice at all.
You have to find the right scaling, rotation and so on.
Often you want to see immediately what happens if you change
some value. But it simply takes *surf* too long
to calculate one image. Here comes the preview in.
Setting the preview buttons in the *main window* to
*3x3* has the effect that only every 9th pixel
is calculated, setting it to *9x9* only every
81st pixel is calculated. But one can still get an impression
of what the image looks like, AND computation is speeded up
by the factor 9 resp. 81.

Up to two preview buttons can be pressed at one time.
If for example *9x9* and *1x1* are pressed,
then the image will be calculated in three steps.
First, every 81st pixel, after that every 9th pixel
and finally every pixel will be calculated.

Especially in animations aliasing is very disturbing. Therefore if
in the *display window*,
*antialiasing level* is set to a value n > 1,
then in a second pass all
pixels differing by a value of at least *antialiasing threshold*
from one of their neighbours are refined. Exactly n^2+1 intensity
values are calculated. In most cases an antialiasing level of
4 will remove aliasing.

On a nifty machine *surf* is fast enough to provide a real time
animation of an algebraic curve of degree < 5. For example

// -------------------------- // animation of a cubic curve // -------------------------- clear_screen; double a=-10.0; loop: curve=y^2-(x^2-1)*(x-a); clear_pixmap; draw_curve; a=a+0.1; if( a <= 10.0 ) goto loop;

calculates some 200 curves. In a 200x200 window,

// -------------------------- // the 4-nodal cubic rotating // -------------------------- width=200; height=200; // set image size double sf=0.3; scale_x=sf; scale_y=sf; scale_z=sf; // set scaling double Pi=2*arccos(0); double w2=sqrt(2); // define some constants poly p=1-z-w2*x; poly q=1-z+w2*x; poly r=1+z+w2*y; poly s=1+z-w2*y; // define tetrahedral coordinates poly cubic=4*(p^3+q^3+r^3+s^3)-(p+q+r+s)^3; // the cubic int i=0; loop: surface=rotate(cubic,2*Pi/100*i,zAxis); // rotate the cubic clear_screen; draw_surface; // draw the cubic filename="cubic"+itostrn(3,i)+".ras"; save_color_image; // save the image i=i+1; if( i < 100 ) goto loop; // repeat 100 times

Here some 100 SUN rasterfiles are created. Afterwards you could use some tool to convert these single images to a movie.

Have you ever watched one of those films with that red and green
glasses? *surf* tries to accomplish exactly this effect
when you set *eye distance* in the
*display window* to a value greater than zero.
The following situation is simulated: The spectator is located
at (0,0,*spectator z*) and the distance between his
eyes is *eye distance*. The surface will appear at
the z-coordinate *distance from screen*.
Furthermore it is possible to adjust to specific
red-green or red-blue glasses by setting
*left eye red value*, *right eye green value* end
*right eye blue value*. In particular it is assumed that
the right eye wears the red glass.

If a color image of a surface/curve has been calculated, this image can
be mapped to a black and white image by pressing the button
*dither surface* or *dither curve*.
The second one is just designed for dithering curves.
The appearance of the black and white image can be altered/adjusted in several
ways in the *dither window*.
Since the mapping itself is done by dithering, the dithering algorithm
can be specified. Currently available are seven algorithms coming in three
groups:

- Floyd-Steinberg filter
- Jarvis, Judis and Ninke filter
- Stucki filter

- Clustered dot ordered dither
- Dispersed dot ordered dither

- 4 x 4 pixels: 16 gray levels,
- 8 x 8 pixels: 64 gray levels or
- 16 x 16 pixels: 256 gray levels.

- Knuth's dot diffusion
- Knuth's smooth dot diffusion

- 1 for resolutions of 1200 dpi or above or
- 2 for resolutions of 600 dpi or above.

The surfaces on black and white images often don't look very impressive;
often it is hard to detect the edges of a surface. An algorithm called
enhancing the edges avoids this drawback. This algorithm takes a value
*alpha* in [0,1] as input.
Best results are achieved with alpha around 0.9.

The intensity of the background on the black and white image can be
specified by altering the value *background* to any value
in [0.1]. Here 0 is black whereas 1 means white.

The *tone scale adjustment* maps intensity values
between 0 and 0.1 to 0, values between 0.1 and 0.9 linear to [0,1]
and values between 0.9 and 1 to 1.
This is used to enhance the contrast of an image. An additional gamma
correction can be also performed to correct the linearity of an output
device.

By specifying *pixel size* one can correct the printer pixel size:
A value of 50 means that the radius of a pixel is exactly
half the distance between two neighbouring pixels. A value of 100
says that the radius of a pixel is exactly the distance between two
neighbouring pixels.

The heart of *surf* is an algorithm which determines all
roots of a polynomial in one variable. Currently you can choose between
seven methods in the *numeric window*.
The first six methods use a chain of derivatives
to determine intervals where the polynomial has exactly one root.
They differ by the iteration method which is used to find the roots
in these intervals. Some of the iteration methods were just implemented
out of academic interest. However, they all work. The last method uses
Rockwoods all roots algorithm: the polynomial is converted into a
bezier function and the roots of the bezier function are approximated by
the roots of the control polygon.

For curves/surfaces of degree less than ten, all methods work. When the degree gets higher, best results are achieved by the bisection, the Newton and the bezier all roots method. At last, for a degree higher than 30 only the bisection methods seems to work (up to degree 50). If a curve has multiple components, the bisection and the Newton method tend to produce the best results.

Moreover it is possible to specify a numerical precision
*epsilon* which is used in all root finders.
Additionally the maximal number of *iterations* of the
iteration methods can be specified.

*surf* can store color images in one of several
file formats. In the *save color image window*
you can choose between

**XWD**(X Window Dump),**SUN rasterfile**,**PPM**(Portable PixMap) and**JPEG**.

- Netscape 216 color cube (8 bit),
- optimized by an octree algorithm (8 bit) and
- True color (24 bit).

*surf* can store black and white images
in different file formats. We have implemented

**Postscript**,**EPS**(Encapsulated Postscript),**TIFF**,**XBM**,**PGM**and**PBM**.

- 75 dpi,
- 100 dpi,
- 150 dpi,
- 300 dpi,
- 600 dpi and
- 1200 dpi.

Next Previous Contents