-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path09-5-shapes-with-interfaces.rkt
executable file
·156 lines (115 loc) · 4.47 KB
/
09-5-shapes-with-interfaces.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#lang racket
;; 09-3-shapes.rkt
(require rackunit)
(require "extras.rkt")
(require 2htdp/image)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; A Tiny System for creating and drawing shapes on a canvas.
;;; demo with (demo)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We don't know what shapes there will be, but we know what
;; operations we will want on shapes. This is the shape interface:
;;; INTERFACE:
;; all geometric shapes support these methods in all contexts
;; a Shape is an object of a class that implements Shape<%>.
(define Shape<%>
(interface ()
;; weight : -> Number
;; RETURNS: the weight of this shape
weight
;; add-to-scene : Scene -> Scene
;; RETURNS: a scene like the given one, but with this shape
;; painted on it.
add-to-scene
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Classes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; We will have a class for each kind of shape
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Circles
;; A Circle is a (new Circle% [x Integer][y Integer][r Integer][c ColorString])
;; REPRESENTS: a circle on the canvas
(define Circle%
(class* object% (Shape<%>)
(init-field
x ; Integer, x pixels of center from left
y ; Integer, y pixels of center from top
r ; Integer, radius
c) ; ColorString
(field [IMG (circle r "solid" c)])
(super-new)
;; for each method, we copy down the contract and purpose
;; statement from the interface, with perhaps additional details
;; relating to this class.
;; weight : -> Integer
;; RETURNS: the weight of this shape
;; DETAILS: this shape is a circle
;; STRATEGY: combine simpler functions
(define/public (weight) (* pi r r))
;; add-to-scene : Scene -> Scene
;; RETURNS: a scene like the given one, but with this shape
;; painted on it.
;; DETAILS: this shape is a circle
;; STRATEGY: call a more general function
(define/public (add-to-scene s) (place-image IMG x y s))
))
;; A Square is a (new Square% [x Integer][y Integer][l Integer][c ColorString])
;; REPRESENTS: a square parallel to sides of canvas
(define Square%
(class* object% (Shape<%>)
(init-field x ; Integer, x pixels of center from left
y ; Integer, y pixels of center from top
l ; Integer, length of one side
c) ; ColorString
(field [IMG (rectangle l l "solid" c)])
(super-new)
;; weight : -> Real
;; RETURNS: the weight of this shape
;; DETAILS: this shape is a square
;; STRATEGY: combine simpler functions
(define/public (weight) (* l l))
;; add-to-scene : Scene -> Scene
;; RETURNS: a scene like the given one, but with this shape
;; painted on it.
;; DETAILS: this shape is a square
;; STRATEGY: call a more general function
(define/public (add-to-scene s) (place-image IMG x y s))
))
;; A Composite is a (new Composite% [front Shape][back Shape])
;; a composite of front and back
(define Composite%
(class* object% (Shape<%>)
(init-field
front ; Shape, the shape in front
back ; Shape, the shape in back
)
(super-new)
;; all we know here is that front and back implement Shape<%>.
;; we don't know if they are circles, squares, or other composites!
;; weight : -> Number
;; RETURNS: the weight of this shape
;; DETAILS: this shape is a composite
;; STRATEGY: recur on the components
(define/public (weight) (+ (send front weight)
(send back weight)))
;; add-to-scene : Scene -> Scene
;; RETURNS: a scene like the given one, but with this shape
;; painted on it.
;; DETAILS: this shape is a composite
;; strategy: recur on the components
(define/public (add-to-scene scene)
(send front add-to-scene
(send back add-to-scene scene)))
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define EMPTY-CANVAS (empty-scene 200 100))
(define s1 (new Circle% [x 50][y 20][r 40][c "red"]))
(define s2 (new Square% [x 80][y 70][l 40][c "blue"]))
(define s3 (new Composite% [front s1][back s2]))
(begin-for-test
(check-= (send s1 weight) (* pi 1600) .1)
(check-equal? (send s2 weight) 1600)
(check-= (send s3 weight) (+ (* pi 1600) 1600) .1))
(define (demo)
(send s3 add-to-scene EMPTY-CANVAS))