001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.type.rectangle; 020 021import icy.type.dimension.Dimension3D; 022import icy.type.geom.Line3D; 023import icy.type.geom.Shape3D; 024import icy.type.point.Point3D; 025 026import java.awt.Rectangle; 027import java.awt.geom.Rectangle2D; 028 029/** 030 * Rectangle3D class.<br> 031 * Incomplete implementation (work in progress...) 032 * 033 * @author Stephane 034 */ 035public abstract class Rectangle3D implements Shape3D, Cloneable 036{ 037 /** 038 * Returns <code>true</code> if the specified Line3D intersects the given Rectangle3D. 039 * 040 * @param line 041 * the Line3D we want to test intersection for 042 * @param rect 043 * the Rectangle3D we want to test intersection for 044 */ 045 public static boolean intersects(Line3D line, Rectangle3D rect) 046 { 047 final double rMinX = rect.getMinX(); 048 final double rMaxX = rect.getMaxX(); 049 final double rMinY = rect.getMinY(); 050 final double rMaxY = rect.getMaxY(); 051 final double rMinZ = rect.getMinZ(); 052 final double rMaxZ = rect.getMaxZ(); 053 054 if ((line.getX2() < rMinX) && (line.getX1() < rMinX)) 055 return false; 056 if ((line.getX2() > rMaxX) && (line.getX1() > rMaxX)) 057 return false; 058 if ((line.getY2() < rMinY) && (line.getY1() < rMinY)) 059 return false; 060 if ((line.getY2() > rMaxY) && (line.getY1() > rMaxY)) 061 return false; 062 if ((line.getZ2() < rMinZ) && (line.getZ1() < rMinZ)) 063 return false; 064 if ((line.getZ2() > rMaxZ) && (line.getZ1() > rMaxZ)) 065 return false; 066 067 if ((line.getX1() > rMinX) && (line.getX1() < rMaxX) && (line.getY1() > rMinY) && (line.getY1() < rMaxY) 068 && (line.getZ1() > rMinZ) && (line.getZ1() < rMaxZ)) 069 return true; 070 071 return inBox(getIntersection(line.getX1() - rMinX, line.getX2() - rMinX, line), rect, 1) 072 || inBox(getIntersection(line.getY1() - rMinY, line.getY2() - rMinY, line), rect, 2) 073 || inBox(getIntersection(line.getZ1() - rMinZ, line.getZ2() - rMinZ, line), rect, 3) 074 || inBox(getIntersection(line.getX1() - rMaxX, line.getX2() - rMaxX, line), rect, 1) 075 || inBox(getIntersection(line.getY1() - rMaxY, line.getY2() - rMaxY, line), rect, 2) 076 || inBox(getIntersection(line.getZ1() - rMaxZ, line.getZ2() - rMaxZ, line), rect, 3); 077 } 078 079 static Point3D getIntersection(double dst1, double dst2, Line3D line) 080 { 081 if ((dst1 * dst2) >= 0d) 082 return null; 083 if (dst1 == dst2) 084 return null; 085 086 final double f = -dst1 / (dst2 - dst1); 087 088 // get line vector 089 Point3D result = line.getVector(); 090 // multiply it by factor 091 result = new Point3D.Double(result.getX() * f, result.getY() * f, result.getZ() * f); 092 // return the hit position 093 return new Point3D.Double(line.getX1() + result.getX(), line.getY1() + result.getY(), line.getZ1() 094 + result.getZ()); 095 } 096 097 static boolean inBox(Point3D hit, Rectangle3D rect, int axis) 098 { 099 if ((hit == null) || (rect == null)) 100 return false; 101 102 switch (axis) 103 { 104 default: 105 return false; 106 case 1: 107 return (hit.getZ() > rect.getMinZ()) && (hit.getZ() < rect.getMaxZ()) && (hit.getY() > rect.getMinY()) 108 && (hit.getY() < rect.getMaxY()); 109 case 2: 110 return (hit.getZ() > rect.getMinZ()) && (hit.getZ() < rect.getMaxZ()) && (hit.getX() > rect.getMinX()) 111 && (hit.getX() < rect.getMaxX()); 112 case 3: 113 return (hit.getX() > rect.getMinX()) && (hit.getX() < rect.getMaxX()) && (hit.getY() > rect.getMinY()) 114 && (hit.getY() < rect.getMaxY()); 115 } 116 } 117 118 /** 119 * Intersects the pair of specified source <code>Rectangle3D</code> objects and puts the result 120 * into the specified destination <code>Rectangle3D</code> object. One of the source rectangles 121 * can also be the destination to avoid creating a third Rectangle3D object, but in this case 122 * the original points of this source rectangle will be overwritten by this method. 123 * 124 * @param src1 125 * the first of a pair of <code>Rectangle3D</code> objects to be intersected with each 126 * other 127 * @param src2 128 * the second of a pair of <code>Rectangle3D</code> objects to be intersected with each 129 * other 130 * @param dest 131 * the <code>Rectangle3D</code> that holds the 132 * results of the intersection of <code>src1</code> and <code>src2</code> 133 */ 134 public static Rectangle3D intersect(Rectangle3D src1, Rectangle3D src2, Rectangle3D dest) 135 { 136 final Rectangle3D result; 137 138 if (dest == null) 139 result = new Rectangle3D.Double(); 140 else 141 result = dest; 142 143 final double x1 = Math.max(src1.getMinX(), src2.getMinX()); 144 final double y1 = Math.max(src1.getMinY(), src2.getMinY()); 145 final double z1 = Math.max(src1.getMinZ(), src2.getMinZ()); 146 final double x2 = Math.min(src1.getMaxX(), src2.getMaxX()); 147 final double y2 = Math.min(src1.getMaxY(), src2.getMaxY()); 148 final double z2 = Math.min(src1.getMaxZ(), src2.getMaxZ()); 149 150 double dx; 151 double dy; 152 double dz; 153 154 // special infinite case 155 if (x2 == java.lang.Double.POSITIVE_INFINITY) 156 dx = java.lang.Double.POSITIVE_INFINITY; 157 else 158 dx = x2 - x1; 159 // special infinite case 160 if (y2 == java.lang.Double.POSITIVE_INFINITY) 161 dy = java.lang.Double.POSITIVE_INFINITY; 162 else 163 dy = y2 - y1; 164 // special infinite case 165 if (z2 == java.lang.Double.POSITIVE_INFINITY) 166 dz = java.lang.Double.POSITIVE_INFINITY; 167 else 168 dz = z2 - z1; 169 170 result.setRect(x1, y1, z1, dx, dy, dz); 171 172 return result; 173 } 174 175 /** 176 * Returns a new <code>Rectangle3D</code> object representing the intersection of this <code>Rectangle3D</code> with 177 * the specified <code>Rectangle3D</code>. 178 * 179 * @param r 180 * the <code>Rectangle3D</code> to be intersected with this <code>Rectangle3D</code> 181 * @return the largest <code>Rectangle3D</code> contained in both the specified <code>Rectangle3D</code> and in this 182 * <code>Rectangle3D</code>. 183 */ 184 public abstract Rectangle3D createIntersection(Rectangle3D r); 185 186 /** 187 * Unions the pair of source <code>Rectangle3D</code> objects and puts the result into the 188 * specified destination <code>Rectangle3D</code> object. One of the source rectangles can also 189 * be the destination to avoid creating a third Rectangle3D object, but in this case the 190 * original points of this source rectangle will be overwritten by this method. 191 * 192 * @param src1 193 * the first of a pair of <code>Rectangle3D</code> objects to be combined with each other 194 * @param src2 195 * the second of a pair of <code>Rectangle3D</code> objects to be combined with each 196 * other 197 * @param dest 198 * the <code>Rectangle3D</code> that holds the 199 * results of the union of <code>src1</code> and <code>src2</code> 200 */ 201 public static Rectangle3D union(Rectangle3D src1, Rectangle3D src2, Rectangle3D dest) 202 { 203 final Rectangle3D result; 204 205 if (dest == null) 206 result = new Rectangle3D.Double(); 207 else 208 result = dest; 209 210 double x1 = Math.min(src1.getMinX(), src2.getMinX()); 211 double y1 = Math.min(src1.getMinY(), src2.getMinY()); 212 double z1 = Math.min(src1.getMinZ(), src2.getMinZ()); 213 double x2 = Math.max(src1.getMaxX(), src2.getMaxX()); 214 double y2 = Math.max(src1.getMaxY(), src2.getMaxY()); 215 double z2 = Math.max(src1.getMaxZ(), src2.getMaxZ()); 216 217 double dx; 218 double dy; 219 double dz; 220 221 // special infinite case 222 if (x2 == java.lang.Double.POSITIVE_INFINITY) 223 dx = java.lang.Double.POSITIVE_INFINITY; 224 else 225 dx = x2 - x1; 226 // special infinite case 227 if (y2 == java.lang.Double.POSITIVE_INFINITY) 228 dy = java.lang.Double.POSITIVE_INFINITY; 229 else 230 dy = y2 - y1; 231 // special infinite case 232 if (z2 == java.lang.Double.POSITIVE_INFINITY) 233 dz = java.lang.Double.POSITIVE_INFINITY; 234 else 235 dz = z2 - z1; 236 237 result.setRect(x1, y1, z1, dx, dy, dz); 238 239 return result; 240 } 241 242 /** 243 * Returns a new <code>Rectangle3D</code> object representing the union of this <code>Rectangle3D</code> with the 244 * specified <code>Rectangle3D</code>. 245 * 246 * @param r 247 * the <code>Rectangle3D</code> to be combined with this <code>Rectangle3D</code> 248 * @return the smallest <code>Rectangle3D</code> containing both the specified <code>Rectangle3D</code> and this 249 * <code>Rectangle3D</code>. 250 */ 251 public abstract Rectangle3D createUnion(Rectangle3D r); 252 253 /** 254 * Sets the position and size of this <code>Rectangle3D</code> to the specified <code>double</code> values. 255 * 256 * @param x 257 * the X coordinate of the minimum corner position of this <code>Rectangle3D</code> 258 * @param y 259 * the Y coordinate of the minimum corner position of this <code>Rectangle3D</code> 260 * @param z 261 * the Z coordinate of the minimum corner position of this <code>Rectangle3D</code> 262 * @param sizeX 263 * size for X dimension of this <code>Rectangle3D</code> 264 * @param sizeY 265 * size for Y dimension of this <code>Rectangle3D</code> 266 * @param sizeZ 267 * size for Z dimension of this <code>Rectangle3D</code> 268 */ 269 public abstract void setRect(double x, double y, double z, double sizeX, double sizeY, double sizeZ); 270 271 /** 272 * Returns the minimum X coordinate. 273 */ 274 public abstract double getX(); 275 276 /** 277 * Returns the minimum Y coordinate. 278 */ 279 public abstract double getY(); 280 281 /** 282 * Returns the minimum Z coordinate. 283 */ 284 public abstract double getZ(); 285 286 /** 287 * Returns the point coordinates. 288 */ 289 public abstract Point3D getPosition(); 290 291 /** 292 * Returns the dimension. 293 */ 294 public abstract Dimension3D getDimension(); 295 296 /** 297 * Returns the size of X dimension. 298 */ 299 public abstract double getSizeX(); 300 301 /** 302 * Returns the size of Y dimension. 303 */ 304 public abstract double getSizeY(); 305 306 /** 307 * Returns the size of Z dimension. 308 */ 309 public abstract double getSizeZ(); 310 311 /** 312 * Returns an integer {@link Rectangle3D} that completely encloses the 313 * double <code>Rectangle</code>. The returned <code>Rectangle</code> might also fail to 314 * completely enclose the original double <code>Rectangle</code> if it overflows 315 * the limited range of the integer data type. 316 * 317 * @return an integer <code>Rectangle</code> that completely encloses 318 * the actual double <code>Rectangle</code>. 319 */ 320 public Rectangle3D.Integer toInteger() 321 { 322 double sx = getSizeX(); 323 double sy = getSizeY(); 324 double sz = getSizeZ(); 325 double x = getX(); 326 double y = getY(); 327 double z = getZ(); 328 int ix = (int) Math.floor(x); 329 int iy = (int) Math.floor(y); 330 int iz = (int) Math.floor(z); 331 int isx; 332 int isy; 333 int isz; 334 335 if (sx < 0d) 336 isx = 0; 337 else if (sx >= java.lang.Integer.MAX_VALUE) 338 isx = java.lang.Integer.MAX_VALUE; 339 else 340 isx = ((int) Math.ceil(x + sx)) - ix; 341 if (sy < 0d) 342 isy = 0; 343 else if (sy >= java.lang.Integer.MAX_VALUE) 344 isy = java.lang.Integer.MAX_VALUE; 345 else 346 isy = ((int) Math.ceil(y + sy)) - iy; 347 if (sz < 0d) 348 isz = 0; 349 else if (sz >= java.lang.Integer.MAX_VALUE) 350 isz = java.lang.Integer.MAX_VALUE; 351 else 352 isz = ((int) Math.ceil(z + sz)) - iz; 353 354 return new Rectangle3D.Integer(ix, iy, iz, isx, isy, isz); 355 } 356 357 /** 358 * Sets the minimum X coordinate. 359 */ 360 public abstract void setX(double x); 361 362 /** 363 * Sets the minimum Y coordinate. 364 */ 365 public abstract void setY(double y); 366 367 /** 368 * Sets the minimum Z coordinate. 369 */ 370 public abstract void setZ(double z); 371 372 /** 373 * Sets the size of X dimension. 374 */ 375 public abstract void setSizeX(double value); 376 377 /** 378 * Sets the size of Y dimension. 379 */ 380 public abstract void setSizeY(double value); 381 382 /** 383 * Sets the size of Z dimension. 384 */ 385 public abstract void setSizeZ(double value); 386 387 /** 388 * Returns the smallest X coordinate of the rectangle. 389 */ 390 public double getMinX() 391 { 392 return getX(); 393 } 394 395 /** 396 * Returns the smallest Y coordinate of the rectangle. 397 */ 398 public double getMinY() 399 { 400 return getY(); 401 } 402 403 /** 404 * Returns the smallest Z coordinate of the rectangle. 405 */ 406 public double getMinZ() 407 { 408 return getZ(); 409 } 410 411 /** 412 * Returns the largest X coordinate of the rectangle. 413 */ 414 public double getMaxX() 415 { 416 // handle this special case 417 if (getSizeX() == java.lang.Double.POSITIVE_INFINITY) 418 return java.lang.Double.POSITIVE_INFINITY; 419 420 return getX() + getSizeX(); 421 } 422 423 /** 424 * Returns the largest Y coordinate of the rectangle. 425 */ 426 public double getMaxY() 427 { 428 // handle this special case 429 if (getSizeY() == java.lang.Double.POSITIVE_INFINITY) 430 return java.lang.Double.POSITIVE_INFINITY; 431 432 return getY() + getSizeY(); 433 } 434 435 /** 436 * Returns the largest Z coordinate of the rectangle. 437 */ 438 public double getMaxZ() 439 { 440 // handle this special case 441 if (getSizeZ() == java.lang.Double.POSITIVE_INFINITY) 442 return java.lang.Double.POSITIVE_INFINITY; 443 444 return getZ() + getSizeZ(); 445 } 446 447 /** 448 * Returns the X coordinate of the center of the rectangle. 449 */ 450 public double getCenterX() 451 { 452 // handle this special case 453 if (isInfiniteX()) 454 return 0d; 455 456 return getX() + (getSizeX() / 2d); 457 } 458 459 /** 460 * Returns the Y coordinate of the center of the rectangle. 461 */ 462 public double getCenterY() 463 { 464 // handle this special case 465 if (isInfiniteY()) 466 return 0d; 467 468 return getY() + (getSizeY() / 2d); 469 } 470 471 /** 472 * Returns the Z coordinate of the center of the rectangle. 473 */ 474 public double getCenterZ() 475 { 476 // handle this special case 477 if (isInfiniteZ()) 478 return 0d; 479 480 return getZ() + (getSizeZ() / 2d); 481 } 482 483 /** 484 * Determines whether the <code>Rectangle5D</code> is empty. 485 * 486 * @return <code>true</code> if the <code>Rectangle5D</code> is empty; <code>false</code> otherwise. 487 */ 488 public boolean isEmpty() 489 { 490 return (getSizeX() <= 0d) || (getSizeY() <= 0d) || (getSizeZ() <= 0d); 491 } 492 493 /** 494 * Returns <code>true</code> if the X dimension should be considered as infinite. 495 */ 496 public boolean isInfiniteX() 497 { 498 return (getX() == java.lang.Double.NEGATIVE_INFINITY) && (getSizeX() == java.lang.Double.POSITIVE_INFINITY); 499 } 500 501 /** 502 * Returns <code>true</code> if the Y dimension should be considered as infinite. 503 */ 504 public boolean isInfiniteY() 505 { 506 return (getY() == java.lang.Double.NEGATIVE_INFINITY) && (getSizeY() == java.lang.Double.POSITIVE_INFINITY); 507 } 508 509 /** 510 * Returns <code>true</code> if the Z dimension should be considered as infinite. 511 */ 512 public boolean isInfiniteZ() 513 { 514 return (getZ() == java.lang.Double.NEGATIVE_INFINITY) && (getSizeZ() == java.lang.Double.POSITIVE_INFINITY); 515 } 516 517 /** 518 * Sets the X dimension to infinite. 519 */ 520 public void setInfiniteX() 521 { 522 setX(java.lang.Double.NEGATIVE_INFINITY); 523 setSizeX(java.lang.Double.POSITIVE_INFINITY); 524 } 525 526 /** 527 * Sets the Y dimension to infinite. 528 */ 529 public void setInfiniteY() 530 { 531 setY(java.lang.Double.NEGATIVE_INFINITY); 532 setSizeY(java.lang.Double.POSITIVE_INFINITY); 533 } 534 535 /** 536 * Sets the Z dimension to infinite. 537 */ 538 public void setInfiniteZ() 539 { 540 setZ(java.lang.Double.NEGATIVE_INFINITY); 541 setSizeZ(java.lang.Double.POSITIVE_INFINITY); 542 } 543 544 @Override 545 public Rectangle3D getBounds() 546 { 547 return new Rectangle3D.Double(this); 548 } 549 550 /** 551 * Tests if the specified coordinates are inside the boundary of the <code>Rectangle3D</code>. 552 * 553 * @param x 554 * the specified X coordinate to be tested 555 * @param y 556 * the specified Y coordinate to be tested 557 * @param z 558 * the specified Z coordinate to be tested 559 * @return <code>true</code> if the specified coordinates are inside 560 * the <code>Rectangle3D</code> boundary; <code>false</code> otherwise. 561 */ 562 @Override 563 public boolean contains(double x, double y, double z) 564 { 565 return (x >= getMinX()) && (y >= getMinY()) && (z >= getMinZ()) && (x < getMaxX()) && (y < getMaxY()) 566 && (z < getMaxZ()); 567 } 568 569 @Override 570 public boolean contains(Point3D p) 571 { 572 return contains(p.getX(), p.getY(), p.getZ()); 573 } 574 575 /** 576 * Tests if the <code>Rectangle3D</code> entirely contains the specified 3D rectangular area. 577 * All coordinates that lie inside the 3D rectangular area must lie within the <code>Rectangle3D</code>. 578 * 579 * @param x 580 * the X coordinate of the minimum corner position of the specified rectangular area 581 * @param y 582 * the Y coordinate of the minimum corner position of the specified rectangular area 583 * @param z 584 * the Z coordinate of the minimum corner position of the specified rectangular area 585 * @param sizeX 586 * size for X dimension of the specified rectangular area 587 * @param sizeY 588 * size for Y dimension of the specified rectangular area 589 * @param sizeZ 590 * size for Z dimension of the specified rectangular area 591 * @return <code>true</code> if the <code>Rectangle3D</code> entirely contains the 592 * specified 3D rectangular area; <code>false</code> otherwise 593 * @see #intersects 594 */ 595 @Override 596 public boolean contains(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 597 { 598 final double maxX; 599 final double maxY; 600 final double maxZ; 601 602 // special infinite case 603 if (sizeX == java.lang.Double.POSITIVE_INFINITY) 604 maxX = java.lang.Double.POSITIVE_INFINITY; 605 else 606 maxX = x + sizeX; 607 // special infinite case 608 if (sizeY == java.lang.Double.POSITIVE_INFINITY) 609 maxY = java.lang.Double.POSITIVE_INFINITY; 610 else 611 maxY = y + sizeY; 612 // special infinite case 613 if (sizeZ == java.lang.Double.POSITIVE_INFINITY) 614 maxZ = java.lang.Double.POSITIVE_INFINITY; 615 else 616 maxZ = z + sizeZ; 617 618 return (x >= getMinX()) && (y >= getMinY()) && (z >= getMinZ()) && (maxX <= getMaxX()) && (maxY <= getMaxY()) 619 && (maxZ <= getMaxZ()); 620 } 621 622 /** 623 * Tests if the <code>Rectangle3D</code> entirely contains the specified <code>Rectangle3D</code>. 624 * 625 * @see #contains(double, double, double, double, double, double) 626 */ 627 @Override 628 public boolean contains(Rectangle3D rect) 629 { 630 return contains(rect.getX(), rect.getY(), rect.getZ(), rect.getSizeX(), rect.getSizeY(), rect.getSizeZ()); 631 } 632 633 /** 634 * Tests if the interior of the <code>Rectangle3D</code> intersects the interior of a specified 635 * 3D rectangular area.<br> 636 * The 3D rectangular area is considered to intersect the <code>Rectangle3D</code> if any point 637 * is contained in both the interior of the <code>Rectangle3D</code> and the specified 638 * rectangular area. 639 * 640 * @param x 641 * the X coordinate of the minimum corner position of the specified rectangular area 642 * @param y 643 * the Y coordinate of the minimum corner position of the specified rectangular area 644 * @param z 645 * the Z coordinate of the minimum corner position of the specified rectangular area 646 * @param sizeX 647 * size for X dimension of the specified rectangular area 648 * @param sizeY 649 * size for Y dimension of the specified rectangular area 650 * @param sizeZ 651 * size for Z dimension of the specified rectangular area 652 * @return <code>true</code> if the interior of the <code>Rectangle3D</code> and 653 * the interior of the 3D rectangular area intersect. 654 */ 655 @Override 656 public boolean intersects(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 657 { 658 final double maxX; 659 final double maxY; 660 final double maxZ; 661 662 // special infinite case 663 if (sizeX == java.lang.Double.POSITIVE_INFINITY) 664 maxX = java.lang.Double.POSITIVE_INFINITY; 665 else 666 maxX = x + sizeX; 667 // special infinite case 668 if (sizeY == java.lang.Double.POSITIVE_INFINITY) 669 maxY = java.lang.Double.POSITIVE_INFINITY; 670 else 671 maxY = y + sizeY; 672 // special infinite case 673 if (sizeZ == java.lang.Double.POSITIVE_INFINITY) 674 maxZ = java.lang.Double.POSITIVE_INFINITY; 675 else 676 maxZ = z + sizeZ; 677 678 return (maxX > getMinX()) && (maxY > getMinY()) && (maxZ > getMinZ()) && (x < getMaxX()) && (y < getMaxY()) 679 && (z < getMaxZ()); 680 } 681 682 /** 683 * Tests if the interior of the <code>Rectangle3D</code> intersects the interior of a specified 684 * <code>Rectangle3D</code>.<br> 685 * 686 * @see #intersects(double, double, double, double, double, double) 687 */ 688 @Override 689 public boolean intersects(Rectangle3D rect) 690 { 691 return intersects(rect.getX(), rect.getY(), rect.getZ(), rect.getSizeX(), rect.getSizeY(), rect.getSizeZ()); 692 } 693 694 /** 695 * Tests if the specified 3D line intersects this <code>Rectangle3D</code>. 696 */ 697 698 public boolean intersectsLine(Line3D line) 699 { 700 return intersects(line, this); 701 } 702 703 /** 704 * Tests if the line specified by the given starting and ending Point intersects the plan defined by this 705 * <code>Rectangle3D</code>. 706 */ 707 708 public boolean intersectsLine(Point3D pt1, Point3D pt2) 709 { 710 return intersects(new Line3D(pt1, pt2), this); 711 } 712 713 /** 714 * Tests if the specified 3D line intersects this <code>Rectangle3D</code>. 715 */ 716 717 public boolean intersectsLine(double x1, double y1, double z1, double x2, double y2, double z2) 718 { 719 return intersects(new Line3D(x1, y1, z1, x2, y2, z2), this); 720 } 721 722 /** 723 * Adds a 3D point, specified by the double precision coordinates arguments, to this <code>Rectangle3D</code>. The 724 * resulting <code>Rectangle3D</code> is the smallest <code>Rectangle3D</code> that contains both the original 725 * <code>Rectangle3D</code> and the 726 * specified 3D point. 727 * <p> 728 * After adding a 3D point, a call to <code>contains</code> with the added point as an argument does not necessarily 729 * return <code>true</code>. The <code>contains</code> method does not return <code>true</code> for points on the 730 * edges of a rectangle. Therefore, if the added 3D point falls on edge of the enlarged rectangle, 731 * <code>contains</code> returns <code>false</code> for that point. 732 * 733 * @param newx 734 * the X coordinate of the new point 735 * @param newy 736 * the Y coordinate of the new point 737 * @param newz 738 * the Z coordinate of the new point 739 */ 740 public void add(double newx, double newy, double newz) 741 { 742 double x1 = Math.min(getMinX(), newx); 743 double x2 = Math.max(getMaxX(), newx); 744 double y1 = Math.min(getMinY(), newy); 745 double y2 = Math.max(getMaxY(), newy); 746 double z1 = Math.min(getMinZ(), newz); 747 double z2 = Math.max(getMaxZ(), newz); 748 749 double dx; 750 double dy; 751 double dz; 752 753 // special infinite case 754 if (x2 == java.lang.Double.POSITIVE_INFINITY) 755 dx = java.lang.Double.POSITIVE_INFINITY; 756 else 757 dx = x2 - x1; 758 // special infinite case 759 if (y2 == java.lang.Double.POSITIVE_INFINITY) 760 dy = java.lang.Double.POSITIVE_INFINITY; 761 else 762 dy = y2 - y1; 763 // special infinite case 764 if (z2 == java.lang.Double.POSITIVE_INFINITY) 765 dz = java.lang.Double.POSITIVE_INFINITY; 766 else 767 dz = z2 - z1; 768 769 setRect(x1, y1, z1, dx, dy, dz); 770 } 771 772 /** 773 * Adds the <code>Point3D</code> object <code>pt</code> to this <code>Rectangle3D</code>. 774 * The resulting <code>Rectangle3D</code> is the smallest <code>Rectangle3D</code> that contains 775 * both the original <code>Rectangle3D</code> and the specified <code>Point3D</code>. 776 * <p> 777 * After adding a point, a call to <code>contains</code> with the added point as an argument does not necessarily 778 * return <code>true</code>. The <code>contains</code> method does not return <code>true</code> for points on the 779 * edges of a rectangle. Therefore, if the added point falls on edge of the enlarged rectangle, 780 * <code>contains</code> returns <code>false</code> for that point. 781 * 782 * @param pt 783 * the new <code>Point3D</code> to add to this <code>Rectangle3D</code>. 784 */ 785 public void add(Point3D pt) 786 { 787 add(pt.getX(), pt.getY(), pt.getZ()); 788 } 789 790 /** 791 * Adds a <code>Rectangle3D</code> object to this <code>Rectangle3D</code>. The resulting <code>Rectangle3D</code> 792 * is the union of the two <code>Rectangle3D</code> objects. 793 * 794 * @param r 795 * the <code>Rectangle3D</code> to add to this <code>Rectangle3D</code>. 796 */ 797 public void add(Rectangle3D r) 798 { 799 union(this, r, this); 800 } 801 802 /** 803 * Convert to 2D rectangle 804 */ 805 public abstract Rectangle2D toRectangle2D(); 806 807 @Override 808 public boolean equals(Object obj) 809 { 810 if (obj == this) 811 return true; 812 813 if (obj instanceof Rectangle3D) 814 { 815 final Rectangle3D rect = (Rectangle3D) obj; 816 return (getX() == rect.getX()) && (getY() == rect.getY()) && (getZ() == rect.getZ()) 817 && (getSizeX() == rect.getSizeX()) && (getSizeY() == rect.getSizeY()) 818 && (getSizeZ() == rect.getSizeZ()); 819 } 820 821 return super.equals(obj); 822 } 823 824 @Override 825 public int hashCode() 826 { 827 long bits = java.lang.Double.doubleToLongBits(getX()); 828 bits ^= java.lang.Double.doubleToLongBits(getY()); 829 bits ^= java.lang.Double.doubleToLongBits(getZ()); 830 bits ^= java.lang.Double.doubleToLongBits(getSizeX()); 831 bits ^= java.lang.Double.doubleToLongBits(getSizeY()); 832 bits ^= java.lang.Double.doubleToLongBits(getSizeZ()); 833 return (((int) bits) ^ ((int) (bits >> 32))); 834 } 835 836 /** 837 * Creates a new object of the same class as this object. 838 * 839 * @return a clone of this instance. 840 * @exception OutOfMemoryError 841 * if there is not enough memory. 842 * @see java.lang.Cloneable 843 */ 844 @Override 845 public Object clone() 846 { 847 try 848 { 849 return super.clone(); 850 } 851 catch (CloneNotSupportedException e) 852 { 853 // this shouldn't happen, since we are Cloneable 854 throw new InternalError(); 855 } 856 } 857 858 @Override 859 public String toString() 860 { 861 return getClass().getName() + "[" + getX() + "," + getY() + "," + getZ() + " - " + getSizeX() + "," 862 + getSizeY() + "," + getSizeZ() + "]"; 863 } 864 865 public static class Double extends Rectangle3D 866 { 867 public double x; 868 public double y; 869 public double z; 870 871 public double sizeX; 872 public double sizeY; 873 public double sizeZ; 874 875 public Double(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 876 { 877 super(); 878 879 this.x = x; 880 this.y = y; 881 this.z = z; 882 this.sizeX = sizeX; 883 this.sizeY = sizeY; 884 this.sizeZ = sizeZ; 885 } 886 887 public Double(Rectangle3D r) 888 { 889 this(r.getX(), r.getY(), r.getZ(), r.getSizeX(), r.getSizeY(), r.getSizeZ()); 890 } 891 892 public Double() 893 { 894 this(0, 0, 0, 0, 0, 0); 895 } 896 897 @Override 898 public void setRect(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 899 { 900 this.x = x; 901 this.y = y; 902 this.z = z; 903 this.sizeX = sizeX; 904 this.sizeY = sizeY; 905 this.sizeZ = sizeZ; 906 } 907 908 @Override 909 public double getX() 910 { 911 return x; 912 } 913 914 @Override 915 public void setX(double value) 916 { 917 x = value; 918 } 919 920 @Override 921 public double getY() 922 { 923 return y; 924 } 925 926 @Override 927 public void setY(double value) 928 { 929 y = value; 930 } 931 932 @Override 933 public double getZ() 934 { 935 return z; 936 } 937 938 @Override 939 public void setZ(double value) 940 { 941 z = value; 942 } 943 944 @Override 945 public double getSizeX() 946 { 947 return sizeX; 948 } 949 950 @Override 951 public void setSizeX(double value) 952 { 953 sizeX = value; 954 } 955 956 @Override 957 public double getSizeY() 958 { 959 return sizeY; 960 } 961 962 @Override 963 public void setSizeY(double value) 964 { 965 sizeY = value; 966 } 967 968 @Override 969 public double getSizeZ() 970 { 971 return sizeZ; 972 } 973 974 @Override 975 public void setSizeZ(double value) 976 { 977 sizeZ = value; 978 } 979 980 @Override 981 public Point3D.Double getPosition() 982 { 983 return new Point3D.Double(x, y, z); 984 } 985 986 @Override 987 public Dimension3D.Double getDimension() 988 { 989 return new Dimension3D.Double(sizeX, sizeY, sizeZ); 990 } 991 992 @Override 993 public Rectangle3D createIntersection(Rectangle3D r) 994 { 995 final Rectangle3D.Double result = new Rectangle3D.Double(); 996 997 intersect(this, r, result); 998 999 return result; 1000 } 1001 1002 @Override 1003 public Rectangle3D createUnion(Rectangle3D r) 1004 { 1005 final Rectangle3D.Double result = new Rectangle3D.Double(); 1006 1007 union(this, r, result); 1008 1009 return result; 1010 } 1011 1012 @Override 1013 public Rectangle2D toRectangle2D() 1014 { 1015 return new Rectangle2D.Double(x, y, sizeX, sizeY); 1016 } 1017 } 1018 1019 public static class Float extends Rectangle3D 1020 { 1021 public float x; 1022 public float y; 1023 public float z; 1024 1025 public float sizeX; 1026 public float sizeY; 1027 public float sizeZ; 1028 1029 public Float(float x, float y, float z, float sizeX, float sizeY, float sizeZ) 1030 { 1031 super(); 1032 1033 this.x = x; 1034 this.y = y; 1035 this.z = z; 1036 this.sizeX = sizeX; 1037 this.sizeY = sizeY; 1038 this.sizeZ = sizeZ; 1039 } 1040 1041 public Float(Rectangle3D r) 1042 { 1043 this((float) r.getX(), (float) r.getY(), (float) r.getZ(), (float) r.getSizeX(), (float) r.getSizeY(), 1044 (float) r.getSizeZ()); 1045 } 1046 1047 public Float() 1048 { 1049 this(0, 0, 0, 0, 0, 0); 1050 } 1051 1052 @Override 1053 public void setRect(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 1054 { 1055 this.x = (float) x; 1056 this.y = (float) y; 1057 this.z = (float) z; 1058 this.sizeX = (float) sizeX; 1059 this.sizeY = (float) sizeY; 1060 this.sizeZ = (float) sizeZ; 1061 } 1062 1063 @Override 1064 public double getX() 1065 { 1066 // special infinite case 1067 if (x == java.lang.Float.NEGATIVE_INFINITY) 1068 return java.lang.Double.NEGATIVE_INFINITY; 1069 if (x == java.lang.Float.POSITIVE_INFINITY) 1070 return java.lang.Double.POSITIVE_INFINITY; 1071 1072 return x; 1073 } 1074 1075 @Override 1076 public void setX(double value) 1077 { 1078 x = (float) value; 1079 } 1080 1081 @Override 1082 public double getY() 1083 { 1084 // special infinite case 1085 if (y == java.lang.Float.NEGATIVE_INFINITY) 1086 return java.lang.Double.NEGATIVE_INFINITY; 1087 if (y == java.lang.Float.POSITIVE_INFINITY) 1088 return java.lang.Double.POSITIVE_INFINITY; 1089 1090 return y; 1091 } 1092 1093 @Override 1094 public void setY(double value) 1095 { 1096 y = (float) value; 1097 } 1098 1099 @Override 1100 public double getZ() 1101 { 1102 // special infinite case 1103 if (z == java.lang.Float.NEGATIVE_INFINITY) 1104 return java.lang.Double.NEGATIVE_INFINITY; 1105 if (z == java.lang.Float.POSITIVE_INFINITY) 1106 return java.lang.Double.POSITIVE_INFINITY; 1107 1108 return z; 1109 } 1110 1111 @Override 1112 public void setZ(double value) 1113 { 1114 z = (float) value; 1115 } 1116 1117 @Override 1118 public double getSizeX() 1119 { 1120 // special infinite case 1121 if (sizeX == java.lang.Float.POSITIVE_INFINITY) 1122 return java.lang.Double.POSITIVE_INFINITY; 1123 1124 return sizeX; 1125 } 1126 1127 @Override 1128 public void setSizeX(double value) 1129 { 1130 sizeX = (float) value; 1131 } 1132 1133 @Override 1134 public double getSizeY() 1135 { 1136 // special infinite case 1137 if (sizeY == java.lang.Float.POSITIVE_INFINITY) 1138 return java.lang.Double.POSITIVE_INFINITY; 1139 1140 return sizeY; 1141 } 1142 1143 @Override 1144 public void setSizeY(double value) 1145 { 1146 sizeY = (float) value; 1147 } 1148 1149 @Override 1150 public double getSizeZ() 1151 { 1152 // special infinite case 1153 if (sizeZ == java.lang.Float.POSITIVE_INFINITY) 1154 return java.lang.Double.POSITIVE_INFINITY; 1155 1156 return sizeZ; 1157 } 1158 1159 @Override 1160 public void setSizeZ(double value) 1161 { 1162 sizeZ = (float) value; 1163 } 1164 1165 @Override 1166 public Point3D.Float getPosition() 1167 { 1168 return new Point3D.Float(x, y, z); 1169 } 1170 1171 @Override 1172 public Dimension3D.Float getDimension() 1173 { 1174 return new Dimension3D.Float(sizeX, sizeY, sizeZ); 1175 } 1176 1177 @Override 1178 public Rectangle3D createIntersection(Rectangle3D r) 1179 { 1180 final Rectangle3D.Float result = new Rectangle3D.Float(); 1181 1182 intersect(this, r, result); 1183 1184 return result; 1185 } 1186 1187 @Override 1188 public Rectangle3D createUnion(Rectangle3D r) 1189 { 1190 final Rectangle3D.Float result = new Rectangle3D.Float(); 1191 1192 union(this, r, result); 1193 1194 return result; 1195 } 1196 1197 @Override 1198 public Rectangle2D toRectangle2D() 1199 { 1200 return new Rectangle2D.Float(x, y, sizeX, sizeY); 1201 } 1202 } 1203 1204 public static class Integer extends Rectangle3D 1205 { 1206 public int x; 1207 public int y; 1208 public int z; 1209 1210 public int sizeX; 1211 public int sizeY; 1212 public int sizeZ; 1213 1214 public Integer(int x, int y, int z, int sizeX, int sizeY, int sizeZ) 1215 { 1216 super(); 1217 1218 this.x = x; 1219 this.y = y; 1220 this.z = z; 1221 this.sizeX = sizeX; 1222 this.sizeY = sizeY; 1223 this.sizeZ = sizeZ; 1224 } 1225 1226 public Integer(Rectangle3D.Integer r) 1227 { 1228 this(r.x, r.y, r.z, r.sizeX, r.sizeY, r.sizeZ); 1229 } 1230 1231 public Integer(Rectangle3D r) 1232 { 1233 this(r.toInteger()); 1234 } 1235 1236 public Integer() 1237 { 1238 this(0, 0, 0, 0, 0, 0); 1239 } 1240 1241 /** 1242 * Sets the bounds of this {@code Rectangle3D} to the integer bounds 1243 * which encompass the specified double bounds. 1244 * 1245 * @param x 1246 * the X coordinate of the minimum corner position of this <code>Rectangle3D</code> 1247 * @param y 1248 * the Y coordinate of the minimum corner position of this <code>Rectangle3D</code> 1249 * @param z 1250 * the Z coordinate of the minimum corner position of this <code>Rectangle3D</code> 1251 * @param sizeX 1252 * size for X dimension of this <code>Rectangle3D</code> 1253 * @param sizeY 1254 * size for Y dimension of this <code>Rectangle3D</code> 1255 * @param sizeZ 1256 * size for Z dimension of this <code>Rectangle3D</code> 1257 */ 1258 @Override 1259 public void setRect(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 1260 { 1261 final Rectangle3D.Integer r = new Rectangle3D.Double(x, y, z, sizeX, sizeY, sizeZ).toInteger(); 1262 setRect(r.x, r.y, r.z, r.sizeX, r.sizeY, r.sizeZ); 1263 } 1264 1265 /** 1266 * Sets the position and size of this <code>Rectangle3D</code> to the specified <code>integer</code> values. 1267 * 1268 * @param x 1269 * the X coordinate of the minimum corner position of this <code>Rectangle3D</code> 1270 * @param y 1271 * the Y coordinate of the minimum corner position of this <code>Rectangle3D</code> 1272 * @param z 1273 * the Z coordinate of the minimum corner position of this <code>Rectangle3D</code> 1274 * @param sizeX 1275 * size for X dimension of this <code>Rectangle3D</code> 1276 * @param sizeY 1277 * size for Y dimension of this <code>Rectangle3D</code> 1278 * @param sizeZ 1279 * size for Z dimension of this <code>Rectangle3D</code> 1280 */ 1281 public void setRect(int x, int y, int z, int sizeX, int sizeY, int sizeZ) 1282 { 1283 this.x = x; 1284 this.y = y; 1285 this.z = z; 1286 this.sizeX = sizeX; 1287 this.sizeY = sizeY; 1288 this.sizeZ = sizeZ; 1289 } 1290 1291 @Override 1292 public double getX() 1293 { 1294 // special infinite case 1295 if (x == java.lang.Integer.MIN_VALUE) 1296 return java.lang.Double.NEGATIVE_INFINITY; 1297 if (x == java.lang.Integer.MAX_VALUE) 1298 return java.lang.Double.POSITIVE_INFINITY; 1299 1300 return x; 1301 } 1302 1303 @Override 1304 public void setX(double value) 1305 { 1306 x = (int) value; 1307 } 1308 1309 @Override 1310 public double getY() 1311 { 1312 // special infinite case 1313 if (y == java.lang.Integer.MIN_VALUE) 1314 return java.lang.Double.NEGATIVE_INFINITY; 1315 if (y == java.lang.Integer.MAX_VALUE) 1316 return java.lang.Double.POSITIVE_INFINITY; 1317 1318 return y; 1319 } 1320 1321 @Override 1322 public void setY(double value) 1323 { 1324 y = (int) value; 1325 } 1326 1327 @Override 1328 public double getZ() 1329 { 1330 // special infinite case 1331 if (z == java.lang.Integer.MIN_VALUE) 1332 return java.lang.Double.NEGATIVE_INFINITY; 1333 if (z == java.lang.Integer.MAX_VALUE) 1334 return java.lang.Double.POSITIVE_INFINITY; 1335 1336 return z; 1337 } 1338 1339 @Override 1340 public void setZ(double value) 1341 { 1342 z = (int) value; 1343 } 1344 1345 @Override 1346 public double getSizeX() 1347 { 1348 // special infinite case 1349 if (sizeX == java.lang.Integer.MAX_VALUE) 1350 return java.lang.Double.POSITIVE_INFINITY; 1351 1352 return sizeX; 1353 } 1354 1355 @Override 1356 public void setSizeX(double value) 1357 { 1358 sizeX = (int) value; 1359 } 1360 1361 @Override 1362 public double getSizeY() 1363 { 1364 // special infinite case 1365 if (sizeY == java.lang.Integer.MAX_VALUE) 1366 return java.lang.Double.POSITIVE_INFINITY; 1367 1368 return sizeY; 1369 } 1370 1371 @Override 1372 public void setSizeY(double value) 1373 { 1374 sizeY = (int) value; 1375 } 1376 1377 @Override 1378 public double getSizeZ() 1379 { 1380 // special infinite case 1381 if (sizeZ == java.lang.Integer.MAX_VALUE) 1382 return java.lang.Double.POSITIVE_INFINITY; 1383 1384 return sizeZ; 1385 } 1386 1387 @Override 1388 public void setSizeZ(double value) 1389 { 1390 sizeZ = (int) value; 1391 } 1392 1393 @Override 1394 public Point3D.Integer getPosition() 1395 { 1396 return new Point3D.Integer(x, y, z); 1397 } 1398 1399 @Override 1400 public Dimension3D.Integer getDimension() 1401 { 1402 return new Dimension3D.Integer(sizeX, sizeY, sizeZ); 1403 } 1404 1405 @Override 1406 public Rectangle3D.Integer toInteger() 1407 { 1408 return (Integer) clone(); 1409 } 1410 1411 @Override 1412 public Rectangle3D createIntersection(Rectangle3D r) 1413 { 1414 final Rectangle3D.Integer result = new Rectangle3D.Integer(); 1415 1416 intersect(this, r, result); 1417 1418 return result; 1419 } 1420 1421 @Override 1422 public Rectangle3D createUnion(Rectangle3D r) 1423 { 1424 final Rectangle3D.Integer result = new Rectangle3D.Integer(); 1425 1426 union(this, r, result); 1427 1428 return result; 1429 } 1430 1431 @Override 1432 public Rectangle2D toRectangle2D() 1433 { 1434 return new Rectangle(x, y, sizeX, sizeY); 1435 } 1436 } 1437 1438}