The Pan# User Manual
top | back | next
4 A Tour of the Pan#
In this section we present a brief overview of the Pan# language. File names
that end in .pan refer to programs in demos/manual that
you should run as you read this section. To see the code in
these examples you can use the "View" menu to look at the source code.
4.1 Programs, Expressions, and Definitions
Pan programs are stored in files with the .pan extension. A
program may import definitions from another file using an
import declaration. An import brings all definitions in an
imported file into scope; there is no way to import a subset of the
definitions in a file. Local names hide imported names; you can
redefine names from imported files or the Prelude.
The statement import foo looks for foo.pan in the
directory of the importing file and the library directory, bin,
created at installation. There is no way to define a more complex
module search path.
There are two sorts of bindings in Pan#.. A definition binds a
name to a
value while a connection creates a object "outside" of the
current image which communicates through the variable on the left of
the <-. All connections are made within a frame of
reference. Connections at the top level of the program are placed in
the full frame of the picture. Imported files cannot have top level
connections in them.
This binding creates a slider control and defines x as the
current value of the slider:
x <- slider "x" (0, 10) 5
As with ordinary definitions, the ordering of connections doesn't
matter. For example, this program:
a <- slider "a" (0, 10) 5
b <- slider "b" (0, 10) 5
picture(x,y) = if (x-a)^2 + (y-b)^2 < 100 then black else white
generates the same images as this one:
b <- slider "b" (0, 10) 5
a <- slider "a" (0, 10) 5
picture(x,y) = if (x-a)^2 + (y-b)^2 < 100 then black else white
4.2 Static Values and Unrolling Loops
Some values in a Pan# program must be static. The control
objects such as sliders must be defined using constant parameters.
For example, this is not allowed:
x <- slider "One slider" (0,10) 1
y <- slider "Another slider" (x, x+10) 1
This would use the value generated by one slider to set the range of
another slider. This program would generate a compile time error
since a parameter to the second slider function is not static.
The following would be allowed:
x = 10
y <- slider "Another slider" (x, x+10) 1
Since x is a constant, the definition of y is valid.
All loops in a Pan# program must be statically unrollable. That is,
indefinite looping is not allowed.
The following code is correct since replicate will loop a fixed
number of times (3):
replicate n i = if n = 0 then invisibleI
else beside i (replicate (n-1) i)
picture = replicate 3 (colorRegion red $ circle (0,0) 20)
However, this will generate an error at compilation time since the
number of iterations cannot be determined at compile time:
replicate n i = if n = 0 then invisibleI
else beside i (replicate (n-1) i)
r <- islider "Number of images" (1,10) 3
picture = replicate r (colorRegion red $ circle (0,0) 20)
4.3 Numeric Functions
Pan# includes a library of standard numeric functions, as described in
section 5. There is no type distinction
between integral and real numbers in Pan#. Functions which expect
integer arguments. mod for example, round any floating point value to
the nearest integer. Angles are always expressed in radians
rather than degrees. Functions cannot be overloaded - that is,
a function or operator can be applied to only one type of object. For
example, the + function only adds numbers. An operator for the
addition of vectors or matrices would have to have a different name.
4.4 Colors
The built-in colors are shown in examples 01-colors.pan and
02-colors2.pan. Colors can be
constructed directly in RGB or HSV space, as shown in example
03-rgbhsv.pan. Arguments to these functions which are out of
their expected range give unpredictable results.
The program
04-lerpC.pan demonstrates linear color interpolation (the name
"lerp" means "linear interpolation",
a term from the graphics community). When interpolation
generates RGB values outside the range [0,1] results are
somewhat odd. The darken and lighten functions
interpolate a color toward black or white, as follows:
lightenC x c = lerpC x c white
darkenC x c = lerpC x c black
Colors may be transparent. The fadeC function makes a
color more transparent: fadeC 1 leaves the color unchanged and
fadeC 0 makes it completely transparent. This is demonstrated
in 05-fade.pan.
The withinC function compares the distance in RGB space between
two colors. The use of withinC and negC (color
negation) is demonstrated in 06-within.pan.
4.5 Strings and Rasters
Strings are used to add text to an image and label controls. The C#
format language converts numbers to character strings.
Strings can then be converted
into rasters (bounded arrays of colors) and thence to continuous
images. The conversion from raster to image can be done a number of
ways. The default is for "square pixels" (no color interpolation)
but bilinear or other interpolation schemes can be used to convert a
raster into an continuous image.
Interpolation is more computationally demanding and
fast conversion from raster to image is usually adequate. The example
07-format.pan uses string concatenation, formatting, and
raster to image conversion to interactively show the mouse location.
This also demonstrates the default coordinate system: distances are
measured in pixels and the origin at the center of the image.
4.6 Functions
Conal Elliott's "Fun of Programming" chapter is the best
demonstration of functions and functional images. If you examine the
examples in demo/fun against the code in this paper you will see
that the code is nearly identical. One of the main differences is
that Pan# allows points to be expressed in polar notation, where
(r @ theta) denotes a point r from the origin at an
angle of theta. This notation can be used in patterns and
expressions.
These examples demonstrate the use of regions: functions from
2-D points to booleans. In addition to the
operators found in the Fun of Programming chapter there are built-in functions
to define a number of basic regions (circles, rectangles, ...) and
convert regions into color images. The
colorRegion function paints a region with a uniform color,
leaving the rest of the image transparent, while colorRegion2
supplies a second color for points outside the region.
4.7 Sized Images
A sized image is an image coupled with a bounding rectangle. String
rasterization and the image control (a control that imports a jpeg or gif
image into a Pan picture) generate sized images. The bounding box
of a sized image can be used to fit these images into a composite picture.
A family of functions is provided to move and scale these sized
images. The arguments
consist of a point, a length, and a sized image. This point is either
the target location for the center (C) or the lower left corner (L) of
the image. The length may specify the width (W), height (H), or zoom
factor (Z) of the image. These images are always scaled uniformly in
the X and Y directions. In 08-sizedimages.pan all of the sized
image placement functions are shown.
4.8 Frames and Controls
Pan# uses frames to:
- determine the relation between screen coordinates and logical
coordinates,
- subdivide an image into separate panes with independent coordinate
systems,
- adapt an image to the physical size of its viewing window,
- overlay images with different coordinate systems, and
- construct the control devices.
We will illustrate the use of frames using the following library
functions:
slider :: String -> (Number, Number) -> Number -> Framed Number
beside :: MFramed ImageC -> MFramed ImageC -> Framed ImageC
zoomIn :: Number -> MFramed ImageC -> Framed ImageC
These functions operate as follows:
- slider creates a control in the current frame of reference
that defines a number within a given range.
- beside joins two color images into a single image by
placing them side by side. These two images may or may not be
framed (this is why MFramed is used instead of Framed).
The resulting frame will contain controls from each of the
sub-images.
- zoomIn scales the coordinates in a frame. Again, the
image to be scaled may or may not be in a frame.
The following function creates a slider control and uses it to scale
the coordinate system in a given frame:
zoomer :: String -> MFramed ImaceC -> Framed ImageC
zoomer name im = let zoom <- slider name (1,100) 50 in
zoomIn zoom im
The first parameter to zoomer is used to label the slider
control. The following picture, found in 09-doublezoom.pan,
shows two squares side by side, each of which has its own zoom
control:
picture = beside (zoomer "Left" square) (zoomer "Right" square)
The MFramed type allows the zoomIn function to be applied
to an ordinary image, of type ImageC), or an image within a
frame of reference, of type Framed ImageC.
Since the slider function is called twice the resulting image
has different sliders.
4.9 Setting the Coordinate System
One way to define the coordinate system in a frame is to specify the
coordinates at the frame boundaries. The fit and
fitStretch functions adjust the coordinate system so that a
given rectangular region, specified by coordinates at the lower left
and upper right of the region, fills the frame. The
fitStretch function places the rectangular region exactly in the
frame while fit scales the coordinate system uniformly and may
need to include some area outside the given rectangle. When padding
is needed it will always center the view region. The example
10-fit.pan demonstrates these functions. These
functions can be used to scale an image to fill a large canvas for the "Save
Image" function.
Another way to deal with the coordinate system is to alter the
inherited coordinate system by moving the origin or zooming in/out.
The functions recenter and lowerLeft are used to
translate the coordinate system in a frame while zoomIn and
zoomOut scale the coordinate system. With recenter,
the coordinate of the point in the center of the frame is specified.
Similarly, lowerLeft adjusts the coordinate at the lower
left corner of the frame. The example 11-panzoom.pan
demonstrates these functions.
The "pixel size" operators return the width or height of a pixel in local
coordinates. This functions can create objects whose size does
not vary as the coordinate system
changes. The program in 12-pixelwidth.pan shows a circle set
against an X and Y axis. The axis is drawn to be exactly 4 pixels
wide and does not change in width during the zooming.
4.10 Sliders and Check Boxes
A slider produces a number from within a
continuous range of values. The value generated by the slider can
also be entered directly in the box displaying the slider value. When
a value outside the slider's range is entered a dialog box allows
the range to be readjusted.
The islider function creates a slider that generates only integers.
Aside from that, it is exactly like an ordinary slider. Run the
program 13-flower.pan for an example using an integral slider.
The tick function obtains a
boolean value rather than numeric value from the user; a
"tick" in the box yields "true". The
arguments to tick are a label string and the initial state of
the box. The example in 14-tickbox.pan shows a tick box in action.
4.11 Imported Images
The image function imports a jpeg/gif file as an
image function. The control device allows the user select the
particular picture returned by the control. The imported image
is centered at (0,0) and is in pixel
coordinates. Another function,
sizedImage, returns a sized image that can be used with image
placement functions. If you want a specific image to appear by
default use imageD. You can import a raster rather than a
continuous image
using imageRaster, allowing more complex image
reconstruction algorithms.
The textbox function generates an image by rendering a string.
The user enters text and chooses a font and font size. The text is
converted to an image which is then returned by the control.
As with the image function, there is a sized image version:
sizedTextbox. Run
15-labeledpicture.pan for an example using this function.
4.12 The Mouse
The
mouse function is a control that observes the mouse position
in the coordinate system of the local frame. The mouse position is
tracked only when the left button is down. If the mouse is outside
the viewing window or the left mouse button is not pressed, the most
recently selected location is
returned. The example 16-mouseCircle.pan shows how this
function works.
A movable point works in much the same way as the mouse except
that the actual mouse position is tracked only when the point is in
range of the mouse. This allows different movable points in to be
controlled separately.
Such points need to be
visually apparent; there is no special indication on the
view window that shows where these points are unless the user invokes
the "show movable points" command.
A boolean indicates when the point is being dragged; this is
normally used to change the appearance of the point. The program
17-rectangle.pan demonstrates the use of movable points.
The coordinates of the initial position for a movable
point are in viewer (pixel) coordinates rather than the local frame of
reference.
4.13 Timers
Times are used to describe animations. A timer is simply a slider that
moves on its own. Timers always start
at 0 and increase up to a user-defined
limit. When the timer hits the limit it will either stop or resume
from zero. The timer menu in the viewer can stop all timers,
at which point they become ordinary sliders. The example in
18-rotatingimage.pan shows the use of timers. The "make
movie" command in the viewer writes out an animation as a series of
numbered image files.
4.14 Random Numbers
The controls randoms and randoms2 generate a 1-D or
2-D function that returns random numbers. Note that a 2-D set of random numbers is
similar to an image. The generated random numbers are in the range
(0,1). These random functions are defined on integers; non-integral
arguments are rounded to the nearest integer.
An initial size determines how
many different random values are present; this random sequence is repeated
outside of the original domain.
4.15 Timing Tracks
A timing track is a sequence of numerically valued events. Tracks are
generated by a special version of the Haskore music system are used to
create animations that are synchronized to notes in a Haskore score.
The getTiming function reads a timing track from a specified
file. The findEvent function returns the state of the timing
track at a specified time. This state consists of three values: the
elapsed time since the last event, the value of the last event, and
the duration of the event. A duration of -1 indicates that the event
is the last one on the track and thus has infinite duration.
A simple example of timing tracks is found in 20-timings.pan.
The Pan# User Manual
top | back | next |
March, 2004