2003-05-02

Copyright © 2003 Danny Brewer

d29583@groovegarden.com

If you wish to modify or distribute this document or the code contained in this document, you may do so only under the terms of either the Open Content License or the LGPL. For more information see the Copyright and License Information section at the end of this document.

NO WARRANTY

The material provided in this document is provided without any warranty whatsoever. For more information, see both of the NO WARRANTY disclaimer in the Open Content license and the NO WARRANTY disclaimer in the Gnu Lesser General Public License at the end of this document.

Tutorial – Programming Drawings in StarBasic

This document is a tutorial to teach you how to use StarBasic to program OpenOffice.org to create drawing documents.

Both OpenOffice.org and Star Office have a built in programming language called StarBasic. Using StarBasic, you can create and manipulate office documents, including drawings.

There are many potential applications of drawings produced by program code. You could build tools which produce simple or complex geometric shapes ready for immediate cut & paste into your own drawing. You could produce tools to build other drawing elements, such as a maze generator. (The author has already done this in Java, but not in StarBasic.) Given access to a database of employee records, you could automatically construct a drawing of an organization chart.

Turtle Graphics in StarBasic

We start off by making simple geometric shapes using a technique called Turtle Graphics. After you complete this part of the tutorial, you will be able to easily write programs in StarBasic that can create office drawings with complex shapes. If you are impatient and want to see a prepackaged demo, then you can immediately skip ahead to Let's Get Started. If you are really, really impatient, then skip to the very end of the section Let's Get Started (Page 6), and look for two buttons after Drawing 1.

About Turtle Graphics

Turtle Graphics systems of various flavors have been around since at least the early 1980's. On early microcomputers, such as the Apple II, a Turtle Graphics interface might be made available in either a BASIC or Pascal language system so that a program could be written to manipulate the turtle graphics system. Turtle graphics systems are easy to program. They are approachable by beginning programmers, and even children.

The main concept in turtle graphics is the turtle. The turtle crawls along a piece of paper. A pen is attached to the turtle. When the pen is down, the turtle's movement leaves a line. When the pen is up, the turtle can move, but leaves no ink behind on the paper. You can call functions to cause the turtle to move forward or to turn.

With the turtle graphics routines provided in this tutorial, a new office drawing document is created with the turtle initially positioned at the center of the drawing, and pointed to the right (or east, or increasing X-axis direction). You can call functions, such as MoveForward( 5 ) to move the turtle forward (to the right) by five units. Then you could call, Turn( 90 ) to cause the turtle to turn clockwise by a right-angle (now pointing down, south or increasing Y-axis direction). If you now called, MoveForward( 5 ) again, then the turtle would advance another five units straight down. If the pen was down when the turtle made these two movements, you just draw a right angle. By calling Turn( 90 ), MoveForward( 5 ), Turn( 90 ), and finally MoveForward( 5 ) again, you would have completed drawing a square.

About the StarBasic macros contained in this document

The document that you are now reading is an OpenOffice.org document. It was initially created using OpenOffice.org version 1.0.2, and then later using verion 1.1 beta. (Running on Windows XP Professional, but that should be irrelevant. The author has tested the examples on OpenOffice.org 1.0.1 running on SuSE Linux 8.1.)

Embedded within this document is a library called TurtleGraphics. Inside that library are modules named TurtleMod and TurtleUtilsMod. These modules contain the necessary code to implement the turtle graphics API you will be using in this tutorial. The code we will develop in this tutorial is very simple and consists of calls to the turtle graphics API provided by these modules.

How the turtle graphics modules work internally is not the main subject of this tutorial. Feel free to study the source code and comments in these modules to learn how they work internally and how you can write your own code to create and manipulate office documents. The source code is commented, but in addition, all identifier names are carefully chosen in an effort to make fewer comments necessary.

Briefly, here is a description of what the modules do.

Library TurtleGraphics contains modules TurtleMod and TurtleUtilsMod.

TurtleMod is the turtle graphics module. It provides the routines to create a turtle graphics drawings, and to manipulate the turtle's position and the pen.

TurtleUtilsMod is a module of utility functions to draw things using turtle graphics. For instance, if you want to draw a star, you can just call one subroutine within TurtleUtilsMod.

Library OOoLib contains a growing collection of modules, including DrawMod.

DrawMod is a (growing) module of code to manipulate OpenOffice.org draw documents. Routines in DrawMod can create a new drawing, and can create shapes on this drawing. At the time of this writing, DrawMod is but a tiny shadow of what I expect it to grow into.

Let's Get Started

Before we do any programming, let's begin with a prepackaged demo.

We will run the test program in the TurtleMod module to test that the turtle graphics system is working properly. This program will produce a drawing with several figures.

From the Tools menu of the document you are now reading, pick Macros, and then from the submenu pick “Macro...”.. You will get a window similar to that pictured in Illustration 1.

(In older versions of OpenOffice.org prior to 1.1 beta, you may have to pick Tools -> Macro..., and the two panels “Macro name” and “Existing macros” may be swapped.)

Also understand that you must be reading this document in the OpenOffice.org or StarOffice software, not using the embedable viewer, such as happens if you downloaded this document and it appears embedded within your web browser.

Illustration 1 This dialog box appears when you pick the Tools -> Macros -> Macro... command.

