1 namespace demo #:...
2 A namespace for demo classes.
3 end namespace demo;
4
5 class Point #:...
6 A point in R2.
7 assocs:...
8 std assoc math;
9 scope:...
10 field x : double;
11 field y : double;
12 lifecycle params:...
13 var x -> x;
14 var y -> y;
15 scope:...
16 end;
17
18 method distance : double #:...
19 Euclidean distance.
20 params:...
21 var point : *demo.Point #:...
22 The point to compute distance to.
23 scope:...
24 dx = self.x() - point.x()
25 dy = self.y() - point.y()
26 return math.sqrt(dx*dx + dy*dy)
27 test:...
28 test.isapprox(
29 1.41421356237,
30 test.p1().distance(test.p2()))
31 test.isapprox(
32 3.04138126515,
33 test.p1().distance(test.p3()))
34 end method distance;
35
36 end class Point;
37
38 class Shape #:...
39 Abstract superclass of all shape classes.
40 scope:...
41 field impl : *demo.ShapeImpl;
42 lifecycle params:...
43 var impl -> impl;
44 scope:...
45 end;
46 end class Shape;
47
48 class Polygon < Shape #:...
49 An n-sided 2D shape.
50 scope:...
51 end;
52
53 class Quadrilateral < Polygon #:...
54 A four-sided polygon with four angles.
55 scope:...
56 end;
57
58 class Parallelogram < Quadrilateral #:...
59 Has two parallel pairs of opposite sides.
60 scope:...
61 end;
62
63 class Rectangle < Parallelogram #:...
64 Has two pairs of opposite sides parallel,
65 and four right angles.
66 scope:...
67 end;
68
69 class Square < Rectangle #:...
70 Has two pairs of parallel sides, four right
71 angles, and all four sides are equal.
72 scope:...
73 end;
74
75 class Rhombus < Parallelogram #:...
76 A parallelogram with four equal sides.
77 scope:...
78 end;
79
80 class Trapezoid < Quadrilateral #:...
81 Has one pair of parallel sides.
82 scope:...
83 end;
84
85 class Ellipse < Shape #:...
86 A curve in a plane surrounding two focal
87 points such that the sum of the distances to
88 the two focal points is constant for every
89 point on the curve.
90 scope:...
91 end;
92
93 class Circle < Ellipse #:...
94 The curve traced out by a point that moves so
95 that its distance from a given point (the
96 center) is constant.
97 scope:...
98 lifecycle params:...
99 var impl : *demo.ShapeImpl;
100 super (impl)
101 scope:...
102 assert isinstance(impl, FocusImpl)
103 end;
104 end;
105
106 class ShapeImpl #:...
107 Abstract superclass of Shape implementation
108 classes.
109 scope:...
110 end class ShapeImpl;
111
112 class PointListImpl < ShapeImpl #:...
113 A list of points.
114 scope:...
115 field data : vec<Point> #:...
116 The list of points.
117 lifecycle params:...
118 var data -> data;
119 scope:...
120 end;
121 end class PointListImpl;
122
123 class TwoPointImpl < ShapeImpl #:...
124 Two points
125 scope:...
126 field point1 : *demo.Point;
127 field point2 : *demo.Point;
128 lifecycle params:...
129 var point1 -> point1;
130 var point2 -> point2;
131 scope:...
132 end;
133
134 method width : any #:...
135 docstr
136 params:...
137 var a : int #:...
138 docstr
139 scope:...
140 test:...
141 end method width;
142
143 end class TwoPointImpl;
144
145 class FocusImpl < ShapeImpl #:...
146 A focus point and radius.
147 scope:...
148 field focus : *demo.Point;
149 field radius : double;
150 lifecycle params:...
151 var radius -> radius var focus -> focus;
152 scope:...
153 end;
154 end class FocusImpl;
155
156 class FociImpl < FocusImpl #:...
157 Two foci and a radius.
158 scope:...
159 field focus2 : *demo.Point;
160 lifecycle params:...
161 var radius : double;
162 var focus : *demo.Point;
163 var focus2 -> focus2;
164 super (radius, focus)
165 scope:...
166 end;
167 end class FociImpl;
168
169 behavior area : double #:...
170 The area inside the shape.
171 scope:...
172 abstract receiver Shape;
173
174 receiver Circle scope:...
175 r = self.impl().radius()
176 return math.pi * r * r
177 test:...
178 test.isapprox(
179 3.14159265359, test.circle().area())
180
181 receiver Rectangle scope:...
182
183 receiver Polygon scope:...
184 end behavior area;
185
186 behavior perimeter alias circumference : double #:...
187 The distance around the edge of the shape.
188 scope:...
189 abstract receiver Shape;
190
191 receiver Circle scope:...
192 return 2 * math.pi * self.radius()
193
194 receiver Rectangle scope:...
195 /# 2 * width + 2 * length
196 width = self.impl().width()
197 length = self.impl().length()
198 return 2 * width + 2 * height
199
200 receiver Polygon scope:...
201 /# Some of lengths of each side.
202 points = self.impl().points()
203 point = points[0]
204 n = len(points)
205 i = 0
206 result = 0.0
207 while i < n:
208 j = (i+1)%n
209 point2 = points[j]
210 result += point.distance(point2)
211 point = point2
212 return result
213
214 end behavior perimeter;
215
216 behavior points : vec<Point> #:...
217 Return the points defining the shape.
218 params:...
219 var error : double = -1.0 #:...
220 If positive, and the shape in question is
221 not a polygon (meaning we will be returning
222 a polygon approximation of the shape),
223 return sufficient points to ensure the
224 error in area between shape and polygon
225 defined by return points is less than this
226 amount.
227 error = abs(1 - (result_area / area))
228 scope:...
229 receiver Shape ::...
230 return self.impl().points()
231
232 abstract receiver ShapeImpl;
233
234 receiver TwoPointImpl ::...
235 impl = self.impl()
236 p1 = impl.point1()
237 p2 = impl.point2()
238 x1 = p1.x()
239 y1 = p1.y()
240 x2 = p2.x()
241 y2 = p2.y()
242 /# Fix this!
243 return [
244 p1, Point(x1, y2), p3, Point(x2, y1)]
245 end behavior points;
246
247 test
248 class TestCase < metax.test.TestCase scope:...
249 field p1 : demo.shapes.Point;
250 field p2 : demo.shapes.Point;
251 field p3 : demo.shapes.Point;
252 field p4 : demo.shapes.Point;
253 field circle : demo.shapes.Circle;
254 field ellipse : demo.shapes.Ellipse;
255 field rectangle : demo.shapes.Rectangle;
256 field square : demo.shapes.Square;
257 field polygon : demo.shapes.Polygon;
258
259 lifecycle setup:...
260 p1 = demo.shapes.Point(0.0, 0.0)
261 p2 = demo.shapes.Point(1.0, 1.0)
262 p3 = demo.shapes.Point(0.5, 3.0)
263 p4 = demo.shapes.Point(-1.0, 2.0)
264 test.p1Is(p1)
265 test.p2Is(p2)
266 test.p3Is(p3)
267 test.p4Is(p4)
268 test.circleIs(demo.shapes.Circle(
269 demo.shapes.FocusImpl(1.0, p1)))
270 test.ellipseIs(demo.shapes.Ellipse(
271 demo.shapes.FociImpl(3.0, p1, p2)))
272 test.rectangleIs(demo.shapes.Rectangle(
273 demo.shapes.TwoPointImpl(p1, p3)))
274 test.squareIs(demo.shapes.Square(
275 demo.shapes.TwoPointImpl(p1, p2)))
276 test.polygonIs(demo.shapes.Polygon(
277 demo.shapes.PointListImpl(
278 (p1, p2, p3, p4))))
279 end;