The Eagle graphics library (Version 0.1)

Tim Love

January 18, 1994

Contents

1 Key Concepts 2 1.1 Contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Layers, Patterns and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Viewing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.5 Animation and interactive editing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.6 File Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Use 3 2.1 Demos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

3 Routines 4 3.1 Layer Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 3.2 Object drawing, creation and removal . . . . . . . . . . . . . . . . . . . . . . . . . 5 3.3 Object manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.4 Selection and Grouping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.5 Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.6 Initialisation and low level graphics routines . . . . . . . . . . . . . . . . . . . . . . 11 3.7 Saving and Loading files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.8 Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.9 Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4 Example 16

eagle is graphics library designed to supercede mXplus and grasp at CUED for C programmers. It can be used on its own or in combination with other graphics libraries. It supports multiple windows, animation, grouping, layers, and perspective.

1 Key Concepts

1.1 Contexts

Each time the library is initialised, a context is returned. The context specifies the window and various other aspects of the appearance of the graphics. All operations act in the current context. The context can be switched using the set context() routine.

1.2 Layers, Patterns and Objects

The library lets one create layers. These are in a stack (one per context). Layers can be pushed or popped. Some or all the layers can be shown onscreen. The onscreen stack can be ‘rotated’.

Offscreen layers can be used to compose patterns which can then be tranferred to the onscreen layers.

Text, Polylines, filled or unfilled polygons and filled or unfilled ellipses can be drawn programmatically. Arbitrary polygons can be drawn interactively too.

Objects can be grouped. One object (or group of objects) is always the current object upon which interactive operations act. Objects can be manipulated and their positions queried. They can be extended to the layer above or below to form solid objects.

Line segments are joined at nodes. A line segment of length 1 is treated as a point.

1.3 Viewing

The gap between layers and the viewpoint elevation can be adjusted interactively, as can the ordering and visibility of layers. The vanishing point can be moved laterally and the distance to the horizon changed.

Any layer can be clipped by the polygons in any other layers.

1.4 Scaling

Views are optionally scaled on redrawing.

1.5 Animation and interactive editing

Polygons in the top layer can be ‘nudged’ using the arrow keys.

The off-screen layers or patterns can be cycled through and copied to the onscreen layers. These patterns can be pre-set to provide a library of components etc.

Using the nearest_line() and nearest_point() routines, many editing facilities can be constructed. Each point in a polygon can be constrained so that it cannot be dragged outside specified x and y ranges. Constraints can also be relative to the coordinates of other points in the polygon (so, for instance, a point can be constrained to have the same y coord as another point). Moving a point redraws dynamically all lines from that point.

The animation facility shows the transition from a polygon’s original shape to its edited shape. Any or all the points of the polygon can be iterated during animation, each at a different speed if required. Ellipses can be transformed into differently sised and positioned ellipses.

Arbitrary functions can be assigned to function keys.

1.6 File Formats

eagle can load in xfig files (though it can’t cope with spline lines) and writes files that can be loaded into xfig.

2 Use

It can be added to an Xlib or Motif application, but it might well contain sufficient routines to make direct use of Xlib unnecessary – it contains setupX() and event_loop() routines along with various color and text utilities.

2.1 Demos

The demos are in /export/Examples/eagle/

viewing.c :- sets up the 8 function keys to control the viewing of a multilayered structure. It uses event_loop() so the following keys work Amongst the options are :-

        u,d -- cycle the layers
        b,s -- make the interlayer gap bigger|smaller
        e,f -- change the elevation
        cursor keys -- nudge the shapes in the top layer. With the SHIFT
               button down, only the current object or group of objects
               move.
        n,N -- create, remove layer
        v   -- create a vertical plank
        r   -- duplicate the rightmost shape.
        left-button - finds nearest point on the top layer.
        middle-button - draws a polygon. Drag, clicking where you want
               points, then click on the right-button to complete.

etc.

mXplus.c :- Shows how eagle’s XAxis and YAxis routines can be used for drawing graphs.