At the top is the category 'soffice' which contains all of the libraries that are attached to the office program. The Standard library is shown under 'soffice', but there are typically others as well. These libraries are independent of any document. Libraries under 'soffice' are always available. This is a good place to put code that you want to be able to run at any time. You can create new libraries under 'soffice' that are available to all your programs.

Libraries contain modules.

Further down, under 'soffice' you can see the TurtleGraphicsTutorial.sxw document, this document, which is hilighted in Illustration 1. Attached to this document are several libraries with names like OOoLib, PolygonStarBuilder, Standard, and TurtleGraphics. (More libraries may be listed than shown in Illustration 1.)

Libraries contain modules.

Within each library are modules. In the TurtleGraphics library, you can see modules named TurtleMod and TurtleUtilsMod.

Select the TurtleMod module. See Illustration 2. Selecting a module under “Macro from” causes the procedures contained within that module to be displayed under the “Existing macros”.

Illustration 2 When you select a module under “Macro from”, the “Existing macros” panel shows you the functions and subroutines within that module.

Notice the various procedures in TurtleMod, such as Main, TurtleTest, CreateTurtleDoc, etc.. The one we are interested in is named Main, which is hilighted in Illustration 2.

With the TurtleMod module selected, and the Main routine selected, click the Edit button. A new window appears as pictured in Illustration 3.

This is the Basic IDE window where you create and edit Basic code.

Notice the two tabs at the bottom of the window named TurtleMod and TurtleUtilsMod. These tabs represent the modules present in this library. In the upper left corner of the window you can see a drop down menu showing all of the libraries, and which library you are presently looking at.

With the TurtleMod module selected (tabs at the bottom, as pictured in Illustration 3), click the Run button. The Run button is located on the toolbar as pictured in Illustration 4 on page 6.

As soon as you click the run button, the program will immediately create a new Draw document with several figures in it. (See Drawing 1 on page 6.)

Illustration 3 The BASIC IDE window. This is where you create and edit Basic code.

Illustration 4 The Run button in the toolbar starts the program running at the first routine.

The figures generated by running the program are pictured in Drawing 1.

Drawing 1 These figures are generated by running the Main routine (a testing routine) in the TurtleMod module.

There is an easier way to run the TurtleMod main routine which generates the figures pictured in Drawing 1. Instead of opening up the BASIC IDE window (Illustration 3 on page 5) and clicking the run button, you can just click on the button below this paragraph named “TurtleMod test routine”.

The other button, “TurtleUtilsMod test routine”, runs the Main routine in the other module TurtleUtilsMod.

Go ahead, click the button now and try it. A new office drawing will be generated by running the program.

This is a clear illustration of the fact that you can put buttons (or indeed, other controls) into your documents which can run macro code contained within your documents. Imagine the possibilities.

Let's write a simple program

From this part of the tutorial forward, you will be making changes to this document by adding additional code that you will write. Therefore, you may want to keep an unmodified original copy of this document in a safe place.

First we will create a new module. Pick the Tools -> Macros -> Macro... command (from the Tools menu). You will get a dialog similar to what is pictured in Illustration 5.

Select the Standard library from the TurtleGraphicsTutorial.sxw document, as illustrated, and then click the New button. (Under older versions of OpenOffice.org, you may not see the Standard library, and so you may pick the TurtleGraphics library instead.)

You will be prompted for the name of your new module. The default will be Module1. You could name it anything you wish, but lets name it “Pentagon1”.

Illustration 5 This dialog appears when you click Organizer from the Macro dialog box.

After you click OK, the Basic IDE window will appear. (Similar to that of Illustration 3 on page 5.) At the bottom of the window, you will notice that there is a new tab for your new Pentagon1 module. See Illustration 6.

Illustration 6 Your new Pentagon1 module is shown in the tabs in the BASIC IDE window.

The following stub of code is initially present in your module.

REM ***** BASIC *****

Sub Main

End Sub

In between the Sub Main and the End Sub, write some new statements so that the module looks like the following.

REM ***** BASIC *****

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

LineForward( 5000 )

Turn( 72 )

LineForward( 5000 )

Turn( 72 )

ReleaseTurtleDoc()

End Sub

See Drawing 2 on page 9 to better understand how this code works.

In the first line of the program you make sure that the TurtleGraphics library is loaded. You will need to do this anytime you write a program using turtle graphics. This line makes all of the modules of the TurtleGraphics library available. (The TurtleGraphics library contains two modules: TurtleMod and TurtleUtilsMod.)

The second line of the program calls the subroutine CreateTurtleDoc(). This routine is contained in the TurtleMod module. It creates a new office Draw document and initializes the turtle graphics for that document. The turtle is initially positioned at the center of the document, pointing to the right.

The next statement in the program, LineForward( 5000 ) causes the turtle to move forward (to the right) by 5 centimeters. The next statement, Turn( 72 ) causes the turtle to turn clockwise 72 degrees. (Turtle now pointing down and right.) The next statement, LineForward( 5000 ) moves the turtle 5 cm in the forward direction. Finally, Turn( 72 ) turns clockwise another 72 degrees.

The last line, ReleaseTurtleDoc() should be called by your program when it is completely finished with the turtle graphics document. Your program could then call CreateTurtleDoc() again and produce a second drawing in the same program run.

To see this code run, click the run button. (See Illustration 4 on page 6 for the location of the run button.)

