;; original shape datatype (define Shape (interface () draw)) (define Rectangle (class* object% (Shape) (width height) (public [draw (lambda (dc x y) (send dc draw-rectangle x y width height))]) (sequence (super-init)))) (define Circle (class* object% (Shape) (radius) (public [draw (lambda (dc x y) (send dc draw-ellipse (- x radius) (- y radius) (* 2 radius) (* 2 radius)))]) (sequence (super-init)))) (define Translated (class* object% (Shape) (orig-shape dx dy) (public [draw (lambda (dc x y) (send orig-shape draw dc (+ x dx) (+ y dy)))]) (sequence (super-init)))) ;; original factory (define Factory (class object% () (public [make-circle (lambda (radius) (make-object Circle radius))] [make-rectangle (lambda (width height) (make-object Rectangle width height))] [make-translated (lambda (shape dx dy) (make-object Translated shape dx dy))]) (sequence (super-init)))) (define the-factory (make-object Factory)) ;; variant extension (define Union (class* object% (Shape) (left right) (public [draw (lambda (dc x y) (send left draw dc x y) (send right draw dc x y))]) (sequence (super-init)))) ;; variant extension factory (define Trans-Factory (class Factory () (public [make-union (lambda (left right) (make-object Union left right))]) (sequence (super-init)))) (set! the-factory (make-object Trans-Factory)) ;; operation extension (define BB-Shape (interface (Shape) bounding-box)) (define-struct BB (left top right bottom)) (define BB-Rectangle (class* Rectangle (BB-Shape) (width height) (public [bounding-box (lambda () (make-BB 0 0 width height))]) (sequence (super-init width height)))) (define BB-Circle (class* Circle (BB-Shape) (r) (public [bounding-box (lambda () (make-BB (- r) (- r) r r))]) (sequence (super-init r)))) (define BB-Translated (class* Translated (BB-Shape) (shape dx dy) (public [bounding-box (lambda () (let ([pre-bb (send shape bounding-box)]) (make-BB (+ (BB-left pre-bb) dx) (+ (BB-top pre-bb) dy) (+ (BB-right pre-bb) dx) (+ (BB-bottom pre-bb) dy))))]) (sequence (super-init shape dx dy)))) (define BB-Union (class* Union (BB-Shape) (left right) (public [bounding-box (lambda () (let ([left-bb (send left bounding-box)] [right-bb (send right bounding-box)]) (make-BB (min (BB-left left-bb) (BB-left right-bb)) (min (BB-top left-bb) (BB-top right-bb)) (max (BB-right left-bb) (BB-right right-bb)) (max (BB-bottom left-bb) (BB-bottom right-bb)))))]) (sequence (super-init left right)))) ;; operation extension factory (define BB-Factory (class Trans-Factory () (override [make-circle (lambda (radius) (make-object BB-Circle radius))] [make-rectangle (lambda (width height) (make-object BB-Rectangle width height))] [make-translated (lambda (shape dx dy) (make-object BB-Translated shape dx dy))] [make-union (lambda (left right) (make-object BB-Union left right))]) (sequence (super-init)))) (set! the-factory (make-object BB-Factory)) ;; client (define shape-canvas% (class canvas% (panel shape) (inherit get-dc get-client-size) (override [on-paint (lambda () (let-values ([(win-width win-height) (get-client-size)]) (let* ([bb (send shape bounding-box)] [size (lambda (left1 right1 left2 right2) (- (/ (- (- right2 left2) (- right1 left1)) 2) left1))] [x (size (BB-left bb) (BB-right bb) 0 win-width)] [y (size (BB-top bb) (BB-bottom bb) 0 win-height)]) (send shape draw (get-dc) x y))))]) (sequence (super-init panel)))) (define display-shape (lambda (a-shape) (unless (is-a? a-shape BB-Shape) (error 'display-shape "expected a BB-Shape, got: ~e" a-shape)) (let* ([frame (make-object frame% "Centered Shapes" #f 150 150)] [canvas (make-object shape-canvas% frame a-shape)]) (send frame show #t)))) (display-shape (send the-factory make-union (send the-factory make-rectangle 10 30) (send the-factory make-translated (send the-factory make-circle 20) 30 30)))
in context | contents |