$K#Graphics in CML
Introduction
CML has a graphics window in which it can display simple graphics. Whenever anything of type picture is evaluated at the top level in CML the corresponding picture gets drawn into the graphics window. The graphics window is a subset of the plane covering approximately from -2.0 to 2.0 in both directions. The following simple values and functions are available to create and manipulate pictures:
Note that the arguments to various of the picture drawing functions are REAL numbers and not integers. Thus an attempt to say "circle(1)" will fail, and you must say "circle(1.0)" or "circle(real 1)".
nullpic
nullpic : picture
A value reprsenting the empty picture. This can be used as the base case for defining pictures recursively; such an example is given below.
point
point : picture
A value that is the picture with a single (black) point at the origin. Note that isolated points will often not be easy to see.
line
line : real -> picture
Returns a picture that is a horizontal (black) line centred on the origin of the length you specify. So line 4.0; draws a line that cuts the graphics window in half.
circle
circle : real -> picture
Returns a picture that is a (black) circle centred on the origin with the given radius.
shift
shift : real*real*picture -> picture
Takes an amount to shift by (in the x and y directions) and a picture and returns that picture shifted by that amount. shift (1.0,0.0,line 2.0) draws a horizontal ray emerging from the origin.
rotate
rotate : real*picture -> picture
The amount to rotate by is specified in degrees by a real number, and the picture returned is a rotation of the picture that is passed as an argument. Positive rotation is clockwise. An example use is
fun vline l = rotate(90.0,line l);
which defines a function similar to line except it returns lines that are vertical in orientation.
scale
scale : real*picture -> picture
Scale takes a scale factor and a picture and returns a picture scaled by that amount. Eg scale(2.0, picture) makes a picture twice the size of the original.
scalex
scalex : real*picture -> picture
Scales a picture in the x direction only. The effect is that the picture is stretched. Combine rotations with scalex to get stretches along other directions.
add
add : picture*picture -> picture
Creates a superposition of pictures. An example of its use is
fun almost_lemniscate r =
add(shift(r,0.0,circle r),shift(~r,0.0,circle r));

paint
paint : colour*picture -> picture
Takes a picture and a colour and returns a similar picture that has been painted with the colour.
rgb
rgb : int*int*int -> colour
Converts triple of Red Green Blue values into a colour (RGB values should be from 0 to 255). Note that the range of colours that can actually be displayed will depend on the setup of your computer, but frequently only a very limited range will be usable. The predefined colour names are often more convenient to use than rgb().
Primary and Secondary colours
The primary and secondary colours are defined as identifiers and have the (hopefully obvious) names black, red, green, yellow, blue, magenta, cyan, white.
An example, drawing polygons
The following function draws polygons (including rational polygons), it is included here to show how complex pictures can be built up using the operations provided, and not necessarily of an example of good coding style.
(* polygon numer denom ll
 * numer and denom are integers and should be the numerator
 * and denominator of the rational polygon you wish to draw
 * (eg 5 1 for drawing a pentagon, 5 2 for drawing a
 * pentagram).
 * The fraction should be represented in reduced
 * form.
 * ll is a real denoting the length of a side.
 *)

fun polygon numer denom ll =
 let
  val hray = shift(ll/2.0,0.0,line ll)
  val rotatestep = (360.0 * real denom) / real numer
  fun poly 0 p = p
    | poly d p = poly (d-1) (add(shift(ll,0.0,rotate(rotatestep,p)),hray))
 in
  poly numer nullpic
 end;
Note that excessively complicated pictures may cause CML to crash, and will certainly made re-drawing the pictures tedious.