;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname hospitals) (read-case-sensitive #t) (teachpacks ((lib "image.rkt" "teachpack" "2htdp") (lib "universe.rkt" "teachpack" "2htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "image.rkt" "teachpack" "2htdp") (lib "universe.rkt" "teachpack" "2htdp"))))) (require geo) ;; DATA DEFINITION ;; ;; A `(bbox X)`, also known as a *bounding box measured with X*, is a structure: ;; > `(make-bbox south north west east)` ;; where `south`, `north`, `west`, and `east` are X's. (define-struct bbox (south north west east)) ; within-bbox : (bbox degrees) -> (point-of-interest -> boolean) ; to return a function that tells if a given point-of-interest is within the given bounding box (define (within-bbox bb) (local [(define (within? pt) (and (<= (bbox-west bb) (usgs-lond pt) (bbox-east bb)) (<= (bbox-south bb) (usgs-latd pt) (bbox-north bb))))] within?)) (define bb1 (make-bbox 42 43 -72 -70)) (check-expect ((within-bbox bb1) (make-usgs "Boston" "test pt" "Middlesex" "MA" 42.33 -71)) true) (check-expect ((within-bbox bb1) (make-usgs "North" "test pt" "Middlesex" "MA" 43.33 -71)) false) (check-expect ((within-bbox bb1) (make-usgs "STL" "test pt" "?" "MO" 38.6 -90.2)) false) ;; A (2Dpoint X) is a structure: ;; (make-point x y value) ;; where `x` and `y` are numbers and `value` is an *X*. (define-struct point (x y value)) ; xy-converter : bbox number -> (point-of-interest -> (2Dpoint point-of-interest)) ; to return a function that attaches (x, y) coordinates to the given point-of-interest, ; relative to the given bbox. Height is the height of the bbox in pixels (define (xy-converter bb height) (local [(define pixels-per-latitude-degree ; # of pixels representing 1 degree of latitude (/ height (- (bbox-north bb) (bbox-south bb)))) (define pixels-per-longitude-degree ; # of pixels representing 1 degree of longitude (* (cosd (average (bbox-north bb) (bbox-south bb))) pixels-per-latitude-degree)) ; x-in-pixels : degrees -> number ; convert the given longitude to an x distance from the west boundary (define (x-in-pixels x-degrees) (* pixels-per-longitude-degree (- x-degrees (bbox-west bb)))) ; y-in-pixels : degrees -> number ; convert the given latitude to a y distance down from the north boundary (define (y-in-pixels y-degrees) (* pixels-per-latitude-degree (- (bbox-north bb) y-degrees))) ; convert : point-of-interest -> (2Dpoint point-of-interest) ; wrap `pt` in its (x, y) coordinates within `bb` (define (convert pt) (make-point (x-in-pixels (usgs-lond pt)) (y-in-pixels (usgs-latd pt)) pt))] convert)) ; cosd : degrees -> number ; to return the cosine of the given number of degrees (define (cosd degrees) (cos (* pi (/ degrees 180)))) (check-within (cosd 45) (/ (sqrt 2) 2) EPSILON) (check-within (cosd 90) 0 EPSILON) ; average : number number -> number ; to return the average of the two given numbers (define (average x y) (/ (+ x y) 2)) (check-expect (average 6 7) 6.5) (check-expect (usgs-latd (make-usgs "X" "X" "X" "X" 42.5 -71)) 42.5) (check-expect (usgs-lond (make-usgs "X" "X" "X" "X" 42.5 -71)) -71) (define c1 (xy-converter (make-bbox 42 43 -72 -70) 100)) (define west (make-usgs "West" "test point" "?" "MA" 42.5 -72)) (define wnw (make-usgs "West Northwest" "test point" "?" "MA" 42.75 -72 )) (define nw (make-usgs "Northwest" "test point" "?" "MA" 43 -72)) (define ne (make-usgs "Northeast" "test point" "?" "MA" 43 -70)) (define sw (make-usgs "Southwest" "test point" "?" "MA" 42 -72)) (define sse (make-usgs "South Southeast" "test pt" "?" "MA" 42 -70.5)) (define mid (make-usgs "Middle" "test pt" "?" "MA" 42.5 -71)) (define shrink (cosd 42.5)) (check-within (c1 west) (make-point 0 50 west) EPSILON) (check-within (c1 wnw) (make-point 0 25 wnw) EPSILON) (check-within (c1 nw) (make-point 0 0 nw) EPSILON) (check-within (c1 sw) (make-point 0 100 sw) EPSILON) (check-within (c1 ne) (make-point (* 200 shrink) 0 ne) EPSILON) (check-within (c1 sse) (make-point (* 2 shrink 75) 100 sse) EPSILON) (check-within (c1 mid) (make-point (* 2 shrink 50) 50 mid) EPSILON) (define EPSILON 0.0001)