OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 part of dart.math; | 4 part of dart.math; |
5 | 5 |
6 /** | 6 /** |
7 * A base class for representing two-dimensional axis-aligned rectangles. | 7 * A base class for representing two-dimensional axis-aligned rectangles. |
8 * | 8 * |
9 * This rectangle uses a left-handed Cartesian coordinate system, with x | 9 * This rectangle uses a left-handed Cartesian coordinate system, with x |
10 * directed to the right and y directed down, as per the convention in 2D | 10 * directed to the right and y directed down, as per the convention in 2D |
(...skipping 21 matching lines...) Expand all Loading... |
32 /** The x-coordinate of the right edge. */ | 32 /** The x-coordinate of the right edge. */ |
33 T get right => left + width; | 33 T get right => left + width; |
34 /** The y-coordinate of the bottom edge. */ | 34 /** The y-coordinate of the bottom edge. */ |
35 T get bottom => top + height; | 35 T get bottom => top + height; |
36 | 36 |
37 String toString() { | 37 String toString() { |
38 return 'Rectangle ($left, $top) $width x $height'; | 38 return 'Rectangle ($left, $top) $width x $height'; |
39 } | 39 } |
40 | 40 |
41 bool operator ==(other) { | 41 bool operator ==(other) { |
42 if (other is !Rectangle) return false; | 42 if (other is! Rectangle) return false; |
43 return left == other.left && top == other.top && right == other.right && | 43 return left == other.left && |
| 44 top == other.top && |
| 45 right == other.right && |
44 bottom == other.bottom; | 46 bottom == other.bottom; |
45 } | 47 } |
46 | 48 |
47 int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode, | 49 int get hashCode => _JenkinsSmiHash.hash4( |
48 right.hashCode, bottom.hashCode); | 50 left.hashCode, top.hashCode, right.hashCode, bottom.hashCode); |
49 | 51 |
50 /** | 52 /** |
51 * Computes the intersection of `this` and [other]. | 53 * Computes the intersection of `this` and [other]. |
52 * | 54 * |
53 * The intersection of two axis-aligned rectangles, if any, is always another | 55 * The intersection of two axis-aligned rectangles, if any, is always another |
54 * axis-aligned rectangle. | 56 * axis-aligned rectangle. |
55 * | 57 * |
56 * Returns the intersection of this and `other`, or `null` if they don't | 58 * Returns the intersection of this and `other`, or `null` if they don't |
57 * intersect. | 59 * intersect. |
58 */ | 60 */ |
59 Rectangle<T> intersection(Rectangle<T> other) { | 61 Rectangle<T> intersection(Rectangle<T> other) { |
60 var x0 = max(left, other.left); | 62 var x0 = max(left, other.left); |
61 var x1 = min(left + width, other.left + other.width); | 63 var x1 = min(left + width, other.left + other.width); |
62 | 64 |
63 if (x0 <= x1) { | 65 if (x0 <= x1) { |
64 var y0 = max(top, other.top); | 66 var y0 = max(top, other.top); |
65 var y1 = min(top + height, other.top + other.height); | 67 var y1 = min(top + height, other.top + other.height); |
66 | 68 |
67 if (y0 <= y1) { | 69 if (y0 <= y1) { |
68 return new Rectangle<T>(x0, y0, x1 - x0, y1 - y0); | 70 return new Rectangle<T>(x0, y0, x1 - x0, y1 - y0); |
69 } | 71 } |
70 } | 72 } |
71 return null; | 73 return null; |
72 } | 74 } |
73 | 75 |
74 | |
75 /** | 76 /** |
76 * Returns true if `this` intersects [other]. | 77 * Returns true if `this` intersects [other]. |
77 */ | 78 */ |
78 bool intersects(Rectangle<num> other) { | 79 bool intersects(Rectangle<num> other) { |
79 return (left <= other.left + other.width && | 80 return (left <= other.left + other.width && |
80 other.left <= left + width && | 81 other.left <= left + width && |
81 top <= other.top + other.height && | 82 top <= other.top + other.height && |
82 other.top <= top + height); | 83 other.top <= top + height); |
83 } | 84 } |
84 | 85 |
85 /** | 86 /** |
86 * Returns a new rectangle which completely contains `this` and [other]. | 87 * Returns a new rectangle which completely contains `this` and [other]. |
87 */ | 88 */ |
88 Rectangle<T> boundingBox(Rectangle<T> other) { | 89 Rectangle<T> boundingBox(Rectangle<T> other) { |
89 var right = max(this.left + this.width, other.left + other.width); | 90 var right = max(this.left + this.width, other.left + other.width); |
90 var bottom = max(this.top + this.height, other.top + other.height); | 91 var bottom = max(this.top + this.height, other.top + other.height); |
91 | 92 |
92 var left = min(this.left, other.left); | 93 var left = min(this.left, other.left); |
93 var top = min(this.top, other.top); | 94 var top = min(this.top, other.top); |
94 | 95 |
95 return new Rectangle<T>(left, top, right - left, bottom - top); | 96 return new Rectangle<T>(left, top, right - left, bottom - top); |
96 } | 97 } |
97 | 98 |
98 /** | 99 /** |
99 * Tests whether `this` entirely contains [another]. | 100 * Tests whether `this` entirely contains [another]. |
100 */ | 101 */ |
101 bool containsRectangle(Rectangle<num> another) { | 102 bool containsRectangle(Rectangle<num> another) { |
102 return left <= another.left && | 103 return left <= another.left && |
103 left + width >= another.left + another.width && | 104 left + width >= another.left + another.width && |
104 top <= another.top && | 105 top <= another.top && |
105 top + height >= another.top + another.height; | 106 top + height >= another.top + another.height; |
106 } | 107 } |
107 | 108 |
108 /** | 109 /** |
109 * Tests whether [another] is inside or along the edges of `this`. | 110 * Tests whether [another] is inside or along the edges of `this`. |
110 */ | 111 */ |
111 bool containsPoint(Point<num> another) { | 112 bool containsPoint(Point<num> another) { |
112 return another.x >= left && | 113 return another.x >= left && |
113 another.x <= left + width && | 114 another.x <= left + width && |
114 another.y >= top && | 115 another.y >= top && |
115 another.y <= top + height; | 116 another.y <= top + height; |
116 } | 117 } |
117 | 118 |
118 Point<T> get topLeft => new Point<T>(this.left, this.top); | 119 Point<T> get topLeft => new Point<T>(this.left, this.top); |
119 Point<T> get topRight => new Point<T>(this.left + this.width, this.top); | 120 Point<T> get topRight => new Point<T>(this.left + this.width, this.top); |
120 Point<T> get bottomRight => new Point<T>(this.left + this.width, | 121 Point<T> get bottomRight => |
121 this.top + this.height); | 122 new Point<T>(this.left + this.width, this.top + this.height); |
122 Point<T> get bottomLeft => new Point<T>(this.left, | 123 Point<T> get bottomLeft => new Point<T>(this.left, this.top + this.height); |
123 this.top + this.height); | |
124 } | 124 } |
125 | 125 |
126 | |
127 /** | 126 /** |
128 * A class for representing two-dimensional rectangles whose properties are | 127 * A class for representing two-dimensional rectangles whose properties are |
129 * immutable. | 128 * immutable. |
130 */ | 129 */ |
131 class Rectangle<T extends num> extends _RectangleBase<T> { | 130 class Rectangle<T extends num> extends _RectangleBase<T> { |
132 final T left; | 131 final T left; |
133 final T top; | 132 final T top; |
134 final T width; | 133 final T width; |
135 final T height; | 134 final T height; |
136 | 135 |
137 /** | 136 /** |
138 * Create a rectangle spanned by `(left, top)` and `(left+width, top+height)`. | 137 * Create a rectangle spanned by `(left, top)` and `(left+width, top+height)`. |
139 * | 138 * |
140 * The rectangle contains the points | 139 * The rectangle contains the points |
141 * with x-coordinate between `left` and `left + width`, and | 140 * with x-coordinate between `left` and `left + width`, and |
142 * with y-coordinate between `top` and `top + height`, both inclusive. | 141 * with y-coordinate between `top` and `top + height`, both inclusive. |
143 * | 142 * |
144 * The `width` and `height` should be non-negative. | 143 * The `width` and `height` should be non-negative. |
145 * If `width` or `height` are negative, they are clamped to zero. | 144 * If `width` or `height` are negative, they are clamped to zero. |
146 * | 145 * |
147 * If `width` and `height` are zero, the "rectangle" comprises only the single | 146 * If `width` and `height` are zero, the "rectangle" comprises only the single |
148 * point `(left, top)`. | 147 * point `(left, top)`. |
149 */ | 148 */ |
150 const Rectangle(this.left, this.top, T width, T height) | 149 const Rectangle(this.left, this.top, T width, T height) |
151 : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero. | 150 : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero. |
152 this.height = (height < 0) ? -height * 0 : height; | 151 this.height = (height < 0) ? -height * 0 : height; |
153 | 152 |
154 /** | 153 /** |
155 * Create a rectangle spanned by the points [a] and [b]; | 154 * Create a rectangle spanned by the points [a] and [b]; |
156 * | 155 * |
157 * The rectangle contains the points | 156 * The rectangle contains the points |
158 * with x-coordinate between `a.x` and `b.x`, and | 157 * with x-coordinate between `a.x` and `b.x`, and |
159 * with y-coordinate between `a.y` and `b.y`, both inclusive. | 158 * with y-coordinate between `a.y` and `b.y`, both inclusive. |
160 * | 159 * |
161 * If the distance between `a.x` and `b.x` is not representable | 160 * If the distance between `a.x` and `b.x` is not representable |
162 * (which can happen if one or both is a double), | 161 * (which can happen if one or both is a double), |
163 * the actual right edge might be slightly off from `max(a.x, b.x)`. | 162 * the actual right edge might be slightly off from `max(a.x, b.x)`. |
164 * Similar for the y-coordinates and the bottom edge. | 163 * Similar for the y-coordinates and the bottom edge. |
165 */ | 164 */ |
166 factory Rectangle.fromPoints(Point<T> a, Point<T> b) { | 165 factory Rectangle.fromPoints(Point<T> a, Point<T> b) { |
167 T left = min(a.x, b.x); | 166 T left = min(a.x, b.x); |
168 T width = max(a.x, b.x) - left; | 167 T width = max(a.x, b.x) - left; |
169 T top = min(a.y, b.y); | 168 T top = min(a.y, b.y); |
170 T height = max(a.y, b.y) - top; | 169 T height = max(a.y, b.y) - top; |
171 return new Rectangle<T>(left, top, width, height); | 170 return new Rectangle<T>(left, top, width, height); |
172 } | 171 } |
173 } | 172 } |
174 | 173 |
175 /** | 174 /** |
176 * A class for representing two-dimensional axis-aligned rectangles with mutable | 175 * A class for representing two-dimensional axis-aligned rectangles with mutable |
177 * properties. | 176 * properties. |
178 */ | 177 */ |
179 class MutableRectangle<T extends num> extends _RectangleBase<T> | 178 class MutableRectangle<T extends num> extends _RectangleBase<T> |
180 implements Rectangle<T> { | 179 implements Rectangle<T> { |
181 | |
182 /** | 180 /** |
183 * The x-coordinate of the left edge. | 181 * The x-coordinate of the left edge. |
184 * | 182 * |
185 * Setting the value will move the rectangle without changing its width. | 183 * Setting the value will move the rectangle without changing its width. |
186 */ | 184 */ |
187 T left; | 185 T left; |
188 /** | 186 /** |
189 * The y-coordinate of the left edge. | 187 * The y-coordinate of the left edge. |
190 * | 188 * |
191 * Setting the value will move the rectangle without changing its height. | 189 * Setting the value will move the rectangle without changing its height. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) { | 225 factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) { |
228 T left = min(a.x, b.x); | 226 T left = min(a.x, b.x); |
229 T width = max(a.x, b.x) - left; | 227 T width = max(a.x, b.x) - left; |
230 T top = min(a.y, b.y); | 228 T top = min(a.y, b.y); |
231 T height = max(a.y, b.y) - top; | 229 T height = max(a.y, b.y) - top; |
232 return new MutableRectangle<T>(left, top, width, height); | 230 return new MutableRectangle<T>(left, top, width, height); |
233 } | 231 } |
234 | 232 |
235 T get width => _width; | 233 T get width => _width; |
236 | 234 |
237 /** | 235 /** |
238 * Sets the width of the rectangle. | 236 * Sets the width of the rectangle. |
239 * | 237 * |
240 * The width must be non-negative. | 238 * The width must be non-negative. |
241 * If a negative width is supplied, it is clamped to zero. | 239 * If a negative width is supplied, it is clamped to zero. |
242 * | 240 * |
243 * Setting the value will change the right edge of the rectangle, | 241 * Setting the value will change the right edge of the rectangle, |
244 * but will not change [left]. | 242 * but will not change [left]. |
245 */ | 243 */ |
246 void set width(T width) { | 244 void set width(T width) { |
247 if (width < 0) width = _clampToZero<T>(width); | 245 if (width < 0) width = _clampToZero<T>(width); |
(...skipping 19 matching lines...) Expand all Loading... |
267 | 265 |
268 /** | 266 /** |
269 * Converts a negative [int] or [double] to a zero-value of the same type. | 267 * Converts a negative [int] or [double] to a zero-value of the same type. |
270 * | 268 * |
271 * Returns `0` if value is int, `0.0` if value is double. | 269 * Returns `0` if value is int, `0.0` if value is double. |
272 */ | 270 */ |
273 T _clampToZero<T extends num>(T value) { | 271 T _clampToZero<T extends num>(T value) { |
274 assert(value < 0); | 272 assert(value < 0); |
275 return -value * 0; | 273 return -value * 0; |
276 } | 274 } |
OLD | NEW |