;;; Scheme Recursive Art Contest Entry ;;; ;;; Please do not include your name or personal info in this file. ;;; ;;; Title: 3D Christmas Tree of Hope ;;; ;;; Description: ;;; ;; Features: ;; - 3D coordinate system ;; - Adjustable viewing position ;; - Chromatic gradient with respect to recursion depth ;; - Tail recursive ;; - With a little bit of modification, this program can draw many many other ;; shapes (I have tried triangle recursion, haxagon, and even a DNA double ;; helix!). You're welcome to download it and play with it on your own! Use ;; your magination :D ;; ;; Partially inspired by "Much Color.So Rainbow.Wow" (Fall 2013 Submission 2) ;; ------ 3D Vector Abstraction ------ ; Access x, y, z component of a point (define (x point) (car point)) (define (y point) (cadr point)) (define (z point) (caddr point)) ; Create a vector from p0 to p1 (define (vector p0 p1) (list (- (x p1) (x p0)) (- (y p1) (y p0)) (- (z p1) (z p0)))) ; Multiplying a scalar constant with a vector (define (s_mul c v) (list (* c (x v)) (* c (y v)) (* c (z v)))) ; Vector subtraction: u - v (define (v_sub u v) (list (- (x u) (x v)) (- (y u) (y v)) (- (z u) (z v)))) ; Calculate dot product of vector u and vector v (define (dot u v) (+ (* (x u) (x v)) (* (y u) (y v)) (* (z u) (z v)))) ; Calculate the projection of a vector v onto a plane with normal vector n (define (proj v n) (v_sub v (s_mul (dot v n) n))) ; Calculate the angle defined by x and y in degrees, ranged from 0 to 359 (define (heading y x) (let ((a (degrees (atan y x)))) (if (< a 0) (+ 360 a) a))) ; Calculate the magnitude of a vector (define (mag v) (sqrt (+ (* (x v) (x v)) (* (y v) (y v)) (* (z v) (z v))))) ;; ------ Drawing Procedure ------ ; NORMAL of the canvas plane, y * tan(view angle) - z = 0 (define (normal view_angle) (let ((n_raw (vector '(0 0 0) (list 0 (tan (radians view_angle)) -1)))) (s_mul (/ 1 (mag n_raw)) n_raw))) ; draw the 2D representative of a 3D vector from p0 to p1 (define (from_to p0 p1) (define r (proj (vector p0 p1) n)) (define i (x r)) (define j_raw (sqrt (+ (* (y r) (y r)) (* (z r) (z r))))) (define j (if (< (z r) 0) (- j_raw) j_raw)) (seth (heading j i)) (fd (mag r))) ; Calculate the position of the next vertex of the square ; * Modify this function to draw other polygons (define (next_vertex curr side_len dir z) (list (+ (x curr) (* side_len (cos (radians dir)))) (+ (y curr) (* side_len (sin (radians dir)))) z)) (define (draw) ; * by changing the initial value of angle 'a', you can spin the graph (define (recur depth r a z curr) (cond ((= depth 0) nil) (else ; go to the starting position (define p0 (list (* r (cos (radians a))) (* r (sin (radians a))) z)) (pu) (from_to curr p0) (pd) ; set the color (cond ((> depth 120) (color2 0 (- 255 (* 6.375 (- depth 120))) 255)) ((> depth 80) (color2 0 255 (* 6.375 (- depth 80)))) ((> depth 40) (color2 (- 255 (* 6.375 (- depth 40))) 255 0)) (else (color2 255 (* 6.375 depth) 0))) ; draw the square ; * add / subtract points to draw other polygons ; ** eg. if you want to draw triangles, use 3 points instead of 4 ; and change the modification on angle 'a' to +150 and +270. ; 150 = 180 - 60 / 2, 270 = 150 + (180 - 60) (define len (* (sqrt 2) r)) (define p1 (next_vertex p0 len (+ a 135) z)) ; 135 = 180 - 90/2 (define p2 (next_vertex p1 len (+ a 225) z)) ; 225 = 135 + (180 - 90) (define p3 (next_vertex p2 len (+ a 315) z)) ; 315 = 225 + (180 - 90) (from_to p0 p1) (from_to p1 p2) (from_to p2 p3) (from_to p3 p0) ; recursive call (recur (- depth 1) (- r 2) (+ a 3) (+ z 3) p0)))) (recur 160 320 10 0 '(0 0 0))) ;; ------ Setup ------ (hideturtle) (pu) (bgcolor 'black) (speed 0) (goto 0 -150) ; view angle is 67 degrees from vertical (define n (normal 67)) ; Please leave this last line alone. You may add additional procedures above ; this line. All Scheme tokens in this file (including the one below) count ; toward the token limit. (draw)