1. CreateTurtleDoc() creates the drawing document. 2. Turtle Initial position. 3. LineForward( 5000 ) Moves the turtle forward, leaving behind a line. 4. Turn( 72 ) Turns the turtle 72 degress clockwise, Turtle is now pointing down and right. 5. LineForward( 5000 ) Moves the turtle forward again, leaving behind another line. 6. Turn( 72 ) Turns the turtle another 72 degress clockwise, but has no visible effect. The turtle is now ready to draw another line in a different direction. Drawing 2 Explanation of the code's actions. A new draw document is produced with the first two segments of a pentagon.

Modify the code to have five LineForward and five Turn commands as follows.

REM ***** BASIC *****

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

LineForward( 5000 )

Turn( 72 )

LineForward( 5000 )

Turn( 72 )

LineForward( 5000 )

Turn( 72 )

LineForward( 5000 )

Turn( 72 )

LineForward( 5000 )

Turn( 72 )

ReleaseTurtleDoc()

End Sub

Next run the code, and it will draw a complete pentagon.

Now lets look at a general purpose subroutine that can draw not only a pentagon, but a polygon with any number of sides. (i.e. 3 sides for a triangle, 6 sides for a hexagon, 4 sides for a square, etc.)

If you look in the TurtleUtilsMod module, you will see a subroutine like this.

Sub DrawPolygon( nNumSides As Integer, nSideLength As Integer )

nFullCircle = GetFullCircleAngle()

nTurnAngle = nFullCircle / nNumSides

For i = 1 To nNumSides

LineForward( nSideLength )

Turn( nTurnAngle )

Next

End Sub

This routine takes two parameters: the number of sides, and the length of each side. The routine simply loops for the number of sides, and does a line, turn, line, turn, etc. to draw the polygon. Similar to the line,turn,line,turn that you wrote in your first routine above.

Notice how the routine gets the angle for a full circle (360 degrees), and then divides that by the number of sides to get the turn angle.

Since this subroutine is general purpose, it doesn't want to make assumptions that might be invalid. For instnace, it doesn't assume that a full circule would be 360. The 360 would only be true if we are measuring angles in degrees.

You can tell the turtle graphics module to measure angles differently, such as in radians, by calling SetFullCircleAngle( 2 * PI ).

No matter how you are measuring angles, calling the GetFullCircleAngle() routine will get you the angular measurement for a full circle. (In this case, 360 degrees.) By dividing that into fifths, or whatever the number of sides is in the polygon, we can calculate the angle to turn at each vertex of the polygon.

Since at the end of drawing the polygon, we make one final turn, the turtle ends up not only at its original position, but also pointed in its original direction. We'll take advantage of this fact in a moment.

To call the DrawPolygon() routine in TurtleUtilsMod, rewrite your code like this and then run it.

REM ***** BASIC *****

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

DrawPolygon( 5, 5000 )

ReleaseTurtleDoc()

End Sub

In fact, you could use any number for the length of the sides, and any number of sides. Try changing the number of sides to 7 to produce a polygon like that in Drawing 3 below.

Drawing 3 The result of calling DrawPolygon( 7, 5000 )

As the number of sides of the polygon increases, it begins to look more and more like a circle. As you increase the number of sides, you need to correspondingly decrease the length of each side

Since the turtle always starts out in the middle of the drawing, pointing to the right, your polygons will tend to appeare in the lower right corner of the document.

Earlier we mentioned that after drawing a polygon, the turtle ends up in its original position and direction. Imagine what would happen if we then turned the turtle a bit, and then repeated the same polygon again, perhaps with a different size polygon each time?

REM ***** BASIC *****

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

DrawPolygon( 6, 1000 )

Turn( 45 )

DrawPolygon( 6, 1100 )

Turn( 45 )

DrawPolygon( 6, 1200 )

Turn( 45 )

DrawPolygon( 6, 1300 )

Turn( 45 )

DrawPolygon( 6, 1400 )

Turn( 45 )

DrawPolygon( 6, 1500 )

ReleaseTurtleDoc()

End Sub

You would end up with something like what is pictured in Drawing 4 below.

Drawing 4 Example of what happens when drawing multiple polygons, turning a 45 degrees after each successive polygon.

This code is provided in the Examples library of this document, in the Multi_Polygons1 module. You can click the following button to run it.

Here is a more sophisticated multi-polygon example with the use of color.

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

' Draw think lines

SetTurtlePenWidth( 100 )

nHue = 0.0 ' Red hue

nSaturation = 0.6 ' Mostly saturated -- sort of pastels

nBrightness = 1.0 ' Full brightness

For i = 0 To 25

' Set the turtle's pen color

SetTurtlePenColor( HSB( nHue, nSaturation, nBrightness ) )

' Draw polygon in that color.

DrawPolygon( 6, 600 + (i * 60) )

' Get positioned for next polygon

Turn( 45 )

JumpForward( 100 + i * 275 )

' Adjust color for next polygon.

' Bump the hue by a certian amount.

nHue = nHue + 0.1

Next

ReleaseTurtleDoc()

End Sub

You can run the example by clicking here.

More detailed comments about the use of HSB color can be found in both the OOoLib's ColorUtils module, and in the Multi_Polygons2 code itself.

The functions provided by the turtle graphics module.

Now that you've written your first program, you might want to know the names of the routines in the turtle graphics module that can be called from your own programs.

If you look through the source of the TurtleMod module, you will find the following functions.

