| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 part of dart.math; | |
| 5 | |
| 6 /** | |
| 7 * A base class for representing two-dimensional axis-aligned rectangles. | |
| 8 * | |
| 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 | |
| 11 * computer graphics. | |
| 12 * | |
| 13 * See also: | |
| 14 * [W3C Coordinate Systems Specification](http://www.w3.org/TR/SVG/coords.htm
l#InitialCoordinateSystem). | |
| 15 * | |
| 16 * The rectangle is the set of points with representable coordinates greater | |
| 17 * than or equal to left/top, and with distance to left/top no greater than | |
| 18 * width/height (to the limit of the precission of the coordinates). | |
| 19 */ | |
| 20 abstract class _RectangleBase<T extends num> { | |
| 21 const _RectangleBase(); | |
| 22 | |
| 23 /** The x-coordinate of the left edge. */ | |
| 24 T get left; | |
| 25 /** The y-coordinate of the top edge. */ | |
| 26 T get top; | |
| 27 /** The width of the rectangle. */ | |
| 28 T get width; | |
| 29 /** The height of the rectangle. */ | |
| 30 T get height; | |
| 31 | |
| 32 /** The x-coordinate of the right edge. */ | |
| 33 T get right => left + width; | |
| 34 /** The y-coordinate of the bottom edge. */ | |
| 35 T get bottom => top + height; | |
| 36 | |
| 37 String toString() { | |
| 38 return 'Rectangle ($left, $top) $width x $height'; | |
| 39 } | |
| 40 | |
| 41 bool operator ==(other) { | |
| 42 if (other is !Rectangle) return false; | |
| 43 return left == other.left && top == other.top && right == other.right && | |
| 44 bottom == other.bottom; | |
| 45 } | |
| 46 | |
| 47 int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode, | |
| 48 right.hashCode, bottom.hashCode); | |
| 49 | |
| 50 /** | |
| 51 * Computes the intersection of `this` and [other]. | |
| 52 * | |
| 53 * The intersection of two axis-aligned rectangles, if any, is always another | |
| 54 * axis-aligned rectangle. | |
| 55 * | |
| 56 * Returns the intersection of this and `other`, or `null` if they don't | |
| 57 * intersect. | |
| 58 */ | |
| 59 Rectangle<T> intersection(Rectangle<T> other) { | |
| 60 var x0 = max(left, other.left); | |
| 61 var x1 = min(left + width, other.left + other.width); | |
| 62 | |
| 63 if (x0 <= x1) { | |
| 64 var y0 = max(top, other.top); | |
| 65 var y1 = min(top + height, other.top + other.height); | |
| 66 | |
| 67 if (y0 <= y1) { | |
| 68 return new Rectangle<T>(x0, y0, x1 - x0, y1 - y0); | |
| 69 } | |
| 70 } | |
| 71 return null; | |
| 72 } | |
| 73 | |
| 74 | |
| 75 /** | |
| 76 * Returns true if `this` intersects [other]. | |
| 77 */ | |
| 78 bool intersects(Rectangle<num> other) { | |
| 79 return (left <= other.left + other.width && | |
| 80 other.left <= left + width && | |
| 81 top <= other.top + other.height && | |
| 82 other.top <= top + height); | |
| 83 } | |
| 84 | |
| 85 /** | |
| 86 * Returns a new rectangle which completely contains `this` and [other]. | |
| 87 */ | |
| 88 Rectangle<T> boundingBox(Rectangle<T> other) { | |
| 89 var right = max(this.left + this.width, other.left + other.width); | |
| 90 var bottom = max(this.top + this.height, other.top + other.height); | |
| 91 | |
| 92 var left = min(this.left, other.left); | |
| 93 var top = min(this.top, other.top); | |
| 94 | |
| 95 return new Rectangle<T>(left, top, right - left, bottom - top); | |
| 96 } | |
| 97 | |
| 98 /** | |
| 99 * Tests whether `this` entirely contains [another]. | |
| 100 */ | |
| 101 bool containsRectangle(Rectangle<num> another) { | |
| 102 return left <= another.left && | |
| 103 left + width >= another.left + another.width && | |
| 104 top <= another.top && | |
| 105 top + height >= another.top + another.height; | |
| 106 } | |
| 107 | |
| 108 /** | |
| 109 * Tests whether [another] is inside or along the edges of `this`. | |
| 110 */ | |
| 111 bool containsPoint(Point<num> another) { | |
| 112 return another.x >= left && | |
| 113 another.x <= left + width && | |
| 114 another.y >= top && | |
| 115 another.y <= top + height; | |
| 116 } | |
| 117 | |
| 118 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 bottomRight => new Point<T>(this.left + this.width, | |
| 121 this.top + this.height); | |
| 122 Point<T> get bottomLeft => new Point<T>(this.left, | |
| 123 this.top + this.height); | |
| 124 } | |
| 125 | |
| 126 | |
| 127 /** | |
| 128 * A class for representing two-dimensional rectangles whose properties are | |
| 129 * immutable. | |
| 130 */ | |
| 131 class Rectangle<T extends num> extends _RectangleBase<T> { | |
| 132 final T left; | |
| 133 final T top; | |
| 134 final T width; | |
| 135 final T height; | |
| 136 | |
| 137 /** | |
| 138 * Create a rectangle spanned by `(left, top)` and `(left+width, top+height)`. | |
| 139 * | |
| 140 * The rectangle contains the points | |
| 141 * with x-coordinate between `left` and `left + width`, and | |
| 142 * with y-coordinate between `top` and `top + height`, both inclusive. | |
| 143 * | |
| 144 * The `width` and `height` should be non-negative. | |
| 145 * If `width` or `height` are negative, they are clamped to zero. | |
| 146 * | |
| 147 * If `width` and `height` are zero, the "rectangle" comprises only the single | |
| 148 * point `(left, top)`. | |
| 149 */ | |
| 150 const Rectangle(this.left, this.top, T width, T height) | |
| 151 : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero. | |
| 152 this.height = (height < 0) ? -height * 0 : height; | |
| 153 | |
| 154 /** | |
| 155 * Create a rectangle spanned by the points [a] and [b]; | |
| 156 * | |
| 157 * The rectangle contains the points | |
| 158 * with x-coordinate between `a.x` and `b.x`, and | |
| 159 * with y-coordinate between `a.y` and `b.y`, both inclusive. | |
| 160 * | |
| 161 * If the distance between `a.x` and `b.x` is not representable | |
| 162 * (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)`. | |
| 164 * Similar for the y-coordinates and the bottom edge. | |
| 165 */ | |
| 166 factory Rectangle.fromPoints(Point<T> a, Point<T> b) { | |
| 167 T left = min(a.x, b.x); | |
| 168 T width = max(a.x, b.x) - left; | |
| 169 T top = min(a.y, b.y); | |
| 170 T height = max(a.y, b.y) - top; | |
| 171 return new Rectangle<T>(left, top, width, height); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 /** | |
| 176 * A class for representing two-dimensional axis-aligned rectangles with mutable | |
| 177 * properties. | |
| 178 */ | |
| 179 class MutableRectangle<T extends num> extends _RectangleBase<T> | |
| 180 implements Rectangle<T> { | |
| 181 | |
| 182 /** | |
| 183 * The x-coordinate of the left edge. | |
| 184 * | |
| 185 * Setting the value will move the rectangle without changing its width. | |
| 186 */ | |
| 187 T left; | |
| 188 /** | |
| 189 * The y-coordinate of the left edge. | |
| 190 * | |
| 191 * Setting the value will move the rectangle without changing its height. | |
| 192 */ | |
| 193 T top; | |
| 194 T _width; | |
| 195 T _height; | |
| 196 | |
| 197 /** | |
| 198 * Create a mutable rectangle spanned by `(left, top)` and | |
| 199 * `(left+width, top+height)`. | |
| 200 * | |
| 201 * The rectangle contains the points | |
| 202 * with x-coordinate between `left` and `left + width`, and | |
| 203 * with y-coordinate between `top` and `top + height`, both inclusive. | |
| 204 * | |
| 205 * The `width` and `height` should be non-negative. | |
| 206 * If `width` or `height` are negative, they are clamped to zero. | |
| 207 * | |
| 208 * If `width` and `height` are zero, the "rectangle" comprises only the single | |
| 209 * point `(left, top)`. | |
| 210 */ | |
| 211 MutableRectangle(this.left, this.top, T width, T height) | |
| 212 : this._width = (width < 0) ? _clampToZero(width) : width, | |
| 213 this._height = (height < 0) ? _clampToZero(height) : height; | |
| 214 | |
| 215 /** | |
| 216 * Create a mutable rectangle spanned by the points [a] and [b]; | |
| 217 * | |
| 218 * The rectangle contains the points | |
| 219 * with x-coordinate between `a.x` and `b.x`, and | |
| 220 * with y-coordinate between `a.y` and `b.y`, both inclusive. | |
| 221 * | |
| 222 * If the distance between `a.x` and `b.x` is not representable | |
| 223 * (which can happen if one or both is a double), | |
| 224 * the actual right edge might be slightly off from `max(a.x, b.x)`. | |
| 225 * Similar for the y-coordinates and the bottom edge. | |
| 226 */ | |
| 227 factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) { | |
| 228 T left = min(a.x, b.x); | |
| 229 T width = max(a.x, b.x) - left; | |
| 230 T top = min(a.y, b.y); | |
| 231 T height = max(a.y, b.y) - top; | |
| 232 return new MutableRectangle<T>(left, top, width, height); | |
| 233 } | |
| 234 | |
| 235 T get width => _width; | |
| 236 | |
| 237 /** | |
| 238 * Sets the width of the rectangle. | |
| 239 * | |
| 240 * The width must be non-negative. | |
| 241 * If a negative width is supplied, it is clamped to zero. | |
| 242 * | |
| 243 * Setting the value will change the right edge of the rectangle, | |
| 244 * but will not change [left]. | |
| 245 */ | |
| 246 void set width(T width) { | |
| 247 if (width < 0) width = _clampToZero(width); | |
| 248 _width = width; | |
| 249 } | |
| 250 | |
| 251 T get height => _height; | |
| 252 | |
| 253 /** | |
| 254 * Sets the height of the rectangle. | |
| 255 * | |
| 256 * The height must be non-negative. | |
| 257 * If a negative height is supplied, it is clamped to zero. | |
| 258 * | |
| 259 * Setting the value will change the bottom edge of the rectangle, | |
| 260 * but will not change [top]. | |
| 261 */ | |
| 262 void set height(T height) { | |
| 263 if (height < 0) height = _clampToZero(height); | |
| 264 _height = height; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * Converts a negative [int] or [double] to a zero-value of the same type. | |
| 270 * | |
| 271 * Returns `0` if value is int, `0.0` if value is double. | |
| 272 */ | |
| 273 num _clampToZero(num value) { | |
| 274 assert(value < 0); | |
| 275 return -value * 0; | |
| 276 } | |
| OLD | NEW |