(define-record-type rectangle (make-rectangle begin end) rectangle? (begin rect-begin ) (end rect-end ) ) ;; let ranges_intersect a b a' b' = a' <= b && a <= b' ;; For two envelopes to intersect, both of their ranges do. (define (rectangles-intersect? (x0, x1, y0, y1) (x0', x1', y0', y1') = ranges_intersect x0 x1 x0' x1' && ranges_intersect y0 y1 y0' y1' let add (x0, x1, y0, y1) (x0', x1', y0', y1') = min x0 x0', max x1 x1', min y0 y0', max y1 y1' let rec add_many = function | e :: [] -> e | e :: es -> add e (add_many es) | [] -> raise (Invalid_argument "can't zero envelopes") let area (x0, x1, y0, y1) = (x1 -. x0) *. (y1 -. y0) let within (x0, x1, y0, y1) (x0', x1', y0', y1') = x0 <= x0' && x1 >= x1' && y0 <= y0' && y1 >= y1' let empty = 0., 0., 0., 0. ;; Whether a point falls within a rectangle, including the rectangle's edges. (define (in-rect? p r) (and (point? p) (rectangle? r) (p>= p (range-begin r)) (p<= p (range-end r)))) ;; rect-union x y yields the smallest rectangle z such that x ``includes`` ;; z and y ``includes`` z. (define rect-union (let ((f (lambda (fl fr) (lambda (a b) (make-rect (fl (rect-begin a) (rect-end b)) (fr (rect-begin b) (rect-end b))))))) (f pmin pmax))) ;; Yields whether the second argument completely falls within the ;; first argument. (define (rect-includes? r) (and (rectangle? r) (lambda (x) (and (rectangle? x) (in-rect? (rect-begin x) r) (in-rect? (rect-end x) r)))))