├── README.md ├── documentation ├── project.clj └── src ├── doc └── FirstClassObjectsDocumentation └── firstclassobjects └── core.clj /README.md: -------------------------------------------------------------------------------- 1 | clojure-intro-class 2 | =================== 3 | 4 | clojure-first-class-objects is a pilot project to use Clojure for introductory computer science courses at the University of Minnesota - Morris 5 | 6 | This repository contains both error-related tools, versions of core functions with preconditions, and a string library for beginners. 7 | 8 | This project abstracts over Quil's fun-mode to add more Racket style functionality. 9 | 10 | **Some added examples of functionality** 11 | 12 | Drawing some Lime rectangles next to each other 13 | 14 | * Quil's fun-mode: 15 | ``` 16 | (let [x 100 17 | y 100 18 | width 50 19 | height 50 20 | numb 6 21 | tot-w (* numb width)] 22 | (q/fill 80 255 80) 23 | (map (q/rect (+ (- x (/ (tot-w) 2)) (* (/ width 2) %)) y width height) (+ 1 (range numb))) 24 | (q/no-fill) 25 | ``` 26 | 27 | * Our super-fun-mode: 28 | ``` 29 | (def lime-rect (create-rect 50 50 :lime)) 30 | (def lime-rects (beside lime-rect 31 | lime-rect 32 | lime-rect 33 | lime-rect 34 | lime-rect 35 | lime-rect) 36 | (ds lime-rects 100 100) 37 | ``` 38 | 39 | Drawing a picture 40 | 41 | * Quil's fun-mode: 42 | ``` 43 | (image (load-image "/src/images/SquidwardsEmbarrasingPhoto.jpg") 100 100) 44 | 45 | ``` 46 | * Our super-fun-mode: 47 | ``` 48 | (def squid-photo (create-picture "/src/images/SquidwardsEmbarrasingPhoto.jpg)) 49 | (ds squid-photo 100 100) 50 | ``` 51 | 52 | Scaling a picture 53 | 54 | * Quil's fun-mode: 55 | ``` 56 | (with-translation [100 100] 57 | (with-rotation (* 2 (/ q/PI 3)) 58 | (image (load-image "/src/images/SquidwardsEmbarrasingPhoto.jpg") 59 | 0 0))) 60 | 61 | ``` 62 | * Our super-fun-mode: 63 | ``` 64 | (def squid-photo (rotate-shape (create-picture "/src/images/SquidwardsEmbarrasingPhoto.jpg) 65 | 120)) 66 | (ds squid-photo 100 100) 67 | ``` 68 | -------------------------------------------------------------------------------- /documentation: -------------------------------------------------------------------------------- 1 | Function usages, argument parameters, and examples. 2 | 3 | f-background [& colors] 4 | "Takes in one through four RBG values (look at quil's fill function for exact RGB parameters) and sets the background of the drawn screen to that." 5 | 6 | 7 | f-text [string x y] 8 | "Draws the given text at the given x y position." 9 | 10 | 11 | f-text-num [number x y] 12 | "Draws the given number at the given x y position." 13 | 14 | 15 | f-text-size [size] 16 | "Changes the size of all following text to the given size. The default size is 12." 17 | 18 | 19 | create-ellipse [width height & colors] 20 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 21 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 22 | 23 | 24 | create-arc [width height start stop & colors] 25 | "Takes in a width, height, starting angle, ending angle, and one through four RBG values (look at quil's fill function for exact RGB parameters). 26 | The start and stop angles are measured in degrees, with 0 or 360 being 3 o'clock. 27 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 28 | 29 | 30 | create-line [x2 y2 stroke & colors] 31 | "Takes in one x and y position, a stroke weight, and one through four RBG values (look at quil's fill function for exact RGB parameters). 32 | The first position is automatically (0,0) and the line is drawn to the specified (x,y). 33 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 34 | 35 | 36 | create-triangle [x2 y2 x3 y3 & colors] 37 | "Takes in two x and y positions and one through four RBG values (look at quil's fill function for exact RGB parameters). 38 | The position of the first vertex is automatically (0,0) so the triangle will be drawn based off that point. 39 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 40 | 41 | 42 | create-quad [x2 y2 x3 y3 x4 y4 & colors] 43 | "Takes in three pairs x and y positions, ordered x2 y2 x3 y3 x4 y4, and one through four RBG values (look at quil's fill function for exact RGB parameters). 44 | The position of the first vertex is automatically (0,0) so the quad will be drawn based on that point. 45 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 46 | 47 | 48 | create-picture [pic] 49 | "Takes in a string of the image location, ex. \"src/images/SquidwardsEmbarrasingPhoto.jpg\". 50 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 51 | 52 | 53 | create-rect [width height & colors] 54 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 55 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 56 | 57 | 58 | ds [shape x y] 59 | "ds (or draw-shape) takes in a shape, an x position to be drawn at, and a y position to be drawn at. 60 | Calls the internal function :ds of the shape or image hashmap with the input variables passed to it and draws the shape or image accordingly." 61 | 62 | 63 | draw-shape [shape x y] 64 | "Serves the same functionality of ds." 65 | 66 | above [& shapes] 67 | "Takes 1 or more shapes and puts them above each other. 68 | The first argument will be on the top, the last argument will be on the bottom. 69 | This returns a new complex shape." 70 | 71 | 72 | beside [& shapes] 73 | "Takes 1 or more shapes and puts them beside each other. 74 | The first argument will be on the left, the last argument will be on the right. 75 | This returns a new complex shape." 76 | 77 | 78 | overlay [& shapes] 79 | "Takes 1 or more shapes and overlays them on each other. 80 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 81 | This returns a new complex shape." 82 | 83 | 84 | overlay-align [vertical horizonal & shapes] 85 | "Takes in a first argument of :top :center or :bottom for the vertical orientation, a second argument of :left :center or :right for the horizontal orientation, 86 | and 1 or more shapes and overlays them on each other with the specified orientation. 87 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 88 | This returns a new complex shape." 89 | 90 | 91 | above-align [align & shapes] 92 | "Takes in a first argument of :right :left for the vertical orientation, 93 | and 1 or more shapes and puts them above each other with the specified alignment. 94 | The first argument will be on top, the last argument will be on bottom. 95 | This returns a new complex shape." 96 | 97 | 98 | beside-align [align & shapes] 99 | "Takes in a first argument of :top :bottom for the vertical orientation, 100 | and 1 or more shapes and puts them beside each other with the specified alignment. 101 | The first argument will be on the left, the last argument will be on the right. 102 | This returns a new complex shape." 103 | 104 | 105 | scale-shape [shape scale-x scale-y] 106 | "Takes in a shape or image, x-axis scale, and y-axis scale. 107 | Scales the shape based off the values input. 108 | This returns a new complex shape if given a complex shape otherwise returns a new simple shape." 109 | 110 | 111 | rotate-shape [shape angle] 112 | "Function that takes in a shape or image and an angle in degrees. 113 | It then rotates the shape or image. 114 | This function returns a new shape. 115 | This function cannot be used on complex shapes." 116 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject org.clojars.clojure-first-class-objects/firstclassobjects "0.0.2" 2 | :description "A pilot project to use Clojure for introductory computer science courses at the University of Minnesota - Morris" 3 | :url "https://github.com/Clojure-Intro-Course/Clojure-FirstClassObjects.git" 4 | :license {:name "Eclipse Public License - v 1.0" 5 | :url "http://www.eclipse.org/legal/epl-v10.html" 6 | :distribution :repo 7 | :comments "same as Clojure"} 8 | :dependencies [[org.clojure/clojure "1.7.0"] 9 | [quil "2.2.5"] 10 | [inflections "0.9.14"]] 11 | :plugins [[lein-autoexpect "1.0"] 12 | [lein-pprint "1.1.2"]] 13 | :scm {:url "https://github.com/Clojure-Intro-Course/Clojure-FirstClassObjects.git"} 14 | :pom-addition [:developers [:developer 15 | [:name "Thomas Hagen"] 16 | [:email "hagen715@morris.umn.edu"] 17 | [:timezone "-6"]]] 18 | :main firstclassobjects.core) 19 | -------------------------------------------------------------------------------- /src/doc/FirstClassObjectsDocumentation: -------------------------------------------------------------------------------- 1 | Welcome to the first-class-objects' Documentation! 2 | 3 | 4 | 5 | f-background 6 | "Takes in one through four RBG values (look at quil's fill function for exact RGB parameters) and sets the background of the drawn screen to that." 7 | [& colors] 8 | 9 | f-text 10 | "Draws the given text at the given x y position." 11 | [string x y] 12 | 13 | f-text-num 14 | "Draws the given number at the given x y position." 15 | [number x y] 16 | 17 | f-text-size 18 | "Changes the size of all following text to the given size. The default size is 12." 19 | [size] 20 | 21 | create-ellipse 22 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 23 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 24 | [width height & colors] 25 | 26 | create-arc 27 | "Takes in a width, height, starting angle, ending angle, and one through four RBG values (look at quil's fill function for exact RGB parameters). 28 | The start and stop angles are measured in degrees, with 0 or 360 being 3 o'clock. 29 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 30 | [width height start stop & colors] 31 | 32 | create-line 33 | "Takes in one x and y position, a stroke weight, and one through four RBG values (look at quil's fill function for exact RGB parameters). 34 | The first position is automatically (0,0) and the line is drawn to the specified (x,y). 35 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 36 | [x2 y2 stroke & colors] 37 | 38 | create-triangle 39 | "Takes in two x and y positions and one through four RBG values (look at quil's fill function for exact RGB parameters). 40 | The position of the first vertex is automatically (0,0) so the triangle will be drawn based off that point. 41 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 42 | [x2 y2 x3 y3 & colors] 43 | 44 | create-quad 45 | "Takes in three pairs x and y positions, ordered x2 y2 x3 y3 x4 y4, and one through four RBG values (look at quil's fill function for exact RGB parameters). 46 | The position of the first vertex is automatically (0,0) so the quad will be drawn based on that point. 47 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 48 | [x2 y2 x3 y3 x4 y4 & colors] 49 | 50 | create-picture 51 | "Takes in a string of the image location, ex. \"src/images/SquidwardsEmbarrasingPhoto.jpg\". 52 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 53 | [pic] 54 | 55 | create-rect 56 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 57 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 58 | [width height & colors] 59 | 60 | ds 61 | "ds (or draw-shape) takes in a shape, an x position to be drawn at, and a y position to be drawn at. 62 | Calls the internal function :ds of the shape or image hashmap with the input variables passed to it and draws the shape or image accordingly." 63 | [shape x y] 64 | 65 | draw-shape 66 | "Serves the same functionality of ds." 67 | 68 | above 69 | "Takes 1 or more shapes and puts them above each other. 70 | The first argument will be on the top, the last argument will be on the bottom. 71 | This returns a new complex shape." 72 | [& shapes] 73 | 74 | beside 75 | "Takes 1 or more shapes and puts them beside each other. 76 | The first argument will be on the left, the last argument will be on the right. 77 | This returns a new complex shape." 78 | [& shapes] 79 | 80 | overlay 81 | "Takes 1 or more shapes and overlays them on each other. 82 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 83 | This returns a new complex shape." 84 | [& shapes] 85 | 86 | overlay-align 87 | "Takes in a first argument of :top :center or :bottom for the vertical orientation, a second argument of :left :center or :right for the horizontal orientation, 88 | and 1 or more shapes and overlays them on each other with the specified orientation. 89 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 90 | This returns a new complex shape." 91 | [vertical horizonal & shapes] 92 | 93 | above-align 94 | "Takes in a first argument of :right :left for the vertical orientation, 95 | and 1 or more shapes and puts them above each other with the specified alignment. 96 | The first argument will be on top, the last argument will be on bottom. 97 | This returns a new complex shape." 98 | [align & shapes] 99 | 100 | beside-align 101 | "Takes in a first argument of :top :bottom for the vertical orientation, 102 | and 1 or more shapes and puts them beside each other with the specified alignment. 103 | The first argument will be on the left, the last argument will be on the right. 104 | This returns a new complex shape." 105 | [align & shapes] 106 | 107 | scale-shape 108 | "Takes in a shape or image, x-axis scale, and y-axis scale. 109 | Scales the shape based off the values input. 110 | This returns a new complex shape if given a complex shape otherwise returns a new simple shape." 111 | [shape scale-x scale-y] 112 | 113 | rotate-shape 114 | "Function that takes in a shape or image and an angle in degrees. 115 | It then rotates the shape or image. 116 | This function returns a new shape. 117 | This function cannot be used on complex shapes." 118 | [shape angle] 119 | -------------------------------------------------------------------------------- /src/firstclassobjects/core.clj: -------------------------------------------------------------------------------- 1 | (ns firstclassobjects.core 2 | (:use [quil.core] 3 | [inflections.core])) 4 | 5 | 6 | (def colors {:red [255 0 0] :blue [0 0 255] :yellow [255 255 0] 7 | :green [0 128 0] :purple [128 0 128] :orange [255 165 0] 8 | :pink [255 192 203] :black [0 0 0] :brown [165 42 42] 9 | :white [255 255 255] :grey [128 128 128] :silver [192 192 192] 10 | :gold [255 215 0] :cyan [0 255 255] :magenta [255 0 255] 11 | :maroon [128 0 0] :navy [0 0 128] :lime [0 255 0] 12 | :teal [0 128 128]}) 13 | 14 | (defn not-nil? [x] 15 | (not (nil? x))) 16 | 17 | (defn check-if-not-nil? [arguments] 18 | (loop [args arguments 19 | n 1] 20 | (if (empty? args) 21 | {:boolean true 22 | :arg-num -1} 23 | (if (nil? (first args)) 24 | {:boolean false 25 | :arg-num n} 26 | (recur (rest args) (inc n)))))) 27 | 28 | (defn eval-color [color] 29 | (if (not-nil? (color colors)) 30 | (apply fill (color colors)) 31 | (throw (RuntimeException. (str "The keyword " color " is not a valid color")))) 32 | (current-fill)) 33 | 34 | 35 | ;-------------------------------------------------------------------------------------------------------------------------------*** UNDERLYING FUNCTIONS *** 36 | 37 | (defn f-arc [& args] 38 | (if (not= (count args) 7) 39 | (throw (Exception. "f-arc expects 7 arguments."))) 40 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 41 | (str "f-arc expects a number but got nil as its "(ordinalize (- (:arg-num (check-if-not-nil? args)) 2))" argument")))]} 42 | (apply arc args)) 43 | 44 | 45 | 46 | (defn f-background 47 | "Takes in one through four RBG values (look at quil's fill function for exact RGB parameters) and sets the background of the drawn screen to that." 48 | [& args] 49 | (if (< 4 (count args)) 50 | (throw (Exception. "f-background expects either 1, 2, 3, or 4 arguments."))) 51 | 52 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 53 | (str "f-background expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 54 | (if (and (= 1 (count args)) (keyword? (first args))) 55 | (background (eval-color (first args))) 56 | (apply background args))) 57 | 58 | 59 | (defn f-ellipse [& args] 60 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 61 | (str "f-ellipse expects a number but got nil as its "(ordinalize (- (:arg-num (check-if-not-nil? args)) 2))" argument")))]} 62 | (apply ellipse args)) 63 | 64 | 65 | (defn f-fill [& args] 66 | (if (< 4 (count args)) 67 | (throw (Exception. "f-fill expects either 1, 2, 3, or 4 arguments."))) 68 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 69 | (str "A shape's color expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 70 | (if (and (= 1 (count args)) (keyword? (first args))) 71 | (fill (eval-color (first args))) 72 | (apply fill args))) 73 | 74 | 75 | (defn f-line [& args] 76 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 77 | (str "f-line expects a number but got nil as its "(ordinalize (- (:arg-num (check-if-not-nil? args)) 2))" argument")))]} 78 | (apply line args)) 79 | 80 | 81 | (defn f-quad [& args] 82 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 83 | (str "f-quad expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 84 | (apply quad args)) 85 | 86 | 87 | (defn f-rect [& args] 88 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 89 | (str "f-rect expects a number but got nil as its "(ordinalize (- (:arg-num (check-if-not-nil? args)) 2))" argument")))]} 90 | (apply rect args)) 91 | 92 | 93 | (defn f-stroke [& args] 94 | (if (< 4 (count args)) 95 | (throw (Exception. "f-stroke expects either 1, 2, 3, or 4 arguments."))) 96 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 97 | (str "A color expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 98 | (if (and (= 1 (count args)) (keyword? (first args))) 99 | (stroke (eval-color (first args))) 100 | (apply stroke args))) 101 | 102 | 103 | (defn f-stroke-weight [weight] 104 | {:pre [(assert (not-nil? weight) "f-stroke-weight expects a number but got nil as its first argument")]} 105 | (stroke-weight weight)) 106 | 107 | 108 | (defn f-text 109 | "Draws the given text at the given x y position." 110 | [& args] 111 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 112 | (str "f-text expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 113 | (apply text args)) 114 | 115 | 116 | (defn f-text-num 117 | "Draws the given number at the given x y position." 118 | [& args] 119 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 120 | (str "f-text-num expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 121 | (apply text-num args)) 122 | 123 | 124 | (defn f-text-size 125 | "Changes the size of all following text to the given size. The default text size is 12." 126 | [size] 127 | {:pre [(assert (not-nil? size) "f-text-size expects a number but got nil as its first argument") 128 | (assert (pos? size) "f-text-size expects a positive number but got a negative number as its first argument")]} 129 | (text-size size)) 130 | 131 | 132 | (defn f-triangle [& args] 133 | {:pre [(not (assert (:boolean (check-if-not-nil? args)) 134 | (str "f-ellipse expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? args)))" argument")))]} 135 | (apply triangle args)) 136 | 137 | ;------------------------------------------------------------------------------------------------------------------------------*** SHAPE FUNCTIONS *** 138 | 139 | (defn create-ellipse 140 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 141 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 142 | [w h & colors] 143 | {:pre [(not (assert (:boolean (check-if-not-nil? [w h])) 144 | (str "create-ellipse expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [w h])))" argument")))]} 145 | {:w w 146 | :h h 147 | :tw w 148 | :th h 149 | :dx 0 150 | :dy 0 151 | :angle 0 152 | :ds (fn [x y pict wid hei cs angle] 153 | (if (> (count colors) 0) 154 | (apply f-fill colors) 155 | (no-fill)) 156 | (with-translation [x y] 157 | (with-rotation [(/ (* PI angle) 180)] 158 | (f-ellipse 0 0 wid hei))) 159 | (no-fill))}) 160 | 161 | 162 | (defn create-arc 163 | "Takes in a width, height, starting angle, ending angle, and one through four RBG values (look at quil's fill function for exact RGB parameters). 164 | The start and stop angles are measured in degrees, with 0 or 360 being 3 o'clock. 165 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 166 | [w h start stop & colors] 167 | {:pre [(not (assert (:boolean (check-if-not-nil? [w h start stop])) 168 | (str "create-arc expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [w h start stop])))" argument")))]} 169 | {:w w 170 | :h h 171 | :tw w 172 | :th h 173 | :dx 0 174 | :dy 0 175 | :angle 0 176 | :ds (fn [x y pict wid hei cs angle] 177 | (if (> (count colors) 0) 178 | (apply f-fill colors) 179 | (no-fill)) 180 | (with-translation [x y] 181 | (with-rotation [(/ (* PI angle) 180)] 182 | (f-arc 0 0 wid hei start stop :pie))) 183 | (no-fill))}) 184 | 185 | 186 | (defn create-line 187 | "Takes in one x and y position, a stroke weight, and one through four RBG values (look at quil's fill function for exact RGB parameters). 188 | The first position is automatically (0,0) and the line is drawn to the specified (x,y). 189 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 190 | [x2 y2 stroke & colors] 191 | {:pre [(not (assert (:boolean (check-if-not-nil? [x2 y2 stroke])) 192 | (str "create-line expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [x2 y2 stroke])))" argument")))]} 193 | {:w x2 194 | :h y2 195 | :tw x2 196 | :th y2 197 | :dx 0 198 | :dy 0 199 | :angle 0 200 | :ds (fn [x y pict wid hei cs angle] 201 | (stroke-weight stroke) 202 | (if (> (count colors) 0) 203 | (apply f-stroke colors) 204 | (no-stroke)) 205 | (with-translation [x y] 206 | (with-rotation [(/ (* PI angle) 180)] 207 | (f-line (- 0 (/ wid 2)) (- 0 (/ hei 2)) (+ 0 (/ wid 2)) (+ 0 (/ hei 2))))) 208 | (f-stroke cs) 209 | (stroke-weight 1))}) 210 | 211 | 212 | (defn create-triangle 213 | "Takes in two x and y positions and one through four RBG values (look at quil's fill function for exact RGB parameters). 214 | The position of the first vertex is automatically (0,0) so the triangle will be drawn based off that point. 215 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 216 | [x2 y2 x3 y3 & colors] 217 | {:pre [(not (assert (:boolean (check-if-not-nil? [x2 y2 x3 y3])) 218 | (str "create-triangle expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [x2 y2 x3 y3])))" argument")))]} 219 | {:w (+ (abs (max 0 x2 x3)) (abs (min 0 x2 x3))) 220 | :h (+ (abs (max 0 y2 y3)) (abs (min 0 y2 y3))) 221 | :tw (+ (abs (max 0 x2 x3)) (abs (min 0 x2 x3))) 222 | :th (+ (abs (max 0 y2 y3)) (abs (min 0 y2 y3))) 223 | :dx 0 224 | :dy 0 225 | :angle 0 226 | :ds (fn [x y pict wid hei cs angle] 227 | (if (> (count colors) 0) 228 | (apply f-fill colors) 229 | (no-fill)) 230 | (with-translation [x y] 231 | (with-rotation [(/ (* PI angle) 180)] 232 | (let [mid-x (quot (+ (max 0 x2 x3) (min 0 x2 x3)) 2) 233 | mid-y (quot (+ (max 0 y2 y3) (min 0 y2 y3)) 2)] 234 | (f-triangle (- 0 mid-x) (- 0 mid-y) 235 | (- x2 mid-x) (- y2 mid-y) 236 | (- x3 mid-x) (- y3 mid-y))))) 237 | (no-fill))}) 238 | 239 | 240 | (defn create-quad 241 | "Takes in three pairs x and y positions, ordered x1 y1 x2 y2 x3 y3, and one through four RBG values (look at quil's fill function for exact RGB parameters). 242 | The position of the first vertex is automatically (0,0) so the quad will be drawn based on that point. 243 | Creates a hashmap of the information relevant to the shape and its draw position and the values needed by the ds function." 244 | [x2 y2 x3 y3 x4 y4 & colors] 245 | {:pre [(not (assert (:boolean (check-if-not-nil? [x2 y2 x3 y3 x4 y4])) 246 | (str "create-quad expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [x2 y2 x3 y3 x4 y4])))" argument")))]} 247 | {:w (+ (abs (max 0 x2 x3 x4)) (abs (min 0 x2 x3 x4))) 248 | :h (+ (abs (max 0 y2 y3 y4)) (abs (min 0 y2 y3 y4))) 249 | :tw (+ (abs (max 0 x2 x3 x4)) (abs (min 0 x2 x3 x4))) 250 | :th (+ (abs (max 0 y2 y3 y4)) (abs (min 0 y2 y3 y4))) 251 | :dx 0 252 | :dy 0 253 | :angle 0 254 | :ds (fn [x y pict wid hei cs angle] 255 | (if (> (count colors) 0) 256 | (apply f-fill colors) 257 | (no-fill)) 258 | (with-translation [x y] 259 | (with-rotation [(/ (* PI angle) 180)] 260 | (let [mid-x (quot (+ (max 0 x2 x3 x4) (min 0 x2 x3 x4)) 2) 261 | mid-y (quot (+ (max 0 y2 y3 y4) (min 0 y2 y3 y4)) 2)] 262 | (f-quad (+ 0 (- 0 mid-x)) (+ 0 (- 0 mid-y)) 263 | (+ 0 (- x2 mid-x)) (+ 0 (- y2 mid-y)) 264 | (+ 0 (- x3 mid-x)) (+ 0 (- y3 mid-y)) 265 | (+ 0 (- x4 mid-x)) (+ 0 (- y4 mid-y)))))) 266 | (no-fill))}) 267 | 268 | 269 | (defn create-picture 270 | "Takes in a string of the image location, ex. \"src/images/SquidwardsEmbarrasingPhoto.jpg\". 271 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 272 | [pic] 273 | {:pre [(not (assert (:boolean (check-if-not-nil? [pic])) 274 | (str "create-picture expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [pic])))" argument")))]} 275 | {:w (.width (load-image pic)) 276 | :h (.height (load-image pic)) 277 | :tw (.width (load-image pic)) 278 | :th (.height (load-image pic)) 279 | :dx 0 280 | :dy 0 281 | :pic pic 282 | :angle 0 283 | :rp (load-image pic) 284 | :ds (fn [x y pict wid hei cs angle] 285 | (with-translation [x y] 286 | (with-rotation [(/ (* PI angle) 180)] (image pict 0 0))))}) 287 | 288 | 289 | (defn create-rect 290 | "Takes in width, height, and one through four RBG values (look at quil's fill function for exact RGB parameters). 291 | Creates a hashmap of the information relevant to the shape and its draw position and values needed by the ds function." 292 | [w h & colors] 293 | {:pre [(not (assert (:boolean (check-if-not-nil? [w h])) 294 | (str "create-rect expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [w h])))" argument")))]} 295 | {:w w 296 | :h h 297 | :tw w 298 | :th h 299 | :dx 0 300 | :dy 0 301 | :angle 0 302 | :ds (fn [x y pict wid hei cs angle] 303 | (if (> (count colors) 0) 304 | (apply f-fill colors) 305 | (no-fill)) 306 | (with-translation [x y] 307 | (with-rotation [(/ (* PI angle) 180)] (f-rect 0 0 wid hei))) 308 | (no-fill))}) 309 | 310 | 311 | (defn ds 312 | "ds (or draw-shape) takes in a shape, an x position to be drawn at, and a y position to be drawn at. 313 | Calls the internal function :ds of the shape or image hashmap with the input variables passed to it and draws the shape or image accordingly." 314 | [shape x y] 315 | {:pre [(not (assert (:boolean (check-if-not-nil? [shape x y])) 316 | (str "draw-shape expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [shape x y])))" argument")))]} 317 | (rect-mode :center) 318 | (image-mode :center) 319 | (if (not (vector? shape)) 320 | ((:ds shape) x y (:rp shape) (:w shape) (:h shape) (current-stroke) (:angle shape)) 321 | (doall (map #((:ds %) (+ x (:dx %)) (+ y (:dy %)) (:rp %) (:w %) (:h %) (current-stroke) (:angle %)) shape)))) 322 | 323 | (def draw-shape ds) 324 | 325 | 326 | ;------------------------------------------------------------------------------------------------------------------------------*** RELATIVE SHAPE FUNCTIONS *** 327 | 328 | (defn w-recur 329 | "Helper function for calc-max-w that goes through and grabs all the :tw within each shape or image. 330 | Returns a vector of those values." 331 | [arguments] 332 | (loop [shapes arguments 333 | vect []] 334 | (if (not= (count shapes) 0) 335 | (if (vector? (first shapes)) 336 | (recur (rest shapes) (conj vect (:tw (first (first shapes))))) 337 | (recur (rest shapes) (conj vect (:tw (first shapes))))) 338 | vect))) 339 | 340 | (defn calc-max-w 341 | "Calculates the max width by finding the maximum :tw of all of the shapes. 342 | This is different from calc-tot-w which adds all of the :tw of the shapes together." 343 | [args] 344 | (def max-w 345 | (apply max (w-recur args)))) 346 | 347 | (defn calc-tot-w 348 | "Calculates the total width by adding all of the :tw of each shape together. 349 | This is different from calc-max-w which grabs the largest :tw of all the shapes." 350 | [args] 351 | (def tot-w 352 | (reduce + (w-recur args)))) 353 | 354 | ;--- 355 | (defn h-recur 356 | "Helper function for calc-max-h that goes through and grabs all the :th within each shape or image. 357 | Returns a vector of those values." 358 | [arguments] 359 | (loop [shapes arguments 360 | vect []] 361 | (if (not= (count shapes) 0) 362 | (if (vector? (first shapes)) 363 | (recur (rest shapes) (conj vect (:th (first (first shapes))))) 364 | (recur (rest shapes) (conj vect (:th (first shapes))))) 365 | vect))) 366 | 367 | (defn calc-max-h 368 | "Calculates the max height by finding the maximum :th of all of the shapes. 369 | This is different from calc-tot-h which adds all of the :th of the shapes together." 370 | [args] 371 | (def max-h 372 | (apply max (h-recur args)))) 373 | 374 | (defn calc-tot-h 375 | "Calculates the total height by adding all of the :th of each shape together. 376 | This is different from calc-max-h which grabs the largest :th of all the shapes." 377 | [args] 378 | (def tot-h 379 | (reduce + (h-recur args)))) 380 | 381 | ;------------------------------------------------------------------------------------------------------------------------------*** ABOVE *** 382 | 383 | 384 | (defn eval-compshape-vertical 385 | "Helper function for eval-shapes-vertical that deals with the complex shapes. 386 | Returns a modified complex shape adjusted for additional shapes." 387 | [arguments numb th] 388 | (loop [shapes arguments 389 | vect []] 390 | (if (not= (count shapes) 0) 391 | (recur (rest shapes) (conj vect (assoc (first shapes) :dy (+ (:dy (first shapes)) (- (+ (quot th 2) numb) (quot tot-h 2))) :tw max-w :th tot-h))) 392 | vect))) 393 | 394 | 395 | (defn eval-shapes-vertical 396 | "Helper function for above that decides whether it is a complex or simple shape and calculates the change in :dy of each shape's hashmap. 397 | Changes the needed information about the new complex shape." 398 | [arguments numb] 399 | (loop [shapes arguments 400 | numb numb 401 | vect []] 402 | (if (not= (count shapes) 0) 403 | (if (vector? (first shapes)) 404 | (recur (rest shapes) (+ (:th (first (first shapes))) numb) (conj vect (eval-compshape-vertical (first shapes) numb (:th (first (first shapes)))))) 405 | (recur (rest shapes) (+ (:th (first shapes)) numb) (conj vect (assoc (first shapes) :dy (- (+ (quot (:th (first shapes)) 2) numb) (quot tot-h 2)) :tw max-w :th tot-h)))) 406 | vect))) 407 | 408 | 409 | (defn above 410 | "Takes 1 or more shapes and puts them above each other. 411 | The first argument will be on the top, the last argument will be on the bottom. 412 | This returns a new complex shape." 413 | [& shapes] 414 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 415 | (str "above expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 416 | (calc-tot-h shapes) 417 | (calc-max-w shapes) 418 | (vec (flatten (eval-shapes-vertical shapes 0)))) 419 | 420 | ;------------------------------------------------------------------------------------------------------------------------------*** BESIDE *** 421 | 422 | (defn eval-compshape-horizontal 423 | "Helper function for eval-shapes-horizontal that deals with the complex shapes. 424 | Returns a modified complex shape adjusted for additional shapes." 425 | [arguments numb tw] 426 | (loop [shapes arguments 427 | vect []] 428 | (if (not= (count shapes) 0) 429 | (recur (rest shapes) (conj vect (assoc (first shapes) :dx (+ (:dx (first shapes)) (- (+ (/ tw 2) numb) (/ tot-w 2))) :tw tot-w :th max-h))) 430 | vect))) 431 | 432 | 433 | (defn eval-shapes-horizontal 434 | "Helper function for beside that decides whether it is a complex or simple shape and calculates the change in :dx of each shape's hashmap. 435 | Changes the needed information about the new complex shape." 436 | [arguments number] 437 | (loop [shapes arguments 438 | numb number 439 | vect []] 440 | (if (not= (count shapes) 0) 441 | (if (vector? (first shapes)) 442 | (recur (rest shapes) (+ (:tw (first (first shapes))) numb) (conj vect (eval-compshape-horizontal (first shapes) numb (:tw (first (first shapes)))))) 443 | (recur (rest shapes) (+ (:tw (first shapes)) numb) (conj vect (assoc (first shapes) :dx (- (+ (/ (:tw (first shapes)) 2) numb) (/ tot-w 2)) :tw tot-w :th max-h)))) 444 | vect))) 445 | 446 | 447 | (defn beside 448 | "Takes 1 or more shapes and puts them beside each other. 449 | The first argument will be on the left, the last argument will be on the right. 450 | This returns a new complex shape." 451 | [& shapes] 452 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 453 | (str "beside expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 454 | (calc-tot-w shapes) 455 | (calc-max-h shapes) 456 | (vec (flatten (eval-shapes-horizontal shapes 0)))) 457 | 458 | 459 | ;------------------------------------------------------------------------------------------------------------------------------*** OVERLAY *** 460 | 461 | (defn eval-compshape-overlay 462 | "Helper function for eval-shapes-overlay that deals with the complex shapes." 463 | [arguments] 464 | (loop [shapes arguments 465 | vect []] 466 | (if (not= (count shapes) 0) 467 | (recur (rest shapes) (conj vect (assoc (first shapes) :tw max-w :th max-h))) 468 | vect))) 469 | 470 | 471 | (defn eval-shapes-overlay 472 | "Helper function for overlay that decides wether it is a complex or simple shape and changes the needed information about the new complex shape." 473 | [arguments] 474 | (loop [shapes arguments 475 | vect []] 476 | (if (not= (count shapes) 0) 477 | (if (vector? (first shapes)) 478 | (recur (rest shapes) (conj vect (eval-compshape-overlay (first shapes)))) 479 | (recur (rest shapes) (conj vect (assoc (first shapes) :tw max-w :th max-h)))) 480 | vect))) 481 | 482 | 483 | (defn overlay 484 | "Takes 1 or more shapes and overlays them on each other. 485 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 486 | This returns a new complex shape." 487 | [& shapes] 488 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 489 | (str "overlay expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 490 | (calc-max-w shapes) 491 | (calc-max-h shapes) 492 | (vec (flatten (eval-shapes-overlay (reverse shapes))))) 493 | 494 | ;------------------------------------------------------------------------------------------------------------------------------*** OVERLAY-ALIGN *** 495 | 496 | (defn overlay-compshape-vertical 497 | "Helper function for eval-compshape-overlay-align that decides what the :dy needs to be changed to." 498 | [vert arg] 499 | (cond 500 | (= vert :top) 501 | (if (= (:th arg) max-h) 502 | (:dy arg) 503 | (+ (- (:dy arg) (quot max-h 2)) (quot (:th arg) 2))) 504 | (= vert :center) 505 | (:dy arg) 506 | (= vert :bottom) 507 | (if (= (:th arg) max-h) 508 | (:dy arg) 509 | (- (+ (:dy arg) (quot max-h 2)) (quot (:th arg) 2))) 510 | :else 511 | (throw (Exception. "The function overlay-align takes :top, :center, or :bottom as its first argument.")))) 512 | 513 | (defn overlay-compshape-horizontal 514 | "Helper function for eval-compshape-overlay-align that decides what the :dx needs to be changed to." 515 | [hor arg] 516 | (cond 517 | (= hor :left) 518 | (if (= (:tw arg) max-w) 519 | (:dx arg) 520 | (+ (- (:dx arg) (quot max-w 2)) (quot (:tw arg) 2))) 521 | (= hor :center) 522 | (:dx arg) 523 | (= hor :right) 524 | (if (= (:tw arg) max-w) 525 | (:dx arg) 526 | (- (+ (:dx arg) (quot max-w 2)) (quot (:tw arg) 2))) 527 | :else 528 | (throw (Exception. "The function overlay-align takes :left, :center, or :right as its second argument.")))) 529 | 530 | (defn eval-compshape-overlay-align 531 | "Helper function for eval-shapes-overlay-align that deals with complex shapes." 532 | [vert hor arguments] 533 | (loop [shapes arguments 534 | vect []] 535 | (if (not= (count shapes) 0) 536 | (recur (rest shapes) (conj vect (assoc (first shapes) :tw max-w :th max-h :dy (overlay-compshape-vertical vert (first shapes)) :dx (overlay-compshape-horizontal hor (first shapes))))) 537 | vect))) 538 | 539 | (defn overlay-vertical 540 | "Helper function for eval-shapes-overlay-align that decides what the :dy needs to be changed to." 541 | [vert arg] 542 | (cond 543 | (= vert :top) 544 | (- (quot (:th arg) 2) (quot max-h 2)) 545 | (= vert :center) 546 | (:dy arg) 547 | (= vert :bottom) 548 | (- (quot max-h 2) (quot (:th arg) 2)) 549 | :else 550 | (throw (Exception. "The function overlay-align takes :top, :center, or :bottom as its first argument.")))) 551 | 552 | (defn overlay-horizontal 553 | "Helper function for eval-shapes-overlay-align that decides what the :dx needs to be changed to." 554 | [hor arg] 555 | (cond 556 | (= hor :left) 557 | (- (quot (:tw arg) 2) (quot max-w 2)) 558 | (= hor :center) 559 | (:dx arg) 560 | (= hor :right) 561 | (- (quot max-w 2) (quot (:tw arg) 2)) 562 | :else 563 | (throw (Exception. "The function overlay-align takes :left, :center, or :right as its second argument.")))) 564 | 565 | (defn eval-shapes-overlay-align 566 | "Helper function for overlay-align that decides which information needs to be changed and to what." 567 | [vert hor arguments] 568 | (loop [shapes arguments 569 | vect []] 570 | (if (not= (count shapes) 0) 571 | (if (vector? (first shapes)) 572 | (recur (rest shapes) (conj vect (eval-compshape-overlay-align vert hor (first shapes)))) 573 | (recur (rest shapes) (conj vect (assoc (first shapes) :tw max-w :th max-h :dy (overlay-vertical vert (first shapes)) :dx (overlay-horizontal hor (first shapes)))))) 574 | vect))) 575 | 576 | (defn overlay-align 577 | "Takes in a first argument of :top :center or :bottom for the vertical orientation, a second argument of :left :center or :right for the horizontal orientation, 578 | and 1 or more shapes and overlays them on each other with the specified orientation. 579 | The first argument will be in the foreground of the shape, the last argument will be the background of the shape. 580 | This returns a new complex shape." 581 | [vert hor & shapes] 582 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 583 | (str "overlay-align expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 584 | (calc-max-w shapes) 585 | (calc-tot-w shapes) 586 | (calc-max-h shapes) 587 | (calc-tot-h shapes) 588 | (vec (flatten (eval-shapes-overlay-align vert hor (reverse shapes))))) 589 | 590 | 591 | ;-------------------------------------------------------------------------------------------------------------------------------*** ABOVE-ALIGN *** 592 | 593 | (defn eval-compshape-above-align-right 594 | "Helper function for eval-shapes-above-align-right that deals with complex shapes." 595 | [arguments numb th] 596 | (loop [shapes arguments 597 | vect []] 598 | (if (not= (count shapes) 0) 599 | (recur (rest shapes) (conj vect (assoc (first shapes) 600 | :dy (+ (:dy (first shapes)) (- (+ (quot th 2) numb) (quot tot-h 2))) 601 | :tw max-w 602 | :th tot-h 603 | :dx (if (= (:tw (first shapes)) max-w) 604 | (:dx (first shapes)) 605 | (- (+ (:dx (first shapes)) (quot max-w 2)) (quot (:tw (first shapes)) 2)))))) 606 | vect))) 607 | 608 | (defn eval-shapes-above-align-right 609 | "Helper function for above-align that decides what changes to make in the hashmap for :right alignment." 610 | [arguments numb] 611 | (loop [shapes arguments 612 | numb numb 613 | vect []] 614 | (if (not= (count shapes) 0) 615 | (if (vector? (first shapes)) 616 | (recur (rest shapes) (+ (:th (first (first shapes))) numb) (conj vect (eval-compshape-above-align-right (first shapes) numb (:th (first (first shapes)))))) 617 | (recur (rest shapes) (+ (:th (first shapes)) numb) (conj vect (assoc (first shapes) 618 | :dy (- (+ (quot (:th (first shapes)) 2) numb) (quot tot-h 2)) 619 | :dx (- (quot max-w 2) (quot (:tw (first shapes)) 2)) 620 | :tw max-w 621 | :th tot-h)))) 622 | vect))) 623 | 624 | (defn eval-compshape-above-align-left 625 | "Helper function for eval-shapes-above-align-left that deals with complex shapes." 626 | [arguments numb th] 627 | (loop [shapes arguments 628 | vect []] 629 | (if (not= (count shapes) 0) 630 | (recur (rest shapes) (conj vect (assoc (first shapes) 631 | :dy (+ (:dy (first shapes)) (- (+ (quot th 2) numb) (quot tot-h 2))) 632 | :tw max-w 633 | :th tot-h 634 | :dx (if (= (:tw (first shapes)) max-w) 635 | (:dx (first shapes)) 636 | (+ (- (:dx (first shapes)) (quot max-w 2)) (quot (:tw (first shapes)) 2)))))) 637 | vect))) 638 | 639 | (defn eval-shapes-above-align-left 640 | "Helper function for above-align that decides what changes to make in the hashmap for :left alignment." 641 | [arguments numb] 642 | (loop [shapes arguments 643 | numb numb 644 | vect []] 645 | (if (not= (count shapes) 0) 646 | (if (vector? (first shapes)) 647 | (recur (rest shapes) (+ (:th (first (first shapes))) numb) (conj vect (eval-compshape-above-align-left (first shapes) numb (:th (first (first shapes)))))) 648 | (recur (rest shapes) (+ (:th (first shapes)) numb) (conj vect (assoc (first shapes) 649 | :dy (- (+ (quot (:th (first shapes)) 2) numb) (quot tot-h 2)) 650 | :dx (- (quot (:tw (first shapes)) 2) (quot max-w 2)) 651 | :tw max-w 652 | :th tot-h)))) 653 | vect))) 654 | 655 | (defn above-align 656 | "Takes in a first argument of :right :left for the vertical orientation, 657 | and 1 or more shapes and puts them above each other with the specified alignment. 658 | The first argument will be on top, the last argument will be on bottom. 659 | This returns a new complex shape." 660 | [align & shapes] 661 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 662 | (str "above-align expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 663 | (calc-tot-h shapes) 664 | (calc-max-w shapes) 665 | (cond 666 | (= align :right) 667 | (vec (flatten (eval-shapes-above-align-right shapes 0))) 668 | (= align :left) 669 | (vec (flatten (eval-shapes-above-align-left shapes 0))) 670 | :else 671 | (throw (Exception. "The function above-align takes in :right or :left as its first argument.")))) 672 | 673 | 674 | ;------------------------------------------------------------------------------------------------------------------------------*** BESIDE-ALIGN *** 675 | 676 | (defn eval-compshape-beside-align-top 677 | "Helper function for eval-shapes-beside-align-top that deals with complex shapes." 678 | [arguments numb tw] 679 | (loop [shapes arguments 680 | vect []] 681 | (if (not= (count shapes) 0) 682 | (recur (rest shapes) (conj vect (assoc (first shapes) 683 | :dx (+ (:dx (first shapes)) (- (+ (quot tw 2) numb) (quot tot-w 2))) 684 | :tw tot-w 685 | :th max-h 686 | :dy (if (= (:th (first shapes)) max-h) 687 | (:dy (first shapes)) 688 | (+ (- (:dy (first shapes)) (quot max-h 2)) (quot (:th (first shapes)) 2)))))) 689 | vect))) 690 | 691 | (defn eval-shapes-beside-align-top 692 | "Helper function for beside-align that decides what changes to make in the hashmap for :top alignment." 693 | [arguments numb] 694 | (loop [shapes arguments 695 | numb numb 696 | vect []] 697 | (if (not= (count shapes) 0) 698 | (if (vector? (first shapes)) 699 | (recur (rest shapes) (+ (:tw (first (first shapes))) numb) (conj vect (eval-compshape-beside-align-top (first shapes) numb (:tw (first (first shapes)))))) 700 | (recur (rest shapes) (+ (:tw (first shapes)) numb) (conj vect (assoc (first shapes) 701 | :dx (- (+ (quot (:tw (first shapes)) 2) numb) (quot tot-w 2)) 702 | :tw tot-w 703 | :th max-h 704 | :dy (- (quot (:th (first shapes)) 2) (quot max-h 2)))))) 705 | vect))) 706 | 707 | (defn eval-compshape-beside-align-bottom 708 | "Helper function for eval-shapes-beside-align-bottom that deals with complex shapes." 709 | [arguments numb tw] 710 | (loop [shapes arguments 711 | vect []] 712 | (if (not= (count shapes) 0) 713 | (recur (rest shapes) (conj vect (assoc (first shapes) 714 | :dx (+ (:dx (first shapes)) (- (+ (quot tw 2) numb) (quot tot-w 2))) 715 | :tw tot-w 716 | :th max-h 717 | :dy (if (= (:th (first shapes)) max-h) 718 | (:dy (first shapes)) 719 | (- (+ (:dy (first shapes)) (quot max-h 2)) (quot (:th (first shapes)) 2)))))) 720 | vect))) 721 | 722 | (defn eval-shapes-beside-align-bottom 723 | "Helper function for beside-align that decides what changes to make in the hashmap for :bottom alignment." 724 | [arguments numb] 725 | (loop [shapes arguments 726 | numb numb 727 | vect []] 728 | (if (not= (count shapes) 0) 729 | (if (vector? (first shapes)) 730 | (recur (rest shapes) (+ (:tw (first (first shapes))) numb) (conj vect (eval-compshape-beside-align-bottom (first shapes) numb (:tw (first (first shapes)))))) 731 | (recur (rest shapes) (+ (:tw (first shapes)) numb) (conj vect (assoc (first shapes) 732 | :dx (- (+ (quot (:tw (first shapes)) 2) numb) (quot tot-w 2)) 733 | :tw tot-w 734 | :th max-h 735 | :dy (- (quot max-h 2) (quot (:th (first shapes)) 2)))))) 736 | vect))) 737 | 738 | (defn beside-align 739 | "Takes in a first argument of :top :bottom for the vertical orientation, 740 | and 1 or more shapes and puts them beside each other with the specified alignment. 741 | The first argument will be on the left, the last argument will be on the right. 742 | This returns a new complex shape." 743 | [align & shapes] 744 | {:pre [(not (assert (:boolean (check-if-not-nil? shapes)) 745 | (str "beside-align expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? shapes)))" argument")))]} 746 | (calc-tot-w shapes) 747 | (calc-max-h shapes) 748 | (cond 749 | (= align :top) 750 | (vec (flatten (eval-shapes-beside-align-top shapes 0))) 751 | (= align :bottom) 752 | (vec (flatten (eval-shapes-beside-align-bottom shapes 0))) 753 | :else 754 | (throw (Exception. "The function beside-align takes in :top or :bottom as its first argument.")))) 755 | 756 | ;------------------------------------------------------------------------------------------------------------------------------*** SCALE-SHAPE *** 757 | 758 | (defn create-new-image-shape 759 | "Helper function for scale-image that makes it so side effects are not a problem" 760 | [shape scale-x scale-y] 761 | (def new-pic (create-picture (:pic shape))) 762 | (resize (:rp new-pic) (* (:w shape) scale-x) (* (:h shape) scale-y)) 763 | new-pic) 764 | 765 | (defn scale-image-helper 766 | "Helper function for scale-shape that decides which values should be changed to what for scale-shape." 767 | [shape scale-x scale-y] 768 | (assoc 769 | (if (not= (:rp shape) nil) 770 | (create-new-image-shape shape scale-x scale-y) 771 | shape) 772 | :w (* (:w shape) scale-x) 773 | :h (* (:h shape) scale-y) 774 | :tw (* (:tw shape) scale-x) 775 | :th (* (:th shape) scale-y) 776 | :dx (* (:dx shape) scale-x) 777 | :dy (* (:dy shape) scale-y) 778 | :angle (:angle shape))) 779 | 780 | (defn scale-complex 781 | "Helper function for scale-shape that breaks a complex shape into simple shapes." 782 | [shape scale-x scale-y] 783 | (map #(scale-image-helper % scale-x scale-y) shape)) 784 | 785 | 786 | (defn scale-shape 787 | "Takes in a shape or image, x-axis scale, and y-axis scale. 788 | Scales the shape based off the values input. 789 | This returns a new complex shape if given a complex shape otherwise returns a new simple shape." 790 | [shape scale-x scale-y] 791 | {:pre [(not (assert (:boolean (check-if-not-nil? [shape scale-x scale-y])) 792 | (str "scale-shape expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [shape scale-x scale-y])))" argument")))]} 793 | (if (vector? shape) 794 | (vec (flatten (scale-complex shape scale-x scale-y))) 795 | (scale-image-helper shape scale-x scale-y))) 796 | 797 | ;------------------------------------------------------------------------------------------------------------------------------*** ROTATE-SHAPE *** 798 | 799 | (defn rotate-shape 800 | "Function that takes in a shape or image and an angle in degrees. 801 | It then rotates the shape or image. 802 | This function returns a new shape. 803 | This function cannot be used on complex shapes." 804 | [shape angle] 805 | {:pre [(not (assert (:boolean (check-if-not-nil? [shape angle])) 806 | (str "rotate-shape expects a number but got nil as its "(ordinalize (:arg-num (check-if-not-nil? [shape angle])))" argument")))]} 807 | (assoc shape :angle angle)) 808 | --------------------------------------------------------------------------------