;;; Procedure: ;;; series ;;; Parameters: ;;; n, a positive integer ;;; width, a positive integer ;;; height, a positive integer ;;; Purpose: ;;; Generates an image using the inputted values. ;;; Produces: ;;; [Nothing, side effects called for.] ;;; Preconditions: ;;; The following procedures must be defined: ;;; draw-stamp-2! ;;; draw-rolled-2! ;;; roll-2! ;;; roll-kernel-2! ;;; spot-col ;;; spot-row ;;; spot-color ;;; image-render-spot! ;;; image-scaled-render-spot! ;;; image-render-spots! ;;; image-scaled-render-spots! ;;; image-draw-circle! ;;; draw-three-parallel-lines! ;;; draw-circle! ;;; Postconditions: ;;; Many images are cut off at the ends because of the sizes. There is a lot of trouble rendering spots when they are rendered at large sizes, especially when the value of n is large. (define series (lambda (n width height) (if (> n 256) (context-set-bgcolor! "black") (context-set-bgcolor! (rgb-new (+ n 1) (+ n 2) (+ n 3)))) (let* ((canvas (image-new width height))) (image-show canvas) (let* ((turtle1 (turtle-new canvas)) (turtle2 (turtle-new canvas))) (turtle-set-color! turtle1 (rgb-new (+ n 5) (* n 2) (+ n 1))) (turtle-set-brush! turtle1 "Circle (13)") (turtle-teleport! turtle1 0 0) (turtle-down! turtle1) (if (>= width height) (begin (turtle-face! turtle1 30) (turtle-forward! turtle1 (+ n width)) (turtle-face! turtle1 180) (turtle-forward! turtle1 (+ n height)) (turtle-face! turtle1 -30) (turtle-forward! turtle1 (+ n width))) (begin (turtle-face! turtle1 60) (turtle-forward! turtle1 (+ n height)) (turtle-face! turtle1 180) (turtle-forward! turtle1 (+ n width)) (turtle-face! turtle1 -60) (turtle-forward! turtle1 (+ n height)))) (turtle-teleport! turtle2 0 0) (turtle-set-color! turtle2 "light steel blue") (turtle-set-brush! turtle2 "Circle (19)") (turtle-face! turtle2 0) (turtle-down! turtle2) (turtle-forward! turtle2 (- width 1)) (turtle-turn! turtle2 90) (turtle-forward! turtle2 (- height 1)) (turtle-turn! turtle2 90) (turtle-forward! turtle2 (- width 1)) (turtle-turn! turtle2 90) (turtle-forward! turtle2 (- height 1))) (let* ((spots (list (list 0 0 "light avocado green") (list 1 1 "yellow") (list 2 2 "yellow-green") (list 3 3 "periwinkle") (list 4 4 "hot pink")))) (if (>= n (+ height width)) (image-render-spots! canvas spots) (cond ((or (>= height 1000) (>= width 1000)) (image-scaled-render-spots! canvas spots n)) ((or (>= height 500) (>= width 500)) (image-scaled-render-spots! canvas spots (/ n 2))) ((or (>= height 250) (>= width 250)) (image-scaled-render-spots! canvas spots (/ n 3))) ((or (and (>= height 125) (< height 60)) ( and (>= width 125) (< width 60))) (image-scaled-render-spots! canvas spots (/ n 4))) (else (image-scaled-render-spots! canvas spots (/ n 8)))))) (context-set-fgcolor! (rgb-new (* n 3) n (* n 4))) (roll-2! canvas (/ width 2) (/ height 2) (/ (* 50 width (modulo (+ n 1) (+ width height))) 20000) (/ (* 5 height (modulo (+ n 1) (+ width height))) 20000) (/ pi 100) 200) (roll-2! canvas (/ width 2) (/ height 2) (/ (* width 100 (modulo (+ n 1) (+ width height))) 20000) (/ (* 10 height (modulo (+ n 1) (+ width height))) 20000) (/ pi 200) 400) (roll-2! canvas (/ width 2) (/ height 2) (/ (* width 200 (modulo (+ n 1) (+ width height))) 20000) (/ (* 20 height (modulo (+ n 1) (+ width height))) 20000) (/ pi 400) 800) (roll-2! canvas (/ width 2) (/ height 2) (/ (* 400 width (modulo (+ n 1) (+ width height))) 20000) (/ (* 40 height (modulo (+ n 1) (+ width height))) 20000) (/ pi 800) 1600)) (context-update-displays!))) Supporting Material: ;;; Procedure: ;;; draw-stamp-2! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; radius, and integer ;;; rotation, a real number ;;; Purpose: ;;; By using the inputted information and the procedure image-draw-line!, the procedure produces an image of a line. ;;; Produces: ;;; [Nothing, called for side effects] ;;; Preconditions: ;;; 0 <= col < (image-width image) ;;; 0 <= row < (image-height image) ;;; Postconditions: ;;; image has been extended with the stamp. (define draw-stamp-2! (lambda (image col row radius rotation) (image-draw-line! image col row (+ col (* radius (cos rotation))) (+ row (* radius (sin rotation)))))) ;;; Procedure: ;;; draw-rolled-2! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; inner-radius, an integer ;;; stamp-radius, an integer ;;; revolution, a real number ;;; Purpose: ;;; Draws one rotated stamp, after rolling it clockwise from the starting ;;; position by an angle of revolution (expressed in radians). ;;; Produces: ;;; [Nothing, called for its side effects] ;;; Preconditions: ;;; 0 <= col < (image.width image) ;;; 0 <= row < (image.height image) ;;; 0 < inner-radius ;;; Postconditions: ;;; The image has been extended appropriately. ;;; Package: ;;; Part of the "roller pipe" drawing utilities. ;;; Props: ;;; Inspired by James Clayson's "Visual Modeling with LOGO". (define draw-rolled-2! (lambda (image col row inner-radius stamp-radius revolution) (context-set-brush! "Circle (01)") (draw-stamp-2! image (+ col (* (+ inner-radius stamp-radius) (cos revolution))) (+ row (* (+ inner-radius stamp-radius) (sin revolution))) stamp-radius (/ (* revolution inner-radius) stamp-radius)))) ;;; Procedure: ;;; roll-2! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; inner-radius, an integer ;;; stamp-radius, an integer ;;; theta, an angle in radians ;;; n, an integer ;;; Purpose: ;;; It first sets the tip of the brush to “Circle (01)” and then draws a circle with the inputted information. The procedure then sends the necessary information to its kernel. ;;; Produces: ;;; [Nothing, called for side effects] ;;; Preconditions: ;;; 0 <= col < (image-width image) ;;; 0 <= row < (image-height image) ;;; 0 < inner-radius ;;; 0 < stamp-radius ;;; 0 < theta ;;; 0 < n ;;; Postconditions: ;;; The procedure sends information to the kernel which recurses and draws the image using other procedures. (define roll-2! (lambda (image col row inner-radius stamp-radius theta n) (context-set-brush! "Circle (01)") (image-draw-circle! image col row inner-radius) (roll-kernel-2! image col row inner-radius stamp-radius theta n 0 0))) ;;; Procedure: ;;; roll-kernel-2! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; inner-radius, an integer ;;; stamp-radius, an integer ;;; theta, an angle in radians ;;; n, an integer ;;; step, an integer ;;; revolution, an integer ;;; Purpose: ;;; The procedure takes the inputted information and sends it to draw-rolled-2! to be drawn. The procedure then recurses back to itself with updated parameters. ;;; Produces: ;;; [Nothing, called for side effects] ;;; Preconditions: ;;; 0 <= col < (image-width image) ;;; 0 <= row < (image-height image) ;;; 0 < inner-radius ;;; 0 < stamp-radius ;;; 0 < theta ;;; 0 < n ;;; 0 <= step ;;; 0 <= revolution ;;; Postconditions: ;;; Parameters are sent to draw-rolled-2 to be drawn. Each time the procedure is recursed, the color for the drawing is changed. Before the procedure executes draw-rolled-2!, the color of the tip o the brush is changed. The color changes each time the procedure is recursed. (define roll-kernel-2! (lambda (image col row inner-radius stamp-radius theta n step revolution) (context-set-fgcolor! (rgb-new n step revolution)) (cond ((< step n) (draw-rolled-2! image col row inner-radius stamp-radius revolution) (roll-kernel-2! image col row inner-radius stamp-radius theta n (+ step 1) (+ revolution theta)))))) ;Extra Business: ;(image-draw-circle! image col row radius) ;Extra Stuff (define spot-new (lambda (col row color) (list col row color))) (define spot-col (lambda (spot) (car spot))) (define spot-row (lambda (spot) (cadr spot))) ;;; Procedure: ;;; spot-color ;;; Parameters: ;;; spot, a spot ;;; Purpose: ;;; Extract the color from a spot. ;;; Produces: ;;; color, an integer (define spot-color (lambda (spot) (caddr spot))) (define spot-nudge-right (lambda (spot) (spot-new (+ 1 (spot-col spot)) (spot-row spot) (spot-color spot)))) (define spot-nudge-up (lambda (spot) (spot-new (spot-col spot) (- (spot-row spot) 1) (spot-color spot)))) (define image-render-spot! (lambda (image spot) (context-set-fgcolor! (spot-color spot)) (image-select-rectangle! image selection-replace (spot-col spot) (spot-row spot) 1 1) (image-fill! image) (image-select-nothing! image))) (define image-scaled-render-spot! (lambda (image spot factor) (context-set-fgcolor! (spot-color spot)) (image-select-ellipse! image selection-replace (* factor (spot-col spot)) (* factor (spot-row spot)) factor factor) (image-fill! image) (image-select-nothing! image))) ;;; Procedure: ;;; spot-htrans ;;; Parameters: ;;; spot, a spot ;;; offset, a number ;;; Purpose: ;;; Translate the spot horizontally by offset. If offset is positive, ;;; the spot is translated right. If offset is negative, the spot ;;; is translated left. ;;; Produces: ;;; new-spot, a spot ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; (spot-col new-spot) = (spot-col spot) + offset (define spot-htrans (lambda (spot offset) (spot-new (+ (spot-col spot) offset) (spot-row spot) (spot-color spot)))) ;;; Procedure: ;;; spot-vtrans ;;; Parameters: ;;; spot, a spot ;;; offset, a number ;;; Purpose: ;;; Translate the spot vertically by offset. If offset is positive, ;;; the spot is translated down. If offset is negative, the spot ;;; is translated up. ;;; Produces: ;;; new-spot, a spot ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; (spot-row new-spot) = (spot-row spot) + offset (define spot-vtrans (lambda (spot offset) (spot-new (spot-col spot) (+ (spot-row spot) offset) (spot-color spot)))) ;;; Procedure: ;;; image-render-spots! ;;; Parameters: ;;; image, an image ;;; spots, a list of spots ;;; Purpose: ;; Draw all of the spots on the image. ;;; Produces: ;;; [Nothing; Called for the side effect] (define image-render-spots! (lambda (image spots) (foreach! (lambda (spot) (image-render-spot! image spot)) spots))) ;;; Procedure: ;;; image-render-big-spots! ;;; Parameters: ;;; image, an image id ;;; spots, a list of spots ;;; Purpose: ;;; Render a list of spots "bigger". ;;; Produces: ;;; Nothing; called for the side effect. ;;; Preconditions: ;;; Each scaled spot can be safely rendered. (define image-render-big-spots! (lambda (image spots) (foreach! (lambda (spot) (image-scaled-render-spot! image spot 20)) spots))) ;;; Procedure: ;;; image-scaled-render-spots! ;;; Parameters: ;;; image, an image ;;; spots, a list of spots. ;;; factor, a number ;;; Purpose: ;; Draw all of the spots in the list on the image, scaled by factor. ;;; Produces: ;;; [Nothing; Called for the side effect] ;;; Preconditions: ;;; factor >= 1 ;;; The position of the scaled spot is within the bounds of the image. ;;; Postconditions: ;;; The image now contains a rendering of each spot. (define image-scaled-render-spots! (lambda (image spots scale) (foreach! (lambda (spot) (image-scaled-render-spot! image spot scale)) spots))) ;;; Procedure: ;;; rgb-greyscale ;;; Parameters: ;;; color, an RGB color ;;; Purpose: ;;; Compute a greyscale version of color. ;;; Produces: ;;; grey, an RGB color ;;; Postconditions: ;;; grey is likely to be interpreted as the same brightness as color. (define rgb-greyscale (lambda (color) (let ((component (+ (* 0.30 (rgb-red color)) (* 0.59 (rgb-green color)) (* 0.11 (rgb-blue color))))) (rgb-new component component component)))) ;;; Procedure: ;;; image-greyscale ;;; Parameters: ;;; image, an image id ;;; Purpose: ;;; Create a new, grey scale version of the inputted image ;;; Produces: ;;; an image ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; The new image is created where every pixel in the image is calculated to be a shade of grey. The calculations are based on the color of the pixels from the inputted image. (define image-greyscale (lambda (image) (image-variant image rgb-greyscale))) ;;; Procedure: ;;; range-scale ;;; Parameters: ;;; val, a real number ;;; source-upper, a real number ;;; target-upper, a real number ;;; Purpose: ;;; Calculates a corresponding number of val in a different range ;;; Produces: ;;; a number ;;; Preconditions: ;;; val must be greater than or equal to zero and must be less than or equal to source-upper ;;; Postconditions: ;;; The calculated number is the result of taking a number within the range [0 source-upper] and scaling that number to fit another range [0 target-upper] The output number has similar properties as the original number in a different range. (define range-scale (lambda (val source-upper target-upper) (* (/ val source-upper) target-upper))) ;;; Procedure: ;;; shift-source ;;; Parameters: ;;; val, a real number ;;; source-lower, a real number ;;; Purpose: ;;; Calculates the value of a number when the range where the number exists, shifts from [source-lower, source-upper] to [0, some-value]. ;;; Produces: ;;; a number ;;; Preconditions: ;;; val must be greater than or equal to source-lower. source-lower must be the lower bound of the range. ;;; Postconditions: ;;; val - source-lower (define shift-source (lambda (val source-lower) (- val source-lower))) ;;; Procedure: ;;; shift-target ;;; Parameters: ;;; val, a real number ;;; target-lower, a real number ;;; Purpose: ;;; Calculates the value of a number when the range where the number exists, shifts from [0, another-value] to [target-lower, target-lower + another-value]. ;;; Produces: ;;; a number ;;; Preconditions: ;;; val must be greater than or equal to 0. ;;; Postconditions: ;;; val + target-lower (define shift-target (lambda (val target-lower) (+ val target-lower))) ;;; Procedure: ;;; range-convert ;;; Parameters: ;;; val, a real number ;;; source-lower, a real number ;;; source-upper, a real number ;;; target-lower, a real number ;;; target-upper, a real number ;;; Purpose: ;;; Translates a number in the range [source-lower, source-upper] to the corresponding number with similar properties in the range [target-lower, target-upper]. ;;; Produces: ;;; a number ;;; Preconditions: ;;; val must be greater than source-lower and less than source-upper. source-lower must be less than source-upper and target-lower must be less than target-upper. ;;; Postconditions: ;;; The result = (((val - source-lower) / (source-upper - source-lower)) * (target-upper - target-lower)) + target-lower (define range-convert (lambda (val source-lower source-upper target-lower target-upper) (shift-target (range-scale (shift-source val source-lower) (shift-source source-upper source-lower) (shift-source target-upper target-lower)) target-lower))) ;;; Procedure: ;;; rgb-fade-to-brown ;;; Parameters: ;;; color, an rgb color ;;; Purpose: ;;; Takes an rgb color and fades the color to a brown shade of that color. ;;; Produces: ;;; an rgb color ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; (rgb-red rgb-new) = (((rgb-red - 0) / (255 - 0)) * (255 - (rgb-red brown)) + (rgb-red brown) ;;; (rgb-green rgb-new) = (((rgb-green - 0) / (255 - 0)) * (255 - (rgb-green brown)) + (rgb-green brown) ;;; (rgb-green rgb-new) = (((rgb-green - 0) / (255 - 0)) * (255 - (rgb-green brown)) + (rgb-green brown) (define rgb-fade-to-brown (lambda (color) (let ((brown (cname->rgb "bakers chocolate"))) (rgb-new (range-convert (rgb-red color) 0 255 (rgb-red brown) 255) (range-convert (rgb-green color) 0 255 (rgb-green brown) 255) (range-convert (rgb-blue color) 0 255 (rgb-blue brown) 255))))) ;;; Procedure: ;;; image-sepia ;;; Parameters: ;;; image, an image id ;;; Purpose: ;;; Creates a new, sepia toned image from the inputted image. ;;; Produces: ;;; an image ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; Every pixel in the original image is first converted to a grey scale using image-greyscale. Once that is done, each pixel is made into a brown shade using rgb-fade-to-brown. The result is a new, sepia toned image. (define image-sepia (lambda (image) (image-variant (image-greyscale image) rgb-fade-to-brown))) ;;; Procedure: ;;; rgb-recolor ;;; Parameters: ;;; color, an rgb color ;;; dark, an rgb color ;;; light, an rgb color ;;; Purpose: ;;; Takes in three colors, the first being the color that will be translated into the range of the the other two colors. dark is the lower bound of the range and light is the upper bound of the range. ;;; Produces: ;;; an rgb color ;;; Preconditions: ;;; [No additional ;;; Postconditions: ;;; The color will have each component recalculated using range-convert. The new components are used to make a new rgb color. (define rgb-recolor (lambda (color dark light) (rgb-new (range-convert (rgb-red color) 0 255 (rgb-red dark) (rgb-red light)) (range-convert (rgb-green color) 0 255 (rgb-green dark) (rgb-green light)) (range-convert (rgb-blue color) 0 255 (rgb-blue dark) (rgb-blue light))))) ;;; Procedure: ;;; image-colorscale ;;; Parameters: ;;; image, an image id ;;; dark, an rgb color ;;; light, an rgb color ;;; Purpose: ;;; Creates a new image, which has a different color scale from the original image. The procedure takes in image and a specific range determined by dark and light. Dark is the lower bound and light is the upper bound of the scale. All the pixels of the original image are reconfigured to the new color scale and a new image is formed. ;;; Produces: ;;; an image ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; Each pixel in the new image is the result of taking the original pixel and applying image-greyscale and specific-recolor to it. (define image-colorscale (lambda (image dark light) (let ((specific-recolor (lambda (color) (rgb-recolor color dark light)))) (image-variant (image-greyscale image) specific-recolor)))) ;;; Procedure: ;;; rgb-bright? ;;; Parameters: ;;; color, an RGB color ;;; Purpose: ;;; Determines whether the color is bright. ;;; Produces: ;;; bright?, a boolean ;;; Preconditions: ;;; color is a valid RGB color. That is, each component is between ;;; 0 and 255, inclusive. ;;; rgb-brightness is defined. ;;; Postconditions: ;;; bright? is true iff (rgb-brightness color) >= 67. (define rgb-bright? (lambda (color) (<= 67 (rgb-brightness color)))) ;;; Procedure: ;;; rgb-dark? ;;; Parameters: ;;; color, an RGB color ;;; Purpose: ;;; Determine if the color appears dark. ;;; Produces: ;;; dark?, a Boolean ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; If color is relatively dark, then dark? is #t. ;;; Otherwise, dark? is #f. (define rgb-dark? (lambda (color) (> 33 (rgb-brightness color)))) ;;; Procedure: ;;; rgb-brightness ;;; Parameters: ;;; color, an RGB color ;;; Purpose: ;;; Computes the brightness of color on a 0 (dark) to 100 (light) scale. ;;; Produces: ;;; b, an integer ;;; Preconditions: ;;; color is a valid RGB color. That is, each component is between ;;; 0 and 255, inclusive. ;;; Postconditions: ;;; If color1 is likely to be perceived as lighter than color2, ;;; then (brightness color1) > (brightness color2). (define rgb-brightness (lambda (color) (round (* 100 (/ (+ (* 0.30 (rgb-red color)) (* 0.59 (rgb-green color)) (* 0.11 (rgb-blue color))) 255))))) ;; Procedure: ;;; rgb-brighter? ;;; Parameters: ;;; color1, a color ;;; color2, a color ;;; Purpose: ;;; Determine if color1 is strictly brighter than color 2. ;;; Produces: ;;; brighter?, a Boolean ;;; Preconditions: ;;; [No additional preconditions.] ;;; Postconditions: ;;; If (rgb-brightness color1) > (rgb-brightness color2) ;;; then brighter is true (#t) ;;; Otherwise ;;; brighter is false (#f) (define rgb-brighter? (lambda (color1 color2) (> (rgb-brightness color1) (rgb-brightness color2)))) ;;; Procedure: ;;; rgb-brighter ;;; Parameters: ;;; color1, an RGB color. ;;; color2, an RGB color. ;;; Purpose: ;;; Find the brighter of color1 and color2. ;;; Produces: ;;; brighter, an RGB color. ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; brighter is either color1 or color2 ;;; (rgb-brightness brighter) >= (rgb-brightness color1) ;;; (rgb-brightness brighter) >= (rgb-brightness color2) (define rgb-brighter (lambda (color1 color2) (if (>= (rgb-brightness color1) (rgb-brightness color2)) color1 color2))) ;;; Procedure: ;;; image-draw-circle! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; radius, an integer ;;; Purpose: ;;; Draws a circle with the specified radius in the current brush and color, ;;; centered at (col,row). ;;; Produces: ;;; [Nothing; Called for the side effect] ;;; Preconditions: ;;; 0 <= col < (image-width image) ;;; 0 <= row < (image-height image) ;;; 0 < radius ;;; Postconditions: ;;; The image now contains the specified circle. (The circle may ;;; not be visible.) (define image-draw-circle! (lambda (image col row radius) (image-select-ellipse! image selection-replace (- col radius) (- row radius) (+ radius radius) (+ radius radius)) (image-stroke! image) (image-select-nothing! image))) ;;; Procedure: ;;; draw-three-parallel-lines! ;;; Parameters: ;;; image, an image ;;; start-col, an integer ;;; start-row, an integer ;;; end-col, an integer ;;; end-row, an integer ;;; hoffset, an integer ;;; voffset, an integer ;;; Purpose: ;;; Draw three parallel lines, with the first from (start-col,start-row) ;;; to (end-col,end-row) and the starting point of the next two offset ;;; horizontally by hoffset (and 2*hoffset) and vertically by voffset ;;; (and 2*voffset). ;;; Produces: ;;; [Nothing; Called for the side effect.] ;;; Preconditions: ;;; All three parallel lines can be drawn on the image. ;;; Postcondtions: ;;; The image has been appropriately modified. (define draw-three-parallel-lines! (lambda (image start-col start-row end-col end-row hoffset voffset) (image-draw-line! image start-col start-row end-col end-row) (image-draw-line! image (+ hoffset start-col) (+ voffset start-row) (+ hoffset end-col) (+ voffset end-row)) (image-draw-line! image (+ (* 2 hoffset) start-col) (+ (* 2 voffset) start-row) (+ (* 2 hoffset) end-col) (+ (* 2 voffset) end-row)))) ;;; Procedure: ;;; draw-circle! ;;; Parameters: ;;; image, an image ;;; col, an integer ;;; row, an integer ;;; radius, an integer ;;; Purpose: ;;; Draws a circle with the specified in the current brush and color, centered at (col,row). ;;; Produces: ;;; [Nothing; Called for the side effect] ;;; Preconditions: ;;; 0 <= col < (image.width image) ;;; 0 <= row < (image.height image) ;;; 0 < radius ;;; Postconditions: ;;; The image now contains the specified circle. (The circle may not be visible.) (define draw-circle! (lambda (image col row radius) (image-select-ellipse! image selection-replace (- col radius) (- row radius) (+ radius radius) (+ radius radius)) (image-stroke! image) (image-select-nothing! image))) ;;; Procedure: ;;; image-safely-render-spots ;;; Parameters: ;;; image, an image ;;; spots: (spot1 spot2 ... spotn), a list of spots ;;; Purpose: ;;; Render a list of spots on an image, but do not render any spots lying outside the bounds of the image. ;;; Produces: ;;; [Nothing; called for side-effect] ;;; Preconditions: ;;; [None] ;;; Postconditions: ;;; List of spots is rendered on image. If a spot's horizontal location is less than 0 or greater than (image-width - 1), or the spot's vertical location is less than 0 or greater than (image-width - 1), that spot is not rendered. (define image-safely-render-spots! (lambda (image spots) (foreach! (lambda (spot) (if (and (<= (spot-col spot) (- (image-width image) 1)) (>= (spot-col spot) 0) (<= (spot-row spot) (- (image-height image) 1)) (>= (spot-row spot) 0)) (image-render-spot! image spot))) spots)))