racket/collects/graphics/doc/graphics.scrbl

1110 lines
35 KiB
Racket

#lang scribble/doc
@(require scribble/manual
(for-label scheme/base
scheme/contract
"../graphics.ss"))
@title{Legacy Graphics Library}
@table-of-contents[]
@section[#:style 'toc]{Viewport Graphics}
The viewport graphics library is a relatively simple toolbox of
graphics commands. The library is not very powerful; it is intended as
a simplified alternative to @schememodname[scheme/gui]'s full
graphical toolbox.
The graphics library originated as SIXlib, a library of X Windows
commands available within Chez Scheme at Rice University. The
functionality of that library has been reproduced (with backward
compatibility) in this version.
@defmodule[graphics/graphics]
@local-table-of-contents[]
@; ----------------------------------------------------------------------
@subsection{Basic Commands}
@defproc[(open-graphics) void?]{
Initializes the library's graphics routines. It must be called before
any other graphics operations.}
@defproc[(close-graphics) void?]{
Closes all of the windows. Until @scheme[open-graphics] is called
again, no graphics routines will work.}
@defproc*[([(open-viewport [name string?]
[horiz exact-nonnegative-integer?]
[vert exact-nonnegative-integer?])
viewport?]
[(open-viewport [name string?]
[dimensions posn?])
viewport?])]{
Creates a new window called @scheme[name]. The window is
@scheme[horiz] pixels wide and @scheme[vert] pixels high. For
backward compatibility, a single @scheme[posn] value can be submitted
in the place of @scheme[horiz] and @scheme[vert]. The result is a
viewport descriptor.}
@defproc*[([(open-pixmap [name string?]
[horiz exact-nonnegative-integer?]
[vert exact-nonnegative-integer?])
viewport?]
[(open-pixmap [name string?]
[dimensions posn?])
viewport?])]{
Like @scheme[open-viewport], but the resulting viewport is not
displayed on the screen. Offscreen pixmaps are useful for executing a
sequence of drawing commands and displaying them all at once with
@scheme[copy-viewport].
Offscreen pixmaps are also useful in conjunction with viewport->snip
(see below). This allows functions to compute with graphical objects
and view the graphics when results are returned to the interactions
window.}
@defproc[(close-viewport [viewport viewport?]) void?]{
Removes the viewport from the screen and makes subsequent operations
dealing with the viewport illegal.}
@defproc[(viewport? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a viewport (i.e., a destination
for drawing), @scheme[#f] otherwise.}
@; ----------------------------------------------------------------------
@subsection{Position Operations}
A position is a pixel location within a viewport. The upper-left
corner is pixel @math{(0, 0)}, and positions increase to the left and
down.
@defstruct[posn ([x real?][y real?])]{
Represents a positions.}
@defproc[((get-pixel [viewport viewport?]) [p posn?]) (one-of/c 0 1)]{
Returns the color of the pixel at position @scheme[p] in
@scheme[viewport]; @scheme[0] denotes white and @scheme[1] denotes not
white.}
@defproc[((get-color-pixel [viewport viewport?]) [p posn?]) rgb?]{
Returns an @scheme[rgb] value for color of the pixel at position
@scheme[p] in @scheme[viewport].}
@defproc[((test-pixel [viewport viewport?]) [color (or/c (integer-in 0 299)
string?
rgb?)])
rgb?]{
Returns the color that will actually be used if @scheme[color] is used
to draw.}
@; ----------------------------------------------------------------------
@subsection{Color Operations}
A color can be represented in three ways: as a color index (an integer
in 0 to 299, inclusive), as a color name string, or as a @scheme[rgb]
value. All drawing functions which take a color argument accept colors
in any form. An @scheme[rgb] value is assigned to an index with
@scheme[change-color].
@defstruct[rgb ([red (real-in 0 1)][green (real-in 0 1)][blue (real-in 0 1)])]{
Takes three values in the range 0 (dark) to 1 (bright) and returns an
@scheme[rgb] (a color).}
@defproc[(change-color [index (integer-in 0 299)] [rgb rgb?])
void?]{
Changes the color at @scheme[index] in the color table to the
color specified in @scheme[rgb]. Only the first twenty-one indices
are initialized; a color index should not be used until it has
been initialized.}
@defproc[(default-display-is-color?) boolean?]{
Returns @scheme[#t] if the default display screen for viewports is in
color or @scheme[#f] otherwise.}
@; ----------------------------------------------------------------------
@subsection{Draw, Clear, and Flip Operations}
The following are the basic graphics operations for drawing to a
viewport. Each function takes a viewport as its argument and returns
a function operating within that viewport. Further arguments, if any,
are curried. For example, @scheme[(draw-line _viewport)] returns a
function, that can then be applied to the proper arguments to draw a
line in the viewport corresponding to viewport descriptor
@scheme[_viewport].
In general, @schemeidfont{draw-} functions make pixels black or
colored, @schemeidfont{clear-} functions make them white, and
@schemeidfont{flip-} commands @deftech{invert} pixels (which makes
black white, white black, and is otherwise ill-defined).
@subsubsection{Viewports}
@defproc[((draw-viewport [viewport viewport?])
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Colors the entire contents of @scheme[viewport] with @scheme[color].}
@defproc[((clear-viewport [viewport viewport?]))
void?]{
Whitens the entire contents of @scheme[viewport].}
@defproc[((flip-viewport [viewport viewport?]))
void?]{
@tech{Inverts} the entire contents of @scheme[viewport].}
@defproc[(copy-viewport [source viewport?] [dest viewport?])
void?]{
Copies the content of @scheme[source] into @scheme[dest].}
@; ----------------------------------------
@subsubsection{Pixels}
@defproc[((draw-pixel [viewport viewport?])
[p posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Colors the pixel in @scheme[viewport] at @scheme[p].}
@defproc[((clear-pixel [viewport viewport?])
[p posn?])
void?]{
Whitens the pixel in @scheme[viewport] at @scheme[p].}
@defproc[((flip-pixel [viewport viewport?])
[p posn?])
void?]{
@tech{Inverts} the pixel in @scheme[viewport] at @scheme[p].}
@; ----------------------------------------
@subsubsection{Lines}
@defproc[((draw-line [viewport viewport?])
[p1 posn?]
[p2 posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a line in @scheme[viewport] connecting positions @scheme[p1] and
@scheme[p2].}
@defproc[((clear-line [viewport viewport?])
[p1 posn?]
[p2 posn?])
void?]{
Whitens a line in @scheme[viewport] connecting positions @scheme[p1]
and @scheme[p2].}
@defproc[((flip-line [viewport viewport?])
[p1 posn?]
[p2 posn?])
void?]{
@tech{Inverts} a line in @scheme[viewport] connecting positions
@scheme[p1] and @scheme[p2].}
@; ----------------------------------------
@subsubsection{Rectangles}
@defproc[((draw-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a rectangle border in the @scheme[viewport] with the top-left of
the rectangle at the position @scheme[p] and with sides @scheme[width]
across and @scheme[height] tall.}
@defproc[((clear-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
Whitens a rectangle border in the @scheme[viewport], analogous to
@scheme[draw-rectangle].}
@defproc[((flip-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
@tech{Inverts} a rectangle border in the @scheme[viewport], analogous
to @scheme[draw-rectangle].}
@defproc[((draw-solid-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a solid rectangle in the @scheme[viewport] with the top-left of
the rectangle at the position @scheme[p] and with sides @scheme[width]
across and @scheme[height] tall.}
@defproc[((clear-solid-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
Whitens a rectangle border in the @scheme[viewport], analogous to
@scheme[draw-solid-rectangle].}
@defproc[((flip-solid-rectangle [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
@tech{Inverts} a rectangle border in the @scheme[viewport], analogous
to @scheme[draw-solid-rectangle].}
@; ----------------------------------------
@subsubsection{Ellipses}
@defproc[((draw-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a ellipse border in the @scheme[viewport]. The ellipse is
inscribed with a rectangle whose top-left is at position @scheme[p]
and with sides @scheme[width] across and @scheme[height] tall.}
@defproc[((clear-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
Whitens a ellipse border in the @scheme[viewport], analogous to
@scheme[draw-ellipse].}
@defproc[((flip-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
@tech{Inverts} a ellipse border in the @scheme[viewport], analogous
to @scheme[draw-ellipse].}
@defproc[((draw-solid-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a solid ellipse in the @scheme[viewport]. The ellipse is
inscribed with a rectangle whose top-left is at position @scheme[p]
and with sides @scheme[width] across and @scheme[height] tall.}
@defproc[((clear-solid-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
Whitens a ellipse border in the @scheme[viewport], analogous to
@scheme[draw-solid-ellipse].}
@defproc[((flip-solid-ellipse [viewport viewport?])
[p posn?]
[width (and/c real? (not/c negative?))]
[height (and/c real? (not/c negative?))])
void?]{
@tech{Inverts} a ellipse border in the @scheme[viewport], analogous
to @scheme[draw-solid-ellipse].}
@; ----------------------------------------
@subsubsection{Polygons}
@defproc[((draw-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a polygon border in @scheme[viewport] using @scheme[points] for
the polygon vertices and @scheme[offset] as an offset added to all
points.}
@defproc[((clear-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?])
void?]{
Whitens a polygon border in @scheme[viewport], analogous to
@scheme[draw-polygon].}
@defproc[((flip-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?])
void?]{
@tech{Inverts} a polygon border in @scheme[viewport], analogous to
@scheme[draw-polygon].}
@defproc[((draw-solid-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a solid polygon in @scheme[viewport] using @scheme[points] for
the polygon vertices and @scheme[offset] as an offset added to all
points.}
@defproc[((clear-solid-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?])
void?]{
Whitens a polygon border in @scheme[viewport], analogous to
@scheme[draw-solid-polygon].}
@defproc[((flip-solid-polygon [viewport viewport?])
[points (listof posn?)]
[offset posn?])
void?]{
@tech{Inverts} a polygon border in @scheme[viewport], analogous to
@scheme[draw-solid-polygon].}
@; ----------------------------------------
@subsubsection{Strings}
@defproc[((draw-string [viewport viewport?])
[p posn?]
[str string?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a string at a specified location in the @scheme[viewport].
The lower left of the string begins at @scheme[p].}
@defproc[((clear-string [viewport viewport?])
[p posn?]
[str string?])
void?]{
Whitens a string at a specified location in the @scheme[viewport].
The lower left of the string begins at @scheme[p].}
@defproc[((flip-string [viewport viewport?])
[p posn?]
[str string?])
void?]{
@tech{Inverts} a string at a specified location in the
@scheme[viewport]. The lower left of the string begins at
@scheme[p].}
@; ----------------------------------------
@subsubsection{Pixmaps}
@defproc[(((draw-pixmap-posn [file path-string?]
[type (one-of/c 'unknown 'unknown/mask
'gif 'gif/mask 'jpeg 'png 'png/mask
'xbm 'xpm 'bmp 'pict)
'unknown/mask])
[viewport viewport?])
[p posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Draws a pixmap into @scheme[viewport] with its upper left corner at
position @scheme[p]. If @scheme[type] is @scheme['unknown] or
@scheme['unknown/mask], then the content of the file is examined to
determine the type. All formats are supported on all platforms,
except @scheme['pict] which is only supported under Mac OS X. The
@scheme['gif/mask], @scheme['png/mask], and @scheme['unknown/mask]
types draw the bitmap with a transparent background if
@scheme[filename] refers to a GIF/PNG file with a transparent
background.
The argument @scheme[color] is only used when the loaded pixmap is
monochrome. In that case, the color is used instead of black in the
drawn image.}
@defproc[((draw-pixmap [viewport viewport?])
[file path-string?]
[p posn?]
[color (or/c (integer-in 0 299)
string?
rgb?)
"black"])
void?]{
Equivalent to @scheme[(((draw-pixmap-posn file) viewport) p color)].}
@defproc[((save-pixmap [viewport viewport?])
[file path-string?]
[type (one-of/c 'gif 'jpeg 'png 'xbm 'xpm 'bmp) 'xpm])
void?]{
Saves the current content of @scheme[viewport] to @scheme[file].
The @scheme[type] argument determines the kind of file that is written.}
@; ----------------------------------------
@;{
@subsection{World Operations}
Every canvas comes with an associated world. A client program can set the world,
start the world's clock, stop the world's clock, and deal with tick events (the
clock ticks) and keyboard inputs (keyevents).
@itemize{
@item{\Function{init-world}
@scheme[((init-world @scheme[viewport]) X)]
Takes a viewport descriptor. It returns a function whose input becomes the
initial value of the world associated with this canvas.}
@item{\Function{set-on-tick-event}
@scheme[((set-on-tick-event @scheme[viewport]) number @scheme[unary procedure])]
Takes a viewport descriptor. It returns a function whose first input is a
number and the second one is a function from worlds to worlds. The number
determines how frequently the clock ticks. The given function is called for
every clock tick on the current world; the result becomes the next world.}
@item{\Function{stop-tick}
@scheme[((stop-tick @scheme[viewport]))]
Takes a viewport descriptor. It returns a function of no arguments that can
stop the clock for this canvas's world.}
@item{\Function{set-on-key-event}
@scheme[((set-on-key-event @scheme[viewport]) unary-procedure)]
Takes a viewport descriptor. It returns a function whose input becomes the
keyevent callback function. This callback consumes the latest keyevent and the
current world and a keyevent; it produces the next world.}
}
@subsection{Miscellaneous Operations}
@itemize{
@item{\Function{get-string-size}
@scheme[((get-string-size @scheme[viewport]) string)]
Takes a viewport descriptor. It returns a
function that returns the size of a string as a list of two numbers:
the width and height.}
@item{\Function{viewport->snip}
@scheme[(viewport->snip @scheme[viewport])]
Takes a viewport descriptor. It returns an
object that can be inserted into an editor buffer to display the
current image in the viewport. (Subsequent drawing to the viewport
does not affect the snip's image.)
When snips are the results of computations in the interactions window, DrScheme will print show the contents of the viewport, right in the interactions window.}
@item{\Function{viewport-dc}
@scheme[(viewport-dc @scheme[viewport])]
Takes a viewport descriptor. It returns an
object that can be used with the primitive MrEd toolbox
functions to draw into the viewport's on-screen representation
(if any). Mirror all such drawing to the result of
@scheme[(viewport-offscreen-dc @scheme[viewport])], too.}
@item{\Function{viewport-offscreen-dc}
@scheme[(viewport-offscreen-dc @scheme[viewport])]
Takes a viewport descriptor. It returns an
object that can be used with the primitive MrEd toolbox
functions to draw into the viewport's off-screen representation.
Mirror all such drawing to the result of
@scheme[(viewport-dc @scheme[viewport])], too.}
}
@subsection{An Example}
@schemeblock[
(open-graphics)
;; nothing appears to happen, but the library is initialized...
(define w (open-viewport "practice" 300 300))
;; viewport appears
((draw-line w) (make-posn 30 30) (make-posn 100 100))
;; line appears
(close-viewport w)
;; viewport disappears
(close-graphics)
;; again, nothing appears to happen, but
;; unclosed viewports (if any) would disappear
]
@subsection{A More Complicated Example}
The use of multiple viewports, viewport descriptors, drawing
operations for multiple viewports is as easy as the use of a single
viewport:
@schemeblock[
(open-graphics)
(let* (;; @scheme[w1] and @scheme[w2] are viewport descriptors for different windows
[w1 (open-viewport "viewport 1" 300 300)]
[w2 (open-viewport "viewport 2" 200 500)]
;; d1 and d2 are functions that draw lines in different viewports
[d1 (draw-line w1)]
[d2 (draw-line w2)])
;; draws a line in viewport labeled "viewport 1"
(d1 (make-posn 100 5) (make-posn 5 100))
;; draws a line in viewport labeled "viewport 2"
(d2 (make-posn 100 100) (make-posn 101 400)))
;; we no longer have access to viewports 1 and 2,
;; since their descriptors did not escape the @scheme[let]
(close-graphics)
;; removes the viewports
]
@subsection{Protecting Graphics Operations}
To guarantee the proper closing of viewports in cases of errors,
especially when a program manages several viewports simultaneously, a
programmer should use @scheme[dynamic-wind:]
@schemeblock[
(let ([w (open-viewport "hello" 100 100)])
(dynamic-wind
;; what we want to happen first: nothing
void
;; the main program (errors constrained to this piece)
(lambda () (draw-pixel 13)) ; an error
;; what we would like to happen, whether the main program finishes
;; normally or not
(lambda () (close-viewport w))))
]
@subsection{Mouse Operations}
The graphics library contains functions that determine where the
mouse is, if there are any clicks, etc.
The functions @scheme[get-mouse-click] and @scheme[ready-mouse-click] first
return a ``mouse-click descriptor,'' and then other functions take
the descriptor and return the mouse's position, which button was
pushed, etc.
Mouse clicks are buffered and returned in the same order in which
they occurred.
Thus, the descriptors returned by @scheme[get-mouse-click] and
@scheme[ready-mouse-click] may be from clicks that occurred long
before these functions were called.
@itemize{
@item{\Function{get-mouse-click}
@scheme[(get-mouse-click @scheme[viewport])]
Takes a viewport descriptor and returns
a mouse click descriptor.
It returns the next mouse click in the @scheme[viewport], waiting for a click
if necessary.}
@item{\Function{ready-mouse-click}
@scheme[(ready-mouse-click @scheme[viewport])]
Takes a viewport descriptor and returns
either a mouse click descriptor, or else @scheme[#f] if none is available.
Unlike the previous function, @scheme[ready-mouse-click] returns immediately.}
@item{\Function{ready-mouse-release}
@scheme[(ready-mouse-release @scheme[viewport])]
Takes a viewport descriptor and returns
either a click descriptor from a mouse-release (button-up) event,
or else @scheme[#f] if none is available.}
@item{\Function{query-mouse-posn}
@scheme[(query-mouse-posn @scheme[viewport])]
Takes a viewport descriptor and returns
either the position of the mouse cursor within the @scheme[viewport],
or else @scheme[#f] if the cursor is currently outside the @scheme[viewport].}
@item{\Function{mouse-click-posn}
@scheme[(mouse-click-posn @scheme[mouse-click])]
Takes a mouse click descriptor and
returns the position of the pixel where the click occurred.}
@item{\Function{left-mouse-click?}
@scheme[(left-mouse-click?\ @scheme[mouse-click])]
Takes a mouse click descriptor and returns
@scheme[#t] if the click occurred with the left mouse button,
or else @scheme[#f].}
@item{\Function{middle-mouse-click?}
@scheme[(middle-mouse-click?\ @scheme[mouse-click])]
Similar to @scheme[left-mouse-click?].}
@item{\Function{right-mouse-click?}
@scheme[(right-mouse-click?\ @scheme[mouse-click])]
Similar to @scheme[left-mouse-click?].}
}
@subsection{Keyboard Operations}
The graphics library contains functions that report key presses from
the keyboard. The functions @scheme[get-key-press] and
@scheme[ready-key-press] return a ``key-press descriptor,'' and then
@scheme[key-value] takes the descriptor and returns a character or
symbol (usually a character) representing the key that was pressed.
Key presses are buffered and returned in the same order in which they
occurred. Thus, the descriptors returned by @scheme[get-key-press] and
@scheme[ready-key-press] may be from presses that occurred long before
these functions were called.
@itemize{
@item{\Function{get-key-press}
@scheme[(get-key-press @scheme[viewport])]
Takes a viewport descriptor and returns
a key press descriptor.
It returns the next key press in the @scheme[viewport], waiting for a click
if necessary.}
@item{\Function{ready-key-press}
@scheme[(ready-key-press @scheme[viewport])]
Takes a viewport descriptor and returns
either a key press descriptor, or else @scheme[#f] if none is available.
Unlike the previous function, @scheme[ready-key-press] returns immediately.}
@item{\Function{key-value}
@scheme[(key-value @scheme[key-press])]
Takes a key press descriptor and returns a character or special
symbol for the key that was pressed. For example, the Enter key
generates \scmch{return}, and the up-arrow key generates @scheme['up].
For a complete list of possible return values, see {\MrEdManual}.}
}
@subsection{Flushing}
@itemize{
@item{\Function{viewport-flush-input}
@scheme[(viewport-flush-input @scheme[viewport])]
As noted above, key presses and mouse clicks are buffered.
@scheme[viewport-flush-input] takes a viewport descriptor
and empties the input buffer of mouse and keyboard events.}
}
@subsection{Unitized Graphics}
To use a unitized version of the graphics library (see {\MzLibManual}
for more information on units), get the signatures
\scmsigfirst{graphics}, \scmsigfirst{graphics:posn-less}, and
\scmsigfirst{graphics:posn} with:
@schemeblock[
(require (libKW "graphics-sig.ss" "graphics"))
]
The \scmsig{graphics} signature includes all of the names defined in
this chapter. The \scmsig{graphics:posn-less} signature contains
everything except the \scm{posn} structure information, and
\scmsig{graphics:posn} contains only the \scm{posn} structure.
To obtain \scmunitfirst{graphics}, which imports \scmsig{mred} (all of
the MrEd classes, functions, and constants) and exports
\scmsig{graphics}:
@schemeblock[
(require (libKW "graphics-unit.ss" "graphics"))
]
The @filepath{graphics-posn-less-unit.ss} library provides
\scmunit{graphics-posn-less}, which imports \scmsig{graphics:posn} in
addition to MrEd.
@; ======================================================================
@section[#:tag "misc:turtles"]{Turtles}
@subsection{Traditional Turtles}
There are two ways to use the turtles in DrScheme. You can
use it as a TeachPack (see the DrScheme manual for details
of TeachPacks) or as a library. Use the
@filepath{turtles.ss} TeachPack.
In the MrEd language or in a module, load turtles with
@schemeblock[
(require (libKW "turtles.ss" "graphics"))
]
The following are the turtle functions:
@itemize{
@item{{@scheme[(turtles b)]}\Function{turtles}
shows and hides the turtles window based on the boolean @scheme[b].
The parameter @scheme[b] is optional; if it is left out, it toggles the
state of the turtles.}
@item{{{@scheme[(move n)]}}\Function{move}
moves the turtle n pixels.}
@item{{{@scheme[(draw n)]}}\Function{draw}
moves the turtle n pixels and draws a line on that path.}
@item{{{@scheme[(erase n)]}}\Function{erase}
moves the turtle n pixels and erases along that path.
\Function{move-offset}
\Function{draw-offset}
\Function{erase-offset}}
@item{{{ @scheme[(move-offset h v)], @scheme[(draw-offset h v)], @scheme[(erase-offset h v)]}}
are just like move, draw and erase, except they take a horizontal and
vertical offset from the turtle's current position.}
@item{{ @scheme[(turn theta)]}\Function{turn}
turns the turtle theta degrees counter-clockwise.}
@item{{ @scheme[(turn/radians theta)]}\Function{turn/radians}
turns the turtle theta radians counter-clockwise.}
@item{{{@scheme[(clear)]}}\Function{clear}
erases the turtles window.}
}
Turtles also defines these syntactic forms:
@itemize{
@item{{{@scheme[(split E)]}}\Function{split}
spawns a new turtle where
the turtle is currently located. In order to distinguish the two turtles,
only the new one evaluates the expression E. For example, if you start
with a fresh turtle-window and type:
\begin{center}
\begin{schemebox}
(split (turn/radians (/ pi 2)))
\end{schemebox}
\end{center}
you will have two turtles, pointing at right angles to each other.
To see that, try this:
\begin{center}
\begin{schemebox}
(draw 100)
\end{schemebox}
\end{center}
You will see two lines. Now, if you evaluate those two expression
again, you will have four turtles, etc}
@item{{{@scheme[(split* E ...)]}}\Function{split*}
is similar to @scheme[(split E ...)], except it creates as many turtles as
there are expressions and each turtles does one of the expression. For
example, to create two turtles, one pointing at $\pi/2$ and one at
$\pi/3$, evaluate this:
\begin{center}
\begin{schemebox}
(split* (turn/radians (/ pi 3)) (turn/radians (/ pi 2)))
\end{schemebox}
\end{center}}
@item{{{@scheme[(tprompt E...)]}}\Function{tprompt}
provides a way to limit the splitting of the turtles. Before
the expression E is run, the state of the turtles (how many, their
positions and headings) is "checkpointed," then E is evaluated and
the state of the turtles is restored, but all drawing that may have
occurred during execution of E remains.
For example, if you do this:
\begin{center}
\begin{schemebox}
(tprompt (draw 100))
\end{schemebox}
\end{center}
the turtle will move forward 100 pixels, draw a line there and then
be immediately put back in it's original position. Also, if you do this:
\begin{center}
\begin{schemebox}
(tprompt (split (turn/radians (/ pi 2))))
\end{schemebox}
\end{center}
the turtle will split into two turtles, one will turn 90 degrees and then
the turtles will be put back into their original state -- as if the split
never took place.
The fern functions below demonstrate more advanced use of @scheme[tprompt].}
}
In the file @filepath{turtle-examples.ss} in the @filepath{graphics} library of your PLT
distribution, you will find these functions and values defined, as
example turtle programs. (The file is located in the @filepath{graphics}
subdirectory of the @filepath{collects} subdirectory of the PLT
distribution).
@itemize{
@item{{{@scheme[(regular-poly sides radius)]}}
draws a regular poly centered at the turtle with
sides @scheme[sides] and with radius @scheme[radius].}
@item{{{@scheme[(regular-polys sides s)]}}
draws s regular polys spaced evenly outwards with sides @scheme[sides].}
@item{{{@scheme[(radial-turtles n)]}}
places $2^n$ turtles spaced evenly pointing radially outward}
@item{{{@scheme[(spaced-turtles n)]}}
places $2^n$ turtles pointing in the same direction as the original turtle
evenly spaced in a line.}
@item{{{@scheme[(spokes)]}}
draws some spokes, using radial-turtles and spaced-turtles}
@item{{{@scheme[(spyro-gyra)]}}
draws a spyro-grya reminiscent shape}
@item{{{@scheme[(neato)]}}
as the name says\ldots}
@item{{{@scheme[(graphics-bexam)]}}
draws a fractal that came up on an exam I took.}
@item{{{@scheme[serp-size]}}
a constant which is a good size for the serp procedures
\index{Serpinski Triangle}}
@item{{@scheme[(serp serp-size)], @scheme[(serp-nosplit serp-size)]}
draws the Serpinski triangle in two different ways, the first using split
heavily. After running the first one, try executing
@scheme[(draw 10)].}
@item{{{@scheme[koch-size]}}
a constant which is a good size for the koch procedures
\index{Koch Snowflake}}
@item{{{@scheme[(koch-split koch-size)],@scheme[(koch-draw koch-size)]}}
draws the same koch snowflake in two different ways.
\index{Lorenz Attractor}
\index{Butterfly Attractor}}
@item{{{@scheme[(lorenz a b c)]}}
watch the lorenz "butterfly" attractor with initial values a b and c.}
@item{{{@scheme[(lorenz1)]}}
a good setting for the lorenz attractor
\index{Peano space-filling curve}}
@item{{@scheme[(peano1 peano-size)]}
This will draw the Peano space-filling curve, using split.}
@item{{@scheme[(peano2 peano-size)]}
This will draw the Peano space-filling curve, without using split.
\index{Fern Fractal}}
@item{{{@scheme[fern-size]}}
a good size for the fern functions}
@item{{{@scheme[(fern1 fern-size)]}}
You will probably want to point the turtle up before running
this one, with something like:
\begin{center}
@scheme[(turn/radians (- (/ pi 2)))]
\end{center}}
@item{{{@scheme[(fern2 fern-size)]}}
a fern -- you may need to backup a little for this one.}
}
@subsection{Value Turtles}
There are two ways to use the turtles in DrScheme. You can
use it as a TeachPack (see the DrScheme manual for details
of TeachPacks) or as a library. Use the
@filepathFirst{value-turtles.ss} TeachPack.
In the MrEd language or in a module, load turtles with
@schemeblock[
(require (libKW "value-turtles.ss" "graphics"))
]
The value turtles are a variation on the turtles library.
Rather than having just a single window where each operation
changes the state of that window, in this library, the
entire turtles window is treated as a value. This means
that each of the primitive operations accepts, in addition
to the usual arguments, a turtles window value and instead
of returning nothing, returns a turtles window value.
The following are the value turtle functions:
@itemize{
@item{{@scheme[(turtles number number [number number number])]}\FunctionK{turtles}{turtlesVal}
creates a new turtles window. The first two arguments are
the width and height of the turtles window. The remaining
arguments specify the x,y position of the initial turtle
and the angle. The default to a turtle in the middle of
the window, pointing to the right.}
@item{{{@scheme[(move n turtles)]}}\FunctionK{move}{moveVal}
moves the turtle n pixels, returning a new turtles window.}
@item{{{@scheme[(draw n turtles)]}}\FunctionK{draw}{drawVal}
moves the turtle n pixels and draws a line on that path,
returning a new turtles window.}
@item{{{@scheme[(erase n turtles)]}}\FunctionK{erase}{eraseVal}
moves the turtle n pixels and erases along that path,
returning a new turtles window.
\FunctionK{move-offset}{move-offsetVal}
\FunctionK{draw-offset}{draw-offsetVal}
\FunctionK{erase-offset}{erase-offsetVal}}
@item{{{@scheme[(move-offset h v turtles)],
@scheme[(draw-offset h v turtles)],
@scheme[(erase-offset h v turtles)]}}
are just like move, draw and erase, except they take a horizontal and
vertical offset from the turtle's current position.}
@item{{ @scheme[(turn theta turtles)]}\FunctionK{turn}{turnVal}
turns the turtle theta degrees counter-clockwise,
returning a new turtles window.}
@item{{ @scheme[(turn/radians theta)]}\FunctionK{turn/radians}{turn/radiansVal}
turns the turtle theta radians counter-clockwise,
returning a new turtles window.}
@item{{@scheme[(merge turtles turtles)]}\Function{merge}
The @scheme[split] and @scheme[tprompt] functionality
provided by the imperative turtles implementation aren't
needed for this, since the turtles window is itself a
value.
Instead, the @scheme[merge] accepts two turtles windows
and combines the state of the two turtles windows into a
single window. The new window contains all of the
turtles of the previous two windows, but only the line
drawings of the first turtles argument.}
}
In the file @filepath{value-turtles-examples.ss} in the
@filepath{graphics} library of your PLT distribution, you will
find these functions and values defined, as example turtle
programs. (The file is located in the @filepath{graphics}
subdirectory of the @filepath{collects} subdirectory of the PLT
distribution).
It contains a sampling of the examples from the normal
turtles implementation, but translated to use @scheme[merge]
and the values turtles.
}