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}