;;;; Problem Solving in Computer Science (Prof. Dave Hollinger)
;;;; Homework #2a (due Sept. 17, 2004)
;;;;
;;;; Submitted by: Benjamin Levinn
;;; Global notes: All of these require the draw.ss teachpack, and drawing functions require
;;; an open canvas.
;; FUNCTION base-angle
;;
;; SYNTAX:
;; (base-angle pos1 pos2)
;;
;; DESCRIPTION
;; Given any two points, finds the reference angle between the line segment connecting
;; them and the x-axis (determined by the first point)
;;
;; INPUT:
;; (posn) pos1 : The first point (the origin)
;; (posn) pos2 : The second point; a point on the ray extending from the origin
;;
;; RETURN:
;; The reference angle (in radians)
;;
;; EXAMPLES:
;; (base-angle (make-posn 50 50) (make-posn (75 25)) = pi/4
;; (base-angle (make-posn 50 50) (make-posn (50 100)) = pi/2
(define (base-angle pos1 pos2)
(cond
;; First we make sure that the two points are not vertical with each other
;; Vertical points make atan barf. Actually, they make / barf, too.
[(= (- (posn-x pos2) (posn-x pos1)) 0) (/ pi 2)]
;; Ugly bit coming up (though there are far worse later). Basically, we determine the
;; tangent of the angle by finding the ratio of the relative y and x values. We're using
;; absolute values because we don't much care about what quadrant it ends up in. Once we
;; have the tangent, we take it's inverse to find the angle, and Tada!
[else (atan (/ (abs (- (posn-y pos2) (posn-y pos1))) (abs (- (posn-x pos2) (posn-x pos1)))))]
)
)
;; FUNCTION distance
;;
;; SYNTAX:
;; (distance pos1 pos2)
;;
;; DESCRIPTION:
;; Determines the distance between points A and B using the Pythagorean Theorem.
;;
;; INPUT:
;; (posn) pos1 : Point A
;; (posn) pos2 : Point B
;;
;; RETURN:
;; The distance between them
;;
;; EXAMPLES:
;; (distance (make-posn 0 0) (make-posn 0 50)) = 50
;; (distance (make-posn 50 50) (make-posn 53 54)) = 5
(define (distance pos1 pos2)
;; Another ugly bugger. But it's just the pythagorean theorem. Honest.
(sqrt (+ (expt (- (posn-x pos1) (posn-x pos2)) 2) (expt (- (posn-y pos1) (posn-y pos2)) 2))))
;; FUNCTION what-angle
;;
;; SYNTAX:
;; (what-angle pos1 pos2)
;;
;; DESCRIPTION:
;; Finds the real angle, like base-angle, but including quadrant information. That is,
;; now it will return a number from 0 to 2pi.
;;
;; INPUT:
;; (posn) pos1 : The first point (the origin)
;; (posn) pos2 : The second point; a point on the ray extending from the origin
;;
;; RETURN
;; Number from 0 to 2pi - the angle that between the x-axis and the ray
;;
;; EXAMPLES:
;; (what-angle (make-posn 50 50) (make-posn (75 25)) = pi/4
;; (what-angle (make-posn 50 50) (make-posn (50 100)) = 3pi/2
(define (what-angle pos1 pos2)
(cond
[(>= (- (posn-y pos2) (posn-y pos1)) 0)
(cond
[(> (- (posn-x pos2) (posn-x pos1)) 0) (base-angle pos1 pos2)] ;; First quadrant
[else (- pi (base-angle pos1 pos2))] ;; Second quadrant
)]
[else
(cond
[(< (- (posn-x pos2) (posn-x pos1)) 0) (+ pi (base-angle pos1 pos2))] ;; Third quadrant
[else (- (* 2 pi) (base-angle pos1 pos2))] ;; Fourth quadrant
)
]
)
)
;; FUNCTION spiral-next-pos
;;
;; SYNTAX:
;; (spiral-next-pos center-pos end-pos step-width decay)
;;
;; DESCRIPTION
;; Determines the next point in the spiral... useful for drawing the lines to draw the
;; spiral itself. Actually, it finds the next step in a circle and subtracts an
;; appropriate amount for decay, giving a net-effect of a spiral.
;;
;; INPUT:
;; (posn) center-pos : The centerpoint of the spiral
;; (posn) end-pos : The point from which we're trying to find the next point
;; (num) step-width : The number of radians each step should be. Smaller numbers mean
;; a finer line.
;; (num) decay : The amount of decay each step. It ranges from zero to one, with
;; 0 being a straight line to the middle and 1 being a circle
;;
;; RETURN:
;; A posn with the next place for the line.
;;
;; EXAMPLES:
;; (spiral-next-pos (make-posn 500 500) (make-posn 500 750) (/ pi 8) 0.99)
(define (spiral-next-pos center-pos end-pos step-width decay)
(make-posn
(+ (* decay (distance center-pos end-pos) (cos (+ (what-angle center-pos end-pos) step-width))) (posn-x center-pos))
(+ (* decay (distance center-pos end-pos) (sin (+ (what-angle center-pos end-pos) step-width))) (posn-y center-pos))
)
)
;; FUNCTION draw-spiral
;;
;; SYNTAX:
;; (draw-spiral center-pos end-pos steps step-width decay color)
;;
;; DESCRIPTION:
;; Draws a spiral
;;
;; INPUT:
;; (posn) center-pos : The centerpoint of the spiral
;; (posn) end-pos : An endpoint of the spiral
;; (num) steps : The number of steps that the spiral should take. The more steps,
;; the further in the spiral will go.
;; (num) step-width : The width of each step in radians
;; (num) decay : How much decay toward the center happens with each step. A value
;; of 0 means total decay; there will just be a single line to the
;; center. A value of 1 means no decay; there will just be a circle.
;; A value in between will cause an inward spiral, and a value above
;; 1 will cause an outward spiral. A negative value will produce funky
;; results.
;; (symbol) color : The color of the spiral
;;
;; RETURNS:
;; true (always)
;;
;; EXAMPLE:
;; (draw-spiral (make-posn 500 500) (make-posn 500 1000) 500 (/ pi 8) 0.99 'Blue)
(define (draw-spiral center-pos end-pos steps step-width decay color)
(cond
[(<= steps 0) true]
[else
(and
(draw-solid-line end-pos (spiral-next-pos center-pos end-pos step-width decay) color)
(draw-spiral center-pos (spiral-next-pos center-pos end-pos step-width decay) (- steps 1) step-width decay color)
)
]
)
)
;; FUNCTION star-next-pos
;;
;; SYNTAX:
;; (star-next-pos center-pos end-pos step-width decay)
;;
;; DESCRIPTION
;; Determines the next point in the star... useful for drawing the lines to draw the
;; star itself.
;;
;; INPUT:
;; (posn) center-pos : The centerpoint of the spiral
;; (posn) end-pos : The point from which we're trying to find the next point
;; (num) step-width : The number of radians each step should be. Smaller numbers mean
;; a finer line.
;; (num) decay : The amount of decay each step. It ranges from zero to one, with
;; 0 being a straight line to the middle and 1 being a circle
;;
;; RETURN:
;; A posn with the next place for the line.
;;
;; EXAMPLES:
;; (star-next-pos (make-posn 500 500) (make-posn 500 750) (/ pi 8) 0.99)
(define (star-next-pos center-pos end-pos step-width decay)
(make-posn
;; This is basically the same as spiral-next-pos, except it sends it to the opposite side.
;; Makes for some interesting results, including the double spiral and star.
(- (posn-x center-pos) (* decay (distance center-pos end-pos) (cos (+ (what-angle center-pos end-pos) step-width))))
(- (posn-y center-pos) (* decay (distance center-pos end-pos) (sin (+ (what-angle center-pos end-pos) step-width))))
)
)
;; FUNCTION draw-double-spiral
;;
;; SYNTAX:
;; (draw-double-spiral center-pos end-pos steps step-width decay color1 color2)
;;
;; DESCRIPTION:
;; Draws two dashed spirals, one inside the other.
;;
;; INPUT:
;; (posn) center-pos : The centerpoint of the spiral
;; (posn) end-pos : An endpoint of the spiral
;; (num) steps : The number of steps that the star should take. The more steps,
;; the further in the star will go.
;; (num) step-width : The width of each step in radians
;; (num) decay : How much decay toward the center happens with each step. A value
;; of 0 means total decay; there will just be a single line to the
;; center. A value of 1 means no decay; there will just be a circle.
;; A value in between will cause an inward spiral, and a value above
;; 1 will cause an outward spiral. A negative value will produce funky
;; results.
;; (symbol) color1 : The color of the outside spiral.
;; (symbol) color2 : The color of the inside spiral.
;;
;; RETURNS:
;; true (always)
;;
;; EXAMPLE:
;; (draw-double-spiral (make-posn 500 500) (make-posn 500 1000) 500 (/ pi 8) 0.99 'Blue)
;;
;; NOTES:
;; This code involves something of a hack between the star code and the spiral code, and
;; as such, the function names within are a bit odd. Understanding exactly what is happening
;; may be slightly confusing, but rest-assured, it works. Comprehension of what is happening
;; becomes significantly easier when the function is played with and values are inserted.
(define (draw-double-spiral center-pos end-pos steps step-width decay color1 color2)
(cond
[(<= steps 0) true]
[else
(and
(draw-solid-line end-pos (spiral-next-pos center-pos end-pos step-width decay) color1)
(draw-double-spiral center-pos (star-next-pos center-pos end-pos step-width decay) (- steps 1) step-width decay color2 color1)
)
]
)
)
;; FUNCTION draw-crazy-star
;;
;; SYNTAX:
;; (draw-crazy-star center-pos end-pos steps step-width decay color1 color2)
;;
;; DESCRIPTION:
;; Draws a peculiar star in either one or two colors, of a user-chosen number of points,
;; and optionally changing point-length. The end result can be a truly funky star that
;; cannot really be described, but instead needs to be seen. But, if you refuse to
;; try it out, just take this to heart: It's just plain odd.
;;
;; INPUT:
;; (posn) center-pos : The centerpoint of the star
;; (posn) end-pos : An endpoint of the star
;; (num) steps : The number of steps that the star should take. The more steps,
;; the further in the star will go.
;; (num) step-width : The width of each step in radians
;; (num) decay : How much decay toward the center happens with each step. A value
;; of 0 means total decay; there will just be a single line to the
;; center. A value of 1 means no decay; there will just be a circle.
;; A value in between will cause an inward spiral with the points, and a
;; value above 1 will cause an outward spiral. A negative value will
;; produce funky results.
;; (symbol) color1 : One star color.
;; (symbol) color2 : The other color (not necessarily different).
;;
;; RETURNS:
;; true (always)
;;
;; EXAMPLE:
;; (draw-crazy star (make-posn 500 500) (make-posn 500 1000) 500 (/ pi 8) 0.99 'Blue)
(define (draw-crazy-star center-pos end-pos steps step-width decay color1 color2)
(cond
[(<= steps 0) true]
[else
(and
(draw-solid-line end-pos (star-next-pos center-pos end-pos step-width decay) color1)
(draw-crazy-star center-pos (star-next-pos center-pos end-pos step-width decay) (- steps 1) step-width decay color2 color1)
)
]
)
)
;(start 400 200)
;(draw-spiral (make-posn 100 100) (make-posn 100 200) 800 (/ pi 4) 0.99 'Blue)
;(draw-spiral (make-posn 300 100) (make-posn 300 200) 800 (/ pi 8) 0.99 'Blue)
;(draw-crazy-star (make-posn 100 100) (make-posn 100 200) 500 (/ pi 8) 0.99 'Blue 'Red)
;(draw-crazy-star (make-posn 300 100) (make-posn 300 200) 500 (/ pi 4) 0.99 'Green 'Yellow)