Module: duim-extended-geometry-internals Synopsis: DUIM extended 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 /// Ellipses and elliptical arcs define protocol <> (<>) function ellipse-center-point (ellipse) => (point :: ); function ellipse-center-position (ellipse) => (x :: , y :: ); function ellipse-radii (ellipse) => (radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: ); function ellipse-start-angle (ellipse) => (angle :: false-or()); function ellipse-end-angle (ellipse) => (angle :: false-or()); end protocol <>; define abstract class () sealed constant slot %center-x :: , required-init-keyword: center-x:; sealed constant slot %center-y :: , required-init-keyword: center-y:; sealed slot %center-point :: false-or() = #f, init-keyword: center-point:; sealed constant slot %radius-1-dx :: , required-init-keyword: radius-1-dx:; sealed constant slot %radius-1-dy :: , required-init-keyword: radius-1-dy:; sealed constant slot %radius-2-dx :: , required-init-keyword: radius-2-dx:; sealed constant slot %radius-2-dy :: , required-init-keyword: radius-2-dy:; sealed constant slot ellipse-start-angle :: false-or() = #f, init-keyword: start-angle:; sealed constant slot ellipse-end-angle :: false-or() = #f, init-keyword: end-angle:; end class ; define method ellipse-center-position (ellipse :: ) => (x :: , y :: ) values(ellipse.%center-x, ellipse.%center-y) end method ellipse-center-position; define method ellipse-center-point (ellipse :: ) => (point :: ) ellipse.%center-point | (ellipse.%center-point := make-point(ellipse.%center-x, ellipse.%center-y)) end method ellipse-center-point; define method ellipse-radii (ellipse :: ) => (radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: ); values(ellipse.%radius-1-dx, ellipse.%radius-1-dy, ellipse.%radius-2-dx, ellipse.%radius-2-dy) end method ellipse-radii; define sealed class (, ) end class ; define sealed domain make (singleton()); define sealed domain initialize (); //--- Should signal if the axes are collinear define inline function make-elliptical-arc (center-x :: , center-y :: , radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: , #key start-angle, end-angle) => (arc :: ) make(, center-x: center-x, center-y: center-y, radius-1-dx: radius-1-dx, radius-1-dy: radius-1-dy, radius-2-dx: radius-2-dx, radius-2-dy: radius-2-dy, start-angle: case start-angle => as(, start-angle); end-angle => 0.0; otherwise => #f end, end-angle: case end-angle => as(, end-angle); start-angle => $2pi; otherwise => #f end) end function make-elliptical-arc; //--- Should signal if the axes are collinear define inline function make-elliptical-arc* (center-point :: , radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: , #key start-angle, end-angle) => (arc :: ) make(, center-point: center-point, center-x: point-x(center-point), center-y: point-y(center-point), radius-1-dx: radius-1-dx, radius-1-dy: radius-1-dy, radius-2-dx: radius-2-dx, radius-2-dy: radius-2-dy, start-angle: case start-angle => as(, start-angle); end-angle => 0.0; otherwise => #f end, end-angle: case end-angle => as(, end-angle); start-angle => $2pi; otherwise => #f end) end function make-elliptical-arc*; define sealed inline method make (class == , #key center-point, radius-1-dx, radius-1-dy, radius-2-dx, radius-2-dy, start-angle, end-angle) => (arc :: ) make-elliptical-arc*(center-point, radius-1-dx, radius-1-dy, radius-2-dx, radius-2-dy, start-angle: start-angle, end-angle: end-angle) end method make; define method transform-region (transform :: , ellipse :: ) => (arc :: ) let (cx, cy) = transform-position(transform, ellipse.%center-x, ellipse.%center-y); let (r1-dx, r1-dy) = transform-distance (transform, ellipse.%radius-1-dx, ellipse.%radius-1-dy); let (r2-dx, r2-dy) = transform-distance (transform, ellipse.%radius-2-dx, ellipse.%radius-2-dy); let start-angle = ellipse-start-angle(ellipse); let end-angle = ellipse-end-angle(ellipse); when (start-angle) // non-#f => end angle is non-#f let (sa, ea) = transform-angles(transform, start-angle, end-angle); start-angle := sa; end-angle := ea end; make-elliptical-arc(cx, cy, r1-dx, r1-dy, r2-dx, r2-dy, start-angle: start-angle, end-angle: end-angle) end method transform-region; define method box-edges (ellipse :: ) => (left :: , top :: , right :: , bottom :: ) elliptical-arc-box(ellipse.%center-x, ellipse.%center-y, ellipse.%radius-1-dx, ellipse.%radius-1-dy, ellipse.%radius-2-dx, ellipse.%radius-2-dy, start-angle: ellipse-start-angle(ellipse), end-angle: ellipse-end-angle(ellipse)) end method box-edges; define method region-equal (e1 :: , e2 :: ) => (true? :: ) e1.%center-x = e2.%center-x & e1.%center-y = e2.%center-y & e1.%radius-1-dx = e2.%radius-1-dx & e1.%radius-1-dy = e2.%radius-1-dy & e1.%radius-2-dx = e2.%radius-2-dx & e1.%radius-2-dy = e2.%radius-2-dy & ellipse-start-angle(e1) = ellipse-start-angle(e2) & ellipse-end-angle(e1) = ellipse-end-angle(e2) end method region-equal; define method region-contains-position? (ellipse :: , x :: , y :: ) => (true? :: ) let (left, top, right, bottom) = box-edges(ellipse); ltrb-contains-position?(left, top, right, bottom, fix-coordinate(x), fix-coordinate(y)) & position-on-thick-ellipse?(x - ellipse.%center-x, y - ellipse.%center-y, ellipse.%radius-1-dx, ellipse.%radius-1-dy, ellipse.%radius-2-dx, ellipse.%radius-2-dy) end method region-contains-position?; define sealed class (, ) end class ; define sealed domain make (singleton()); define sealed domain initialize (); define inline function make-ellipse (center-x :: , center-y :: , radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: , #key start-angle, end-angle) => (ellipse :: ) make(, center-x: center-x, center-y: center-y, radius-1-dx: radius-1-dx, radius-1-dy: radius-1-dy, radius-2-dx: radius-2-dx, radius-2-dy: radius-2-dy, start-angle: case start-angle => as(, start-angle); end-angle => 0.0; otherwise => #f end, end-angle: case end-angle => as(, end-angle); start-angle => $2pi; otherwise => #f end) end function make-ellipse; define inline function make-ellipse* (center-point :: , radius-1-dx :: , radius-1-dy :: , radius-2-dx :: , radius-2-dy :: , #key start-angle, end-angle) => (ellipse :: ) make(, center-point: center-point, center-x: point-x(center-point), center-y: point-y(center-point), radius-1-dx: radius-1-dx, radius-1-dy: radius-1-dy, radius-2-dx: radius-2-dx, radius-2-dy: radius-2-dy, start-angle: case start-angle => as(, start-angle); end-angle => 0.0; otherwise => #f end, end-angle: case end-angle => as(, end-angle); start-angle => $2pi; otherwise => #f end) end function make-ellipse*; define sealed inline method make (class == , #key center-point, radius-1-dx, radius-1-dy, radius-2-dx, radius-2-dy, start-angle, end-angle) => (ellipse :: ) make-ellipse*(center-point, radius-1-dx, radius-1-dy, radius-2-dx, radius-2-dy, start-angle: start-angle, end-angle: end-angle) end method make; define method transform-region (transform :: , ellipse :: ) => (ellipse :: ) let (cx, cy) = transform-position(transform, ellipse.%center-x, ellipse.%center-y); let (r1-dx, r1-dy) = transform-distance(transform, ellipse.%radius-1-dx, ellipse.%radius-1-dy); let (r2-dx, r2-dy) = transform-distance(transform, ellipse.%radius-2-dx, ellipse.%radius-2-dy); let start-angle = ellipse-start-angle(ellipse); let end-angle = ellipse-end-angle(ellipse); when (start-angle) // non-#f => end angle is non-#f let (sa, ea) = transform-angles(transform, start-angle, end-angle); start-angle := sa; end-angle := ea end; make-ellipse(cx, cy, r1-dx, r1-dy, r2-dx, r2-dy, start-angle: start-angle, end-angle: end-angle) end method transform-region; define method box-edges (ellipse :: ) => (left :: , top :: , right :: , bottom :: ) elliptical-arc-box(ellipse.%center-x, ellipse.%center-y, ellipse.%radius-1-dx, ellipse.%radius-1-dy, ellipse.%radius-2-dx, ellipse.%radius-2-dy, start-angle: ellipse-start-angle(ellipse), end-angle: ellipse-end-angle(ellipse), thickness: #f) // filled... end method box-edges; define method region-equal (e1 :: , e2 :: ) => (true? :: ) e1.%center-x = e2.%center-x & e1.%center-y = e2.%center-y & e1.%radius-1-dx = e2.%radius-1-dx & e1.%radius-1-dy = e2.%radius-1-dy & e1.%radius-2-dx = e2.%radius-2-dx & e1.%radius-2-dy = e2.%radius-2-dy & ellipse-start-angle(e1) = ellipse-start-angle(e2) & ellipse-end-angle(e1) = ellipse-end-angle(e2) end method region-equal; define method region-contains-position? (ellipse :: , x :: , y :: ) => (true? :: ) let (left, top, right, bottom) = box-edges(ellipse); ltrb-contains-position?(left, top, right, bottom, fix-coordinate(x), fix-coordinate(y)) & position-inside-ellipse?(x - ellipse.%center-x, y - ellipse.%center-y, ellipse.%radius-1-dx, ellipse.%radius-1-dy, ellipse.%radius-2-dx, ellipse.%radius-2-dy) end method region-contains-position?;