Rather than show the source of each function, only the calling interface of each function will be described here. If you are curious as to how the functions actually work, the source code is in the TurtleMod module for all to see.

:Lines beginning with a single quote mark (') are comments.

' Create a new draw document for Turtle Graphics.

' Initially...

' * the turtle is positioned at the center of the draw document.

' * the turtle is pointed to the east, right, or along positive X-axis

' * angles are measured in DEGREES

' * the pen is down, so any turtle movement will draw lines

Sub CreateTurtleDoc()

' Finish working with a Turtle Graphics drawing.

Sub ReleaseTurtleDoc()

' Turn the turtle so that it is pointing in a different direction.

' The turtle turns clockwise by whatever angle is specified.

Sub Turn( nAngle As Double )

' Point to an absolute angle.

' Zero is the original angle, pointing right, east or increasing X-axis.

Sub TurnTo( nAngle As Double )

' Return the direction the turtle is pointing.

' You could use this to capture the turtle's angle direction,

' draw some stuff, and then call TurnTo() to return

' the turtle to the angle you captured.

Function GetTurtleDirection() As Double

' Functions to move the pen up or down.

' Drawing only occurs when the pen is down.

' You can also inquire as to whether the pen is up or down.

' Return TRUE if the pen is down.

Function IsPenDown() As Boolean

' Return TRUE if the pen is up.

Function IsPenUp() As Boolean

' Force the pen up.

Sub PenUp()

' Calling this with no parameter forces the pen down,

' complementary to PenUp() above.

' Call with a boolean parameter TRUE or FALSE to

' move the pen Down or Up respectively.

Sub PenDown( Optional lPenDown As Boolean )

' Move the turtle some distance in its present direction.

' Whether a line is drawn depends on whether the pen is down.

' (Negative distances move backwards.)

' The distance is measured in 1/1000 of a centimeter. So a

' distance of 5000 would mean 5 cm.

Sub MoveForward( nDistance As Integer )

' Move the turtle to an absolute location on the page.

' The turtle remains pointed in the same direction it was.

' The parameters are measured in 1/1000 cm from the extreme

' upper left corner of the document.

Sub MoveTo( nNewX As Integer, nNewY As Integer )

' Move the turtle a relative amount along the X and Y axis.

' The turtle remains pointed in the same direction it was.

' The parameters are measured in 1/1000 cm from the present

' position of the turtle. Negative X values move to the left.

' Negative Y values move towards the top of the document.

Sub MoveBy( nDeltaX As Integer, nDeltaY As Integer )

' Move the turtle some distance in its present direction.

' The pen will be put down and a line will be drawn.

' The pen is always down after calling this.

' The distance is measured in 1/1000 of a centimeter. So a

' distance of 5000 would mean 5 cm.

Sub LineForward( nDistance As Integer )

' Draw a line from the current location to an absolute location.

' The turtle remains pointed in the same direction it was.

' The pen is always down after calling this.

' The parameters are measured in 1/1000 cm from the extreme

' upper left corner of the document.

Sub LineTo( nNewX As Integer, nNewY As Integer )

' Draw line by a relative amount along the X and Y axis.

' The turtle remains pointed in the same direction it was.

' The pen is always down after calling this.

' The parameters are measured in 1/1000 cm from the present

' position of the turtle. Negative X values move to the left.

' Negative Y values move towards the top of the document.

Sub LineBy( nDeltaX As Integer, nDeltaY As Integer )

' Move the turtle some distance in its present direction.

' The pen will be put up and no line will be drawn.

' The pen is always up after calling this.

' The distance is measured in 1/1000 of a centimeter. So a

' distance of 5000 would mean 5 cm.

Sub JumpForward( nDistance As Integer )

' Move the turtle to an absolute location.

' The turtle remains pointed in the same direction it was.

' The pen is always up after calling this.

' The parameters are measured in 1/1000 cm from the extreme

' upper left corner of the document.

Sub JumpTo( nNewX As Integer, nNewY As Integer )

' Move the turtle a relative amount.

' The turtle remains pointed in the same direction it was.

' The pen is always up after calling this.

' The parameters are measured in 1/1000 cm from the present

' position of the turtle. Negative X values move to the left.

' Negative Y values move towards the top of the document.

Sub JumpBy( nDeltaX As Integer, nDeltaY As Integer )

' Get the turtle's X position.

' The value returned represents 1/000ths of a cm

' from the extreme left edge of the document.

Function GetTurtleXPosition() As Integer

' Get the turtle's Y position.

' The value returned represents 1/000ths of a cm

' from the extreme top edge of the document.

Function GetTurtleYPosition() As Integer

' Set the color of the turtle's pen.

' When the turtle is created, its pen is initially black.

Sub SetTurtlePenColor( nColor )

' Get the color of the turtle's pen.

Function GetTurtlePenColor()

' Set the width of the turtle's pen.

' When the turtle is created, its pen width is initially zero,

' which means the thinnest possible line.

Sub SetTurtlePenWidth( nPenWidth )

' Get the width of the turtle's pen.

Function GetTurtlePenWidth()

' Change what units angles are measured in.

' If you wanted to measure angles in radians,

' you could simply call...

'	SetFullCircleAngle( 2 * PI )

' to change angular measurements to radians.

' To convert back to using degrees for angular measurements,

' simply call...

'	SetFullCircleAngle( 360 )

' For gradians...

'	SetFullCircleAngle( 400 )

' You can measure angles in any arbitrary units you wish.

' For instance, to measure angles as fractions of a circle,

' just specify 1.0 as the full circle measurement.

'	setFullCircleAngle( 1.0 )

' A right angle would now be measured as 0.25.

' A full turnaround to the opposite direction would be measured as 0.5.

' A full circle would be measured as 1.0.

Sub SetFullCircleAngle( nFullCircleAngle As Integer )

' Return the angular measurement for a full circle.

' This function is complementary to SetFullCircleAngle().

Function GetFullCircleAngle() As Double

' A utility function.

' No matter what units the turtle is using for angular measurement,

' this function converts an angle into radians and returns it.

Function ConvertAngleToRadians( nAngle As Double ) As Double

From your own programs you can call any of the above functions to manipulate the turtle. By consulting OpenOffice.org's built in help (see the Help menu) you can see the proper syntax for Basic, variables, subroutines, loops, etc. Combined with these easy to use turtle graphics routines, you should now be able to program simple (or complex) drawings without having to learn UNO, UML, or the OpenOffice.org object model. (Not that I would discourage anyone from learning these things!)

You must always call CreateTurtleDoc() first and ReleaseTurtleDoc() last. Because of limitations in StarBasic you can only have one turtle graphics document active at once. (If StarBasic had allowed me to define new classes, I would have encapsulated each turtle into its own object and your program could create several active turtles concurrently, or even seperate turtle drawing documents concurrently.)

To turn the turtle you can either call Turn() or TurnTo(). Turn() turns the turtle clockwise by a specified angle. TurnTo() always turns the turtle to an absolute angle. You can always return the turtle to its origianl direction (pointing east or right or increasing X-axis direction) by calling TurnTo( 0 ).

Calling GetTurtleDirection() will return to you the angle the turtle is currently pointed. You could use this to capture the turtle's current direction. Draw something, and then later do a TurnTo() to point the turtle in the original direction you earlier captured.

Calling IsPenDown() or IsPenUp() will tell you if the pen is up or down You can take action based on this by putting the call in an If statement. For example...

If IsPenDown() Then

...take some action...

EndIf

The function MoveForward() moves the turtle forward by a specified amount. The units are measured in 1000'ths of centimeters. So moving forward by 5000 means to move forward by 5 cm.

The function MoveBy( x, y ) allows you to move the turtle by a certain amount on the x and y axis. This is a move relative to the present position. The turtle is left pointing in the same direction it was previously pointing.

The function MoveTo( x, y ) allows you to move the turtle to any absolute position. Coordinate 0,0 is the top left of the entire drawing.

All three of the above move functions cause turtle motion to occur. A line is drawn if the pen is down. No line is drawn if the pen is up.

The functions LineForward(), LineBy(), and LineTo() are similar to the three “move” functions. The difference is that these first put the pen down before turtle movement occurs. The pen will always be down after a call to any of these functions.

Similarly, the three “jump” functions JumpForward(), JumpBy(), and JumpTo() first put the pen up before turtle movement occurs. The pen will always be up after a call to any of these functions.

You can call the two functions GetTurtleXPosition() and GetTurtleYPosition() to return the turtle's current location on the page. This could be useful to capture the turtle's current location, draw something, and then move the turtle back to the original location you captured earlier.

The function SetFullCircleAngle() allows you to change the measurement of angular units. For example, to work in degrees (which is the default) you could call SetFullCircleAngle( 360 ) which means that a full circle is 360 of whatever units you are using. If you wanted to measure angles in radians, then you would write SetFullCircleAngle( 2 * PI ), since there are two-pi radians in a full circle. Similarly calling SetFullCircleAngle( 400 ) would set angular units to Gradians.

You can make up your own angular units. Calling SetFullCircleAngle( 1.0 ) would mean that angles are measured in fractions of a circle. So turning by 0.25 would be a right angle turn clockwise. Turning by 0.5 would turn to point in the opposite direction. (i.e. 180 degrees)

Calling GetFullCircleAngle() will return what angle makes up a full circle. If you are trying to write subroutines that work in any unit of angular measure, then you should first call GetFullCircleAngle() and then work in fractions of a circle. Don't just hardcode numbers like 360 for a full circle, 90 for a right angle, etc. Use GetFullCircleAngle() / 4 instead of 90 to represent a right angle.

Calling ConvertAngleToRadians() will convert any angle, in the current unit of measurement, into radians. This is useful so you can call functions such as sin() or cos() which want angles measured in radians.

How to draw a star

Now that you've learned how to draw simple polygons using turtle graphics, let's draw something more complex. We're going to examine how the stars in Drawing 1 on page 6 were created.

A star can be drawn inside of any enclosing polygon. The concept is to interconnect vertexes of the polygon with lines. Each line connects one vertex to another vertex. If the line simply connected each vertex directly to the next adjacent vertex, then you would have a polygon, as in Drawing 5A.

Vertex 1 Vertex 2 Vertex 4 Vertex 5 Vertex 3 Vertex 1 Vertex 2 Vertex 4 Vertex 5 Vertex 3 A B Drawing 5 If you connect each vertex to the next vertex, as in A, then you have a polygon. If instead each vertex is connected to the 2nd vertex away, then you have a star as in B.

Intead, if a line connects from a vertex to the next vertex two positions ahead, you end up with a star as in Drawing 5B. Vertex 1 connects to Vertex 3 and then Vertex 5, skipping ahead by 2 each time. This same pattern holds true even if the number of vertexes or sides is not five. For instance, a nine sided polygon is shown in Drawing 6A. A nine pointed star, where each vertex is connected 4 vertexes ahead, is pictured in Drawing 6B.

B A Drawing 6 A nine sided polygon (A), and a nine pointed star where each vertex connects to the vertex 4 vertexes ahead of it (B).

The easiest way to draw a star is to first draw an imaginary polygon and collect the locations of all of its vertexes. If you look inside the module TurtleUtilsMod, you will see the CollectPolygonPoints() function which does this.

' Collect the points of a polygon.

' Works like drawPolygon, but no polygon is drawn.

' The LineForward() operation is replaced by JumpForward().

' Each point visited is gathered into the two arrays xs() and ys(),

' both of which must be dimensioned to hold numSides elements.

Sub CollectPolygonPoints( nNumSides As Long, nSideLength As Long,_

xs() As Long ,_

ys() As Long )

nFullCircle = GetFullCircleAngle()

nTurnAngle = nFullCircle / nNumSides

For i = 1 To nNumSides

xs(i) = GetTurtleXPosition()

ys(i) = GetTurtleYPosition()

JumpForward( nSideLength )

Turn( nTurnAngle )

Next

End Sub

This routine is called by passing it both the number of sides for the polygon, and the length of each side very similarly to the DrawPolygon() routine we examined earlier. Similarly to DrawPolygon(), this routine traces the steps of a polygon, but doesn't actually draw it. The LineForward() call is replaced with JumpForward(). Prior to each jump, the current turtle position is collected into a pair of arrays. Like DrawPolygon(), the turtle ends up at its initial position and direction.

For the third and fourth parameters you must pass in two arrays. Both arrays must have been dimensioned to equal the number of sides in nNumSides. When the CollectPolygonPoints() returns, the two arrays will have been filled out with the x and y coordinates of each vertex of the polygon.

Now that all the points of the enclosing polygon are known, we can draw a line from the first point to one of the other points, skipping several points ahead each time, thus forming a star. The routine InscribeStar() does this.

' Draw a star inside of the polygon that would be drawn if you had

' called DrawPolygon with the same parameters.

' The star is drawn by drawing a line between points of the polyggon.

' A line is drawn from one point to another point which is nSkipPoints

' further along the polygon. For example, if you pass 3 for nSkipPoints,

' then a line will be drawn that connects every third vertex along the

' ploygon's perimeter -- thus inscribing a "star" inside the polygon.

' If you pass 1 for skipPoints, then this routine behaves EXACTLY like

' DrawPolygon().

Sub InscribeStar( nNumSides As Long, nSideLength As Long,_

Optional nSkipPoints As Long )

If IsMissing( nSkipPoints ) Then

nSkipPoints = 2

EndIf

Dim xs( nNumSides ) As Long

Dim ys( nNumSides ) As Long

CollectPolygonPoints( nNumSides, nSideLength, xs(), ys() )

Dim visited( nNumSides ) As Boolean

nNumPointsVisited = 0

nPoint = 1

While nNumPointsVisited < nNumSides

' Find the next un-visited point.

While visited( nPoint )

nPoint = nPoint + 1

WEnd

' Start at this point

JumpTo( xs( nPoint ), ys( nPoint ) )

' Inscribe a star.

While NOT visited( nPoint )

' This point is now visited

visited( nPoint ) = TRUE

nNumPointsVisited = nNumPointsVisited + 1

' Move to next point.

nPoint = nPoint + nSkipPoints

nPoint = ((nPoint - 1) Mod nNumSides) + 1

LineTo( xs( nPoint ), ys( nPoint ) )

WEnd

WEnd

' Return to original location.

JumpTo( xs( 1 ), ys( 1 ) )

End Sub

InscribeStar() first collects the points of the polygon into two dimensioned arrays xs and ys. Then it sets up a variable and an array to keep track of how many vertexes have been visited, and which ones. The drawing begins from point 1. It first finds an unvisited point, which would be point 1. Jump to this point. Then begin drawing lines from this point to subsequent points, skipping ahead by several points to form a star. When we finally encounter a point that has previously been visited, the drawing stops. We may not yet have visited all of the points. See the triangle in Drawing 7.

Vertex 1 Drawing 7 A nine sided polygon with a star inside it. The lines of the star each skip three points ahead. After the first complete shape is drawn, a triangle, the star is still not complete.

In Drawing 7, after the first shape is drawn, the star is not yet complete. The first shape is only a triangle. There are still unvisited points. InscribeStar() finds the next unvisited point and repeats the proces of drawing a triangle until all points have been visited.

You can create a new module, similarly to how you created the Pentagon1 module earlier, and write code to draw your own stars like this.

REM ***** BASIC *****

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

' First row of stars

JumpTo( 4000, 2000 )

InscribeStar( 9, 2000, 1 )

JumpTo( 13000, 2000 )

InscribeStar( 9, 2000, 2 )

' Second row of stars

JumpTo( 4000, 9000 )

InscribeStar( 9, 2000, 3 )

JumpTo( 13000, 9000 )

InscribeStar( 9, 2000, 4 )

ReleaseTurtleDoc()

End Sub

In this example, four stars are drawn. Each is a nine point star whose sides are 2000 units (2 cm) in length. What differs for each star is how many vertexes are skipped for the interconnections. The output from this routine is pictured in Drawing 8.

Drawing 8 Four nine point stars. The difference in ech one is how many vertexes are skipped for each interconnection.

A Tool for drawing Stars and Ploygons

In this document, you can find another library called PolygonStarBuilder. This library provides a module and a dialog box which act as a tool for building stars or polygons.

To try out the tool, click this button.

A dialog box will appear which has the parameters for your star or polygon. See Illustration 7.

You can set the check boxes to draw either a polygon, a star, or both. If you draw a star, you can indicate how many points ahead each line in the star should skip.

If you leave the radius at the default 10 cm, the figure drawn will mostly fill the width of a standard US Letter page.

When you click the Create button, a new drawing will be created.

Try different parameters.

For instance, if you use 90 sides, and set vertexes to skip to 23, then you will get the figure shown in Drawing 9.

Illustration 7 The Star and Polygon builder tool

Drawing 9 The figure obtained by drawing both a star and polygon with 90 sides, and skipping 23 vertexes for each interconnection of the star.

Drawing Spirals

Drawing a spiral using turtle graphics is very much like drawing a polygon. You repeatedly move, turn, move, turn, etc. If you move the same amount each time, you eventually reach your starting point, forming a polygon or star. If instead, you move a little bit further each time you turn, you do not return to your starting point, but end up spiraling forever outward.

Try writing a program like this.

Sub Main

' Make sure the TurtleGraphics library of modules is loaded.

BasicLibraries.LoadLibrary( "TurtleGraphics" )

CreateTurtleDoc()

' These parameters control the spiral.

nLen = 50

nLenMultiplier = 1.01

nTurnAngle = 8

nNumTimes = 300

' This loop draws the spiral based on the parameters.

for i = 1 to nNumTimes

MoveForward( nLen )

Turn( nTurnAngle )

nLen = nLen * nLenMultiplier

next i

ReleaseTurtleDoc()

End Sub

The program contains four parameters that control the appearance of the spiral. The spiral is produced by looping 300 times (nNumTimes). On each loop, we move forward by nLen, which starts out as 50/1000 cm; followed by turning 8 degrees (nTurnAngle). Each time, we lengthen the distance we move by nLenMultiplier which is 1.01.

If you want to see the results of running this program, then click the button below.

Here is an even colder spiral in color.

Check out the code to see how this works.

Lower level machinery

This OpenOffice.org Writer document (that you are reading), contains attached macros that you can access from the menu command Tools -> Macro. This document contains several libraries. Earlier you saw that one of the libraries is named TurtleGraphics. Within the TurtleGraphics library are modules, TurtleMod and TurtleUtilsMod which make it easy for you to program drawings.

The turtle graphics implementation is built upon some lower level machinery.

There is a library called OOoLib. This library contains modules to make programming OpenOffice.org macros easier. This library, in particular, is growing constantly. (That is, the author is planning on expanding it greatly.)

The library OOoLib contains a module named DrawMod. The DrawMod module contains functions useful for manipulating OpenOffice.org Draw documents.

The following information is useful only if you are interested in exploring a level deeper than the simple turtle graphics api provided by TurtleMod and its utility functions in TurtleUtilsMod.

The library OOoLib will eventually contain modules for manipulating other office document types as well as drawings. (For instance, a module named WriterMod might have high-level useful routines for manipulating Writer documents.)

The functions in DrawMod are as follows. Lines beginning with a single quote (') are comments. Just the function signatures are presented here. If you are curious about how a function works, the source code is there in the module for all to see.

Function MakeNewDrawDoc() As Object

Function MakePoint( x As Long, y As Long ) As com.sun.star.awt.Point

Function MakeSize( width As Long, height As Long ) As com.sun.star.awt.Size

Function MakeRectangleShape( oDoc As Object,_

Optional position As com.sun.star.awt.Point,_

Optional size As com.sun.star.awt.Size )

Function MakeEllipseShape( oDoc As Object,_

Optional position As com.sun.star.awt.Point,_

Optional size As com.sun.star.awt.Size )

Function MakeTextShape( oDoc As Object,_

Optional position As com.sun.star.awt.Point,_

Optional size As com.sun.star.awt.Size )

Function MakeLineShape( oDoc As Object,_

Optional position As com.sun.star.awt.Point,_

Optional size As com.sun.star.awt.Size )

Function MakeShape( oDoc As Object, cShapeClassName As String,_

Optional position As com.sun.star.awt.Point,_

Optional size As com.sun.star.awt.Size )

The function MakeNewDrawDoc() creates a new drawing document which is returned as the function result.

The functions MakePoint() and MakeSize() create a point object or a size object. Both of these are convenience functions to make it easier to read and write your code.

The four similar functions MakeRectangleShape(), MakeEllipseShape(), MakeTextShape(), and MakeLineShape() create and return a shape object. Once you have a shape object, you can manipulate its text, its fill color, its line color and style, and other properties. (More about this shortly.)

Finally, the function MakeShape() is a lower level function called by the four functions just described. You probably don't want to call MakeShape() directly unless you need to create a shape that can not be created by one of the sugar-coated shape functions previously described. If you call MakeShape() you must pass the class name of the shape to create. (See the source code to, for example, MakeRectangleShape() for an example of how MakeShape() is called.)

So how do you put these functions together into a coherent program?

Here is an example.

Sub Main

' Make sure the OOoLib library of modules are loaded.

' You only need this line if your module is NOT

' a module in the OOoLib library.

BasicLibraries.LoadLibrary( "OOoLib" )

' Create a new Draw document

Dim oDrawDoc As Object

oDrawDoc = MakeNewDrawDoc()

' Get the first page

Dim oPage As Object

oPage = oDrawDoc.drawPages( 0 )

' Draw some shapes

Dim oShape As Object

Dim oSize As Object

oSize = MakeSize( 1000, 2000 )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 1000, 1000 ), oSize )

