1 /*
   2  * Copyright (c) 1995, 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 package com.javafx.experiments.utils3d.geom;
  34 
  35 /**
  36  * A <code>Rectangle</code> specifies an area in a coordinate space that is
  37  * enclosed by the <code>Rectangle</code> object's upper-left point
  38  * {@code (x,y)}
  39  * in the coordinate space, its width, and its height.
  40  * <p>
  41  * A <code>Rectangle</code> object's <code>width</code> and
  42  * <code>height</code> are <code>public</code> fields. The constructors
  43  * that create a <code>Rectangle</code>, and the methods that can modify
  44  * one, do not prevent setting a negative value for width or height.
  45  * <p>
  46  * <a name="Empty">
  47  * A {@code Rectangle} whose width or height is exactly zero has location
  48  * along those axes with zero dimension, but is otherwise considered empty.
  49  * The {@link #isEmpty} method will return true for such a {@code Rectangle}.
  50  * Methods which test if an empty {@code Rectangle} contains or intersects
  51  * a point or rectangle will always return false if either dimension is zero.
  52  * Methods which combine such a {@code Rectangle} with a point or rectangle
  53  * will include the location of the {@code Rectangle} on that axis in the
  54  * result as if the {@link #add(Point)} method were being called.
  55  * </a>
  56  * <p>
  57  * <a name="NonExistant">
  58  * A {@code Rectangle} whose width or height is negative has neither
  59  * location nor dimension along those axes with negative dimensions.
  60  * Such a {@code Rectangle} is treated as non-existant along those axes.
  61  * Such a {@code Rectangle} is also empty with respect to containment
  62  * calculations and methods which test if it contains or intersects a
  63  * point or rectangle will always return false.
  64  * Methods which combine such a {@code Rectangle} with a point or rectangle
  65  * will ignore the {@code Rectangle} entirely in generating the result.
  66  * If two {@code Rectangle} objects are combined and each has a negative
  67  * dimension, the result will have at least one negative dimension.
  68  * </a>
  69  * <p>
  70  * Methods which affect only the location of a {@code Rectangle} will
  71  * operate on its location regardless of whether or not it has a negative
  72  * or zero dimension along either axis.
  73  * <p>
  74  * Note that a {@code Rectangle} constructed with the default no-argument
  75  * constructor will have dimensions of {@code 0x0} and therefore be empty.
  76  * That {@code Rectangle} will still have a location of {@code (0,0)} and
  77  * will contribute that location to the union and add operations.
  78  * Code attempting to accumulate the bounds of a set of points should
  79  * therefore initially construct the {@code Rectangle} with a specifically
  80  * negative width and height or it should use the first point in the set
  81  * to construct the {@code Rectangle}.
  82  * For example:
  83  * <pre>
  84  *     Rectangle bounds = new Rectangle(0, 0, -1, -1);
  85  *     for (int i = 0; i < points.length; i++) {
  86  *         bounds.add(points[i]);
  87  *     }
  88  * </pre>
  89  * or if we know that the points array contains at least one point:
  90  * <pre>
  91  *     Rectangle bounds = new Rectangle(points[0]);
  92  *     for (int i = 1; i < points.length; i++) {
  93  *         bounds.add(points[i]);
  94  *     }
  95  * </pre>
  96  * <p>
  97  * This class uses 32-bit integers to store its location and dimensions.
  98  * Frequently operations may produce a result that exceeds the range of
  99  * a 32-bit integer.
 100  * The methods will calculate their results in a way that avoids any
 101  * 32-bit overflow for intermediate results and then choose the best
 102  * representation to store the final results back into the 32-bit fields
 103  * which hold the location and dimensions.
 104  * The location of the result will be stored into the {@link #x} and
 105  * {@link #y} fields by clipping the true result to the nearest 32-bit value.
 106  * The values stored into the {@link #width} and {@link #height} dimension
 107  * fields will be chosen as the 32-bit values that encompass the largest
 108  * part of the true result as possible.
 109  * Generally this means that the dimension will be clipped independently
 110  * to the range of 32-bit integers except that if the location had to be
 111  * moved to store it into its pair of 32-bit fields then the dimensions
 112  * will be adjusted relative to the "best representation" of the location.
 113  * If the true result had a negative dimension and was therefore
 114  * non-existant along one or both axes, the stored dimensions will be
 115  * negative numbers in those axes.
 116  * If the true result had a location that could be represented within
 117  * the range of 32-bit integers, but zero dimension along one or both
 118  * axes, then the stored dimensions will be zero in those axes.
 119  */
 120 public class Rectangle {
 121 
 122     /**
 123      * The X coordinate of the upper-left corner of the <code>Rectangle</code>.
 124      */
 125     public int x;
 126 
 127     /**
 128      * The Y coordinate of the upper-left corner of the <code>Rectangle</code>.
 129      */
 130     public int y;
 131 
 132     /**
 133      * The width of the <code>Rectangle</code>.
 134      */
 135     public int width;
 136 
 137     /**
 138      * The height of the <code>Rectangle</code>.
 139      */
 140     public int height;
 141 
 142     /**
 143      * Constructs a new <code>Rectangle</code> whose upper-left corner
 144      * is at (0,&nbsp;0) in the coordinate space, and whose width and
 145      * height are both zero.
 146      */
 147     public Rectangle() {
 148         this(0, 0, 0, 0);
 149     }
 150 
 151     /**
 152      * Constructs a new <code>Rectangle</code>, initialized to match
 153      * the values of the specified <code>Rectangle</code>.
 154      * @param r  the <code>Rectangle</code> from which to copy initial values
 155      *           to a newly constructed <code>Rectangle</code>
 156      */
 157     public Rectangle(BaseBounds b) {
 158         setBounds(b);
 159     }
 160 
 161     /**
 162      * Constructs a new <code>Rectangle</code>, initialized to match
 163      * the values of the specified <code>BaseBounds</code>. Since BaseBounds has
 164      * float values, the Rectangle will be created such that the bounding rectangle
 165      * of the specified BaseBounds would always lie within the bounding box
 166      * specified by this Rectangle.
 167      * @param r  the <code>BaseBounds</code> from which to copy initial values
 168      *           to a newly constructed <code>Rectangle</code>
 169      */
 170     public Rectangle(Rectangle r) {
 171         this(r.x, r.y, r.width, r.height);
 172     }
 173 
 174     /**
 175      * Constructs a new <code>Rectangle</code> whose upper-left corner is
 176      * specified as
 177      * {@code (x,y)} and whose width and height
 178      * are specified by the arguments of the same name.
 179      * @param     x the specified X coordinate
 180      * @param     y the specified Y coordinate
 181      * @param     width    the width of the <code>Rectangle</code>
 182      * @param     height   the height of the <code>Rectangle</code>
 183      */
 184     public Rectangle(int x, int y, int width, int height) {
 185         this.x = x;
 186         this.y = y;
 187         this.width = width;
 188         this.height = height;
 189     }
 190 
 191     /**
 192      * Constructs a new <code>Rectangle</code> whose upper-left corner
 193      * is at (0,&nbsp;0) in the coordinate space, and whose width and
 194      * height are specified by the arguments of the same name.
 195      * @param width the width of the <code>Rectangle</code>
 196      * @param height the height of the <code>Rectangle</code>
 197      */
 198     public Rectangle(int width, int height) {
 199         this(0, 0, width, height);
 200     }
 201 
 202     /**
 203      * Sets the bounding <code>Rectangle</code> of this <code>Rectangle</code>
 204      * to match the specified <code>Rectangle</code>.
 205      * <p>
 206      * This method is included for completeness, to parallel the
 207      * <code>setBounds</code> method of <code>Component</code>.
 208      * @param r the specified <code>Rectangle</code>
 209      * @see       #getBounds
 210      * @see       java.awt.Component#setBounds(java.awt.Rectangle)
 211      */
 212     public void setBounds(Rectangle r) {
 213         setBounds(r.x, r.y, r.width, r.height);
 214     }
 215 
 216     /**
 217      * Sets the bounding <code>Rectangle</code> of this
 218      * <code>Rectangle</code> to the specified
 219      * <code>x</code>, <code>y</code>, <code>width</code>,
 220      * and <code>height</code>.
 221      * <p>
 222      * This method is included for completeness, to parallel the
 223      * <code>setBounds</code> method of <code>Component</code>.
 224      * @param x the new X coordinate for the upper-left
 225      *                    corner of this <code>Rectangle</code>
 226      * @param y the new Y coordinate for the upper-left
 227      *                    corner of this <code>Rectangle</code>
 228      * @param width the new width for this <code>Rectangle</code>
 229      * @param height the new height for this <code>Rectangle</code>
 230      * @see       #getBounds
 231      * @see       java.awt.Component#setBounds(int, int, int, int)
 232      */
 233     public void setBounds(int x, int y, int width, int height) {
 234         reshape(x, y, width, height);
 235     }
 236 
 237     public void setBounds(BaseBounds b) {
 238         x = (int) Math.floor(b.getMinX());
 239         y = (int) Math.floor(b.getMinY());
 240         int x2 = (int) Math.ceil(b.getMaxX());
 241         int y2 = (int) Math.ceil(b.getMaxY());
 242         width = x2 - x;
 243         height = y2 - y;
 244     }
 245 
 246     /**
 247      * Checks whether or not this <code>Rectangle</code> contains the
 248      * point at the specified location {@code (cx,cy)}.
 249      *
 250      * @param cx the specified X coordinate
 251      * @param cy the specified Y coordinate
 252      * @return    <code>true</code> if the point
 253      *            {@code (cx,cy)} is inside this
 254      *            <code>Rectangle</code>;
 255      *            <code>false</code> otherwise.
 256      */
 257     public boolean contains(int cx, int cy) {
 258         int tw = this.width;
 259         int th = this.height;
 260         if ((tw | th) < 0) {
 261             // At least one of the dimensions is negative...
 262             return false;
 263         }
 264         // Note: if either dimension is zero, tests below must return false...
 265         int tx = this.x;
 266         int ty = this.y;
 267         if (cx < tx || cy < ty) {
 268             return false;
 269         }
 270         tw += tx;
 271         th += ty;
 272         //    overflow || intersect
 273         return ((tw < tx || tw > cx) &&
 274                 (th < ty || th > cy));
 275      }
 276 
 277     /**
 278      * Checks whether or not this <code>Rectangle</code> entirely contains
 279      * the specified <code>Rectangle</code>.
 280      *
 281      * @param     r   the specified <code>Rectangle</code>
 282      * @return    <code>true</code> if the <code>Rectangle</code>
 283      *            is contained entirely inside this <code>Rectangle</code>;
 284      *            <code>false</code> otherwise
 285      */
 286     public boolean contains(Rectangle r) {
 287         return contains(r.x, r.y, r.width, r.height);
 288     }
 289 
 290     /**
 291      * Checks whether this <code>Rectangle</code> entirely contains
 292      * the <code>Rectangle</code>
 293      * at the specified location {@code (cx,cy)} with the
 294      * specified dimensions {@code (cw,ch)}.
 295      * @param     cx the specified X coordinate
 296      * @param     cy the specified Y coordinate
 297      * @param     cw   the width of the <code>Rectangle</code>
 298      * @param     ch   the height of the <code>Rectangle</code>
 299      * @return    <code>true</code> if the <code>Rectangle</code> specified by
 300      *            {@code (cx, cy, cw, ch)}
 301      *            is entirely enclosed inside this <code>Rectangle</code>;
 302      *            <code>false</code> otherwise.
 303      */
 304     public boolean contains(int cx, int cy, int cw, int ch) {
 305         int tw = this.width;
 306         int th = this.height;
 307         if ((tw | th | cw | ch) < 0) {
 308             // At least one of the dimensions is negative...
 309             return false;
 310         }
 311         // Note: if any dimension is zero, tests below must return false...
 312         int tx = this.x;
 313         int ty = this.y;
 314         if (cx < tx || cy < ty) {
 315             return false;
 316         }
 317         tw += tx;
 318         cw += cx;
 319         if (cw <= cx) {
 320             // cx+cw overflowed or cw was zero, return false if...
 321             // either original tw or cw was zero or
 322             // tx+tw did not overflow or
 323             // the overflowed cx+cw is smaller than the overflowed tx+tw
 324             if (tw >= tx || cw > tw) return false;
 325         } else {
 326             // cx+cw did not overflow and cw was not zero, return false if...
 327             // original tw was zero or
 328             // tx+tw did not overflow and tx+tw is smaller than cx+cw
 329             if (tw >= tx && cw > tw) return false;
 330         }
 331         th += ty;
 332         ch += cy;
 333         if (ch <= cy) {
 334             if (th >= ty || ch > th) return false;
 335         } else {
 336             if (th >= ty && ch > th) return false;
 337         }
 338         return true;
 339     }
 340 
 341     public Rectangle intersection(Rectangle r) {
 342         Rectangle ret = new Rectangle(this);
 343         ret.intersectWith(r);
 344         return ret;
 345     }
 346 
 347     public void intersectWith(Rectangle r) {
 348         if (r == null) {
 349             return;
 350         }
 351         int tx1 = this.x;
 352         int ty1 = this.y;
 353         int rx1 = r.x;
 354         int ry1 = r.y;
 355         long tx2 = tx1; tx2 += this.width;
 356         long ty2 = ty1; ty2 += this.height;
 357         long rx2 = rx1; rx2 += r.width;
 358         long ry2 = ry1; ry2 += r.height;
 359         if (tx1 < rx1) tx1 = rx1;
 360         if (ty1 < ry1) ty1 = ry1;
 361         if (tx2 > rx2) tx2 = rx2;
 362         if (ty2 > ry2) ty2 = ry2;
 363         tx2 -= tx1;
 364         ty2 -= ty1;
 365         // tx2,ty2 will never overflow (they will never be
 366         // larger than the smallest of the two source w,h)
 367         // they might underflow, though...
 368         if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
 369         if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
 370         setBounds(tx1, ty1, (int) tx2, (int) ty2);
 371     }
 372 
 373     /**
 374      * Translates this <code>Rectangle</code> the indicated distance,
 375      * to the right along the X coordinate axis, and
 376      * downward along the Y coordinate axis.
 377      * @param dx the distance to move this <code>Rectangle</code>
 378      *                 along the X axis
 379      * @param dy the distance to move this <code>Rectangle</code>
 380      *                 along the Y axis
 381      * @see       java.awt.Rectangle#setLocation(int, int)
 382      * @see       java.awt.Rectangle#setLocation(java.awt.Point)
 383      */
 384     public void translate(int dx, int dy) {
 385         int oldv = this.x;
 386         int newv = oldv + dx;
 387         if (dx < 0) {
 388             // moving leftward
 389             if (newv > oldv) {
 390                 // negative overflow
 391                 // Only adjust width if it was valid (>= 0).
 392                 if (width >= 0) {
 393                     // The right edge is now conceptually at
 394                     // newv+width, but we may move newv to prevent
 395                     // overflow.  But we want the right edge to
 396                     // remain at its new location in spite of the
 397                     // clipping.  Think of the following adjustment
 398                     // conceptually the same as:
 399                     // width += newv; newv = MIN_VALUE; width -= newv;
 400                     width += newv - Integer.MIN_VALUE;
 401                     // width may go negative if the right edge went past
 402                     // MIN_VALUE, but it cannot overflow since it cannot
 403                     // have moved more than MIN_VALUE and any non-negative
 404                     // number + MIN_VALUE does not overflow.
 405                 }
 406                 newv = Integer.MIN_VALUE;
 407             }
 408         } else {
 409             // moving rightward (or staying still)
 410             if (newv < oldv) {
 411                 // positive overflow
 412                 if (width >= 0) {
 413                     // Conceptually the same as:
 414                     // width += newv; newv = MAX_VALUE; width -= newv;
 415                     width += newv - Integer.MAX_VALUE;
 416                     // With large widths and large displacements
 417                     // we may overflow so we need to check it.
 418                     if (width < 0) width = Integer.MAX_VALUE;
 419                 }
 420                 newv = Integer.MAX_VALUE;
 421             }
 422         }
 423         this.x = newv;
 424 
 425         oldv = this.y;
 426         newv = oldv + dy;
 427         if (dy < 0) {
 428             // moving upward
 429             if (newv > oldv) {
 430                 // negative overflow
 431                 if (height >= 0) {
 432                     height += newv - Integer.MIN_VALUE;
 433                     // See above comment about no overflow in this case
 434                 }
 435                 newv = Integer.MIN_VALUE;
 436             }
 437         } else {
 438             // moving downward (or staying still)
 439             if (newv < oldv) {
 440                 // positive overflow
 441                 if (height >= 0) {
 442                     height += newv - Integer.MAX_VALUE;
 443                     if (height < 0) height = Integer.MAX_VALUE;
 444                 }
 445                 newv = Integer.MAX_VALUE;
 446             }
 447         }
 448         this.y = newv;
 449     }
 450 
 451     public RectBounds toRectBounds() {
 452         return new RectBounds(x, y, x+width, y+height);
 453     }
 454 
 455     /**
 456      * Adds a point, specified by the integer arguments {@code newx,newy}
 457      * to the bounds of this {@code Rectangle}.
 458      * <p>
 459      * If this {@code Rectangle} has any dimension less than zero,
 460      * the rules for <a href=#NonExistant>non-existant</a>
 461      * rectangles apply.
 462      * In that case, the new bounds of this {@code Rectangle} will
 463      * have a location equal to the specified coordinates and
 464      * width and height equal to zero.
 465      * <p>
 466      * After adding a point, a call to <code>contains</code> with the
 467      * added point as an argument does not necessarily return
 468      * <code>true</code>. The <code>contains</code> method does not
 469      * return <code>true</code> for points on the right or bottom
 470      * edges of a <code>Rectangle</code>. Therefore, if the added point
 471      * falls on the right or bottom edge of the enlarged
 472      * <code>Rectangle</code>, <code>contains</code> returns
 473      * <code>false</code> for that point.
 474      * If the specified point must be contained within the new
 475      * {@code Rectangle}, a 1x1 rectangle should be added instead:
 476      * <pre>
 477      *     r.add(newx, newy, 1, 1);
 478      * </pre>
 479      * @param newx the X coordinate of the new point
 480      * @param newy the Y coordinate of the new point
 481      */
 482     public void add(int newx, int newy) {
 483         if ((width | height) < 0) {
 484             this.x = newx;
 485             this.y = newy;
 486             this.width = this.height = 0;
 487             return;
 488         }
 489         int x1 = this.x;
 490         int y1 = this.y;
 491         long x2 = this.width;
 492         long y2 = this.height;
 493         x2 += x1;
 494         y2 += y1;
 495         if (x1 > newx) x1 = newx;
 496         if (y1 > newy) y1 = newy;
 497         if (x2 < newx) x2 = newx;
 498         if (y2 < newy) y2 = newy;
 499         x2 -= x1;
 500         y2 -= y1;
 501         if (x2 > Integer.MAX_VALUE) x2 = Integer.MAX_VALUE;
 502         if (y2 > Integer.MAX_VALUE) y2 = Integer.MAX_VALUE;
 503         reshape(x1, y1, (int) x2, (int) y2);
 504     }
 505 
 506     /**
 507      * Adds a <code>Rectangle</code> to this <code>Rectangle</code>.
 508      * The resulting <code>Rectangle</code> is the union of the two
 509      * rectangles.
 510      * <p>
 511      * If either {@code Rectangle} has any dimension less than 0, the
 512      * result will have the dimensions of the other {@code Rectangle}.
 513      * If both {@code Rectangle}s have at least one dimension less
 514      * than 0, the result will have at least one dimension less than 0.
 515      * <p>
 516      * If either {@code Rectangle} has one or both dimensions equal
 517      * to 0, the result along those axes with 0 dimensions will be
 518      * equivalent to the results obtained by adding the corresponding
 519      * origin coordinate to the result rectangle along that axis,
 520      * similar to the operation of the {@link #add(Point)} method,
 521      * but contribute no further dimension beyond that.
 522      * <p>
 523      * If the resulting {@code Rectangle} would have a dimension
 524      * too large to be expressed as an {@code int}, the result
 525      * will have a dimension of {@code Integer.MAX_VALUE} along
 526      * that dimension.
 527      * @param  r the specified <code>Rectangle</code>
 528      */
 529     public void add(Rectangle r) {
 530         long tx2 = this.width;
 531         long ty2 = this.height;
 532         if ((tx2 | ty2) < 0) {
 533             reshape(r.x, r.y, r.width, r.height);
 534         }
 535         long rx2 = r.width;
 536         long ry2 = r.height;
 537         if ((rx2 | ry2) < 0) {
 538             return;
 539         }
 540         int tx1 = this.x;
 541         int ty1 = this.y;
 542         tx2 += tx1;
 543         ty2 += ty1;
 544         int rx1 = r.x;
 545         int ry1 = r.y;
 546         rx2 += rx1;
 547         ry2 += ry1;
 548         if (tx1 > rx1) tx1 = rx1;
 549         if (ty1 > ry1) ty1 = ry1;
 550         if (tx2 < rx2) tx2 = rx2;
 551         if (ty2 < ry2) ty2 = ry2;
 552         tx2 -= tx1;
 553         ty2 -= ty1;
 554         // tx2,ty2 will never underflow since both original
 555         // rectangles were non-empty
 556         // they might overflow, though...
 557         if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE;
 558         if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE;
 559         reshape(tx1, ty1, (int) tx2, (int) ty2);
 560     }
 561 
 562     /**
 563      * Resizes the <code>Rectangle</code> both horizontally and vertically.
 564      * <p>
 565      * This method modifies the <code>Rectangle</code> so that it is
 566      * <code>h</code> units larger on both the left and right side,
 567      * and <code>v</code> units larger at both the top and bottom.
 568      * <p>
 569      * The new <code>Rectangle</code> has {@code (x - h, y - v)}
 570      * as its upper-left corner,
 571      * width of {@code (width + 2h)},
 572      * and a height of {@code (height + 2v)}.
 573      * <p>
 574      * If negative values are supplied for <code>h</code> and
 575      * <code>v</code>, the size of the <code>Rectangle</code>
 576      * decreases accordingly.
 577      * The {@code grow} method will check for integer overflow
 578      * and underflow, but does not check whether the resulting
 579      * values of {@code width} and {@code height} grow
 580      * from negative to non-negative or shrink from non-negative
 581      * to negative.
 582      * @param h the horizontal expansion
 583      * @param v the vertical expansion
 584      */
 585     public void grow(int h, int v) {
 586         long x0 = this.x;
 587         long y0 = this.y;
 588         long x1 = this.width;
 589         long y1 = this.height;
 590         x1 += x0;
 591         y1 += y0;
 592 
 593         x0 -= h;
 594         y0 -= v;
 595         x1 += h;
 596         y1 += v;
 597 
 598         if (x1 < x0) {
 599             // Non-existant in X direction
 600             // Final width must remain negative so subtract x0 before
 601             // it is clipped so that we avoid the risk that the clipping
 602             // of x0 will reverse the ordering of x0 and x1.
 603             x1 -= x0;
 604             if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
 605             if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
 606             else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
 607         } else { // (x1 >= x0)
 608             // Clip x0 before we subtract it from x1 in case the clipping
 609             // affects the representable area of the rectangle.
 610             if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
 611             else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
 612             x1 -= x0;
 613             // The only way x1 can be negative now is if we clipped
 614             // x0 against MIN and x1 is less than MIN - in which case
 615             // we want to leave the width negative since the result
 616             // did not intersect the representable area.
 617             if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
 618             else if (x1 > Integer.MAX_VALUE) x1 = Integer.MAX_VALUE;
 619         }
 620 
 621         if (y1 < y0) {
 622             // Non-existant in Y direction
 623             y1 -= y0;
 624             if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
 625             if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
 626             else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
 627         } else { // (y1 >= y0)
 628             if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
 629             else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
 630             y1 -= y0;
 631             if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
 632             else if (y1 > Integer.MAX_VALUE) y1 = Integer.MAX_VALUE;
 633         }
 634 
 635         reshape((int) x0, (int) y0, (int) x1, (int) y1);
 636     }
 637 
 638     private void reshape(int x, int y, int width, int height) {
 639         this.x = x;
 640         this.y = y;
 641         this.width = width;
 642         this.height = height;
 643     }
 644 
 645     /**
 646      * {@inheritDoc}
 647      */
 648     public boolean isEmpty() {
 649         return (width <= 0) || (height <= 0);
 650     }
 651 
 652     /**
 653      * Checks whether two rectangles are equal.
 654      * <p>
 655      * The result is <code>true</code> if and only if the argument is not
 656      * <code>null</code> and is a <code>Rectangle</code> object that has the
 657      * same upper-left corner, width, and height as
 658      * this <code>Rectangle</code>.
 659      * @param obj the <code>Object</code> to compare with
 660      *                this <code>Rectangle</code>
 661      * @return    <code>true</code> if the objects are equal;
 662      *            <code>false</code> otherwise.
 663      */
 664     @Override
 665     public boolean equals(Object obj) {
 666         if (obj instanceof Rectangle) {
 667             Rectangle r = (Rectangle)obj;
 668             return ((x == r.x) &&
 669                     (y == r.y) &&
 670                     (width == r.width) &&
 671                     (height == r.height));
 672         }
 673         return super.equals(obj);
 674     }
 675 
 676     @Override
 677     public int hashCode() {
 678         int bits = Float.floatToIntBits(x);
 679         bits += Float.floatToIntBits(y) * 37;
 680         bits += Float.floatToIntBits(width) * 43;
 681         bits += Float.floatToIntBits(height) * 47;
 682         return bits;
 683     }
 684 
 685     /**
 686      * Returns a <code>String</code> representing this
 687      * <code>Rectangle</code> and its values.
 688      * @return a <code>String</code> representing this
 689      *               <code>Rectangle</code> object's coordinate and size values.
 690      */
 691     @Override
 692     public String toString() {
 693         return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
 694     }
 695 }