From 9a8ae82ae3475dcfd1609d1a0075ad101a19b87b Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Sat, 17 Jan 2015 22:09:55 -0800 Subject: [PATCH 01/13] entered data for george, draws correctly --- src/escher/core.clj | 72 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 6f8da5a..d541054 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -7,6 +7,8 @@ (def draw-line q/line) +;; origin, e1, and e2 (all 2-D vectors) define a frame + (def whole-window {:origin [0 0] :e1 [width 0] :e2 [0 height]}) @@ -19,19 +21,32 @@ :e1 [100 0] :e2 [0 200]}) +; gw +(defn make-vect [x y] + [x y]) + + +; gw +(defn make-segment [p1 p2] + [p1 p2]) + +; gw (defn add-vec [[x1 y1] [x2 y2]] - ;; COMPLETE (Ex 2.46) + [(+ x1 x2) (+ y1 y2)] ) +; gw (defn sub-vec [[x1 y1] [x2 y2]] - ;; COMPLETE + [(- x1 x2) (- y1 y2)] ) (defn scale-vec [[x y] s] - ;; COMPLETE + [(* x s) (* y s)] ) (defn frame-coord-map + "Returns function that maps [x y] relative to the frame + defined by origin (a point) and vectors e1, e2." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin @@ -39,6 +54,8 @@ (scale-vec e2 y))))) (defn frame-painter [{:keys [origin e1 e2]}] + "Draws parallelogram 'frame' based on origin and vectors e1 and e2. + Must execute within a sketch." (let [corner (add-vec origin (add-vec e1 e2))] (draw-line origin (add-vec origin e1)) (draw-line origin (add-vec origin e2)) @@ -84,12 +101,18 @@ (left frame) (right frame)))) +; gw (defn below [p1 p2] - ; COMPLETE (Ex 2.51) + (rotate (beside (rotate270 p1) + (rotate270 p2))) ) -(defn path [& veclist] - ; COMPLETE +; gw +(defn path + "Creates a seq of pairs-of-points from a 'bare' list of points. Use to + draw a continuous line through the list of points." + [& veclist] + (partition 2 1 veclist) ) @@ -143,11 +166,43 @@ (defn square-limit [p n] (combine-four (corner-split p n))) +;; George data + +(def p1 (make-vect 0 0.35)) +(def p2 (make-vect 0.15 0.6)) +(def p3 (make-vect 0.3 0.4)) +(def p4 (make-vect 0.35 0.5)) +(def p5 (make-vect 0.25 1.0)) +(def p6 (make-vect 0.4 1.0)) +(def p7 (make-vect 0.5 0.7)) +(def p8 (make-vect 0.6 1.0)) +(def p9 (make-vect 0.75 1.0)) +(def p10 (make-vect 0.6 0.55)) +(def p11 (make-vect 1 0.85)) +(def p12 (make-vect 1 0.65)) +(def p13 (make-vect 0.75 0.35)) +(def p14 (make-vect 0.6 0.35)) +(def p15 (make-vect 0.65 0.15)) +(def p16 (make-vect 0.6 0)) +(def p17 (make-vect 0.4 0)) +(def p18 (make-vect 0.35 0.15)) +(def p19 (make-vect 0.4 0.35)) +(def p20 (make-vect 0.3 0.35)) +(def p21 (make-vect 0.15 0.4)) +(def p22 (make-vect 0.0 0.15)) + ; Ex2.49, Make these shapes with segment-painter/path (def box ) (def x) (def diamond) -(def george) +; gw +(def george-data + (path p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 + p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 + p21 p22)) +; gw +(def george (segment-painter george-data)) + (defn draw [picture] (picture whole-window)) @@ -172,7 +227,8 @@ ;; (frame-painter frame1) ;; (draw x) ;; (draw box) - ;; (george frame2) + ;; (george whole-window) + (draw george) ;; (draw (rotate george)) ;; (draw (flip-horiz george)) ;; (draw (beside box box)) From 2423a78194fd2c48ce0622325b69b464525f3386 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Sat, 17 Jan 2015 23:53:04 -0800 Subject: [PATCH 02/13] added flip-horiz, rotate, rotate180, rotate270 also added comments to help orient new users --- src/escher/core.clj | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index d541054..a2d74cc 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -2,12 +2,17 @@ (require [quil.core :as q]) (:gen-class)) +;; In Quil, [0 0] is upper left corner of window. +;; Increasing x values move a point to the right. +;; Increasing y values move a point downward. + (def width 600) (def height 600) (def draw-line q/line) -;; origin, e1, and e2 (all 2-D vectors) define a frame +;; origin, e1, and e2 (all 2-D vectors) define a frame. +;; Think of e1 as the x-axis, e2 as the y-axis. (def whole-window {:origin [0 0] :e1 [width 0] @@ -46,7 +51,8 @@ (defn frame-coord-map "Returns function that maps [x y] relative to the frame - defined by origin (a point) and vectors e1, e2." + defined by origin (a vector to be interpreted as the point + describing the origin) and vectors e1 (x-axis), e2 (y-axis)." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin @@ -80,12 +86,10 @@ (transform-picture p [0 1] [1 1] [0 0])) (defn flip-horiz [p] - ;; COMPLETE (Ex 2.50) - ) + (transform-picture p [1 0] [0 0] [1 1])) (defn rotate [p] - ;; COMPLETE - ) + (transform-picture p [1 0] [1 1] [0 0])) (defn rotate180 [p] (rotate (rotate p))) @@ -191,6 +195,10 @@ (def p21 (make-vect 0.15 0.4)) (def p22 (make-vect 0.0 0.15)) +;; Example usage of path: +;; (path p1 p2 p3) --> +;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) + ; Ex2.49, Make these shapes with segment-painter/path (def box ) (def x) @@ -227,10 +235,10 @@ ;; (frame-painter frame1) ;; (draw x) ;; (draw box) - ;; (george whole-window) - (draw george) + ;; (draw george) ;; (draw (rotate george)) - ;; (draw (flip-horiz george)) + (draw (beside george (rotate180 george))) + ;; (draw (flip-vert george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) ;; (draw (beside (below george george) From 7711d3491cd3cf7604ee6dcfde79dc6435ec9eb1 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Thu, 22 Jan 2015 20:03:08 -0800 Subject: [PATCH 03/13] added shapes; fcns for flipping, rotating, below shapes: box, x, diamond, george segment-lists allow compound shapes to be drawn using concat; see diamond-x fcns: flip-horiz, flip-vert; rotate, rotate180, rotate270; below --- src/escher/core.clj | 66 +++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index a2d74cc..473ca8f 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -26,21 +26,21 @@ :e1 [100 0] :e2 [0 200]}) -; gw + (defn make-vect [x y] [x y]) -; gw + (defn make-segment [p1 p2] [p1 p2]) -; gw + (defn add-vec [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)] ) -; gw + (defn sub-vec [[x1 y1] [x2 y2]] [(- x1 x2) (- y1 y2)] ) @@ -105,19 +105,17 @@ (left frame) (right frame)))) -; gw + (defn below [p1 p2] (rotate (beside (rotate270 p1) - (rotate270 p2))) - ) + (rotate270 p2)))) + -; gw (defn path - "Creates a seq of pairs-of-points from a 'bare' list of points. Use to + "Creates a seq of line-segments from a 'bare' list of points. Use to draw a continuous line through the list of points." [& veclist] - (partition 2 1 veclist) - ) + (partition 2 1 veclist)) (defn quartet [p1 p2 p3 p4] @@ -200,16 +198,41 @@ ;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) ; Ex2.49, Make these shapes with segment-painter/path -(def box ) -(def x) -(def diamond) -; gw -(def george-data + +;; By defining segment-lists separately, you can combine figures +;; by concat'ting their segment-lists--see diamond-x. + +(def box-segs + (path (make-vect 0 0) (make-vect 0.99 0) + (make-vect 0.99 0.99) (make-vect 0 0.99) + (make-vect 0 0))) +(def box + (segment-painter box-segs)) + +(def x-segs + (concat (path (make-vect 0 0) (make-vect 1 1)) + (path (make-vect 1 0) (make-vect 0 1)))) +(def x + (segment-painter x-segs)) + + +(def diamond-segs + (path (make-vect 0.5 0) (make-vect 1 0.5) + (make-vect 0.5 1) (make-vect 0 0.5) + (make-vect 0.5 0))) + +(def diamond + (segment-painter diamond-segs)) + +(def diamond-x + (segment-painter (concat diamond-segs x-segs))) + +(def george-segs (path p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 p21 p22)) -; gw -(def george (segment-painter george-data)) + +(def george (segment-painter george-segs)) (defn draw [picture] @@ -236,8 +259,11 @@ ;; (draw x) ;; (draw box) ;; (draw george) - ;; (draw (rotate george)) - (draw (beside george (rotate180 george))) + ;; (draw (rotate180 george)) + ;; (draw (beside (flip-horiz george) (flip-vert george))) + ;; (draw (beside (flip-horiz george) george)) + (draw (below (flip-horiz george) george)) + ;; (draw (beside box x)) ;; (draw (flip-vert george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) From 9b218f6212cb0104ce2de058f18e4b5c2d7a6635 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Fri, 23 Jan 2015 21:16:09 -0800 Subject: [PATCH 04/13] docs, comments, split fcn, arrow picture, cleanup Abstracted split-up, split-right into higher-level split function. --- src/escher/core.clj | 202 +++++++++++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 76 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 473ca8f..9d774f8 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -6,6 +6,8 @@ ;; Increasing x values move a point to the right. ;; Increasing y values move a point downward. + +;; defines size of Quil window (def width 600) (def height 600) @@ -27,14 +29,11 @@ :e2 [0 200]}) -(defn make-vect [x y] +(defn make-vec [x y] [x y]) - - -(defn make-segment [p1 p2] - [p1 p2]) - +(defn make-segment [vec1 vec2] + [vec1 vec2]) (defn add-vec [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)] @@ -49,10 +48,12 @@ [(* x s) (* y s)] ) + (defn frame-coord-map "Returns function that maps [x y] relative to the frame defined by origin (a vector to be interpreted as the point - describing the origin) and vectors e1 (x-axis), e2 (y-axis)." + describing the origin) and vectors e1 (x-axis), e2 (y-axis). + See SICP, 2nd ed., page 183." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin @@ -61,20 +62,27 @@ (defn frame-painter [{:keys [origin e1 e2]}] "Draws parallelogram 'frame' based on origin and vectors e1 and e2. - Must execute within a sketch." + Must execute within a Quil sketch." (let [corner (add-vec origin (add-vec e1 e2))] (draw-line origin (add-vec origin e1)) (draw-line origin (add-vec origin e2)) (draw-line (add-vec origin e2) corner) (draw-line (add-vec origin e1) corner))) -(defn segment-painter [segment-list] +(defn segment-painter + "Returns a function that, when given a frame as its argument, draws + the list of line segments in that frame." + [segment-list] (fn [frame] (let [m (frame-coord-map frame)] (doseq [[start end] segment-list] (draw-line (m start) (m end)))))) -(defn transform-picture [p origin e1 e2] +(defn transform-picture + "Transforms a picture by into a different picture, based on new vectors + for origin, e1, and e2. See SICP, 2nd ed., page 187-8. (Note that SICP + calls pictures 'painters' because they know how to paint themselves." + [p origin e1 e2] (fn [frame] (let [map (frame-coord-map frame) new-origin (map origin)] @@ -106,7 +114,9 @@ (right frame)))) -(defn below [p1 p2] +(defn below + "Draws p2 below p1." + [p1 p2] (rotate (beside (rotate270 p1) (rotate270 p2)))) @@ -130,24 +140,24 @@ (below top bottom)))) -(defn right-split [p n] - (if (= n 0) - p - (let [smaller (right-split p (dec n))] - (beside p (below smaller smaller))))) - -(defn up-split [p n] - ;; COMPLETE (Ex 2.44) - ) (defn split [f g] - ; COMPLETE (Ex 2.45) - "Should be able to do + "Higher-order function that allows the + following redefinitions: + (def right-split (split beside below)) - (def up-split (split below beside) - and replace the existing *-split fns" - ) + (def up-split (split below beside))" + (fn self-fn [p n] + (if (= n 0) + p + (let [smaller (self-fn p (dec n))] + (f p (g smaller smaller)))))) + +(def right-split (split beside below)) +(def up-split (split below beside)) + + (defn corner-split [p n] (if (= n 0) @@ -160,82 +170,118 @@ (beside (below p top-left) (below bottom-right corner))))) -(def combine-four (square-of-four flip-horiz - identity - rotate180 - flip-vert)) + +(def combine-four (square-of-four rotate180 + flip-vert + flip-horiz + identity)) (defn square-limit [p n] (combine-four (corner-split p n))) -;; George data - -(def p1 (make-vect 0 0.35)) -(def p2 (make-vect 0.15 0.6)) -(def p3 (make-vect 0.3 0.4)) -(def p4 (make-vect 0.35 0.5)) -(def p5 (make-vect 0.25 1.0)) -(def p6 (make-vect 0.4 1.0)) -(def p7 (make-vect 0.5 0.7)) -(def p8 (make-vect 0.6 1.0)) -(def p9 (make-vect 0.75 1.0)) -(def p10 (make-vect 0.6 0.55)) -(def p11 (make-vect 1 0.85)) -(def p12 (make-vect 1 0.65)) -(def p13 (make-vect 0.75 0.35)) -(def p14 (make-vect 0.6 0.35)) -(def p15 (make-vect 0.65 0.15)) -(def p16 (make-vect 0.6 0)) -(def p17 (make-vect 0.4 0)) -(def p18 (make-vect 0.35 0.15)) -(def p19 (make-vect 0.4 0.35)) -(def p20 (make-vect 0.3 0.35)) -(def p21 (make-vect 0.15 0.4)) -(def p22 (make-vect 0.0 0.15)) - ;; Example usage of path: ;; (path p1 p2 p3) --> ;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) -; Ex2.49, Make these shapes with segment-painter/path - ;; By defining segment-lists separately, you can combine figures ;; by concat'ting their segment-lists--see diamond-x. + +;; making George drawing + +(def p1 (make-vec 0 0.35)) +(def p2 (make-vec 0.15 0.6)) +(def p3 (make-vec 0.3 0.4)) +(def p4 (make-vec 0.35 0.5)) +(def p5 (make-vec 0.25 1.0)) +(def p6 (make-vec 0.4 1.0)) +(def p7 (make-vec 0.5 0.7)) +(def p8 (make-vec 0.6 1.0)) +(def p9 (make-vec 0.75 1.0)) +(def p10 (make-vec 0.6 0.55)) +(def p11 (make-vec 1 0.85)) +(def p12 (make-vec 1 0.65)) +(def p13 (make-vec 0.75 0.35)) +(def p14 (make-vec 0.6 0.35)) +(def p15 (make-vec 0.65 0.15)) +(def p16 (make-vec 0.6 0)) +(def p17 (make-vec 0.4 0)) +(def p18 (make-vec 0.35 0.15)) +(def p19 (make-vec 0.4 0.35)) +(def p20 (make-vec 0.3 0.35)) +(def p21 (make-vec 0.15 0.4)) +(def p22 (make-vec 0.0 0.15)) + +(def george-segs + (concat + (path p1 p2 p3 p4 p5) + (path p6 p7 p8) + (path p9 p10 p11) + (path p12 p13 p14 p15 p16) + (path p17 p18 p19 p20 p21 p22))) + +(def george (segment-painter george-segs)) + + +;; making arrow drawing + +(def length-delta 0.1) +(def arrow-dx 0.1) +(def arrow-dy 0.3) + +(def a1 (make-vec 0.5 (- 1 length-delta))) +(def a2 (make-vec 0.5 length-delta)) +(def shaft-segs (path a1 a2)) + +(def a3 (make-vec (- 0.5 arrow-dx) (+ arrow-dy length-delta))) +(def a4 (make-vec (+ 0.5 arrow-dx) (+ arrow-dy length-delta))) +(def head-segs (path a3 a2 a4)) + +(def arrow (segment-painter (concat shaft-segs head-segs))) + + +;; making box drawing + (def box-segs - (path (make-vect 0 0) (make-vect 0.99 0) - (make-vect 0.99 0.99) (make-vect 0 0.99) - (make-vect 0 0))) + (path (make-vec 0 0) (make-vec 1 0) + (make-vec 1 1) (make-vec 0 1) + (make-vec 0 0))) (def box (segment-painter box-segs)) (def x-segs - (concat (path (make-vect 0 0) (make-vect 1 1)) - (path (make-vect 1 0) (make-vect 0 1)))) + (concat (path (make-vec 0 0) (make-vec 1 1)) + (path (make-vec 1 0) (make-vec 0 1)))) (def x (segment-painter x-segs)) +;; making diamond drawing + (def diamond-segs - (path (make-vect 0.5 0) (make-vect 1 0.5) - (make-vect 0.5 1) (make-vect 0 0.5) - (make-vect 0.5 0))) + (path (make-vec 0.5 0) (make-vec 1 0.5) + (make-vec 0.5 1) (make-vec 0 0.5) + (make-vec 0.5 0))) (def diamond (segment-painter diamond-segs)) + +;; making diamond-x drawing + (def diamond-x (segment-painter (concat diamond-segs x-segs))) -(def george-segs - (path p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 - p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 - p21 p22)) -(def george (segment-painter george-segs)) +;; making diag drawing + +(def diag (segment-painter [[[0 0] [1 1]]])) + -(defn draw [picture] +(defn draw + "Draws picture, using the entire Quil window." + [picture] (picture whole-window)) (defn image-painter [img] @@ -248,9 +294,10 @@ ; COMPLETE ))) -(def diag (segment-painter [[[0 0] [1 1]]])) - -(defn draw-image [] +(defn draw-image + "'Container' for executing drawings within a Quil sketch. + Experiment by uncommenting one or more lines, or add your own." + [] (let [man (image-painter (q/load-image "data/man.gif")) bruce (image-painter (q/load-image "data/bruce.jpg")) angels (image-painter (q/load-image "data/angels.jpg"))] @@ -262,7 +309,9 @@ ;; (draw (rotate180 george)) ;; (draw (beside (flip-horiz george) (flip-vert george))) ;; (draw (beside (flip-horiz george) george)) - (draw (below (flip-horiz george) george)) + ;; (draw (below (flip-horiz george) george)) + ;; (draw (right-split george 3)) + ;; (draw (up-split george 3)) ;; (draw (beside box x)) ;; (draw (flip-vert george)) ;; (draw (beside box box)) @@ -275,13 +324,14 @@ ;; (draw ((square-of-four identity flip-vert ;; flip-horiz rotate) ;; george)) + (draw (square-limit arrow 4)) + ; Needs image-painter ;; (bruce frame1) ;; (bruce frame2) ;; (draw (beside george bruce)) - ;; (draw (corner-split bruce 4)) - ;; (draw (square-limit bruce 3)) + ;; (draw (corner-split george 4)) ;; (draw (beside bruce (below bruce ;; george))) )) From f8dc53523901f84b162294b3ba8f2bd7a6a3ac6f Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Fri, 27 Feb 2015 22:04:49 -0800 Subject: [PATCH 05/13] mostly completed, w/docstrings & refactoring for beginners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source code refactored, with comments and docstrings added, to make it easy for beginners to get up to speed quickly. Does not implement image-painter. To give yourself a chance to complete the exercise as ‘thattommyhall’ intended, delete the bodies of the following functions: add-vec sub-vec scale-vec flip-horiz rotate below path right-split (uncomment by removing “#_”) up-split (uncomment by removing “#_”) split Just evaluate this file to see the “goal” function, square-limit, draw itself. This version uses the “higher-level” versions of right-split and up-split. If you decide to write the code for up-split and derive the higher-level function ‘split’, you will need to comment out or remove the versions of right-split and up-split that follow split in the source code and un-comment the versions that precede split in the source code. Enjoy, and please give me feedback if you find my version helpful! --- src/escher/core.clj | 525 ++++++++++++++++++++++++++++++++------------ 1 file changed, 380 insertions(+), 145 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 9d774f8..40a75b5 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -2,39 +2,15 @@ (require [quil.core :as q]) (:gen-class)) -;; In Quil, [0 0] is upper left corner of window. -;; Increasing x values move a point to the right. -;; Increasing y values move a point downward. - - -;; defines size of Quil window -(def width 600) -(def height 600) - -(def draw-line q/line) - -;; origin, e1, and e2 (all 2-D vectors) define a frame. -;; Think of e1 as the x-axis, e2 as the y-axis. - -(def whole-window {:origin [0 0] - :e1 [width 0] - :e2 [0 height]}) - -(def frame1 {:origin [200 50] - :e1 [200 100] - :e2 [150 200]}) - -(def frame2 {:origin [50 50] - :e1 [100 0] - :e2 [0 200]}) - +;;================================================================== +;; +;; vector-manipulation primitives +;; +;;================================================================== (defn make-vec [x y] [x y]) -(defn make-segment [vec1 vec2] - [vec1 vec2]) - (defn add-vec [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)] ) @@ -49,46 +25,138 @@ ) +;;================================================================== +;; +;; What is a frame? +;; +;; A frame represents a transformation from one coordinate system +;; to another. The transformation described by: +;; +;; {:origin [n1 n2], :e1 [n3 n4], :e2 [n5 n6]} +;; +;; can express combinations of translation, scaling, shearing, +;; and reflection. +;; +;;================================================================== + + (defn frame-coord-map "Returns function that maps [x y] relative to the frame defined by origin (a vector to be interpreted as the point - describing the origin) and vectors e1 (x-axis), e2 (y-axis). - See SICP, 2nd ed., page 183." + describing the origin) and vectors e1 (x-axis), e2 (y-axis)-- + see SICP, 2nd ed., page 183. + + In this function, the frame describes the portion of the canvas + within which any untransformed picture will draw itself." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin (add-vec (scale-vec e1 x) (scale-vec e2 y))))) -(defn frame-painter [{:keys [origin e1 e2]}] - "Draws parallelogram 'frame' based on origin and vectors e1 and e2. + +;;================================================================== +;; +;; What is a picture? +;; +;; A picture is a function that, when given a frame, knows how to +;; draw itself in that frame. As such, it hides its implementation +;; details. +;; +;; This file defines two functions that draw pictures: +;; +;; segment-painter: creates a picture from line segments +;; image-painter: creates a picture from a GIF image +;; +;;================================================================== + + + +;;================================================================== +;; +;; Utilities for drawing simple graphics using line segments +;; +;;================================================================== + +(defn make-segment + "Represent a line segment as a vector of two vectors--e.g., + [[0 0] [1 0]] represents a line from [0 0] to [1 0]." + [vec1 vec2] + [vec1 vec2]) + +(defn path + "Creates a seq of line-segments from a 'bare' list of points. Use to + draw a continuous line through the list of points--e.g., + + (path [[0 1] [0 0] [1 0]]) + + returns two line segments connecting the three points in sequence: + + [ [[0 1] [0 0]] [[0 0] [1 0]] ]" + [& veclist] + (partition 2 1 veclist)) + +(def draw-line q/line) + + + +;;================================================================== +;; +;; for images drawn with line segments, this function returns +;; the picture (i.e., a function) that draws the desired image +;; +;;================================================================== + +(defn segment-painter + "Returns a picture that draws the given list of line segments. Must execute within a Quil sketch." + [segment-list] + ; xform-pt is a function that maps a point to the given frame + (fn [frame] + (let [xform-pt (frame-coord-map frame)] + (doseq [[start end] segment-list] + (draw-line (xform-pt start) (xform-pt end)))))) + + +(defn frame-painter [{:keys [origin e1 e2]}] + "Draws a parallelogram 'frame' based on origin and + vectors e1 and e2. Must execute within a Quil sketch. + + (Used only to confirm minimal project functionality: in draw-image, + uncomment '(frame-painter frame1)' and evaluate the code + in this file.)" (let [corner (add-vec origin (add-vec e1 e2))] (draw-line origin (add-vec origin e1)) (draw-line origin (add-vec origin e2)) (draw-line (add-vec origin e2) corner) (draw-line (add-vec origin e1) corner))) -(defn segment-painter - "Returns a function that, when given a frame as its argument, draws - the list of line segments in that frame." - [segment-list] - (fn [frame] - (let [m (frame-coord-map frame)] - (doseq [[start end] segment-list] - (draw-line (m start) (m end)))))) (defn transform-picture - "Transforms a picture by into a different picture, based on new vectors - for origin, e1, and e2. See SICP, 2nd ed., page 187-8. (Note that SICP - calls pictures 'painters' because they know how to paint themselves." + "Returns a transformed picture based on the values of origin, + e1, and e2, which together describe a transformation frame. + + Note that the returned picture will draw itself inside a + different frame (frame2), which can be considered to be a + drawing frame. The coordinates of origin, e1, and e2 are + usually within the range [0 1]--i.e.,a unit square with + origin [0 0]. Coordinates > 1 will draw outside the drawing + frame." [p origin e1 e2] - (fn [frame] - (let [map (frame-coord-map frame) - new-origin (map origin)] + (fn [frame2] + (let [unit-sq-xform (frame-coord-map frame2) + new-origin (unit-sq-xform origin)] (p {:origin new-origin - :e1 (sub-vec (map e1) new-origin) - :e2 (sub-vec (map e2) new-origin)})))) + :e1 (sub-vec (unit-sq-xform e1) new-origin) + :e2 (sub-vec (unit-sq-xform e2) new-origin)})))) + + + +;;================================================================== +;; +;; basic transformations of a single picture +;; +;;================================================================== (defn flip-vert [p] (transform-picture p [0 1] [1 1] [0 0])) @@ -103,9 +171,20 @@ (rotate (rotate p))) (defn rotate270 [p] - (rotate (rotate (rotate p)))) + (transform-picture p [0 1] [0 0] [1 1])) + -(defn beside [p1 p2] + +;;================================================================== +;; +;; transformations that combine 2 or 4 pictures into a new picture +;; +;;================================================================== + +(defn beside + "Returns a picture that, splitting its frame in half vertically, draws + p1 in the left half and p2 in the right half." + [p1 p2] (let [split [0.5 0] left (transform-picture p1 [0 0] split [0 1]) right (transform-picture p2 split [1 0] [0.5 1])] @@ -113,53 +192,73 @@ (left frame) (right frame)))) - (defn below - "Draws p2 below p1." + "Returns a picture that, splitting its frame in half horizintally, + draws p1 in the top half and p2 in the bottom half." [p1 p2] (rotate (beside (rotate270 p1) (rotate270 p2)))) +(defn quartet + "Returns a picture that subdivides its frame into quarters and + draws p1-p4 in order, left-to-right and top-to-bottom." + [p1 p2 p3 p4] + (below (beside p1 p2) + (beside p3 p4))) -(defn path - "Creates a seq of line-segments from a 'bare' list of points. Use to - draw a continuous line through the list of points." - [& veclist] - (partition 2 1 veclist)) -(defn quartet [p1 p2 p3 p4] - (below (beside p1 p2) - (beside p3 p4))) +;;================================================================== +;; +;; building-blocks for "goal" function, square-limit +;; +;;================================================================== -(defn square-of-four [tl tr - bl br] - (fn [p] - (let [top (beside (tl p) (tr p)) - bottom (beside (bl p) (br p))] - (below top - bottom)))) +#_(defn right-split [p n] + (if (= n 0) + p + (let [smaller (right-split p (dec n))] + (beside p (below smaller smaller))))) +#_(defn up-split [p n] + ;; COMPLETE (Ex 2.44) + ) (defn split [f g] - "Higher-order function that allows the - following redefinitions: - - (def right-split (split beside below)) - (def up-split (split below beside))" + "Higher-order function that allows the functions right-split + and left-split to be defined without duplicated code. (Hint: + define each function independently, then analyze the resulting + code to enable each function's redefinition in terms of the + two picture transformations f and g.)" (fn self-fn [p n] (if (= n 0) p (let [smaller (self-fn p (dec n))] (f p (g smaller smaller)))))) -(def right-split (split beside below)) -(def up-split (split below beside)) - - - -(defn corner-split [p n] +(def right-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the left half of the frame. Draws two copies of + (right-split p (- n 1)), stacked vertically, in the right half + of the frame. If n=0, draws p in the given frame." + (split beside below)) + +(def up-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the top half of the frame. Draws two copies of + (right-split p (- n 1)), one to the right of the other, in the + bottom half of the frame. If n=0, draws p in the current frame." + (split below beside)) + +(defn corner-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the upper-left quarter of frame. Draws two copies + of (right-split p (- n 1)) in upper-right quarter of frame. + Draws two copies of (top-split p (- n 1)) in the bottom-left + quarter of frame. Draws (corner-split p (- n 1)) in the bottom- + right quarter of frame. Wherever n=0, draws p in current frame." + [p n] (if (= n 0) p (let [up (up-split p (dec n)) @@ -170,60 +269,87 @@ (beside (below p top-left) (below bottom-right corner))))) +(defn square-of-four + "Returns a picture that subdivides its frame into quarters and + transforms the same picture p in four different ways, then + draws the results in order, left-to-right and top-to-bottom." + [tl tr + bl br] + (fn [p] + (let [top (beside (tl p) (tr p)) + bottom (beside (bl p) (br p))] + (below top + bottom)))) (def combine-four (square-of-four rotate180 flip-vert flip-horiz identity)) -(defn square-limit [p n] +(defn square-limit + "Returns a picture that has a 2 x 2 block of p in the center, encircled + by n borders of picture p, with each successive version of p being + half the size of the one that it immediately surrounds." + [p n] (combine-four (corner-split p n))) -;; Example usage of path: -;; (path p1 p2 p3) --> -;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) -;; By defining segment-lists separately, you can combine figures -;; by concat'ting their segment-lists--see diamond-x. +;;================================================================== +;;================================================================== +;; +;; Quil setup +;; +;;================================================================== +;;================================================================== -;; making George drawing +;; In Quil, [0 0] is upper left corner of window. +;; Increasing x values move a point to the right. +;; Increasing y values move a point downward. -(def p1 (make-vec 0 0.35)) -(def p2 (make-vec 0.15 0.6)) -(def p3 (make-vec 0.3 0.4)) -(def p4 (make-vec 0.35 0.5)) -(def p5 (make-vec 0.25 1.0)) -(def p6 (make-vec 0.4 1.0)) -(def p7 (make-vec 0.5 0.7)) -(def p8 (make-vec 0.6 1.0)) -(def p9 (make-vec 0.75 1.0)) -(def p10 (make-vec 0.6 0.55)) -(def p11 (make-vec 1 0.85)) -(def p12 (make-vec 1 0.65)) -(def p13 (make-vec 0.75 0.35)) -(def p14 (make-vec 0.6 0.35)) -(def p15 (make-vec 0.65 0.15)) -(def p16 (make-vec 0.6 0)) -(def p17 (make-vec 0.4 0)) -(def p18 (make-vec 0.35 0.15)) -(def p19 (make-vec 0.4 0.35)) -(def p20 (make-vec 0.3 0.35)) -(def p21 (make-vec 0.15 0.4)) -(def p22 (make-vec 0.0 0.15)) -(def george-segs - (concat - (path p1 p2 p3 p4 p5) - (path p6 p7 p8) - (path p9 p10 p11) - (path p12 p13 p14 p15 p16) - (path p17 p18 p19 p20 p21 p22))) +;; defines size of Quil window + +(def width 600) +(def height 600) + +;; origin, e1, and e2 (all 2-D vectors) define a frame. +;; Think of origin as a point, e1 as the x-axis, e2 as the y-axis. + +(def whole-window {:origin [0 0] + :e1 [width 0] + :e2 [0 height]}) + +(def frame1 {:origin [200 50] + :e1 [200 100] + :e2 [150 200]}) + +(def frame2 {:origin [50 50] + :e1 [100 0] + :e2 [0 200]}) + +(defn draw + "Draws picture, using the entire Quil window." + [picture] + (picture whole-window)) + -(def george (segment-painter george-segs)) +;;================================================================== +;;================================================================== +;; +;; PICTURES THAT ARE DRAWN USING SEGMENT-PAINTER +;; +;;================================================================== +;;================================================================== -;; making arrow drawing + +;;================================================================== +;; +;; arrow: a picture that draws an arrow pointing toward the +;; top of the screen +;; +;;================================================================== (def length-delta 0.1) (def arrow-dx 0.1) @@ -240,23 +366,45 @@ (def arrow (segment-painter (concat shaft-segs head-segs))) -;; making box drawing + +;;================================================================== +;; +;; box: a picture that draws a square +;; +;;================================================================== + (def box-segs (path (make-vec 0 0) (make-vec 1 0) (make-vec 1 1) (make-vec 0 1) (make-vec 0 0))) + (def box (segment-painter box-segs)) + + +;;================================================================== +;; +;; x: a picture that draws an "x" (as if from the vertices of 'box') +;; +;;================================================================== + (def x-segs (concat (path (make-vec 0 0) (make-vec 1 1)) (path (make-vec 1 0) (make-vec 0 1)))) + (def x (segment-painter x-segs)) -;; making diamond drawing + +;;================================================================== +;; +;; diamond: a picture that draws a square for which one diagonal +;; is horizontal and the other is vertical +;; +;;================================================================== (def diamond-segs (path (make-vec 0.5 0) (make-vec 1 0.5) @@ -267,22 +415,100 @@ (segment-painter diamond-segs)) -;; making diamond-x drawing + +;;================================================================== +;; +;; diamond-x: a picture that draws both 'x' and 'diamond' (in +;; the same frame) +;; +;;================================================================== + +;; Note that you can use (concat path1 path2 ... pathN) +;; to combine multiple non-connected paths into a single +;; sequence of line segments (for use with segment-painter). (def diamond-x (segment-painter (concat diamond-segs x-segs))) -;; making diag drawing +;;================================================================== +;; +;; george: a "man" figure using line segments +;; +;;================================================================== + +(def p1 (make-vec 0 0.35)) +(def p2 (make-vec 0.15 0.6)) +(def p3 (make-vec 0.3 0.4)) +(def p4 (make-vec 0.35 0.5)) +(def p5 (make-vec 0.25 1.0)) +(def p6 (make-vec 0.4 1.0)) +(def p7 (make-vec 0.5 0.7)) +(def p8 (make-vec 0.6 1.0)) +(def p9 (make-vec 0.75 1.0)) +(def p10 (make-vec 0.6 0.55)) +(def p11 (make-vec 1 0.85)) +(def p12 (make-vec 1 0.65)) +(def p13 (make-vec 0.75 0.35)) +(def p14 (make-vec 0.6 0.35)) +(def p15 (make-vec 0.65 0.15)) +(def p16 (make-vec 0.6 0)) +(def p17 (make-vec 0.4 0)) +(def p18 (make-vec 0.35 0.15)) +(def p19 (make-vec 0.4 0.35)) +(def p20 (make-vec 0.3 0.35)) +(def p21 (make-vec 0.15 0.4)) +(def p22 (make-vec 0.0 0.15)) + +;; draws a small square in the upper left corner +;(def p23 (make-vec 0.0 0.0)) +;(def p24 (make-vec 0.03 0.0)) +;(def p25 (make-vec 0.03 0.03)) +;(def p26 (make-vec 0.0 0.03)) + +;; draws a slightly larger square in the lower right corner +;(def p27 (make-vec 1 1)) +;(def p28 (make-vec 0.94 1)) +;(def p29 (make-vec 0.94 0.94)) +;(def p30 (make-vec 1 0.94)) + +(def george-segs + (concat + (path p1 p2 p3 p4 p5) + (path p6 p7 p8) + (path p9 p10 p11) + (path p12 p13 p14 p15 p16) + (path p17 p18 p19 p20 p21 p22) + +; (path p23 p24 p25 p26 p23) ; dot for origin +; (path p27 p28 p29 p30 p27) ; larger dot for opposite corner + )) + +(def george (segment-painter george-segs)) + + +; unused by other code, as far as I can tell (def diag (segment-painter [[[0 0] [1 1]]])) -(defn draw - "Draws picture, using the entire Quil window." - [picture] - (picture whole-window)) + +;;================================================================== +;;================================================================== +;; +;; for images drawn with GIFs and JPGs, this function returns +;; the picture (i.e., a function) that draws the desired image +;; +;; (This function needs to be completed. People have found +;; the following URLs helpful: +;; +;; http://quil.info/api/transform +;; http://homepages.inf.ed.ac.uk/rbf/HIPR2/affine.htm +;; http://www.cs.colorado.edu/~mcbryan/5229.03/mail/55.htm ) +;; +;;================================================================== +;;================================================================== (defn image-painter [img] (fn [{[ox oy] :origin @@ -294,8 +520,12 @@ ; COMPLETE ))) -(defn draw-image - "'Container' for executing drawings within a Quil sketch. + + + + +(defn draw-pictures + "'Container' for executing drawing(s) within a Quil sketch. Experiment by uncommenting one or more lines, or add your own." [] (let [man (image-painter (q/load-image "data/man.gif")) @@ -305,40 +535,45 @@ ;; (frame-painter frame1) ;; (draw x) ;; (draw box) - ;; (draw george) - ;; (draw (rotate180 george)) - ;; (draw (beside (flip-horiz george) (flip-vert george))) - ;; (draw (beside (flip-horiz george) george)) - ;; (draw (below (flip-horiz george) george)) - ;; (draw (right-split george 3)) - ;; (draw (up-split george 3)) - ;; (draw (beside box x)) - ;; (draw (flip-vert george)) + ;; (george frame2) + ;; (draw (rotate george)) + ;; (draw (flip-horiz george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) ;; (draw (beside (below george george) - ;; (flip-horiz (below george george)))) + ;; (flip-horiz (below george george)))) ;; (draw (below (beside george (flip-horiz george)) - ;; (beside george (flip-horiz george)))) + ;; (beside george (flip-horiz george)))) ;; (draw ((square-of-four identity flip-vert ;; flip-horiz rotate) - ;; george)) - (draw (square-limit arrow 4)) + ;; george)) + + (draw (square-limit george 3)) + ; these pictures need image-painter to be implemented - ; Needs image-painter ;; (bruce frame1) ;; (bruce frame2) ;; (draw (beside george bruce)) - ;; (draw (corner-split george 4)) - ;; (draw (beside bruce (below bruce - ;; george))) + ;; (draw (corner-split bruce 4)) + ;; (draw (square-limit bruce 3)) + ;; (draw (beside bruce (below bruce + ;; george))) )) + + +;;================================================================== +;; +;; this is the code that sets the size of the Quil window and +;; causes draw-pictures to be executed +;; +;;================================================================== + (q/defsketch escher :title "Escher" - :draw draw-image + :draw draw-pictures :size [width height]) (defn -main []) From 2666ba0e4c98867bf2cd9c5832f225ee6141c262 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Sat, 21 Mar 2015 20:48:00 -0700 Subject: [PATCH 06/13] "over" xform, basic HSB color --- src/escher/core.clj | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 40a75b5..7e9243d 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -206,6 +206,10 @@ (below (beside p1 p2) (beside p3 p4))) +(defn over [p1 p2] + (fn [frame] + (p2 frame) + (p1 frame))) ;;================================================================== @@ -520,7 +524,15 @@ ; COMPLETE ))) +(def red [0 100 100]) +(def green [33 100 100]) +(def blue [66 100 100]) +(defn hsbpic + [p [h s b]] + (fn [frame] + (q/with-stroke [h s b] + (p frame)))) @@ -530,8 +542,12 @@ [] (let [man (image-painter (q/load-image "data/man.gif")) bruce (image-painter (q/load-image "data/bruce.jpg")) - angels (image-painter (q/load-image "data/angels.jpg"))] - (q/background 255) + angels (image-painter (q/load-image "data/angels.jpg")) + ] + (q/stroke-weight 4) + (q/color-mode :hsb 100) + + (q/background 0 0 100) ;; (frame-painter frame1) ;; (draw x) ;; (draw box) @@ -540,8 +556,12 @@ ;; (draw (flip-horiz george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) - ;; (draw (beside (below george george) - ;; (flip-horiz (below george george)))) + #_(draw (beside (hsvpic (below george george) red) + (hsvpic (flip-horiz (below george george)) blue))) + + (draw (over (hsbpic george red) + (hsbpic (rotate george) blue))) + ;; (draw (below (beside george (flip-horiz george)) ;; (beside george (flip-horiz george)))) @@ -549,7 +569,15 @@ ;; flip-horiz rotate) ;; george)) - (draw (square-limit george 3)) + ;(q/stroke 133 20 50) + + #_(q/with-stroke [200 50 50] + (draw (square-limit george 3))) + + + ;(draw (color-picture (square-limit george 2) 255 0 0)) + + ;(println (format "%x" (q/current-stroke))) ; these pictures need image-painter to be implemented @@ -571,9 +599,14 @@ ;; ;;================================================================== +(defn setup [] + ; draw will be called 4 times per second + ;(q/frame-rate 4) + ) + (q/defsketch escher :title "Escher" :draw draw-pictures :size [width height]) -(defn -main []) +;(defn -main []) From 9c020b3147d8ac39e78917f15e4381db05566a1a Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Mon, 23 Mar 2015 11:45:55 -0700 Subject: [PATCH 07/13] adds definition of 'over' picture xformation This reverts commit f8dc53523901f84b162294b3ba8f2bd7a6a3ac6f. Conflicts: src/escher/core.clj --- src/escher/core.clj | 521 ++++++++++++++------------------------------ 1 file changed, 160 insertions(+), 361 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 7e9243d..59e958e 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -2,15 +2,39 @@ (require [quil.core :as q]) (:gen-class)) -;;================================================================== -;; -;; vector-manipulation primitives -;; -;;================================================================== +;; In Quil, [0 0] is upper left corner of window. +;; Increasing x values move a point to the right. +;; Increasing y values move a point downward. + + +;; defines size of Quil window +(def width 600) +(def height 600) + +(def draw-line q/line) + +;; origin, e1, and e2 (all 2-D vectors) define a frame. +;; Think of e1 as the x-axis, e2 as the y-axis. + +(def whole-window {:origin [0 0] + :e1 [width 0] + :e2 [0 height]}) + +(def frame1 {:origin [200 50] + :e1 [200 100] + :e2 [150 200]}) + +(def frame2 {:origin [50 50] + :e1 [100 0] + :e2 [0 200]}) + (defn make-vec [x y] [x y]) +(defn make-segment [vec1 vec2] + [vec1 vec2]) + (defn add-vec [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)] ) @@ -25,138 +49,46 @@ ) -;;================================================================== -;; -;; What is a frame? -;; -;; A frame represents a transformation from one coordinate system -;; to another. The transformation described by: -;; -;; {:origin [n1 n2], :e1 [n3 n4], :e2 [n5 n6]} -;; -;; can express combinations of translation, scaling, shearing, -;; and reflection. -;; -;;================================================================== - - (defn frame-coord-map "Returns function that maps [x y] relative to the frame defined by origin (a vector to be interpreted as the point - describing the origin) and vectors e1 (x-axis), e2 (y-axis)-- - see SICP, 2nd ed., page 183. - - In this function, the frame describes the portion of the canvas - within which any untransformed picture will draw itself." + describing the origin) and vectors e1 (x-axis), e2 (y-axis). + See SICP, 2nd ed., page 183." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin (add-vec (scale-vec e1 x) (scale-vec e2 y))))) - -;;================================================================== -;; -;; What is a picture? -;; -;; A picture is a function that, when given a frame, knows how to -;; draw itself in that frame. As such, it hides its implementation -;; details. -;; -;; This file defines two functions that draw pictures: -;; -;; segment-painter: creates a picture from line segments -;; image-painter: creates a picture from a GIF image -;; -;;================================================================== - - - -;;================================================================== -;; -;; Utilities for drawing simple graphics using line segments -;; -;;================================================================== - -(defn make-segment - "Represent a line segment as a vector of two vectors--e.g., - [[0 0] [1 0]] represents a line from [0 0] to [1 0]." - [vec1 vec2] - [vec1 vec2]) - -(defn path - "Creates a seq of line-segments from a 'bare' list of points. Use to - draw a continuous line through the list of points--e.g., - - (path [[0 1] [0 0] [1 0]]) - - returns two line segments connecting the three points in sequence: - - [ [[0 1] [0 0]] [[0 0] [1 0]] ]" - [& veclist] - (partition 2 1 veclist)) - -(def draw-line q/line) - - - -;;================================================================== -;; -;; for images drawn with line segments, this function returns -;; the picture (i.e., a function) that draws the desired image -;; -;;================================================================== - -(defn segment-painter - "Returns a picture that draws the given list of line segments. - Must execute within a Quil sketch." - [segment-list] - ; xform-pt is a function that maps a point to the given frame - (fn [frame] - (let [xform-pt (frame-coord-map frame)] - (doseq [[start end] segment-list] - (draw-line (xform-pt start) (xform-pt end)))))) - - (defn frame-painter [{:keys [origin e1 e2]}] - "Draws a parallelogram 'frame' based on origin and - vectors e1 and e2. Must execute within a Quil sketch. - - (Used only to confirm minimal project functionality: in draw-image, - uncomment '(frame-painter frame1)' and evaluate the code - in this file.)" + "Draws parallelogram 'frame' based on origin and vectors e1 and e2. + Must execute within a Quil sketch." (let [corner (add-vec origin (add-vec e1 e2))] (draw-line origin (add-vec origin e1)) (draw-line origin (add-vec origin e2)) (draw-line (add-vec origin e2) corner) (draw-line (add-vec origin e1) corner))) +(defn segment-painter + "Returns a function that, when given a frame as its argument, draws + the list of line segments in that frame." + [segment-list] + (fn [frame] + (let [m (frame-coord-map frame)] + (doseq [[start end] segment-list] + (draw-line (m start) (m end)))))) (defn transform-picture - "Returns a transformed picture based on the values of origin, - e1, and e2, which together describe a transformation frame. - - Note that the returned picture will draw itself inside a - different frame (frame2), which can be considered to be a - drawing frame. The coordinates of origin, e1, and e2 are - usually within the range [0 1]--i.e.,a unit square with - origin [0 0]. Coordinates > 1 will draw outside the drawing - frame." + "Transforms a picture by into a different picture, based on new vectors + for origin, e1, and e2. See SICP, 2nd ed., page 187-8. (Note that SICP + calls pictures 'painters' because they know how to paint themselves." [p origin e1 e2] - (fn [frame2] - (let [unit-sq-xform (frame-coord-map frame2) - new-origin (unit-sq-xform origin)] + (fn [frame] + (let [map (frame-coord-map frame) + new-origin (map origin)] (p {:origin new-origin - :e1 (sub-vec (unit-sq-xform e1) new-origin) - :e2 (sub-vec (unit-sq-xform e2) new-origin)})))) - - - -;;================================================================== -;; -;; basic transformations of a single picture -;; -;;================================================================== + :e1 (sub-vec (map e1) new-origin) + :e2 (sub-vec (map e2) new-origin)})))) (defn flip-vert [p] (transform-picture p [0 1] [1 1] [0 0])) @@ -171,20 +103,9 @@ (rotate (rotate p))) (defn rotate270 [p] - (transform-picture p [0 1] [0 0] [1 1])) - - - -;;================================================================== -;; -;; transformations that combine 2 or 4 pictures into a new picture -;; -;;================================================================== + (rotate (rotate (rotate p)))) -(defn beside - "Returns a picture that, splitting its frame in half vertically, draws - p1 in the left half and p2 in the right half." - [p1 p2] +(defn beside [p1 p2] (let [split [0.5 0] left (transform-picture p1 [0 0] split [0 1]) right (transform-picture p2 split [1 0] [0.5 1])] @@ -192,19 +113,14 @@ (left frame) (right frame)))) + (defn below - "Returns a picture that, splitting its frame in half horizintally, - draws p1 in the top half and p2 in the bottom half." + "Draws p2 below p1." [p1 p2] (rotate (beside (rotate270 p1) (rotate270 p2)))) -(defn quartet - "Returns a picture that subdivides its frame into quarters and - draws p1-p4 in order, left-to-right and top-to-bottom." - [p1 p2 p3 p4] - (below (beside p1 p2) - (beside p3 p4))) + (defn over [p1 p2] (fn [frame] @@ -212,57 +128,44 @@ (p1 frame))) -;;================================================================== -;; -;; building-blocks for "goal" function, square-limit -;; -;;================================================================== +(defn path + "Creates a seq of line-segments from a 'bare' list of points. Use to + draw a continuous line through the list of points." + [& veclist] + (partition 2 1 veclist)) -#_(defn right-split [p n] - (if (= n 0) - p - (let [smaller (right-split p (dec n))] - (beside p (below smaller smaller))))) +(defn quartet [p1 p2 p3 p4] + (below (beside p1 p2) + (beside p3 p4))) + +(defn square-of-four [tl tr + bl br] + (fn [p] + (let [top (beside (tl p) (tr p)) + bottom (beside (bl p) (br p))] + (below top + bottom)))) -#_(defn up-split [p n] - ;; COMPLETE (Ex 2.44) - ) (defn split [f g] - "Higher-order function that allows the functions right-split - and left-split to be defined without duplicated code. (Hint: - define each function independently, then analyze the resulting - code to enable each function's redefinition in terms of the - two picture transformations f and g.)" + "Higher-order function that allows the + following redefinitions: + + (def right-split (split beside below)) + (def up-split (split below beside))" (fn self-fn [p n] (if (= n 0) p (let [smaller (self-fn p (dec n))] (f p (g smaller smaller)))))) -(def right-split - "Returns a picture based on picture p and level-of-recursion n. - Draws p in the left half of the frame. Draws two copies of - (right-split p (- n 1)), stacked vertically, in the right half - of the frame. If n=0, draws p in the given frame." - (split beside below)) - -(def up-split - "Returns a picture based on picture p and level-of-recursion n. - Draws p in the top half of the frame. Draws two copies of - (right-split p (- n 1)), one to the right of the other, in the - bottom half of the frame. If n=0, draws p in the current frame." - (split below beside)) - -(defn corner-split - "Returns a picture based on picture p and level-of-recursion n. - Draws p in the upper-left quarter of frame. Draws two copies - of (right-split p (- n 1)) in upper-right quarter of frame. - Draws two copies of (top-split p (- n 1)) in the bottom-left - quarter of frame. Draws (corner-split p (- n 1)) in the bottom- - right quarter of frame. Wherever n=0, draws p in current frame." - [p n] +(def right-split (split beside below)) +(def up-split (split below beside)) + + + +(defn corner-split [p n] (if (= n 0) p (let [up (up-split p (dec n)) @@ -273,87 +176,60 @@ (beside (below p top-left) (below bottom-right corner))))) -(defn square-of-four - "Returns a picture that subdivides its frame into quarters and - transforms the same picture p in four different ways, then - draws the results in order, left-to-right and top-to-bottom." - [tl tr - bl br] - (fn [p] - (let [top (beside (tl p) (tr p)) - bottom (beside (bl p) (br p))] - (below top - bottom)))) (def combine-four (square-of-four rotate180 flip-vert flip-horiz identity)) -(defn square-limit - "Returns a picture that has a 2 x 2 block of p in the center, encircled - by n borders of picture p, with each successive version of p being - half the size of the one that it immediately surrounds." - [p n] +(defn square-limit [p n] (combine-four (corner-split p n))) +;; Example usage of path: +;; (path p1 p2 p3) --> +;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) +;; By defining segment-lists separately, you can combine figures +;; by concat'ting their segment-lists--see diamond-x. -;;================================================================== -;;================================================================== -;; -;; Quil setup -;; -;;================================================================== -;;================================================================== - -;; In Quil, [0 0] is upper left corner of window. -;; Increasing x values move a point to the right. -;; Increasing y values move a point downward. - - -;; defines size of Quil window - -(def width 600) -(def height 600) - -;; origin, e1, and e2 (all 2-D vectors) define a frame. -;; Think of origin as a point, e1 as the x-axis, e2 as the y-axis. - -(def whole-window {:origin [0 0] - :e1 [width 0] - :e2 [0 height]}) - -(def frame1 {:origin [200 50] - :e1 [200 100] - :e2 [150 200]}) - -(def frame2 {:origin [50 50] - :e1 [100 0] - :e2 [0 200]}) -(defn draw - "Draws picture, using the entire Quil window." - [picture] - (picture whole-window)) +;; making George drawing +(def p1 (make-vec 0 0.35)) +(def p2 (make-vec 0.15 0.6)) +(def p3 (make-vec 0.3 0.4)) +(def p4 (make-vec 0.35 0.5)) +(def p5 (make-vec 0.25 1.0)) +(def p6 (make-vec 0.4 1.0)) +(def p7 (make-vec 0.5 0.7)) +(def p8 (make-vec 0.6 1.0)) +(def p9 (make-vec 0.75 1.0)) +(def p10 (make-vec 0.6 0.55)) +(def p11 (make-vec 1 0.85)) +(def p12 (make-vec 1 0.65)) +(def p13 (make-vec 0.75 0.35)) +(def p14 (make-vec 0.6 0.35)) +(def p15 (make-vec 0.65 0.15)) +(def p16 (make-vec 0.6 0)) +(def p17 (make-vec 0.4 0)) +(def p18 (make-vec 0.35 0.15)) +(def p19 (make-vec 0.4 0.35)) +(def p20 (make-vec 0.3 0.35)) +(def p21 (make-vec 0.15 0.4)) +(def p22 (make-vec 0.0 0.15)) +(def george-segs + (concat + (path p1 p2 p3 p4 p5) + (path p6 p7 p8) + (path p9 p10 p11) + (path p12 p13 p14 p15 p16) + (path p17 p18 p19 p20 p21 p22))) -;;================================================================== -;;================================================================== -;; -;; PICTURES THAT ARE DRAWN USING SEGMENT-PAINTER -;; -;;================================================================== -;;================================================================== +(def george (segment-painter george-segs)) -;;================================================================== -;; -;; arrow: a picture that draws an arrow pointing toward the -;; top of the screen -;; -;;================================================================== +;; making arrow drawing (def length-delta 0.1) (def arrow-dx 0.1) @@ -370,45 +246,23 @@ (def arrow (segment-painter (concat shaft-segs head-segs))) - -;;================================================================== -;; -;; box: a picture that draws a square -;; -;;================================================================== - +;; making box drawing (def box-segs (path (make-vec 0 0) (make-vec 1 0) (make-vec 1 1) (make-vec 0 1) (make-vec 0 0))) - (def box (segment-painter box-segs)) - - -;;================================================================== -;; -;; x: a picture that draws an "x" (as if from the vertices of 'box') -;; -;;================================================================== - (def x-segs (concat (path (make-vec 0 0) (make-vec 1 1)) (path (make-vec 1 0) (make-vec 0 1)))) - (def x (segment-painter x-segs)) - -;;================================================================== -;; -;; diamond: a picture that draws a square for which one diagonal -;; is horizontal and the other is vertical -;; -;;================================================================== +;; making diamond drawing (def diamond-segs (path (make-vec 0.5 0) (make-vec 1 0.5) @@ -419,100 +273,22 @@ (segment-painter diamond-segs)) - -;;================================================================== -;; -;; diamond-x: a picture that draws both 'x' and 'diamond' (in -;; the same frame) -;; -;;================================================================== - -;; Note that you can use (concat path1 path2 ... pathN) -;; to combine multiple non-connected paths into a single -;; sequence of line segments (for use with segment-painter). +;; making diamond-x drawing (def diamond-x (segment-painter (concat diamond-segs x-segs))) +;; making diag drawing -;;================================================================== -;; -;; george: a "man" figure using line segments -;; -;;================================================================== - -(def p1 (make-vec 0 0.35)) -(def p2 (make-vec 0.15 0.6)) -(def p3 (make-vec 0.3 0.4)) -(def p4 (make-vec 0.35 0.5)) -(def p5 (make-vec 0.25 1.0)) -(def p6 (make-vec 0.4 1.0)) -(def p7 (make-vec 0.5 0.7)) -(def p8 (make-vec 0.6 1.0)) -(def p9 (make-vec 0.75 1.0)) -(def p10 (make-vec 0.6 0.55)) -(def p11 (make-vec 1 0.85)) -(def p12 (make-vec 1 0.65)) -(def p13 (make-vec 0.75 0.35)) -(def p14 (make-vec 0.6 0.35)) -(def p15 (make-vec 0.65 0.15)) -(def p16 (make-vec 0.6 0)) -(def p17 (make-vec 0.4 0)) -(def p18 (make-vec 0.35 0.15)) -(def p19 (make-vec 0.4 0.35)) -(def p20 (make-vec 0.3 0.35)) -(def p21 (make-vec 0.15 0.4)) -(def p22 (make-vec 0.0 0.15)) - -;; draws a small square in the upper left corner -;(def p23 (make-vec 0.0 0.0)) -;(def p24 (make-vec 0.03 0.0)) -;(def p25 (make-vec 0.03 0.03)) -;(def p26 (make-vec 0.0 0.03)) - -;; draws a slightly larger square in the lower right corner -;(def p27 (make-vec 1 1)) -;(def p28 (make-vec 0.94 1)) -;(def p29 (make-vec 0.94 0.94)) -;(def p30 (make-vec 1 0.94)) - -(def george-segs - (concat - (path p1 p2 p3 p4 p5) - (path p6 p7 p8) - (path p9 p10 p11) - (path p12 p13 p14 p15 p16) - (path p17 p18 p19 p20 p21 p22) - -; (path p23 p24 p25 p26 p23) ; dot for origin -; (path p27 p28 p29 p30 p27) ; larger dot for opposite corner - )) - -(def george (segment-painter george-segs)) - - -; unused by other code, as far as I can tell (def diag (segment-painter [[[0 0] [1 1]]])) - -;;================================================================== -;;================================================================== -;; -;; for images drawn with GIFs and JPGs, this function returns -;; the picture (i.e., a function) that draws the desired image -;; -;; (This function needs to be completed. People have found -;; the following URLs helpful: -;; -;; http://quil.info/api/transform -;; http://homepages.inf.ed.ac.uk/rbf/HIPR2/affine.htm -;; http://www.cs.colorado.edu/~mcbryan/5229.03/mail/55.htm ) -;; -;;================================================================== -;;================================================================== +(defn draw + "Draws picture, using the entire Quil window." + [picture] + (picture whole-window)) (defn image-painter [img] (fn [{[ox oy] :origin @@ -524,6 +300,7 @@ ; COMPLETE ))) +<<<<<<< HEAD (def red [0 100 100]) (def green [33 100 100]) (def blue [66 100 100]) @@ -538,6 +315,10 @@ (defn draw-pictures "'Container' for executing drawing(s) within a Quil sketch. +======= +(defn draw-image + "'Container' for executing drawings within a Quil sketch. +>>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners Experiment by uncommenting one or more lines, or add your own." [] (let [man (image-painter (q/load-image "data/man.gif")) @@ -551,22 +332,34 @@ ;; (frame-painter frame1) ;; (draw x) ;; (draw box) - ;; (george frame2) - ;; (draw (rotate george)) - ;; (draw (flip-horiz george)) + ;; (draw george) + ;; (draw (rotate180 george)) + ;; (draw (beside (flip-horiz george) (flip-vert george))) + ;; (draw (beside (flip-horiz george) george)) + ;; (draw (below (flip-horiz george) george)) + ;; (draw (right-split george 3)) + ;; (draw (up-split george 3)) + ;; (draw (beside box x)) + ;; (draw (flip-vert george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) +<<<<<<< HEAD #_(draw (beside (hsvpic (below george george) red) (hsvpic (flip-horiz (below george george)) blue))) (draw (over (hsbpic george red) (hsbpic (rotate george) blue))) +======= + ;; (draw (beside (below george george) + ;; (flip-horiz (below george george)))) +>>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners ;; (draw (below (beside george (flip-horiz george)) - ;; (beside george (flip-horiz george)))) + ;; (beside george (flip-horiz george)))) ;; (draw ((square-of-four identity flip-vert ;; flip-horiz rotate) +<<<<<<< HEAD ;; george)) ;(q/stroke 133 20 50) @@ -578,18 +371,22 @@ ;(draw (color-picture (square-limit george 2) 255 0 0)) ;(println (format "%x" (q/current-stroke))) +======= + ;; george)) + (draw (square-limit arrow 4)) +>>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners - ; these pictures need image-painter to be implemented + ; Needs image-painter ;; (bruce frame1) ;; (bruce frame2) ;; (draw (beside george bruce)) - ;; (draw (corner-split bruce 4)) - ;; (draw (square-limit bruce 3)) - ;; (draw (beside bruce (below bruce - ;; george))) + ;; (draw (corner-split george 4)) + ;; (draw (beside bruce (below bruce + ;; george))) )) +<<<<<<< HEAD ;;================================================================== @@ -604,9 +401,11 @@ ;(q/frame-rate 4) ) +======= +>>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners (q/defsketch escher :title "Escher" - :draw draw-pictures + :draw draw-image :size [width height]) ;(defn -main []) From 85cf553895cb827bb18d53c7dd3e27c958bba5f2 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Mon, 23 Mar 2015 12:39:47 -0700 Subject: [PATCH 08/13] now uses clj-tuple for creating vectors, hash maps --- project.clj | 1 + src/escher/core.clj | 71 ++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/project.clj b/project.clj index 9e76180..8364b82 100644 --- a/project.clj +++ b/project.clj @@ -4,6 +4,7 @@ :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] + [clj-tuple "0.2.0"] [quil "2.2.4"]] :main ^:skip-aot escher.core :target-path "target/%s" diff --git a/src/escher/core.clj b/src/escher/core.clj index 7e9243d..174888c 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -1,5 +1,6 @@ (ns escher.core - (require [quil.core :as q]) + (require [quil.core :as q] + [clj-tuple :as tup]) (:gen-class)) ;;================================================================== @@ -9,20 +10,17 @@ ;;================================================================== (defn make-vec [x y] - [x y]) + (tup/vector x y)) (defn add-vec [[x1 y1] [x2 y2]] - [(+ x1 x2) (+ y1 y2)] - ) + (tup/vector (+ x1 x2) (+ y1 y2))) (defn sub-vec [[x1 y1] [x2 y2]] - [(- x1 x2) (- y1 y2)] - ) + (tup/vector (- x1 x2) (- y1 y2))) (defn scale-vec [[x y] s] - [(* x s) (* y s)] - ) + (tup/vector (* x s) (* y s))) ;;================================================================== @@ -82,7 +80,7 @@ "Represent a line segment as a vector of two vectors--e.g., [[0 0] [1 0]] represents a line from [0 0] to [1 0]." [vec1 vec2] - [vec1 vec2]) + (tup/vector vec1 vec2)) (defn path "Creates a seq of line-segments from a 'bare' list of points. Use to @@ -146,9 +144,9 @@ (fn [frame2] (let [unit-sq-xform (frame-coord-map frame2) new-origin (unit-sq-xform origin)] - (p {:origin new-origin - :e1 (sub-vec (unit-sq-xform e1) new-origin) - :e2 (sub-vec (unit-sq-xform e2) new-origin)})))) + (p (tup/hash-map :origin new-origin + :e1 (sub-vec (unit-sq-xform e1) new-origin) + :e2 (sub-vec (unit-sq-xform e2) new-origin)))))) @@ -159,19 +157,19 @@ ;;================================================================== (defn flip-vert [p] - (transform-picture p [0 1] [1 1] [0 0])) + (transform-picture p (tup/vector 0 1) (tup/vector 1 1) (tup/vector 0 0))) (defn flip-horiz [p] - (transform-picture p [1 0] [0 0] [1 1])) + (transform-picture p (tup/vector 1 0) (tup/vector 0 0) (tup/vector 1 1))) (defn rotate [p] - (transform-picture p [1 0] [1 1] [0 0])) + (transform-picture p (tup/vector 1 0) (tup/vector 1 1) (tup/vector 0 0))) (defn rotate180 [p] (rotate (rotate p))) (defn rotate270 [p] - (transform-picture p [0 1] [0 0] [1 1])) + (transform-picture p (tup/vector 0 1) (tup/vector 0 0) (tup/vector 1 1))) @@ -185,9 +183,9 @@ "Returns a picture that, splitting its frame in half vertically, draws p1 in the left half and p2 in the right half." [p1 p2] - (let [split [0.5 0] - left (transform-picture p1 [0 0] split [0 1]) - right (transform-picture p2 split [1 0] [0.5 1])] + (let [split (tup/vector 0.5 0) + left (transform-picture p1 (tup/vector 0 0) split (tup/vector 0 1)) + right (transform-picture p2 split (tup/vector 1 0) (tup/vector 0.5 1))] (fn [frame] (left frame) (right frame)))) @@ -320,17 +318,17 @@ ;; origin, e1, and e2 (all 2-D vectors) define a frame. ;; Think of origin as a point, e1 as the x-axis, e2 as the y-axis. -(def whole-window {:origin [0 0] - :e1 [width 0] - :e2 [0 height]}) +(def whole-window {:origin (tup/vector 0 0) + :e1 (tup/vector width 0) + :e2 (tup/vector 0 height)}) -(def frame1 {:origin [200 50] - :e1 [200 100] - :e2 [150 200]}) +(def frame1 {:origin (tup/vector 200 50) + :e1 (tup/vector 200 100) + :e2 (tup/vector 150 200)}) -(def frame2 {:origin [50 50] - :e1 [100 0] - :e2 [0 200]}) +(def frame2 {:origin (tup/vector 50 50) + :e1 (tup/vector 100 0) + :e2 (tup/vector 0 200)}) (defn draw "Draws picture, using the entire Quil window." @@ -524,9 +522,9 @@ ; COMPLETE ))) -(def red [0 100 100]) -(def green [33 100 100]) -(def blue [66 100 100]) +(def red (tup/vector 0 100 100)) +(def green (tup/vector 33 100 100)) +(def blue (tup/vector 66 100 100)) (defn hsbpic [p [h s b]] @@ -544,10 +542,10 @@ bruce (image-painter (q/load-image "data/bruce.jpg")) angels (image-painter (q/load-image "data/angels.jpg")) ] - (q/stroke-weight 4) - (q/color-mode :hsb 100) + #_(q/stroke-weight 4) + #_(q/color-mode :hsb 100) - (q/background 0 0 100) + #_(q/background 0 0 100) ;; (frame-painter frame1) ;; (draw x) ;; (draw box) @@ -559,7 +557,7 @@ #_(draw (beside (hsvpic (below george george) red) (hsvpic (flip-horiz (below george george)) blue))) - (draw (over (hsbpic george red) + #_(draw (over (hsbpic george red) (hsbpic (rotate george) blue))) ;; (draw (below (beside george (flip-horiz george)) @@ -574,6 +572,7 @@ #_(q/with-stroke [200 50 50] (draw (square-limit george 3))) + (draw (square-limit george 3)) ;(draw (color-picture (square-limit george 2) 255 0 0)) @@ -609,4 +608,4 @@ :draw draw-pictures :size [width height]) -;(defn -main []) +(defn -main []) From 15a11980725c61982f32080825a68d377695f29a Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Mon, 23 Mar 2015 20:41:26 -0700 Subject: [PATCH 09/13] revert to more 'intelligent' code for segment-painter This reverts commit f8dc53523901f84b162294b3ba8f2bd7a6a3ac6f. Conflicts: src/escher/core.clj --- src/escher/core.clj | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 174888c..0e8d2d8 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -105,16 +105,6 @@ ;; ;;================================================================== -(defn segment-painter - "Returns a picture that draws the given list of line segments. - Must execute within a Quil sketch." - [segment-list] - ; xform-pt is a function that maps a point to the given frame - (fn [frame] - (let [xform-pt (frame-coord-map frame)] - (doseq [[start end] segment-list] - (draw-line (xform-pt start) (xform-pt end)))))) - (defn frame-painter [{:keys [origin e1 e2]}] "Draws a parallelogram 'frame' based on origin and @@ -129,6 +119,15 @@ (draw-line (add-vec origin e2) corner) (draw-line (add-vec origin e1) corner))) +(defn segment-painter + "Returns a picture that draws the given list of line segments. + Must execute within a Quil sketch." + [segment-list] + ; xform-pt is a function that maps a point to the given frame + (fn [frame] + (let [xform-pt (frame-coord-map frame)] + (doseq [[start end] segment-list] + (draw-line (xform-pt start) (xform-pt end)))))) (defn transform-picture "Returns a transformed picture based on the values of origin, From 711dcdabd6a2c9ca235ef64368f220f1ed1c48b4 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Mon, 23 Mar 2015 20:46:55 -0700 Subject: [PATCH 10/13] added dependency for clj-tuple --- project.clj | 1 + src/escher/core.clj | 189 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 149 insertions(+), 41 deletions(-) diff --git a/project.clj b/project.clj index 9e76180..8364b82 100644 --- a/project.clj +++ b/project.clj @@ -4,6 +4,7 @@ :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] + [clj-tuple "0.2.0"] [quil "2.2.4"]] :main ^:skip-aot escher.core :target-path "target/%s" diff --git a/src/escher/core.clj b/src/escher/core.clj index 59e958e..1b2290e 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -1,5 +1,6 @@ (ns escher.core - (require [quil.core :as q]) + (require [quil.core :as q] + [clj-tuple :as tup]) (:gen-class)) ;; In Quil, [0 0] is upper left corner of window. @@ -30,23 +31,20 @@ (defn make-vec [x y] - [x y]) + (tup/vector x y)) (defn make-segment [vec1 vec2] [vec1 vec2]) (defn add-vec [[x1 y1] [x2 y2]] - [(+ x1 x2) (+ y1 y2)] - ) + (tup/vector (+ x1 x2) (+ y1 y2))) (defn sub-vec [[x1 y1] [x2 y2]] - [(- x1 x2) (- y1 y2)] - ) + (tup/vector (- x1 x2) (- y1 y2))) (defn scale-vec [[x y] s] - [(* x s) (* y s)] - ) + (tup/vector (* x s) (* y s))) (defn frame-coord-map @@ -60,6 +58,71 @@ (add-vec (scale-vec e1 x) (scale-vec e2 y))))) + +;;================================================================== +;; +;; What is a picture? +;; +;; A picture is a function that, when given a frame, knows how to +;; draw itself in that frame. As such, it hides its implementation +;; details. +;; +;; This file defines two functions that draw pictures: +;; +;; segment-painter: creates a picture from line segments +;; image-painter: creates a picture from a GIF image +;; +;;================================================================== + + + +;;================================================================== +;; +;; Utilities for drawing simple graphics using line segments +;; +;;================================================================== + +(defn make-segment + "Represent a line segment as a vector of two vectors--e.g., + [[0 0] [1 0]] represents a line from [0 0] to [1 0]." + [vec1 vec2] + (tup/vector vec1 vec2)) + +(defn path + "Creates a seq of line-segments from a 'bare' list of points. Use to + draw a continuous line through the list of points--e.g., + + (path [[0 1] [0 0] [1 0]]) + + returns two line segments connecting the three points in sequence: + + [ [[0 1] [0 0]] [[0 0] [1 0]] ]" + [& veclist] + (partition 2 1 veclist)) + +(def draw-line q/line) + + + +;;================================================================== +;; +;; for images drawn with line segments, this function returns +;; the picture (i.e., a function) that draws the desired image +;; +;;================================================================== + +(defn segment-painter + "Returns a picture that draws the given list of line segments. + Must execute within a Quil sketch." + [segment-list] + ; xform-pt is a function that maps a point to the given frame + (fn [frame] + (let [xform-pt (frame-coord-map frame)] + (doseq [[start end] segment-list] + (draw-line (xform-pt start) (xform-pt end)))))) + + +>>>>>>> color-anim (defn frame-painter [{:keys [origin e1 e2]}] "Draws parallelogram 'frame' based on origin and vectors e1 and e2. Must execute within a Quil sketch." @@ -83,21 +146,29 @@ for origin, e1, and e2. See SICP, 2nd ed., page 187-8. (Note that SICP calls pictures 'painters' because they know how to paint themselves." [p origin e1 e2] - (fn [frame] - (let [map (frame-coord-map frame) - new-origin (map origin)] - (p {:origin new-origin - :e1 (sub-vec (map e1) new-origin) - :e2 (sub-vec (map e2) new-origin)})))) + (fn [frame2] + (let [unit-sq-xform (frame-coord-map frame2) + new-origin (unit-sq-xform origin)] + (p (tup/hash-map :origin new-origin + :e1 (sub-vec (unit-sq-xform e1) new-origin) + :e2 (sub-vec (unit-sq-xform e2) new-origin)))))) + + + +;;================================================================== +;; +;; basic transformations of a single picture +;; +;;================================================================== (defn flip-vert [p] - (transform-picture p [0 1] [1 1] [0 0])) + (transform-picture p (tup/vector 0 1) (tup/vector 1 1) (tup/vector 0 0))) (defn flip-horiz [p] - (transform-picture p [1 0] [0 0] [1 1])) + (transform-picture p (tup/vector 1 0) (tup/vector 0 0) (tup/vector 1 1))) (defn rotate [p] - (transform-picture p [1 0] [1 1] [0 0])) + (transform-picture p (tup/vector 1 0) (tup/vector 1 1) (tup/vector 0 0))) (defn rotate180 [p] (rotate (rotate p))) @@ -109,6 +180,23 @@ (let [split [0.5 0] left (transform-picture p1 [0 0] split [0 1]) right (transform-picture p2 split [1 0] [0.5 1])] + (transform-picture p (tup/vector 0 1) (tup/vector 0 0) (tup/vector 1 1)))) + + + +;;================================================================== +;; +;; transformations that combine 2 or 4 pictures into a new picture +;; +;;================================================================== + +(defn beside + "Returns a picture that, splitting its frame in half vertically, draws + p1 in the left half and p2 in the right half." + [p1 p2] + (let [split (tup/vector 0.5 0) + left (transform-picture p1 (tup/vector 0 0) split (tup/vector 0 1)) + right (transform-picture p2 split (tup/vector 1 0) (tup/vector 0.5 1))] (fn [frame] (left frame) (right frame)))) @@ -193,6 +281,40 @@ ;; by concat'ting their segment-lists--see diamond-x. +;;================================================================== +;;================================================================== +;; +;; Quil setup +;; +;;================================================================== +;;================================================================== + +;; In Quil, [0 0] is upper left corner of window. +;; Increasing x values move a point to the right. +;; Increasing y values move a point downward. + + +;; defines size of Quil window + +(def width 600) +(def height 600) + +;; origin, e1, and e2 (all 2-D vectors) define a frame. +;; Think of origin as a point, e1 as the x-axis, e2 as the y-axis. + +(def whole-window {:origin (tup/vector 0 0) + :e1 (tup/vector width 0) + :e2 (tup/vector 0 height)}) + +(def frame1 {:origin (tup/vector 200 50) + :e1 (tup/vector 200 100) + :e2 (tup/vector 150 200)}) + +(def frame2 {:origin (tup/vector 50 50) + :e1 (tup/vector 100 0) + :e2 (tup/vector 0 200)}) +>>>>>>> color-anim + ;; making George drawing (def p1 (make-vec 0 0.35)) @@ -300,10 +422,9 @@ ; COMPLETE ))) -<<<<<<< HEAD -(def red [0 100 100]) -(def green [33 100 100]) -(def blue [66 100 100]) +(def red (tup/vector 0 100 100)) +(def green (tup/vector 33 100 100)) +(def blue (tup/vector 66 100 100)) (defn hsbpic [p [h s b]] @@ -313,22 +434,18 @@ -(defn draw-pictures - "'Container' for executing drawing(s) within a Quil sketch. -======= (defn draw-image "'Container' for executing drawings within a Quil sketch. ->>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners Experiment by uncommenting one or more lines, or add your own." [] (let [man (image-painter (q/load-image "data/man.gif")) bruce (image-painter (q/load-image "data/bruce.jpg")) angels (image-painter (q/load-image "data/angels.jpg")) ] - (q/stroke-weight 4) - (q/color-mode :hsb 100) + #_(q/stroke-weight 4) + #_(q/color-mode :hsb 100) - (q/background 0 0 100) + #_(q/background 0 0 100) ;; (frame-painter frame1) ;; (draw x) ;; (draw box) @@ -343,23 +460,17 @@ ;; (draw (flip-vert george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) -<<<<<<< HEAD #_(draw (beside (hsvpic (below george george) red) (hsvpic (flip-horiz (below george george)) blue))) - (draw (over (hsbpic george red) + #_(draw (over (hsbpic george red) (hsbpic (rotate george) blue))) -======= - ;; (draw (beside (below george george) - ;; (flip-horiz (below george george)))) ->>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners ;; (draw (below (beside george (flip-horiz george)) ;; (beside george (flip-horiz george)))) ;; (draw ((square-of-four identity flip-vert ;; flip-horiz rotate) -<<<<<<< HEAD ;; george)) ;(q/stroke 133 20 50) @@ -367,14 +478,13 @@ #_(q/with-stroke [200 50 50] (draw (square-limit george 3))) + (draw (square-limit george 3)) ;(draw (color-picture (square-limit george 2) 255 0 0)) ;(println (format "%x" (q/current-stroke))) -======= ;; george)) (draw (square-limit arrow 4)) ->>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners ; Needs image-painter @@ -386,7 +496,6 @@ ;; george))) )) -<<<<<<< HEAD ;;================================================================== @@ -401,11 +510,9 @@ ;(q/frame-rate 4) ) -======= ->>>>>>> parent of f8dc535... mostly completed, w/docstrings & refactoring for beginners (q/defsketch escher :title "Escher" :draw draw-image :size [width height]) -;(defn -main []) +(defn -main []) From db075d902a858bd25dca310227465e0db62ce2fa Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Mon, 23 Mar 2015 21:03:30 -0700 Subject: [PATCH 11/13] replaced entire file by contents in color-anim branch --- src/escher/core.clj | 365 +++++++++++++++++++++++++++----------------- 1 file changed, 228 insertions(+), 137 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 7257e7e..0e8d2d8 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -3,32 +3,11 @@ [clj-tuple :as tup]) (:gen-class)) -;; In Quil, [0 0] is upper left corner of window. -;; Increasing x values move a point to the right. -;; Increasing y values move a point downward. - - -;; defines size of Quil window -(def width 600) -(def height 600) - -(def draw-line q/line) - -;; origin, e1, and e2 (all 2-D vectors) define a frame. -;; Think of e1 as the x-axis, e2 as the y-axis. - -(def whole-window {:origin [0 0] - :e1 [width 0] - :e2 [0 height]}) - -(def frame1 {:origin [200 50] - :e1 [200 100] - :e2 [150 200]}) - -(def frame2 {:origin [50 50] - :e1 [100 0] - :e2 [0 200]}) - +;;================================================================== +;; +;; vector-manipulation primitives +;; +;;================================================================== (defn make-vec [x y] (tup/vector x y)) @@ -62,8 +41,11 @@ (defn frame-coord-map "Returns function that maps [x y] relative to the frame defined by origin (a vector to be interpreted as the point - describing the origin) and vectors e1 (x-axis), e2 (y-axis). - See SICP, 2nd ed., page 183." + describing the origin) and vectors e1 (x-axis), e2 (y-axis)-- + see SICP, 2nd ed., page 183. + + In this function, the frame describes the portion of the canvas + within which any untransformed picture will draw itself." [{:keys [origin e1 e2]}] (fn [[x y]] (add-vec origin @@ -125,8 +107,12 @@ (defn frame-painter [{:keys [origin e1 e2]}] - "Draws parallelogram 'frame' based on origin and vectors e1 and e2. - Must execute within a Quil sketch." + "Draws a parallelogram 'frame' based on origin and + vectors e1 and e2. Must execute within a Quil sketch. + + (Used only to confirm minimal project functionality: in draw-image, + uncomment '(frame-painter frame1)' and evaluate the code + in this file.)" (let [corner (add-vec origin (add-vec e1 e2))] (draw-line origin (add-vec origin e1)) (draw-line origin (add-vec origin e2)) @@ -144,9 +130,15 @@ (draw-line (xform-pt start) (xform-pt end)))))) (defn transform-picture - "Transforms a picture by into a different picture, based on new vectors - for origin, e1, and e2. See SICP, 2nd ed., page 187-8. (Note that SICP - calls pictures 'painters' because they know how to paint themselves." + "Returns a transformed picture based on the values of origin, + e1, and e2, which together describe a transformation frame. + + Note that the returned picture will draw itself inside a + different frame (frame2), which can be considered to be a + drawing frame. The coordinates of origin, e1, and e2 are + usually within the range [0 1]--i.e.,a unit square with + origin [0 0]. Coordinates > 1 will draw outside the drawing + frame." [p origin e1 e2] (fn [frame2] (let [unit-sq-xform (frame-coord-map frame2) @@ -176,13 +168,7 @@ (rotate (rotate p))) (defn rotate270 [p] - (rotate (rotate (rotate p)))) - -(defn beside [p1 p2] - (let [split [0.5 0] - left (transform-picture p1 [0 0] split [0 1]) - right (transform-picture p2 split [1 0] [0.5 1])] - (transform-picture p (tup/vector 0 1) (tup/vector 0 0) (tup/vector 1 1)))) + (transform-picture p (tup/vector 0 1) (tup/vector 0 0) (tup/vector 1 1))) @@ -203,14 +189,19 @@ (left frame) (right frame)))) - (defn below - "Draws p2 below p1." + "Returns a picture that, splitting its frame in half horizintally, + draws p1 in the top half and p2 in the bottom half." [p1 p2] (rotate (beside (rotate270 p1) (rotate270 p2)))) - +(defn quartet + "Returns a picture that subdivides its frame into quarters and + draws p1-p4 in order, left-to-right and top-to-bottom." + [p1 p2 p3 p4] + (below (beside p1 p2) + (beside p3 p4))) (defn over [p1 p2] (fn [frame] @@ -218,44 +209,57 @@ (p1 frame))) -(defn path - "Creates a seq of line-segments from a 'bare' list of points. Use to - draw a continuous line through the list of points." - [& veclist] - (partition 2 1 veclist)) - -(defn quartet [p1 p2 p3 p4] - (below (beside p1 p2) - (beside p3 p4))) +;;================================================================== +;; +;; building-blocks for "goal" function, square-limit +;; +;;================================================================== -(defn square-of-four [tl tr - bl br] - (fn [p] - (let [top (beside (tl p) (tr p)) - bottom (beside (bl p) (br p))] - (below top - bottom)))) +#_(defn right-split [p n] + (if (= n 0) + p + (let [smaller (right-split p (dec n))] + (beside p (below smaller smaller))))) +#_(defn up-split [p n] + ;; COMPLETE (Ex 2.44) + ) (defn split [f g] - "Higher-order function that allows the - following redefinitions: - - (def right-split (split beside below)) - (def up-split (split below beside))" + "Higher-order function that allows the functions right-split + and left-split to be defined without duplicated code. (Hint: + define each function independently, then analyze the resulting + code to enable each function's redefinition in terms of the + two picture transformations f and g.)" (fn self-fn [p n] (if (= n 0) p (let [smaller (self-fn p (dec n))] (f p (g smaller smaller)))))) -(def right-split (split beside below)) -(def up-split (split below beside)) - - - -(defn corner-split [p n] +(def right-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the left half of the frame. Draws two copies of + (right-split p (- n 1)), stacked vertically, in the right half + of the frame. If n=0, draws p in the given frame." + (split beside below)) + +(def up-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the top half of the frame. Draws two copies of + (right-split p (- n 1)), one to the right of the other, in the + bottom half of the frame. If n=0, draws p in the current frame." + (split below beside)) + +(defn corner-split + "Returns a picture based on picture p and level-of-recursion n. + Draws p in the upper-left quarter of frame. Draws two copies + of (right-split p (- n 1)) in upper-right quarter of frame. + Draws two copies of (top-split p (- n 1)) in the bottom-left + quarter of frame. Draws (corner-split p (- n 1)) in the bottom- + right quarter of frame. Wherever n=0, draws p in current frame." + [p n] (if (= n 0) p (let [up (up-split p (dec n)) @@ -266,21 +270,30 @@ (beside (below p top-left) (below bottom-right corner))))) +(defn square-of-four + "Returns a picture that subdivides its frame into quarters and + transforms the same picture p in four different ways, then + draws the results in order, left-to-right and top-to-bottom." + [tl tr + bl br] + (fn [p] + (let [top (beside (tl p) (tr p)) + bottom (beside (bl p) (br p))] + (below top + bottom)))) (def combine-four (square-of-four rotate180 flip-vert flip-horiz identity)) -(defn square-limit [p n] +(defn square-limit + "Returns a picture that has a 2 x 2 block of p in the center, encircled + by n borders of picture p, with each successive version of p being + half the size of the one that it immediately surrounds." + [p n] (combine-four (corner-split p n))) -;; Example usage of path: -;; (path p1 p2 p3) --> -;; (([0 0.35] [0.15 0.6]) ([0.15 0.6] [0.3 0.4])) - -;; By defining segment-lists separately, you can combine figures -;; by concat'ting their segment-lists--see diamond-x. ;;================================================================== @@ -316,43 +329,28 @@ :e1 (tup/vector 100 0) :e2 (tup/vector 0 200)}) -;; making George drawing +(defn draw + "Draws picture, using the entire Quil window." + [picture] + (picture whole-window)) -(def p1 (make-vec 0 0.35)) -(def p2 (make-vec 0.15 0.6)) -(def p3 (make-vec 0.3 0.4)) -(def p4 (make-vec 0.35 0.5)) -(def p5 (make-vec 0.25 1.0)) -(def p6 (make-vec 0.4 1.0)) -(def p7 (make-vec 0.5 0.7)) -(def p8 (make-vec 0.6 1.0)) -(def p9 (make-vec 0.75 1.0)) -(def p10 (make-vec 0.6 0.55)) -(def p11 (make-vec 1 0.85)) -(def p12 (make-vec 1 0.65)) -(def p13 (make-vec 0.75 0.35)) -(def p14 (make-vec 0.6 0.35)) -(def p15 (make-vec 0.65 0.15)) -(def p16 (make-vec 0.6 0)) -(def p17 (make-vec 0.4 0)) -(def p18 (make-vec 0.35 0.15)) -(def p19 (make-vec 0.4 0.35)) -(def p20 (make-vec 0.3 0.35)) -(def p21 (make-vec 0.15 0.4)) -(def p22 (make-vec 0.0 0.15)) -(def george-segs - (concat - (path p1 p2 p3 p4 p5) - (path p6 p7 p8) - (path p9 p10 p11) - (path p12 p13 p14 p15 p16) - (path p17 p18 p19 p20 p21 p22))) -(def george (segment-painter george-segs)) +;;================================================================== +;;================================================================== +;; +;; PICTURES THAT ARE DRAWN USING SEGMENT-PAINTER +;; +;;================================================================== +;;================================================================== -;; making arrow drawing +;;================================================================== +;; +;; arrow: a picture that draws an arrow pointing toward the +;; top of the screen +;; +;;================================================================== (def length-delta 0.1) (def arrow-dx 0.1) @@ -369,23 +367,45 @@ (def arrow (segment-painter (concat shaft-segs head-segs))) -;; making box drawing + +;;================================================================== +;; +;; box: a picture that draws a square +;; +;;================================================================== + (def box-segs (path (make-vec 0 0) (make-vec 1 0) (make-vec 1 1) (make-vec 0 1) (make-vec 0 0))) + (def box (segment-painter box-segs)) + + +;;================================================================== +;; +;; x: a picture that draws an "x" (as if from the vertices of 'box') +;; +;;================================================================== + (def x-segs (concat (path (make-vec 0 0) (make-vec 1 1)) (path (make-vec 1 0) (make-vec 0 1)))) + (def x (segment-painter x-segs)) -;; making diamond drawing + +;;================================================================== +;; +;; diamond: a picture that draws a square for which one diagonal +;; is horizontal and the other is vertical +;; +;;================================================================== (def diamond-segs (path (make-vec 0.5 0) (make-vec 1 0.5) @@ -396,22 +416,100 @@ (segment-painter diamond-segs)) -;; making diamond-x drawing + +;;================================================================== +;; +;; diamond-x: a picture that draws both 'x' and 'diamond' (in +;; the same frame) +;; +;;================================================================== + +;; Note that you can use (concat path1 path2 ... pathN) +;; to combine multiple non-connected paths into a single +;; sequence of line segments (for use with segment-painter). (def diamond-x (segment-painter (concat diamond-segs x-segs))) -;; making diag drawing +;;================================================================== +;; +;; george: a "man" figure using line segments +;; +;;================================================================== + +(def p1 (make-vec 0 0.35)) +(def p2 (make-vec 0.15 0.6)) +(def p3 (make-vec 0.3 0.4)) +(def p4 (make-vec 0.35 0.5)) +(def p5 (make-vec 0.25 1.0)) +(def p6 (make-vec 0.4 1.0)) +(def p7 (make-vec 0.5 0.7)) +(def p8 (make-vec 0.6 1.0)) +(def p9 (make-vec 0.75 1.0)) +(def p10 (make-vec 0.6 0.55)) +(def p11 (make-vec 1 0.85)) +(def p12 (make-vec 1 0.65)) +(def p13 (make-vec 0.75 0.35)) +(def p14 (make-vec 0.6 0.35)) +(def p15 (make-vec 0.65 0.15)) +(def p16 (make-vec 0.6 0)) +(def p17 (make-vec 0.4 0)) +(def p18 (make-vec 0.35 0.15)) +(def p19 (make-vec 0.4 0.35)) +(def p20 (make-vec 0.3 0.35)) +(def p21 (make-vec 0.15 0.4)) +(def p22 (make-vec 0.0 0.15)) + +;; draws a small square in the upper left corner +;(def p23 (make-vec 0.0 0.0)) +;(def p24 (make-vec 0.03 0.0)) +;(def p25 (make-vec 0.03 0.03)) +;(def p26 (make-vec 0.0 0.03)) + +;; draws a slightly larger square in the lower right corner +;(def p27 (make-vec 1 1)) +;(def p28 (make-vec 0.94 1)) +;(def p29 (make-vec 0.94 0.94)) +;(def p30 (make-vec 1 0.94)) + +(def george-segs + (concat + (path p1 p2 p3 p4 p5) + (path p6 p7 p8) + (path p9 p10 p11) + (path p12 p13 p14 p15 p16) + (path p17 p18 p19 p20 p21 p22) + +; (path p23 p24 p25 p26 p23) ; dot for origin +; (path p27 p28 p29 p30 p27) ; larger dot for opposite corner + )) + +(def george (segment-painter george-segs)) + + +; unused by other code, as far as I can tell (def diag (segment-painter [[[0 0] [1 1]]])) -(defn draw - "Draws picture, using the entire Quil window." - [picture] - (picture whole-window)) + +;;================================================================== +;;================================================================== +;; +;; for images drawn with GIFs and JPGs, this function returns +;; the picture (i.e., a function) that draws the desired image +;; +;; (This function needs to be completed. People have found +;; the following URLs helpful: +;; +;; http://quil.info/api/transform +;; http://homepages.inf.ed.ac.uk/rbf/HIPR2/affine.htm +;; http://www.cs.colorado.edu/~mcbryan/5229.03/mail/55.htm ) +;; +;;================================================================== +;;================================================================== (defn image-painter [img] (fn [{[ox oy] :origin @@ -435,8 +533,8 @@ -(defn draw-image - "'Container' for executing drawings within a Quil sketch. +(defn draw-pictures + "'Container' for executing drawing(s) within a Quil sketch. Experiment by uncommenting one or more lines, or add your own." [] (let [man (image-painter (q/load-image "data/man.gif")) @@ -450,25 +548,19 @@ ;; (frame-painter frame1) ;; (draw x) ;; (draw box) - ;; (draw george) - ;; (draw (rotate180 george)) - ;; (draw (beside (flip-horiz george) (flip-vert george))) - ;; (draw (beside (flip-horiz george) george)) - ;; (draw (below (flip-horiz george) george)) - ;; (draw (right-split george 3)) - ;; (draw (up-split george 3)) - ;; (draw (beside box x)) - ;; (draw (flip-vert george)) + ;; (george frame2) + ;; (draw (rotate george)) + ;; (draw (flip-horiz george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) #_(draw (beside (hsvpic (below george george) red) (hsvpic (flip-horiz (below george george)) blue))) - #_(draw (over (hsbpic george red) + #_(draw (over (hsbpic george red) (hsbpic (rotate george) blue))) ;; (draw (below (beside george (flip-horiz george)) - ;; (beside george (flip-horiz george)))) + ;; (beside george (flip-horiz george)))) ;; (draw ((square-of-four identity flip-vert ;; flip-horiz rotate) @@ -484,17 +576,16 @@ ;(draw (color-picture (square-limit george 2) 255 0 0)) ;(println (format "%x" (q/current-stroke))) - ;; george)) - (draw (square-limit arrow 4)) + ; these pictures need image-painter to be implemented - ; Needs image-painter ;; (bruce frame1) ;; (bruce frame2) ;; (draw (beside george bruce)) - ;; (draw (corner-split george 4)) - ;; (draw (beside bruce (below bruce - ;; george))) + ;; (draw (corner-split bruce 4)) + ;; (draw (square-limit bruce 3)) + ;; (draw (beside bruce (below bruce + ;; george))) )) @@ -513,7 +604,7 @@ (q/defsketch escher :title "Escher" - :draw draw-image + :draw draw-pictures :size [width height]) (defn -main []) From 0fed3274733f2b73ee693843face7cc188acc42f Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Thu, 16 Apr 2015 21:03:36 -0700 Subject: [PATCH 12/13] added support for midje autotest --- project.clj | 11 +++++++++-- repl/scratch.clj | 4 ++++ src/escher/core.clj | 14 +++++++------- test/escher/core_test.clj | 11 ----------- test/escher/t_core.clj | 15 +++++++++++++++ 5 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 repl/scratch.clj delete mode 100644 test/escher/core_test.clj create mode 100644 test/escher/t_core.clj diff --git a/project.clj b/project.clj index 8364b82..66633cd 100644 --- a/project.clj +++ b/project.clj @@ -4,8 +4,15 @@ :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] - [clj-tuple "0.2.0"] + [clj-tuple "0.2.1"] [quil "2.2.4"]] :main ^:skip-aot escher.core :target-path "target/%s" - :profiles {:uberjar {:aot :all}}) + :profiles {:uberjar {:aot :all} + :dev {:dependencies [[midje "1.6.3"]]}} + :plugins [[lein-midje "3.1.3"]] + ) +;; To start a development session, in a terminal window, do: +;; +;; cd /Users/gr/GitHub/escher +;; lein midje :autotest diff --git a/repl/scratch.clj b/repl/scratch.clj new file mode 100644 index 0000000..3764ee0 --- /dev/null +++ b/repl/scratch.clj @@ -0,0 +1,4 @@ +(ns scratch + (:require [clojure.repl :refer :all] + [clojure.test :refer :all] + [escher.core :refer :all])) diff --git a/src/escher/core.clj b/src/escher/core.clj index 0e8d2d8..10a3766 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -541,10 +541,10 @@ bruce (image-painter (q/load-image "data/bruce.jpg")) angels (image-painter (q/load-image "data/angels.jpg")) ] - #_(q/stroke-weight 4) - #_(q/color-mode :hsb 100) + (q/stroke-weight 4) + (q/color-mode :hsb 100) - #_(q/background 0 0 100) + (q/background 0 0 100) ;; (frame-painter frame1) ;; (draw x) ;; (draw box) @@ -553,8 +553,8 @@ ;; (draw (flip-horiz george)) ;; (draw (beside box box)) ;; (draw (combine-four george)) - #_(draw (beside (hsvpic (below george george) red) - (hsvpic (flip-horiz (below george george)) blue))) + (draw (beside (hsbpic (below george george) red) + (hsbpic (flip-horiz (below george george)) blue))) #_(draw (over (hsbpic george red) (hsbpic (rotate george) blue))) @@ -571,7 +571,7 @@ #_(q/with-stroke [200 50 50] (draw (square-limit george 3))) - (draw (square-limit george 3)) + #_(draw (square-limit george 3)) ;(draw (color-picture (square-limit george 2) 255 0 0)) @@ -607,4 +607,4 @@ :draw draw-pictures :size [width height]) -(defn -main []) +;;(defn -main []) diff --git a/test/escher/core_test.clj b/test/escher/core_test.clj deleted file mode 100644 index a4e8639..0000000 --- a/test/escher/core_test.clj +++ /dev/null @@ -1,11 +0,0 @@ -(ns escher.core-test - (:require [clojure.test :refer :all] - [escher.core :refer :all])) - -(deftest vectors - (is (= (scale-vec [2 3] 4) - [8 12])) - (is (= (add-vec [-1 2] [3 -2]) - [2 0])) - (is (= (sub-vec [2 -3] [-1 -2]) - [3 -1]))) diff --git a/test/escher/t_core.clj b/test/escher/t_core.clj new file mode 100644 index 0000000..d37a64c --- /dev/null +++ b/test/escher/t_core.clj @@ -0,0 +1,15 @@ +(ns escher.t-core + (:use midje.sweet) + (:require +;; [clojure.test :refer :all] + [escher.core :refer :all]) +;; [escher.core :as core]) + ) + +(facts "about utility fcns" + (fact (scale-vec [2 3] 4) => + [8 12]) + (fact (add-vec [-1 2] [3 -2]) => + [2 0]) + (fact (sub-vec [2 -3] [-1 -2]) => + [3 -1])) From cd5f4ba75b86ce430b45b8df02a04b225992b204 Mon Sep 17 00:00:00 2001 From: Gregg Williams Date: Thu, 16 Apr 2015 21:26:06 -0700 Subject: [PATCH 13/13] replaced t/vector with make-vec, as appropriate --- src/escher/core.clj | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/escher/core.clj b/src/escher/core.clj index 10a3766..0cb8f5c 100644 --- a/src/escher/core.clj +++ b/src/escher/core.clj @@ -1,6 +1,6 @@ (ns escher.core (require [quil.core :as q] - [clj-tuple :as tup]) + [clj-tuple :as t]) (:gen-class)) ;;================================================================== @@ -10,17 +10,17 @@ ;;================================================================== (defn make-vec [x y] - (tup/vector x y)) + (t/vector x y)) (defn add-vec [[x1 y1] [x2 y2]] - (tup/vector (+ x1 x2) (+ y1 y2))) + (make-vec (+ x1 x2) (+ y1 y2))) (defn sub-vec [[x1 y1] [x2 y2]] - (tup/vector (- x1 x2) (- y1 y2))) + (make-vec (- x1 x2) (- y1 y2))) (defn scale-vec [[x y] s] - (tup/vector (* x s) (* y s))) + (make-vec (* x s) (* y s))) ;;================================================================== @@ -80,7 +80,7 @@ "Represent a line segment as a vector of two vectors--e.g., [[0 0] [1 0]] represents a line from [0 0] to [1 0]." [vec1 vec2] - (tup/vector vec1 vec2)) + (make-vec vec1 vec2)) (defn path "Creates a seq of line-segments from a 'bare' list of points. Use to @@ -143,7 +143,7 @@ (fn [frame2] (let [unit-sq-xform (frame-coord-map frame2) new-origin (unit-sq-xform origin)] - (p (tup/hash-map :origin new-origin + (p (t/hash-map :origin new-origin :e1 (sub-vec (unit-sq-xform e1) new-origin) :e2 (sub-vec (unit-sq-xform e2) new-origin)))))) @@ -156,19 +156,19 @@ ;;================================================================== (defn flip-vert [p] - (transform-picture p (tup/vector 0 1) (tup/vector 1 1) (tup/vector 0 0))) + (transform-picture p (make-vec 0 1) (make-vec 1 1) (make-vec 0 0))) (defn flip-horiz [p] - (transform-picture p (tup/vector 1 0) (tup/vector 0 0) (tup/vector 1 1))) + (transform-picture p (make-vec 1 0) (make-vec 0 0) (make-vec 1 1))) (defn rotate [p] - (transform-picture p (tup/vector 1 0) (tup/vector 1 1) (tup/vector 0 0))) + (transform-picture p (make-vec 1 0) (make-vec 1 1) (make-vec 0 0))) (defn rotate180 [p] (rotate (rotate p))) (defn rotate270 [p] - (transform-picture p (tup/vector 0 1) (tup/vector 0 0) (tup/vector 1 1))) + (transform-picture p (make-vec 0 1) (make-vec 0 0) (make-vec 1 1))) @@ -182,9 +182,9 @@ "Returns a picture that, splitting its frame in half vertically, draws p1 in the left half and p2 in the right half." [p1 p2] - (let [split (tup/vector 0.5 0) - left (transform-picture p1 (tup/vector 0 0) split (tup/vector 0 1)) - right (transform-picture p2 split (tup/vector 1 0) (tup/vector 0.5 1))] + (let [split (make-vec 0.5 0) + left (transform-picture p1 (make-vec 0 0) split (make-vec 0 1)) + right (transform-picture p2 split (make-vec 1 0) (make-vec 0.5 1))] (fn [frame] (left frame) (right frame)))) @@ -317,17 +317,17 @@ ;; origin, e1, and e2 (all 2-D vectors) define a frame. ;; Think of origin as a point, e1 as the x-axis, e2 as the y-axis. -(def whole-window {:origin (tup/vector 0 0) - :e1 (tup/vector width 0) - :e2 (tup/vector 0 height)}) +(def whole-window {:origin (make-vec 0 0) + :e1 (make-vec width 0) + :e2 (make-vec 0 height)}) -(def frame1 {:origin (tup/vector 200 50) - :e1 (tup/vector 200 100) - :e2 (tup/vector 150 200)}) +(def frame1 {:origin (make-vec 200 50) + :e1 (make-vec 200 100) + :e2 (make-vec 150 200)}) -(def frame2 {:origin (tup/vector 50 50) - :e1 (tup/vector 100 0) - :e2 (tup/vector 0 200)}) +(def frame2 {:origin (make-vec 50 50) + :e1 (make-vec 100 0) + :e2 (make-vec 0 200)}) (defn draw "Draws picture, using the entire Quil window." @@ -521,9 +521,9 @@ ; COMPLETE ))) -(def red (tup/vector 0 100 100)) -(def green (tup/vector 33 100 100)) -(def blue (tup/vector 66 100 100)) +(def red (t/vector 0 100 100)) +(def green (t/vector 33 100 100)) +(def blue (t/vector 66 100 100)) (defn hsbpic [p [h s b]]