oShape.FillColor = RGB( 255, 0, 0 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 2200, 1000 ), oSize )

oShape.FillColor = RGB( 255, 127, 0 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 3400, 1000 ), oSize )

oShape.FillColor = RGB( 255, 255, 0 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 4600, 1000 ), oSize )

oShape.FillColor = RGB( 127, 255, 63 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 5800, 1000 ), oSize )

oShape.FillColor = RGB( 0, 255, 0 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 7000, 1000 ), oSize )

oShape.FillColor = RGB( 0, 255, 127 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 8200, 1000 ), oSize )

oShape.FillColor = RGB( 0, 255, 255 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 9400, 1000 ), oSize )

oShape.FillColor = RGB( 0, 127, 255 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 10600, 1000 ), oSize )

oShape.FillColor = RGB( 0, 0, 255 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 11800, 1000 ), oSize )

oShape.FillColor = RGB( 127, 0, 255 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 13000, 1000 ), oSize )

oShape.FillColor = RGB( 255, 0, 255 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 14200, 1000 ), oSize )

oShape.FillColor = RGB( 255, 0, 127 )

oPage.add( oShape )

oShape = MakeRectangleShape( oDrawDoc, MakePoint( 15400, 1000 ), oSize )

oShape.FillColor = RGB( 255, 0, 0 )

