| 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 // TODO(rnystrom): Type promotion doesn't currently promote the [other] | |
| 44 // to Rectangle from the above line, so do it explicitly here to avoid a | |
| 45 // dynamic send and work around: | |
| 46 // https://github.com/dart-lang/sdk/issues/27551 | |
| 47 var otherRect = other as Rectangle; | |
| 48 return left == otherRect.left && | |
| 49 top == otherRect.top && | |
| 50 right == otherRect.right && | |
| 51 bottom == otherRect.bottom; | |
| 52 } | |
| 53 | |
| 54 int get hashCode => _JenkinsSmiHash.hash4(left.hashCode, top.hashCode, | |
| 55 right.hashCode, bottom.hashCode); | |
| 56 | |
| 57 /** | |
| 58 * Computes the intersection of `this` and [other]. | |
| 59 * | |
| 60 * The intersection of two axis-aligned rectangles, if any, is always another | |
| 61 * axis-aligned rectangle. | |
| 62 * | |
| 63 * Returns the intersection of this and `other`, or `null` if they don't | |
| 64 * intersect. | |
| 65 */ | |
| 66 Rectangle<T> intersection(Rectangle<T> other) { | |
| 67 var x0 = max(left, other.left); | |
| 68 var x1 = min(left + width, other.left + other.width); | |
| 69 | |
| 70 if (x0 <= x1) { | |
| 71 var y0 = max(top, other.top); | |
| 72 var y1 = min(top + height, other.top + other.height); | |
| 73 | |
| 74 if (y0 <= y1) { | |
| 75 return new Rectangle<T>(x0, y0, x1 - x0, y1 - y0); | |
| 76 } | |
| 77 } | |
| 78 return null; | |
| 79 } | |
| 80 | |
| 81 | |
| 82 /** | |
| 83 * Returns true if `this` intersects [other]. | |
| 84 */ | |
| 85 bool intersects(Rectangle<num> other) { | |
| 86 return (left <= other.left + other.width && | |
| 87 other.left <= left + width && | |
| 88 top <= other.top + other.height && | |
| 89 other.top <= top + height); | |
| 90 } | |
| 91 | |
| 92 /** | |
| 93 * Returns a new rectangle which completely contains `this` and [other]. | |
| 94 */ | |
| 95 Rectangle<T> boundingBox(Rectangle<T> other) { | |
| 96 var right = max(this.left + this.width, other.left + other.width); | |
| 97 var bottom = max(this.top + this.height, other.top + other.height); | |
| 98 | |
| 99 var left = min(this.left, other.left); | |
| 100 var top = min(this.top, other.top); | |
| 101 | |
| 102 return new Rectangle<T>(left, top, right - left, bottom - top); | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * Tests whether `this` entirely contains [another]. | |
| 107 */ | |
| 108 bool containsRectangle(Rectangle<num> another) { | |
| 109 return left <= another.left && | |
| 110 left + width >= another.left + another.width && | |
| 111 top <= another.top && | |
| 112 top + height >= another.top + another.height; | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Tests whether [another] is inside or along the edges of `this`. | |
| 117 */ | |
| 118 bool containsPoint(Point<num> another) { | |
| 119 return another.x >= left && | |
| 120 another.x <= left + width && | |
| 121 another.y >= top && | |
| 122 another.y <= top + height; | |
| 123 } | |
| 124 | |
| 125 Point<T> get topLeft => new Point<T>(this.left, this.top); | |
| 126 Point<T> get topRight => new Point<T>(this.left + this.width, this.top); | |
| 127 Point<T> get bottomRight => new Point<T>(this.left + this.width, | |
| 128 this.top + this.height); | |
| 129 Point<T> get bottomLeft => new Point<T>(this.left, | |
| 130 this.top + this.height); | |
| 131 } | |
| 132 | |
| 133 | |
| 134 /** | |
| 135 * A class for representing two-dimensional rectangles whose properties are | |
| 136 * immutable. | |
| 137 */ | |
| 138 class Rectangle<T extends num> extends _RectangleBase<T> { | |
| 139 final T left; | |
| 140 final T top; | |
| 141 final T width; | |
| 142 final T height; | |
| 143 | |
| 144 /** | |
| 145 * Create a rectangle spanned by `(left, top)` and `(left+width, top+height)`. | |
| 146 * | |
| 147 * The rectangle contains the points | |
| 148 * with x-coordinate between `left` and `left + width`, and | |
| 149 * with y-coordinate between `top` and `top + height`, both inclusive. | |
| 150 * | |
| 151 * The `width` and `height` should be non-negative. | |
| 152 * If `width` or `height` are negative, they are clamped to zero. | |
| 153 * | |
| 154 * If `width` and `height` are zero, the "rectangle" comprises only the single | |
| 155 * point `(left, top)`. | |
| 156 */ | |
| 157 const Rectangle(this.left, this.top, T width, T height) | |
| 158 : this.width = (width < 0) ? -width * 0 : width, // Inline _clampToZero. | |
| 159 this.height = (height < 0) ? -height * 0 : height; | |
| 160 | |
| 161 /** | |
| 162 * Create a rectangle spanned by the points [a] and [b]; | |
| 163 * | |
| 164 * The rectangle contains the points | |
| 165 * with x-coordinate between `a.x` and `b.x`, and | |
| 166 * with y-coordinate between `a.y` and `b.y`, both inclusive. | |
| 167 * | |
| 168 * If the distance between `a.x` and `b.x` is not representable | |
| 169 * (which can happen if one or both is a double), | |
| 170 * the actual right edge might be slightly off from `max(a.x, b.x)`. | |
| 171 * Similar for the y-coordinates and the bottom edge. | |
| 172 */ | |
| 173 factory Rectangle.fromPoints(Point<T> a, Point<T> b) { | |
| 174 T left = min(a.x, b.x); | |
| 175 T width = max(a.x, b.x) - left; | |
| 176 T top = min(a.y, b.y); | |
| 177 T height = max(a.y, b.y) - top; | |
| 178 return new Rectangle<T>(left, top, width, height); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 /** | |
| 183 * A class for representing two-dimensional axis-aligned rectangles with mutable | |
| 184 * properties. | |
| 185 */ | |
| 186 class MutableRectangle<T extends num> extends _RectangleBase<T> | |
| 187 implements Rectangle<T> { | |
| 188 | |
| 189 /** | |
| 190 * The x-coordinate of the left edge. | |
| 191 * | |
| 192 * Setting the value will move the rectangle without changing its width. | |
| 193 */ | |
| 194 T left; | |
| 195 /** | |
| 196 * The y-coordinate of the left edge. | |
| 197 * | |
| 198 * Setting the value will move the rectangle without changing its height. | |
| 199 */ | |
| 200 T top; | |
| 201 T _width; | |
| 202 T _height; | |
| 203 | |
| 204 /** | |
| 205 * Create a mutable rectangle spanned by `(left, top)` and | |
| 206 * `(left+width, top+height)`. | |
| 207 * | |
| 208 * The rectangle contains the points | |
| 209 * with x-coordinate between `left` and `left + width`, and | |
| 210 * with y-coordinate between `top` and `top + height`, both inclusive. | |
| 211 * | |
| 212 * The `width` and `height` should be non-negative. | |
| 213 * If `width` or `height` are negative, they are clamped to zero. | |
| 214 * | |
| 215 * If `width` and `height` are zero, the "rectangle" comprises only the single | |
| 216 * point `(left, top)`. | |
| 217 */ | |
| 218 MutableRectangle(this.left, this.top, T width, T height) | |
| 219 : this._width = (width < 0) ? _clampToZero/*<T>*/(width) : width, | |
| 220 this._height = (height < 0) ? _clampToZero/*<T>*/(height) : height; | |
| 221 | |
| 222 /** | |
| 223 * Create a mutable rectangle spanned by the points [a] and [b]; | |
| 224 * | |
| 225 * The rectangle contains the points | |
| 226 * with x-coordinate between `a.x` and `b.x`, and | |
| 227 * with y-coordinate between `a.y` and `b.y`, both inclusive. | |
| 228 * | |
| 229 * If the distance between `a.x` and `b.x` is not representable | |
| 230 * (which can happen if one or both is a double), | |
| 231 * the actual right edge might be slightly off from `max(a.x, b.x)`. | |
| 232 * Similar for the y-coordinates and the bottom edge. | |
| 233 */ | |
| 234 factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) { | |
| 235 T left = min(a.x, b.x); | |
| 236 T width = max(a.x, b.x) - left; | |
| 237 T top = min(a.y, b.y); | |
| 238 T height = max(a.y, b.y) - top; | |
| 239 return new MutableRectangle<T>(left, top, width, height); | |
| 240 } | |
| 241 | |
| 242 T get width => _width; | |
| 243 | |
| 244 /** | |
| 245 * Sets the width of the rectangle. | |
| 246 * | |
| 247 * The width must be non-negative. | |
| 248 * If a negative width is supplied, it is clamped to zero. | |
| 249 * | |
| 250 * Setting the value will change the right edge of the rectangle, | |
| 251 * but will not change [left]. | |
| 252 */ | |
| 253 void set width(T width) { | |
| 254 if (width < 0) width = _clampToZero/*<T>*/(width); | |
| 255 _width = width; | |
| 256 } | |
| 257 | |
| 258 T get height => _height; | |
| 259 | |
| 260 /** | |
| 261 * Sets the height of the rectangle. | |
| 262 * | |
| 263 * The height must be non-negative. | |
| 264 * If a negative height is supplied, it is clamped to zero. | |
| 265 * | |
| 266 * Setting the value will change the bottom edge of the rectangle, | |
| 267 * but will not change [top]. | |
| 268 */ | |
| 269 void set height(T height) { | |
| 270 if (height < 0) height = _clampToZero/*<T>*/(height); | |
| 271 _height = height; | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 /** | |
| 276 * Converts a negative [int] or [double] to a zero-value of the same type. | |
| 277 * | |
| 278 * Returns `0` if value is int, `0.0` if value is double. | |
| 279 */ | |
| 280 num/*=T*/ _clampToZero/*<T extends num>*/(num/*=T*/ value) { | |
| 281 assert(value < 0); | |
| 282 return -value * 0; | |
| 283 } | |
| OLD | NEW |