venn.c :- is about 70 lines long. If you run the executable you’ll see 2 rectangles and a circle, the latter being clipped by the rectangles. Nudging the rectangles changes the visibility of the circle. The most recently created object is drawn with dashed lines (the current object).

elect.c :- shows how patterns (grouped, offscreen shapes) can be used.

        p  -- cycles thru the patterns.
        c  -- adds the current pattern to the top layer.

The first 5 function keys have functions assigned to them.

reuse.c :- shows how an existing window can be used.

three windows.c :- shows how the graphics library handles multiple windows.

using xb.c :- shows how Xlib, eagle and xb (a library for using buttons etc) can work together.

cued.c :- A view of CUED, using xb and eagle.

three d.c :- A view of CUED with solid and planar objects, using xb and eagle.

motif.c :- eagle in a motif window.

loadsave.c :- Loading xfig files (try those in /export/Examples/xfig/).

animation.c :- Converts a cross to a star and back again.

2.2 Documentation

The documentation is in ~tpl/SRC/eagle/doc/eagle.tex.

3 Routines

3.1 Layer Operations

void layer_display_mode(int mode)
/*   Changes the mode of layer display.
*   `mode' can be SHOW_ALL_LAYERS, SHOW_TOP_LAYER, SHOW_BASE_AND_TOP
*/
void show_borders(int mode)
/* If 'mode' is 0, don't show the boders of the layers, overwise
* show them.
*/
void top_to_bottom(void)
/*   Moves the top layer to the bottom, moving the other layers up.
*
*/
void bottom_to_top(void)
/*
*   Moves the bottom layer to the top, moving the other layers down.
*/
void to_top(int layer)
/*
*   Moves the specified screen layer to the top.
*/
void to_bottom(int layer)
/*
*   Moves the specified screen layer to the bottom.
*/
void initialise_stack(int num)
/*
*   Initialises the first `num' screen layers to be the first `num'
*   logical layers.
*/
int add_layer(char* name)
/*
* Add a new layer and set its name. Returns which logical layer.
*/
void remove_layer(void)
/*
* Remove the most recently added layer
*/
bitfield clip_layer(int layer, bitfield cliplayers)
/*
* Determines which layers will clip the given layer.
* Each bit in `layers' represents a logical layer.
* The old value is returned.

*/
void draw_layers(void)
/*
* Draws the layers
*/

3.2 Object drawing, creation and removal

void draw_poly(Object *polyp, int logical_layer, int screen_layer)
/*
*  Draw the specified poly from the specified logical_layer
*  into the specified screen layer.
*/
void draw_layer(int screen_layer, int logical_layer)
/*
* Draw the specified logical_layer into the specified screen layer.
*/
Object* add_circle(Object **addr_of_poly, int x, int y, int w, int h,
                int fill, int color)
/*
*  Create a circle of the specified dimensions.
*/
Object * add_poly(Object **addr_of_poly, int color, int fill,
                  int width, int height,
                  int type, int fullh, int fullw, int three_d)
/* Add a polygon to the object list that includes the polygon
* pointed to by addr_of_poly.
* color - an X11 color
* fill  - FILLED or UNFILLED. If the polygon is unfilled, the outline is in
*         the specified color, otherwise it is black.
* width  - This is used as an offset when adding a polygon to the
*          right of this one. If this value is 0, then the offset
*          is calculated dynamically.
* height - This is used as an offset when adding a polygon above
*          this one. If this value is 0, then the offset
*          is calculated dynamically.
* three_d - FLAT, UP or DOWN. If UP, then the polygon is extended to
*          the layer above.
*/
int add_poly_to_fill_layer(int num, int color)
/*
*  Add a full-size polygon to screen layer `num'.
*
*/
Object * add_text(Object **addr_of_poly, char* text, int x, int y,
                 unsigned long color, int* width, int* height);

