;; Koch snowflake fractal using using teachpack draw.ss ;; ;; also includes a GUI based control panel (used to create ;; koch snowflakes). ;; Some geometric stuff used to determine the endpoints of lines. ;; distance between 2 points (define (dist p1 p2) (sqrt (+ (expt (- (posn-x p1) (posn-x p2)) 2) (expt (- (posn-y p1) (posn-y p2)) 2)))) ;; ;; given three points p0, p1 and p2, rotate p2 about p1 relative to ;; the angle determined by the direction from p0 to p1. (define (rotate p0 p1 p2 angle) (local ((define hyp01 (dist p0 p1)) (define hyp12 (dist p1 p2)) (define angle01 (atan (- (posn-y p1) (posn-y p0)) (- (posn-x p1) (posn-x p0))))) (make-posn (+ (posn-x p1) (* hyp12 (cos (+ angle01 angle)))) (+ (posn-y p1) (* hyp12 (sin (+ angle01 angle))))))) (define PI 3.141593) ;; ;; draw-koch-line consumes two posn and a number and returns true. ;; ;; (draw-koch-line start end depth) draws a factal line. The line is ;; divided into three equal parts. The middle part is replace with two ;; lines of the same length as the 1/3 they replace, but at an angle. ;; depth controls whether or not the lines are draw as actual lines ;; (depth=0) or as koch-lines. ;; ;; no support for color here - always uses black... (define (draw-koch-line start end depth) (cond ;; depth 0 - we just draw the line. [(= 0 depth) (draw-solid-line start end 'black)] [else (local ;; compute the points 1/3 and 2/3rd of the way between ;; start and end. ((define p1 (make-posn (+ (posn-x start) (/ (- (posn-x end) (posn-x start)) 3)) (+ (posn-y start) (/ (- (posn-y end) (posn-y start)) 3)))) (define p2 (make-posn (+ (posn-x start) (* (- (posn-x end) (posn-x start)) 2/3)) (+ (posn-y start) (* (- (posn-y end) (posn-y start)) 2/3)))) ;; compute the 3rd endpoint used to draw a koch line, ;; this involves rotating a point.... (define pmid (rotate start p1 p2 (- 0 (* PI 1/3 ))))) ;; draw the 4 lines that make up a koch line ;; (each is drawn recursively) (and (draw-koch-line start p1 (- depth 1)) (draw-koch-line p2 end (- depth 1)) (draw-koch-line p1 pmid (- depth 1)) (draw-koch-line pmid p2 (- depth 1))))])) ;; ;; draws a kock snowflake of specified depth. ;; ;; p1 is the starting point - upper left of the initial triangle. ;; (define (draw-koch-snowflake p1 len depth) (local ((define p2 (make-posn (+ len (posn-x p1)) (posn-y p1))) (define p3 (make-posn (/ (+ (posn-x p1) (posn-x p2)) 2) (+ (posn-y p1) (* .866 len))))) (and (draw-koch-line p1 p2 depth) (draw-koch-line p2 p3 depth) (draw-koch-line p3 p1 depth)))) ;; test: depth 8 koch snowflake ;;(start 400 400) ;;(draw-koch-snowflake (make-posn 100 100) 200 8) ;; GUI control system (define (koch-control windowsize) (local ((define depth (make-text "Depth:")) (define width (make-text "Width:")) ;; buton handler - called when the user presses the "Create" button (define (create-handler e) (and ;; create new window (start windowsize windowsize) ;; draw the right size snowflake in the window (draw-koch-snowflake (make-posn 50 100 ) (string->number (text-contents width)) (string->number (text-contents depth)))))) (create-window (list (list (make-message "Koch Snowflake Control Panel")) (list depth) (list width) (list (make-button "Create" create-handler)))))) (koch-control 300)