;; Logo Turtle Graphics implementation for Impromptu

;; Andrew R. Brown 2006 

;;

;; Users will need to use a hybrid Scheme/Logo syntax. All Impromptu Turtle Graphics

;; commands start with tg: In particular,

;; a) scheme's bracket syntax and basic function structures and style remain

;;    (even when using "tg:to" and "tg:make" rather than "define")

;;    (functions conclude with closing brackets, rather than with "end")

;; b) keywords with two parts are written with a hyturtle:pen, e.g., tg:pen-up

;; c) the "tg:repeat" syntax uses separate body statements rather than a list of them

;; d) math functions are still done with prefix notation

;; e) color commands, "tg:set-pc" and "tg:set-bg" take a list of r g b a values between 0 and 1

;; f) you can't use "tg:make" inside proceedures, use set! instead to update a variable's value 

;;

;; Other significant differences include:

;; a) there is no visible turtle

;; b) "tg:set-bg" does not change tg:background colour until "tg:clear-screen"  or "tg:clear" is called 



(define canvas-width 600)

(define canvas-height 600)

(define turtle:canvas (gfx:make-canvas canvas-width canvas-height))


(define turtle:position (cons (/ canvas-width 2) (/ canvas-height 2)))

(define turtle:direction 90)

(define turtle:pen #t)

(define turtle:pen-color '(0 0 0 1))

(define turtle:bg-color '(1 1 1 1))


(gfx:clear-canvas (now) turtle:canvas turtle:bg-color)


(define tg:forward

   (lambda (distance)

      (let* ((ang (* (/ turtle:direction 360) (acos -1) 2))

             (x (+ (car turtle:position) (* (cos ang) distance)))

             (y (+ (cdr turtle:position) (* (sin ang) distance))))

         (if turtle:pen (gfx:draw-path (now) turtle:canvas (gfx:make-line (car turtle:position) (cdr turtle:position) x y) turtle:pen-color '()))

         (set-car! turtle:position x)

         (set-cdr! turtle:position y))

      turtle:position))


(define tg:back

   (lambda (distance)

      (set! turtle:direction (- turtle:direction 180))

      (tg:forward distance)

      (set! turtle:direction (+ turtle:direction 180))

      turtle:position))


(define tg:right

   (lambda (degrees)

      (set! turtle:direction (- turtle:direction degrees))

      turtle:direction))


(define tg:left

   (lambda (degrees)

      (set! turtle:direction (+ turtle:direction degrees))

      turtle:direction))


(define tg:pen-up

   (lambda ()

      (set! turtle:pen #f)))


(define tg:pen-down

   (lambda ()

      (set! turtle:pen #t)))


(define tg:home

   (lambda ()

      (if turtle:pen (begin (gfx:draw-path (now) 

                                turtle:canvas 

                                (gfx:make-line (car turtle:position) (cdr turtle:position)

                                             (/ canvas-width 2) (/ canvas-height 2))

                                turtle:pen-color '())

                     (set-car! turtle:position (/ canvas-width 2))

                     (set-cdr! turtle:position (/ canvas-height 2))))))


(define tg:clear

   (lambda ()

      (gfx:clear-canvas (now) turtle:canvas turtle:bg-color)))

   


(define tg:clear-screen

   (lambda ()

      (gfx:clear-canvas (now) turtle:canvas turtle:bg-color)

      (set-car! turtle:position (/ canvas-width 2))

      (set-cdr! turtle:position (/ canvas-height 2))

      (set! turtle:direction 90)))


(define tg:set-pc

   (lambda (red green blue alpha)

      (set! turtle:pen-color (list red green blue alpha))))


(define tg:set-bg

   (lambda (red green blue alpha)

      (set! turtle:bg-color (list red green blue alpha))))


(define tg:set-x

   (lambda (distance)

      (if turtle:pen (gfx:draw-path (now) turtle:canvas 

                         (gfx:make-line (car turtle:position) (cdr turtle:position)

                                      (+ (car turtle:position) distance) (cdr turtle:position))

                         turtle:pen-color '()))

      (set-car! turtle:position (+ (car turtle:position) distance))))


(define tg:get-x

   (lambda ()

      (car turtle:position)))


(define tg:set-y

   (lambda (distance)

      (if turtle:pen (gfx:draw-path (now) turtle:canvas 

                         (gfx:make-line (car turtle:position) (cdr turtle:position)

                                      (car turtle:position) (+ (cdr turtle:position) distance))

                         turtle:pen-color '()))

      (set-cdr! turtle:position (+ (cdr turtle:position) distance))))


(define tg:get-y

   (lambda ()

      (cdr turtle:position)))


(define tg:set-pos

   (lambda (x-distance y-distance)

      (if turtle:pen (gfx:draw-path (now) turtle:canvas 

                         (gfx:make-line (car turtle:position) (cdr turtle:position)

                                      (+ (car turtle:position) x-distance) (+ (cdr turtle:position) y-distance))

                         turtle:pen-color '()))

      (set-car! turtle:position (+ (car turtle:position) x-distance))

      (set-cdr! turtle:position (+ (cdr turtle:position) y-distance))))


(macro (tg:repeat args)

   `(let loop ((i ,(cadr args)))

       ,@(cddr args)

       (if (> i 1) (loop (- i 1)))))


(macro (tg:make args)

   `(define ,@(cdr args)))


(macro (tg:to args)

   `(define ,@(cdr args)))


(define tg:first car)


(define tg:but-first cdr)


(define tg:last

   (lambda (lst)

      (car (reverse lst))))


(define tg:but-last

   (lambda (lst)

      (reverse (cdr (reverse lst)))))


(define tg:count length)


(define tg:item

   (lambda (index lst)

      (list-ref lst (- index 1))))


(define tg:l-put

   (lambda (obj lst)

      (reverse (cons obj (reverse lst)))))