void XAxis (int xlo, int xhi, int y, int ticksize, int labello,
        int labelhi, int nxticks, char *title, int color)
{
/*
* draw an axis between (xlo, y) and (xhi, y), consisting of
* nxticks 'ticks' between the ends. the ticks are lines drawn
* ticksize units below the axis, negative ticksize is acceptable.
* each tick is labelled in proportion to the range [xlo,xhi]
* the title string is
* inserted centred below these labels under the axis.
* The axes and labels form a group.
*/
void
YAxis(int ylo, int yhi, int x, int ticksize, int labello, int labelhi,
     int nyticks, char* title, int color)
/*
* draw an axis between (x, ylo) and (x, yhi), consisting of
* nyticks 'ticks' between the ends. the ticks are lines drawn
* ticksize units left of the axis, negative ticksize is acceptable.
* each tick is labelled in proportion to the range [ylo,yhi]
* using the floating point format (possibly) set up by a
* previous call to MxpFloatFormat_svc() the title string is
* inserted just above the axis.
* The axes and labels form a group.
*/

int draw_v_plank(void)
/*
*  Draw a vertical plank in the top layer.
*/
int set_pwidth(int w)
/*
* Sets width of vertical plank. Returns old value.
*/
int draw_h_plank(void)
/*
*  Draw a horizontal plank in the top layer.
*/
int set_pheight(int w)
/*
* Sets width of horizonal plank. Returns old value.
*/
void create_layout(int x,int y,int w,int h,int angle)
/*
*   Create a parallelogram in logical layer 0 with the specified
*   characteristics. Angle is in degrees clockwise from 3 o'clock
*/

Object * free_draw_routine(int init_x, int init_y, int poly)
/*
*   Draw a polygon if poly is 0, else a polyline. Returns
*   NULL if less than 3 points were set, otherwise returns a
*   pointer to the created object.
*/
void add_coords(Coord * addr_of_coord,int x,int y,int type)
/*
*  Add (x,y) to the list of coords pointed to by addr_of_coord.
*  `type' indicates the type of the line that this point is the
*  start of.
*/
Object * add_poly_coords(Object **addr_of_poly, int color, int fill,
  int three_d, XPoint points[], int num_of_points)
/*
*  Creates a polygon from the given coordinates.
*/
Object * add_polyline_coords(Object **addr_of_poly, int color,
  int three_d, XPoint points[], int num_of_points)
/*
*  Creates a polyline from the given coordinates.
*/
int draw_line(Object *object, int node1, int node2, int x1, int y1,
             int x2, int y2, int mode,int frame)
/*
*
*/
int join(Object *polygon, int node1, int node2);
/*
*    Create a line between node1 and node2 of the polygon
*/
int copy_right(int layer)
/*
* Create a copy of the right-most object in the specified
* screen? layer, offset by the value of the width parameter of
* the object, or calculated on the fly.
*/
int copy_above(int layer)
/*
* Create a copy of the up-most object in the specified
* screen? layer, offset by the value of the height parameter of
* the object, or calculated on the fly.
*/
int copy_layer(Layer *to, Layer *from)
/*

*    Copy all from layer `from' into layer `to'.
*/
void remove_object(int layer, Object *polyp)
/*
*   Remove specified possibly grouped object, freeing
*   associated structures.
*/
void remove_single object(Object *polyp)
/*
*   Remove specified object, freeing associated structures.
*/

void remove_coords(Coord * addr_of_coord)
/*
*   Remove (free) this and subsequent coordinate structures.
*/

3.3 Object manipulation

void nudge_one_x(Object *object, int increment, int constrained)
/*
*    Move this `object' only by the specified x value. If
*    `constrained' is non-zero, the move will only take place if
*    all the points remain in the limits.
*/
void nudge_one_y(Object *object, int increment, int constrained)
/*
*    Move this `object' only by the specified y value.  If
*    `constrained' is non-zero, the move will only take place if
*    all the points remain in the limits.
*/
void nudge_obj_x(Object *object, int increment)
/*
*    Move objects in the group that contains `object' by the
*    specified x value. Constrained
*/
void nudge_obj_y(Object *object, int increment)
/*
*    Move objects in the group that contains `object' by the
*    specified x value. Constrained.
*/
void nudge_x(int layer, int increment)
/*
*    Move all objects in specified layer by the specified x value.
*    Constrained.

*/
void nudge_y(int layer, int increment)
/*
*    Move all objects in specified layer by the specified y value.
*    Constrained.
*/
void centre_object(Object *object)
/*
* Centre the given object
*/
void flip_object_v(Object *object);
/*
*  Flip around mid x
*/
void flip_object_h(Object *object);
/*
*  Flip around mid y
*/
int full_height(int layer)
/*
*  Extend the parallelograms in the layer so that they have the maximum
*  allowed height.
*/
void clip_to_layout(void)
/*
*  Clip the top layer to logical layer 0.
*/
void embellish(int num,int type)
/*
*    Embellish line `num' of current poly with line type specified
*/

3.4 Selection and Grouping

void next_poly(void)
/*
*    Set current object to the next object on the current layer
*    (if it exists) else the first object on subsequent layers (if
*    it exists).
*/
int find_next_occupied_layer(int current_layer)
/*
*    Return the next layer that is occupied.
*/
void previous_poly(void)

/*  Set current object to the previous object on the current layer
*  (if it exists) else the lastt object on previous layers (if
*  it exists).
*/
int find_previous_occupied_layer(int current_layer)
/*
*  Return the previous  layer that is occupied.
*/
Object ** FirstObjectAddress(int layer);
/*
*   Returns the address of the pointer to the first object in the layer
*/
Object * GetObject(int layer,int num);
/*
*   Returns a pointer to the num'th object in the layer. Returns NULL
*   if no such object.
*/
int GetXCoord(Object* object,int num)
/*
*  Returns x coord of num'th node of the polygon.
*/
int GetYCoord(Object* object,int num)
/*
*  Returns y coord of num'th node of the polygon.
*/
int add_to_group (Object *old_object, Object *new_object)
/*  Add new_object to the group that old_object is in. If
*  old_object isn't in a group, create one. If new_object
*  is already in a group return -1, else return 1.
*/
int group (Object *first_object, Object *last_object)
/*
* Group all the objects from first_object to last_object.
* Returns the number of grouped objects.
*/
void ungroup(Object *object)
/*
*   Ungroup all objects in the group that object belongs to.
*   If object doesn't belong to a group, do nothing.
*/
void group_layer(int logical_layer);
/*
* Group all objects in the layer
*/

void ungroup_layer(int logical_layer);
/*
* Ungroup all objects in the layer
*/
int in_chosen_group(Object *object)
/*
*  Returns 1 if the object is in the same group as the chosen
*  poly, else 0.
*/

3.5 Patterns

int add_pattern(char *name)
/*
*  Add an offscreen layer with the given name.
*  Returns the number of the pattern if success (these are offset by
*  32), else -1.
*/
int copy_pattern_right(Layer *to, Layer *from)
/*
*  Copy the pattern pointed to by `from' just to the right of
*  objects in the layer pointed to by `to'.
*/
void cycle_thru_patterns(void)
/*
*  change the current pattern.
*
*/
void draw_pattpoly(Object *polyp)
/*
*  draw the pattern pointed to by polyp
*  where?
*/
void draw_pattern(int pattern)
/*
*  Draw the pattern indexed by `pattern'. Where?
*/

3.6 Initialisation and low level graphics routines

Context*  setupX(Display **display, Window *window, int x, int y,
            int w, int h, char* title, char *bitmap)
/*
*   Initialise the window dimensions and title.
*   If *display or window is NULL, then a new window is created
*   with the specified geometry otherwise the existing window
*   and geometry is used.
*   If title is non-NULL then the window is given this title.
*   If bitmap is non-NULL this file is read to provide the icon bitmap.
*/

void set_context(Context*)
/*
*  Change the context (i.e. the window, etc)
*/
Context * context_of_window(Window* window)
/*
*  Return context given a window. Returns NULL on failure.
*/
int event_loop(XEvent*)
/*
*  Processes the event and returns. If the argument is NULL, the
*  routine continues processing events and doesn't return.
*/
void redraw_window(Window)
/*
*  Redraws the specified window. If the argument is NULL all windows
*  are redrawn. (TPL - shouldn't this be context rather than window?
*/
int draw_lines(int mode)
/*
*  Redraws all the lines.
*/
int erase_lines(int mode)
/*
*  Erases all the lines.
*/
int requestColor(char *name)
/*
*   Returns the nearest color.
*/
int setfont(char* fontname)
/*
* Sets the font of the current context. Returns 1 on failure, else
* returns 0
*/
Object * nearest_point(int layer, int * node, short x, short y)
/*
*   If a point in the specified layer is within tolerance,
*   returns a pointer to the object and sets *node to the number
*   of the nearest node. Otherwise NULL is returned.
*/
int find_nearest_point_in_object(Object *object, short x,short y)
/*   Return the index of the closest point to the specified
*   coordinate, if object is a polygon. If object is a circle,
*   returns 0 if close enough to the centre. Returns -1 if there is
*   no point nearer than tolerance.

*/
int find_nearest_line(Object *object, short x, short y)
/*   Return the index of the closest line to the specified
*   coordinate. Returns -1 if there is no line nearer than
*   tolerance.
*/
int set_tolerance(int num)
/*
*  Sets the limits for the nearest point routines in pixels.
*  Default is 5. Returns old value.
*/
int mod(int a,int b)
/*
*  Returns the modulus.
*/
int min_dist(int x1,int y1, int x2,int y2, int x,int y)
/*
*  Returns the perpendicular distance from (x,y) to the line
*  segment (x1,y1) (x2,y2).
*/
int point_in_box(int x,int y,int xbox,int ybox,int wbox,int hbox)
/*
*  Returns 1 if the point (x,y) is in the specified box, otherwise
*  returns 0.
*/
int bb_of_object(Object *polyp, int *minx, int *miny, int *maxx, int *maxy)
/*
*  Returns greater side of the bounding box of an object or group
*  of objects in user coords.
*/
int bb_intersect(Rect *bb1, Rect *bb2)
/*
* Returns 1 if the rectangles intersect, else 0.
*/
void display_coords(int point,int one_or_two)
/*
*   Displays onscreen the coords of the specified point of the current
*   object.  (TPL - where?)
*/
void display_mouse_coords(int x,int y)
/*
*  Print pointer coords (as translated onto the top layer). (TPL - where?)
*/
void   setfn(int f, void* routine);
/*

 *     Set up function key f so that the specified routine is called
 *     when it's pressed.
 */

3.7 Saving and Loading files

The format used for files is an extension of the FIG format. Information that cannot be held in this format are included as comment lines beginning with #EAGLE. eagle can load in FIG files but cannot represent all the information. In particular, splines aren’t supported in eagle.

FIG only supports a few named colors. The colormatch routine lets the user specify the mapping between FIG and eagle colors.

int save_to_file(char* file_name, Context *context, int layer, int scale)
/* Save to the specified file. If context is NULL, the current
 * context is used. If layer is 0 (TPL ???) all the layers are saved,
 * otherwise just the top one is. The figures are scaled according to
 * the value of scale.
 */
int load_file(char* file_name)
/* Load in a fig file (protocol 1.4 or newer)
 * Returns 0 on success, non-zero on failure
 */

int colormatch(char *figcolor, int eagle_color)
/* Specify the mapping between FIG and eagle colors.
 * Not needed if you're already using the colors Black, Green, Cyan, Red,
 * Magenta, Yellow, White in eagle.
 */
int eagle2figcolor(unsigned int eagle_color);
int fig2eaglecolor(unsigned int fig_color);
/* mapping between fig and eagle colors */

3.8 Animation

void Timer(int mseconds);
/*
 *  Pauses for mseconds (milliseconds)
 */
int check_move(int node, int x,int  y)
/*
 *  Returns 1 if the move of specified node to (x,y) is valid.
 */
int do_move(int node, int x, int y)
/*
 *  Moves specified node to (x,y)
 */
void iterate(void )
/*
 *  TBA

 */
void iterate_one(void)
/*
 *  TBA
 */

int setup_animation(Object* from, Object *to);
/* Prepare all the nodes of 'from' for animation. The first node of
 * 'from' will be setup to move to the coords of the first node of
 * 'to', etc. If 'from' is an ellipse, then 'to' must be an ellipse. For
 * ellipses, the coords and radii are set up for iteration.
 * If 'from' is a polygon or polyline, 'from' has to be one of those too.
 * -1 is returned if there's a mismatch. If 'from' has fewer points than
 * 'to', -2 is returned. 1 is returned if the operation's successful.
 */
void animate_node(Coord *coord, int x, int y, int steps);
/* Prepares the node for animation. x,y is a vector describing in
 * screen coords the final position. steps is the maximum number of
 * steps that the pont will take to reach this position. If steps
 * is -1, then the number of steps will be determined at the time
 * of animation.
 */
Animation *get_node_animate_info(Coord *coord);
/*
 *  Return a pointer to a node's animation info.
 */
void animate(Object *object, int num_of_steps);
/* Animate object using a maximum of num_of_steps steps. If a node has
 * an animation steps value of -1, then it moves taking num_of_steps.
 */

3.9 Transformations

int xtransform(int x)
int reverse_xtransform(int x)
int ytransform(int y)
int reverse_ytransform(int y)
int xperspective(int x,int y)
int rev_xperspective(int x,int y)
int yperspective(int y)
int rev_yperspective(int y)
int yperspective_and_transform(int layer,int y)
int rev_yperspective_and_transform(int layer,int y)

int constrained_y(int y,int x)
/*
 *  Returns the clipped value of y for x on the layer.
 */
int get_maxy(int x, int layer)
/*
 *  Returns maximum permissible y for x on the layer.
 */
int get_miny(int x, int layer)
/*
 *  Returns mimimum permissible y for x on the layer.
 */
int set_horizon(int horizon)
/*
 *  Change the distance to the horizon (default 1000)
 */
void set_pad_percents(double xpercent, double ypercent)
/*
 *   Sets the size of the blank border around the graphics. Default is 5%.
 */
int set_vanishing_point(int percent)
/*
 *  Sets the vertical position of the vanishing point. 0 is at the
 *  minimum x limit, 100 is at the maximum x limit. Values outside
 * the 0-100 range are allowed. Returns old value.
 */
int set_elevation(int degrees)
/*
 * Sets elevation (angle from the horizon) in degrees.
 * Returns old value.
 */
int set_gap(int pixels)
/*
 * Sets inter-layer gap in pixels. Returns old value.
 */
int set_rescale(int mode)
/*
 * if mode is 0, don't rescale the graphics in future
 */

4 Example

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>

#include <X11/Xutil.h>
#include <string.h>
#include "eagle.h"
main(int argc, char *argv[])
{
int layer;
unsigned long red, blue, purple;
Display *display;
Window window;
XPoint points[10];
int num_of_points;
display = (Display*) NULL;
window =  (Window) NULL;
setupX(&display, &window, 30, 30, 430, 430,"Venn Diagram", NULL);
set_gap(40);
red = requestColor("red");
blue = requestColor("blue");
purple = requestColor("purple");
num_of_points = 4;
layer = add_layer("set A");
points[0].x = 10;
points[0].y = 10;
points[1].x = 10;
points[1].y = 80;
points[2].x = 80;
points[2].y = 80;
points[3].x = 80;
points[3].y = 10;
add_poly_coords(FirstObjectAddress(layer), blue, FILLED, FLAT,points,4);
layer = add_layer("set B");
points[0].x = 30;
points[0].y = 30;
points[1].x = 30;
points[1].y = 90;
points[2].x = 100;
points[2].y = 90;
points[3].x = 100;
points[3].y = 30;
add_poly_coords(FirstObjectAddress(layer), red, FILLED, FLAT,points,4);
layer = add_layer("AB Intersection");
add_circle(FirstObjectAddress(layer), 100, 80, 150, 150,
               FILLED, purple);
/* clip the circle in the newest layer with the lower layers */

clip_layer(layer, 1+2);
initialise_stack(3);
event_loop(NULL);
}