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