Module: duim-geometry-internals Synopsis: DUIM geometry Author: Scott McKay, Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// The basic region protocol define protocol <> () // Basic protocol function region-empty? (region :: ) => (true? :: ); function region-equal (region1 :: , region2 :: ) => (true? :: ); function region-contains-position? (region :: , x :: , y :: ) => (true? :: ); function region-contains-region? (region1 :: , region2 :: ) => (true? :: ); function region-intersects-region? (region1 :: , region2 :: ) => (true? :: ); function region-union (region1 :: , region2 :: ) => (region :: ); function region-intersection (region1 :: , region2 :: ) => (region :: ); function region-difference (region1 :: , region2 :: ) => (region :: ); // Compound regions function do-regions (function :: , region :: , #key normalize?) => (); function region-set-function (region :: ) => (function); function region-set-regions (region :: , #key normalize?) => (regions :: ); // Regions meet transforms function transform-region (transform :: , region :: ) => (region :: ); function untransform-region (transform :: , region :: ) => (region :: ); function transform-region! (transform :: , region :: ) => (region :: ); function untransform-region! (transform :: , region :: ) => (region :: ); end protocol <>; /// The basic region classes define method untransform-region (transform :: , region :: ) => (region :: ) transform-region(invert-transform(transform), region) end method untransform-region; // The default method creates a new region define method transform-region! (transform :: , region :: ) => (region :: ) transform-region(transform, region) end method transform-region!; // The default method creates a new region define method untransform-region! (transform :: , region :: ) => (region :: ) transform-region!(invert-transform(transform), region) end method untransform-region!; define method \= (region1 :: , region2 :: ) => (true? :: ) region1 == region2 | region-equal(region1, region2) end method \=; /// General cases of region arithmetic // Exclude the general case of 'region-equal' define method region-equal (region1 :: , region2 :: ) => (true? :: ) #f end method region-equal; // Exclude the general case of 'region-contains-position?' define method region-contains-position? (region :: , x :: , y :: ) => (true? :: ) #f end method region-contains-position?; // Exclude the general case of 'region-contains-region?' define method region-contains-region? (region1 :: , region2 :: ) => (true? :: ) #f end method region-contains-region?; // Exclude the general case of 'region-intersects-region?' define method region-intersects-region? (region1 :: , region2 :: ) => (true? :: ) #f end method region-intersects-region?; define method region-empty? (region :: ) => (true? :: ) #f end method region-empty?; /// Nowhere define sealed class () end class ; define sealed domain make (singleton()); define sealed domain initialize (); define constant $nowhere :: = make(); define method region-equal (nowhere1 :: , nowhere2 :: ) => (true? :: ) #t end method region-equal; define method region-contains-region? (region :: , nowhere :: ) => (true? :: ) #t end method region-contains-region?; define method region-contains-region? (nowhere :: , region :: ) => (true? :: ) #f end method region-contains-region?; define method region-contains-region? (nowhere1 :: , nowhere2 :: ) => (true? :: ) #f end method region-contains-region?; define method region-empty? (region :: ) => (true? :: ) #t end method region-empty?; define method transform-region (transform :: , region :: ) => (region :: ) region end method transform-region; /// Everywhere define sealed class () end class ; define sealed domain make (singleton()); define sealed domain initialize (); define constant $everywhere :: = make(); define inline function everywhere? (region) => (true? :: ) region == $everywhere end function everywhere?; define method region-equal (everywhere1 :: , everywhere2 :: ) => (true? :: ) #t end method region-equal; define method region-contains-position? (everywhere :: , x :: , y :: ) => (true? :: ) #t end method region-contains-position?; define method region-contains-region? (region :: , everywhere :: ) => (true? :: ) #f end method region-contains-region?; define method region-contains-region? (everywhere :: , region :: ) => (true? :: ) #t end method region-contains-region?; define method region-contains-region? (everywhere1 :: , everywhere2 :: ) => (true? :: ) #t end method region-contains-region?; define method region-intersects-region? (everywhere :: , region :: ) => (true? :: ) ~(region == $nowhere) end method region-intersects-region?; define method region-intersects-region? (region :: , everywhere :: ) => (true? :: ) ~(region == $nowhere) end method region-intersects-region?; define method region-intersects-region? (everywhere1 :: , everywhere2 :: ) => (true? :: ) #t end method region-intersects-region?; define method region-empty? (region :: ) => (true? :: ) #f end method region-empty?; define method transform-region (transform :: , region :: ) => (region :: ) region end method transform-region; /// Points define protocol <> (<>) function point-position (point :: ) => (x :: , y :: ); getter point-x (point :: ) => (x :: ); getter point-y (point :: ) => (y :: ); end protocol <>; define sealed class () sealed slot point-x :: , required-init-keyword: x:; sealed slot point-y :: , required-init-keyword: y:; end class ; define inline function make-point (x :: , y :: ) => (point :: ) make(, x: x, y: y) end function make-point; define sealed inline method make (class == , #key x, y) => (point :: ) make-point(x, y) end method make; define sealed domain make (singleton()); define sealed domain initialize (); define sealed inline method point-position (point :: ) => (x :: , y :: ) values(point-x(point), point-y(point)) end method point-position; define sealed method region-equal (point1 :: , point2 :: ) => (true? :: ) point-x(point1) = point-x(point2) & point-y(point1) = point-y(point2) end method region-equal; define method transform-region (transform :: , point :: ) => (point :: ) let (x, y) = transform-position(transform, point-x(point), point-y(point)); make-point(x, y) end method transform-region; define sealed method box-edges (point :: ) => (left :: , top :: , right :: , bottom :: ) fix-box(point-x(point), point-y(point), point-x(point) + 1, point-y(point) + 1) end method box-edges; define sealed method region-contains-position? (point :: , x :: , y :: ) => (true? :: ) point-x(point) = x & point-y(point) = y end method region-contains-position?; define sealed method region-contains-region? (point1 :: , point2 :: ) => (true? :: ) point-x(point1) = point-x(point2) & point-y(point1) = point-y(point2) end method region-contains-region?; define method region-contains-region? (region :: , point :: ) => (true? :: ) region-contains-position?(region, point-x(point), point-y(point)) end method region-contains-region?; define sealed method region-intersects-region? (point1 :: , point2 :: ) => (true? :: ) point-x(point1) = point-x(point2) & point-y(point1) = point-y(point2) end method region-intersects-region?; define method region-intersects-region? (point :: , region :: ) => (true? :: ) region-contains-position?(region, point-x(point), point-y(point)) end method region-intersects-region?; define method region-intersects-region? (region :: , point :: ) => (true? :: ) region-contains-position?(region, point-x(point), point-y(point)) end method region-intersects-region?; define sealed method region-intersection (point1 :: , point2 :: ) => (region :: ) if (point-x(point1) = point-x(point2) & point-y(point1) = point-y(point2)) point1 else $nowhere end end method region-intersection; /// Region Sets define method region-set-function (region :: ) => (function) union end method region-set-function; define method region-set-regions (region :: , #key normalize?) => (regions :: ) ignore(normalize?); vector(region) end method region-set-regions; define method do-regions (function :: , region :: , #key normalize?) => () ignore(normalize?); function(region) end method do-regions; define method do-regions (function :: , region :: , #rest args, #key normalize?) => () dynamic-extent(args); ignore(normalize?); do(function, apply(region-set-regions, region, args)) end method do-regions; define method region-contains-position? (region-set :: , x :: , y :: ) => (true? :: ) block (return) local method contains-position? (region) => () when (region-contains-position?(region, x, y)) return(#t) end end method; do-regions(contains-position?, region-set); #f end end method region-contains-position?; define method region-contains-region? (region-set :: , other-region :: ) => (true? :: ) block (return) local method contains-region? (region) => () when (region-contains-region?(region, other-region)) return(#t) end end method; do-regions(contains-region?, region-set); #f end end method region-contains-region?; define method box-edges (region-set :: ) => (left :: , top :: , right :: , bottom :: ) let left :: = $largest-coordinate; let top :: = $largest-coordinate; let right :: = $smallest-coordinate; let bottom :: = $smallest-coordinate; local method add-region (region) => () let (rl, rt, rr, rb) = box-edges(region); min!(left, rl); min!(top, rt); max!(right, rr); max!(bottom, rb); end method; do-regions(add-region, region-set); values(left, top, right, bottom) end method box-edges;