(define floating-vector-ref (access floating-vector-ref (->environment '(student pictures))))
(define floating-vector-set! (access floating-vector-set! (->environment '(student pictures))))
(define *screen-width* 128)
(define *screen-height* 128)
(define *last-screen-row* (- *screen-height* 1))
(define *last-screen-column* (- *screen-width* 1))
(define *the-screen* (make-picture *screen-width* *screen-height* 255.))
(define (screen-frame)
(make-frame (make-vect 0 0)
(make-vect *screen-width* 0)
(make-vect 0 *screen-height*)))
(define (set-painter-resolution! res)
(let ((res (inexact->exact res)))
(set! *screen-width* res)
(set! *screen-height* res)
(set! *last-screen-row* (- *screen-height* 1))
(set! *last-screen-column* (- *screen-width* 1))
(set! *the-screen* (make-picture *screen-width* *screen-height* 255.))
'set))
(define (number->painter number)
(let ((picture-data (access picture-data (->environment '(student pictures))))
(invalidate-cached-values (access invalidate-cached-values
(->environment '(student pictures))))
(h (exact->inexact *screen-width*))
(v (exact->inexact *screen-height*))
(value (exact->inexact number)))
(lambda (frame)
(let* ((frame (make-inexact-frame frame))
(frame-map (frame-mapping-info h v frame)))
(if (degenerate? frame-map)
'done
(let ((segments (frame-map-segments frame-map))
(lowest-row (frame-map-lowest-row frame-map))
(highest-row (frame-map-highest-row frame-map)))
(invalidate-cached-values *the-screen*)
(let rowloop ((r lowest-row))
(if (> r highest-row)
'done
(let ((intersections (row-intersects-segments r segments)))
(if (null? intersections)
'done
(let ((start-col (max 0 (car intersections)))
(stop-col (min *last-screen-column* (cadr intersections))))
(fill-row-with-value
start-col stop-col
(vector-ref (picture-data *the-screen*) r)
value)))
(rowloop (+ r 1)))))))))))
(define (fill-row-with-value start-column end-column row-vector value)
(if (> start-column end-column)
'done
(let fill-loop ((column start-column))
(if (fix:> column end-column)
'done
(begin
(floating-vector-set! row-vector column value)
(fill-loop (fix:+ column 1)))))))
(define (segments->painter segments)
(lambda (frame)
(let ((coord-map
(lambda (v)
(vector-add (frame-origin frame)
(vector-add (vector-scale (vector-xcor v) (frame-edge1 frame))
(vector-scale (vector-ycor v) (frame-edge2 frame)))))))
(for-each
(lambda (seg)
(draw-line-on-screen (coord-map (segment-start seg))
(coord-map (segment-end seg))))
segments))))
(define (draw-line-on-screen start end)
(let* ((value (exact->inexact 0)) (data ((access picture-data (->environment '(student pictures)))
*the-screen*))
(invalidate-cached-values (access invalidate-cached-values
(->environment '(student pictures))))
(xs (vector-xcor start))
(ys (vector-ycor start))
(xe (vector-xcor end))
(ye (vector-ycor end))
(xinc (if (< xs xe) 1 -1))
(dx (round->exact (abs (- xs xe))))
(yinc (if (< ys ye) 1 -1))
(dy (round->exact (abs (- ys ye))))
(dx2 (* dx 2))
(dy2 (* dy 2))
(x (round->exact xs))
(y (round->exact ys)))
(invalidate-cached-values *the-screen*)
(plot-if-on-screen x y data value)
(if (> dx dy)
(let ((dxy (- dy2 dx2)) (s (- dy2 dx)))
(let loop ((i 1))
(if (fix:> i dx)
'done
(begin
(if (fix:>= s 0)
(begin (set! y (fix:+ y yinc))
(set! s (fix:+ s dxy)))
(set! s (fix:+ s dy2)))
(set! x (fix:+ x xinc))
(plot-if-on-screen x y data value)
(loop (fix:+ i 1))))))
(let ((dxy (- dx2 dy2)) (s (- dx2 dy)))
(let loop ((i 1))
(if (fix:> i dy)
'done
(begin
(if (fix:>= s 0)
(begin (set! x (fix:+ x xinc))
(set! s (fix:+ s dxy)))
(set! s (fix:+ s dx2)))
(set! y (fix:+ y yinc))
(plot-if-on-screen x y data value)
(loop (fix:+ i 1)))))))))
(define (plot-if-on-screen x y data value)
(if (and (fix:>= x 0)
(fix:>= y 0)
(fix:<= x *last-screen-column*)
(fix:<= y *last-screen-row*))
(floating-vector-set! (vector-ref data y) x value)))
(define (procedure->painter proc)
(if (not (procedure? proc))
(error "Argument not a procedure--PROCEDURE->PAINTER" proc))
(let ((picture-data (access picture-data (->environment '(student pictures))))
(invalidate-cached-values
(access invalidate-cached-values (->environment '(student pictures))))
(h 1.0) (v 1.0))
(lambda (frame)
(let* ((frame (make-inexact-frame frame))
(frame-map (frame-mapping-info h v frame)))
(if (degenerate? frame-map)
'done
(let ((segments (frame-map-segments frame-map))
(lowest-row (frame-map-lowest-row frame-map))
(highest-row (frame-map-highest-row frame-map))
(picture-x-step (frame-map-x-step frame-map))
(picture-y-step (frame-map-y-step frame-map))
(inv-map (frame-map-inv-map frame-map)))
(invalidate-cached-values *the-screen*)
(let rowloop ((r lowest-row))
(if (> r highest-row)
'done
(let ((intersections (row-intersects-segments r segments)))
(if (null? intersections)
'done
(let ((start-col (max 0 (car intersections)))
(stop-col (min *last-screen-column* (cadr intersections))))
(fill-row-from-procedure
r start-col stop-col inv-map
picture-x-step picture-y-step
(vector-ref (picture-data *the-screen*) r)
proc)))
(rowloop (+ r 1)))))))))))
(define (fill-row-from-procedure row start-column end-column inv-map
picture-x-step picture-y-step
row-vector
proc
)
(let* ((inexr (exact->inexact row))
(picture-start-point (inv-map (make-vect (exact->inexact start-column) inexr)))
(picture-start-x (vector-xcor picture-start-point))
(picture-start-y (vector-ycor picture-start-point)))
(if (> start-column end-column)
'done
(let fill-loop ((picture-x picture-start-x)
(picture-y picture-start-y)
(column start-column))
(if (fix:> column end-column)
'done
(begin
(floating-vector-set!
row-vector
column
(exact->inexact (proc picture-x picture-y)))
(fill-loop (flo:+ picture-x picture-x-step)
(flo:+ picture-y picture-y-step)
(fix:+ column 1))))))))
(define (picture->painter picture)
(if (not (access picture? (->environment '(student pictures))))
(error "Argument not a picture--PICTURE->PAINTER" picture))
(let ((h (exact->inexact (picture-width picture)))
(v (exact->inexact (picture-height picture)))
(picture-data (access picture-data (->environment '(student pictures))))
(invalidate-cached-values (access invalidate-cached-values
(->environment '(student pictures)))))
(lambda (frame)
(let* ((frame (make-inexact-frame frame))
(frame-map (frame-mapping-info h v frame)))
(if (degenerate? frame-map)
'done
(let ((segments (frame-map-segments frame-map))
(lowest-row (frame-map-lowest-row frame-map))
(highest-row (frame-map-highest-row frame-map))
(picture-x-step (frame-map-x-step frame-map))
(picture-y-step (frame-map-y-step frame-map))
(inv-map (frame-map-inv-map frame-map))
(picture-array (picture-data picture))
(picture-row-max (- (picture-height picture) 1))
(picture-row-min 0)
(picture-column-max (- (picture-width picture) 1))
(picture-column-min 0))
(invalidate-cached-values *the-screen*)
(let rowloop ((r lowest-row))
(if (> r highest-row)
'done
(let ((intersections (row-intersects-segments r segments)))
(if (null? intersections)
'done
(let ((start-col (max 0 (car intersections)))
(stop-col (min *last-screen-column* (cadr intersections))))
(fill-row-from-picture
r start-col stop-col inv-map
picture-x-step picture-y-step
(vector-ref (picture-data *the-screen*) r)
picture-array
picture-row-min picture-row-max
picture-column-min picture-column-max)))
(rowloop (+ r 1)))))))))))
(define (fill-row-from-picture row start-column end-column inv-map
picture-x-step picture-y-step
row-vector picture-array
picture-row-min picture-row-max
picture-column-min picture-column-max
)
(let* ((inexr (exact->inexact row))
(picture-start-point (inv-map (make-vect (exact->inexact start-column) inexr)))
(picture-start-x (vector-xcor picture-start-point))
(picture-start-y (vector-ycor picture-start-point))
(picture-end-point (inv-map (make-vect (exact->inexact end-column) inexr)))
(picture-end-x (vector-xcor picture-end-point))
(picture-end-y (vector-ycor picture-end-point))
(x-start->exact (if (> picture-x-step 0) floor->exact ceiling->exact))
(y-start->exact (if (> picture-y-step 0) floor->exact ceiling->exact))
(x-end->exact (if (> picture-x-step 0) ceiling->exact floor->exact))
(y-end->exact (if (> picture-y-step 0) ceiling->exact floor->exact)))
(let find-real-start-loop ()
(if (or (point-in-picture (x-start->exact picture-start-x) (y-start->exact picture-start-y)
picture-row-min picture-row-max
picture-column-min picture-column-max)
(> start-column end-column))
'done
(begin (set! picture-start-x (+ picture-start-x picture-x-step))
(set! picture-start-y (+ picture-start-y picture-y-step))
(set! start-column (+ start-column 1))
(find-real-start-loop))))
(let find-real-end-loop ()
(if (or (point-in-picture (x-end->exact picture-end-x) (y-end->exact picture-end-y)
picture-row-min picture-row-max
picture-column-min picture-column-max)
(< end-column start-column))
'done
(begin (set! picture-end-x (- picture-end-x picture-x-step))
(set! picture-end-y (- picture-end-y picture-y-step))
(set! end-column (- end-column 1))
(find-real-end-loop))))
(if (> start-column end-column)
'done
(if (= picture-y-step 0)
(let fill-loop ((picture-x picture-start-x)
(column start-column))
(let ((picture-row (vector-ref picture-array (round->exact picture-start-y))))
(if (fix:> column end-column)
'done
(begin
(floating-vector-set! row-vector
column
(floating-vector-ref picture-row (round->exact picture-x)))
(fill-loop (flo:+ picture-x picture-x-step)
(fix:+ column 1))))))
(let fill-loop ((picture-x picture-start-x)
(picture-y picture-start-y)
(column start-column))
(if (fix:> column end-column)
'done
(begin
(floating-vector-set!
row-vector
column
(floating-vector-ref (vector-ref picture-array (round->exact picture-y))
(round->exact picture-x)))
(fill-loop (flo:+ picture-x picture-x-step)
(flo:+ picture-y picture-y-step)
(fix:+ column 1)))))))))
(define (point-in-picture picture-access-column picture-access-row
picture-row-min picture-row-max
picture-column-min picture-column-max)
(and (fix:<= picture-access-row picture-row-max)
(fix:>= picture-access-row picture-row-min)
(fix:<= picture-access-column picture-column-max)
(fix:>= picture-access-column picture-column-min)))
(define (frame-mapping-info h v frame)
(let* ((frame-org (frame-origin frame))
(a11 (/ (vector-xcor (frame-edge1 frame)) h))
(a12 (/ (vector-xcor (frame-edge2 frame)) v))
(a21 (/ (vector-ycor (frame-edge1 frame)) h))
(a22 (/ (vector-ycor (frame-edge2 frame)) v))
(det (- (* a11 a22) (* a21 a12))))
(if (<= (abs det) 1.e-4)
(list 'degenerate)
(let* ((b11 (/ a22 det))
(b21 (/ (- a21) det))
(b12 (/ (- a12) det))
(b22 (/ a11 det))
(inv-map
(lambda (v)
(let ((v (vector-sub v frame-org)))
(let ((x (vector-xcor v)) (y (vector-ycor v)))
(make-vect (+ (* b11 x) (* b12 y))
(+ (* b21 x) (* b22 y)))))))
(x-step b11)
(y-step b21)
(vertices
(list (frame-origin frame)
(vector-add (frame-origin frame) (frame-edge1 frame))
(vector-add (frame-origin frame) (frame-edge2 frame))
(vector-add (frame-origin frame)
(vector-add (frame-edge1 frame) (frame-edge2 frame)))))
(segments (points->segment-checks vertices))
(vector-ycors (map vector-ycor vertices))
(lowest-row (max 0 (floor->exact (apply min vector-ycors))))
(highest-row (min *last-screen-row* (ceiling->exact (apply max vector-ycors)))))
(list 'ok x-step y-step
segments
lowest-row highest-row
inv-map)))))
(define (degenerate? frame-map)
(eq? (car frame-map) 'degenerate))
(define (frame-map-x-step frame-map) (list-ref frame-map 1))
(define (frame-map-y-step frame-map) (list-ref frame-map 2))
(define (frame-map-segments frame-map) (list-ref frame-map 3))
(define (frame-map-lowest-row frame-map) (list-ref frame-map 4))
(define (frame-map-highest-row frame-map) (list-ref frame-map 5))
(define (frame-map-inv-map frame-map) (list-ref frame-map 6))
(define (points->segment-checks points)
(let* ((p1 (list-ref points 0))
(p2 (list-ref points 1))
(p3 (list-ref points 2))
(p4 (list-ref points 3))
(s1 (make-segment-check p1 p2))
(s2 (make-segment-check p1 p3))
(s3 (make-segment-check p2 p4))
(s4 (make-segment-check p3 p4)))
(list s1 s2 s3 s4)))
(define (make-segment-check p1 p2)
(define (make-seg lower higher)
(let* ((xs (vector-xcor lower))
(xe (vector-xcor higher))
(ys (vector-ycor lower))
(ye (vector-ycor higher))
(dx (- xe xs))
(dy (- ye ys))
(dx/dy (if (< (abs dy) 1.e-4) false (/ dx dy))))
(list xs xe ys ye dx/dy)))
(if (< (vector-ycor p1) (vector-ycor p2))
(make-seg p1 p2)
(make-seg p2 p1)))
(define (segment-check-xs s) (list-ref s 0))
(define (segment-check-xe s) (list-ref s 1))
(define (segment-check-ys s) (list-ref s 2))
(define (segment-check-ye s) (list-ref s 3))
(define (segment-check-dx/dy s) (list-ref s 4))
(define (row-intersects-segments row segments)
(let* ((y (exact->inexact row))
(intersections
(map (lambda (seg) (row-intersects-segment y seg)) segments))
(flush-nulls (apply append intersections)))
(if (null? flush-nulls)
'()
(let ((start-col (apply min flush-nulls))
(stop-col (apply max flush-nulls)))
(list start-col stop-col)))))
(define (row-intersects-segment y s)
(let* ((xs (segment-check-xs s))
(ys (segment-check-ys s))
(xe (segment-check-xe s))
(ye (segment-check-ye s))
(dx/dy (segment-check-dx/dy s)))
(if (not dx/dy)
(if (= (round->exact y) (round->exact ys))
(list (round->exact xs) (round->exact xe))
'())
(if (<= ys y ye)
(list (round->exact
(+ xs (* (- y ys) dx/dy))))
'()))))
(define (make-inexact-frame frame)
(make-frame (make-inexact-vect (frame-origin frame))
(make-inexact-vect (frame-edge1 frame))
(make-inexact-vect (frame-edge2 frame))))
(define (make-inexact-vect vector)
(make-vect (exact->inexact (vector-xcor vector))
(exact->inexact (vector-ycor vector))))