oPage.add( oShape )

End Sub

This routine is present in the OOoLib library in module DrawMod, as the subroutine DrawModTest(). You can simply run the main entry point in DrawMod to see this test program run.

As you can see, the program creates a new draw document. It then obtains the first page of the draw document. And then it proceeds to create rectangle shapes of specified size, position and fillcolor and add each one to the page.

The functions in OOoLib are conveniences for programming OpenOffice.org's api directly. If you are more interested in this you should visit http://api.openoffice.org and study the developer's guide and other documentation. The StarOffice Programmer's Tutorial is particularly helpful.

Other examples in development

This document is an evolving project.

In fact, the growth of this document may require that it be split into multiple documents in time.

Here are some other program examples that are being developed.

The accompanying text to explain these examples is not written yet.

Copyright and License Information

This document and the code contained within are Copyright © 2003 by Danny Brewer.

This document and the code contained within it are licensed for modification or distribution under the terms of either the Open Content License or the Gnu Lesser General Public License (LGPL). If you wish to modify or distribute this document or the code contained or embedded in this document, you are hereby granted a license to do so under either the terms of either the Open Content License or the LGPL.

OpenContent License (OPL)
Version 1.0, July 14, 1998.
This document outlines the principles underlying the OpenContent (OC) movement and may be redistributed provided it remains unaltered. For legal purposes, this document is the license under which OpenContent is made available for use.
The original version of this document may be found at http://opencontent.org/opl.shtml
LICENSE
Terms and Conditions for Copying, Distributing, and Modifying
Items other than copying, distributing, and modifying the Content with which this license was distributed (such as using etc.) are outside the scope of this license.
1. You may copy and distribute exact replicas of the OpenContent (OC) as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the OC a copy of this License along with the OC. You may at your option charge a fee for the media and/or handling involved in creating a unique copy of the OC for use offline, you may at your option offer instructional support for the OC in exchange for a fee, or you may at your option offer warranty in exchange for a fee. You may not charge a fee for the OC itself. You may not charge a fee for the sole service of providing access to and/or use of the OC via a network (e.g. the Internet), whether it be via the world wide web, FTP, or any other method.
2. You may modify your copy or copies of the OpenContent or any portion of it, thus forming works based on the Content, and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified content to carry prominent notices stating that you changed it, the exact nature and content of the changes, and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the OC or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License, unless otherwise permitted under applicable Fair Use law.
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the OC, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the OC, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Exceptions are made to this requirement to release modified works free of charge under this license only in compliance with Fair Use law where applicable.
3. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to copy, distribute or modify the OC. These actions are prohibited by law if you do not accept this License. Therefore, by distributing or translating the OC, or by deriving works herefrom, you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or translating the OC.
NO WARRANTY
4. BECAUSE THE OPENCONTENT (OC) IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE OC, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE OC "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK OF USE OF THE OC IS WITH YOU. SHOULD THE OC PROVE FAULTY, INACCURATE, OR OTHERWISE UNACCEPTABLE YOU ASSUME THE COST OF ALL NECESSARY REPAIR OR CORRECTION.
5. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MIRROR AND/OR REDISTRIBUTE THE OC AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE OC, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

GNU LESSER GENERAL PUBLIC LICENSE

Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.

59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.]

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software—to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.

To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.

Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.

When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.

We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.

For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.

Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) The modified work must itself be a software library.

b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.

c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.

d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.

(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.

Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.

If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:

a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)

b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.

c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.

d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.

e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.

7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:

a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.

b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.

11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

Danny Brewer

2003-02-28T10:44:46