220 lines
7.1 KiB
Racket
220 lines
7.1 KiB
Racket
#lang scheme
|
|
|
|
(require mzlib/math
|
|
(only-in deinprogramm/image rectangle line overlay image-color? image image-color)
|
|
(only-in lang/private/imageeq image?)
|
|
deinprogramm/contract/contract-syntax)
|
|
|
|
(provide set-color
|
|
turn
|
|
draw
|
|
move
|
|
run
|
|
sequence
|
|
turtle
|
|
image
|
|
image-color)
|
|
|
|
; used to convert angles
|
|
(define pi/180 (/ pi 180))
|
|
|
|
; convert angle value
|
|
; (: grad->rad (number -> number))
|
|
(define grad->rad
|
|
(lambda (grad)
|
|
(* pi/180 grad)))
|
|
|
|
(define turtle (contract
|
|
(predicate (lambda (x)
|
|
(and (vector? x)
|
|
(= (vector-length x) 8)
|
|
(number? (vector-ref x 0))
|
|
(number? (vector-ref x 1))
|
|
(number? (vector-ref x 2))
|
|
(number? (vector-ref x 3))
|
|
(number? (vector-ref x 4))
|
|
(image? (vector-ref x 5))
|
|
(image-color? (vector-ref x 6)))))))
|
|
|
|
; This function is only for internal use.
|
|
; (new-turtle-priv h w x y angle img color state)
|
|
; creates a new turtle with hight h, width w.
|
|
; The cursor is at position (x,y) and the view direction
|
|
; is defined by an angle value relative to the vector (1,0) .
|
|
; The two next componets represents the image and the
|
|
; color of the pen. The last component represents an abritary
|
|
; value, that allows to transport state with the turtle.
|
|
(: new-turtle-priv (number number number number number image image-color %A -> turtle))
|
|
(define new-turtle-priv
|
|
(lambda (h w x y angle img color state)
|
|
(vector h w x y angle img color state)))
|
|
|
|
|
|
; (new-turtle h w color)
|
|
; creates a new turtle with the pen color color and sets the
|
|
; width of the image to w and the hight to h.
|
|
; The background of the image is gray and the position of the
|
|
; cursor is (0,0) and the view direction is (1,0).
|
|
(: new-turtle (number number image-color -> turtle))
|
|
(define new-turtle
|
|
(lambda (h w color)
|
|
(let ((x (floor (/ w 2)))
|
|
(y (floor (/ h 2))))
|
|
(new-turtle-priv h w x y 0 (rectangle w h "solid" "gray") color #f))))
|
|
|
|
; (new-turtle-complex h w color bgcolor x y angle)
|
|
; creates a new turtle with the pen color color and sets the
|
|
; width of the image to w and the hight to h.
|
|
; The background of the image is bgcolor and the position of the
|
|
; cursor is (x,y) and the view direction is (1,0) * e^(- i angle).
|
|
(: new-turtle (number number image-color image-color number number number -> turtle))
|
|
(define new-turtle-complex
|
|
(lambda (h w color bgcolor x y angle)
|
|
(new-turtle-priv h w x y angle (rectangle w h "solid" bgcolor) color #f)))
|
|
|
|
|
|
; For internal use only
|
|
(: get-h (turtle -> number))
|
|
(define get-h (lambda (t) (vector-ref t 0)))
|
|
(: get-w (turtle -> number))
|
|
(define get-w (lambda (t) (vector-ref t 1)))
|
|
(: get-x (turtle -> number))
|
|
(define get-x (lambda (t) (vector-ref t 2)))
|
|
(: get-y (turtle -> number))
|
|
(define get-y (lambda (t) (vector-ref t 3)))
|
|
(: get-angle (turtle -> number))
|
|
(define get-angle (lambda (t) (vector-ref t 4)))
|
|
(: get-iamge (turtle -> image))
|
|
(define get-image (lambda (t) (vector-ref t 5)))
|
|
(: get-color (turtle -> image-color))
|
|
(define get-color (lambda (t) (vector-ref t 6)))
|
|
(: get-state (turtle -> %A))
|
|
(define get-state (lambda (t) (vector-ref t 7)))
|
|
|
|
; (set-color color)
|
|
; returns a function of type turtle -> turtle.
|
|
; Use the result to change the color of the pen.
|
|
(: set-color (image-color -> (turtle -> turtle)))
|
|
(define set-color
|
|
(lambda (color)
|
|
(lambda (t)
|
|
(let* ((h (get-h t))
|
|
(w (get-w t))
|
|
(x (get-x t))
|
|
(y (get-y t))
|
|
(angle (get-angle t))
|
|
(image (get-image t)))
|
|
(new-turtle-priv h w x y angle image color #f)))))
|
|
|
|
; (turn angle)
|
|
; returns a function of type turtle -> turtle.
|
|
; Use the result to turn the view of the turtle (counter-clockwise).
|
|
(: turn (number -> (turtle -> turtle)))
|
|
(define turn
|
|
(lambda (grad)
|
|
(lambda (t)
|
|
(let* ((h (get-h t))
|
|
(w (get-w t))
|
|
(x (get-x t))
|
|
(y (get-y t))
|
|
(angle (get-angle t))
|
|
(image (get-image t))
|
|
(color (get-color t))
|
|
(state (get-state t)))
|
|
(new-turtle-priv h w x y (- angle grad) image color state)))))
|
|
|
|
; For internal use only
|
|
; (move-cursor turtle length)
|
|
; returns a new turtle where the cursor
|
|
; is moved length steps along the view vector.
|
|
(: move-cursor (turtle number -> turtle))
|
|
(define move-cursor
|
|
(lambda (t length)
|
|
(let* ((h (get-h t))
|
|
(w (get-w t))
|
|
(x (get-x t))
|
|
(y (get-y t))
|
|
(angle (get-angle t))
|
|
(image (get-image t))
|
|
(color (get-color t))
|
|
(state (get-state t))
|
|
(newx (+ x (* length (cos (grad->rad angle)))))
|
|
(newy (+ y (* length (sin (grad->rad angle))))))
|
|
(new-turtle-priv h w newx newy angle image color state))))
|
|
|
|
; (draw length)
|
|
; returns a function of type turtle -> turtle.
|
|
; The result can be used to move the turtle and draw a line.
|
|
(: draw (number -> (turtle -> turtle)))
|
|
(define draw
|
|
(lambda (length)
|
|
(lambda (t)
|
|
(let* ((h (get-h t))
|
|
(w (get-w t))
|
|
(x (get-x t))
|
|
(y (get-y t))
|
|
(angle (get-angle t))
|
|
(image (get-image t))
|
|
(color (get-color t))
|
|
(state (get-state t))
|
|
; Compute new coordinats
|
|
(newx (+ x (* length (cos (grad->rad angle)))))
|
|
(newy (+ y (* length (sin (grad->rad angle))))))
|
|
(new-turtle-priv
|
|
h w
|
|
newx newy angle
|
|
; Compute new image
|
|
(overlay image
|
|
(line w h x y newx newy color) 0 0)
|
|
color state)))))
|
|
|
|
; (move length)
|
|
; returns a function of type turtle -> turtle.
|
|
; The result can be used to move the turtle without drawing a line.
|
|
(: move (number -> (turtle -> turtle)))
|
|
(define move
|
|
(lambda (length)
|
|
(lambda (t)
|
|
(move-cursor t length))))
|
|
|
|
; runs a turtle function
|
|
(: run ((turtle -> turtle) number number image-color -> image))
|
|
(define run
|
|
(lambda (t->t h w color)
|
|
(get-image (t->t (new-turtle h w color)))))
|
|
|
|
; ; runs a turtle function
|
|
; ; (: run* ((turtle -> turtle) -> turtle -> image))
|
|
; (define run*
|
|
; (lambda (t->t h w color bgcolor x y angle)
|
|
; (get-image (t->t (new-turtle h w color bgcolor x y angle)))))
|
|
|
|
; This function is only for internal use.
|
|
(define comp_priv_2
|
|
(lambda (f1 f2)
|
|
(lambda (t)
|
|
(f2 (f1 t)))))
|
|
|
|
; This function is only for internal use.
|
|
(define comp_priv
|
|
(lambda (l)
|
|
(cond
|
|
((null? l) (error "sequence erwartet mind. ein Argument"))
|
|
((list? l)
|
|
(let ((head (car l))
|
|
(tail (cdr l)))
|
|
(if (null? tail)
|
|
head
|
|
(comp_priv_2 head (comp_priv tail))))))))
|
|
|
|
; This function allows to do a list of
|
|
; turtle -> turtle
|
|
; functions into one new function, that do
|
|
; one action of the turtle, then later the rest.
|
|
; Define the type alias tip = turtle -> turtle.
|
|
(define tip (contract (turtle -> turtle)))
|
|
(: do (tip ... -> tip))
|
|
(define sequence (lambda l (comp_priv l)))
|
|
|
|
|