sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1507311 - in /sis/branches/JDK7/core/sis-referencing/src: main/java/org/apache/sis/geometry/Envelope2D.java test/java/org/apache/sis/geometry/Envelope2DTest.java
Date Fri, 26 Jul 2013 13:48:39 GMT
Author: desruisseaux
Date: Fri Jul 26 13:48:39 2013
New Revision: 1507311

URL: http://svn.apache.org/r1507311
Log:
Ported the LatLonRect.toJavaRectangles() method to Envelope2D (part of SIS-69 task).

Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/Envelope2DTest.java

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java?rev=1507311&r1=1507310&r2=1507311&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
[UTF-8] Fri Jul 26 13:48:39 2013
@@ -82,6 +82,7 @@ import java.util.Objects;
  *   <li>{@link #getSpan(int)}</li>
  *   <li>{@link #getMedian(int)}</li>
  *   <li>{@link #isEmpty()}</li>
+ *   <li>{@link #toRectangles()}</li>
  *   <li>{@link #contains(double,double)}</li>
  *   <li>{@link #contains(Rectangle2D)} and its variant receiving {@code double} arguments</li>
  *   <li>{@link #intersects(Rectangle2D)} and its variant receiving {@code double}
arguments</li>
@@ -99,7 +100,7 @@ import java.util.Objects;
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Johann Sorel (Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.4
  * @module
  *
  * @see GeneralEnvelope
@@ -112,6 +113,17 @@ public class Envelope2D extends Rectangl
     private static final long serialVersionUID = 761232175464415062L;
 
     /**
+     * The number of dimensions in every {@code Envelope2D}.
+     */
+    private static final int DIMENSION = 2;
+
+    /**
+     * An empty array of Java2D rectangles, to be returned by {@link #toRectangles()}
+     * when en envelope is empty.
+     */
+    private static final Rectangle2D.Double[] EMPTY = new Rectangle2D.Double[0];
+
+    /**
      * The coordinate reference system, or {@code null}.
      */
     private CoordinateReferenceSystem crs;
@@ -153,7 +165,7 @@ public class Envelope2D extends Rectangl
          */
         this(lowerCorner.getOrdinate(0), lowerCorner.getOrdinate(1),
              upperCorner.getOrdinate(0), upperCorner.getOrdinate(1));
-        ensureDimensionMatches("crs", 2, crs);
+        ensureDimensionMatches("crs", DIMENSION, crs);
         this.crs = crs;
     }
 
@@ -225,7 +237,7 @@ public class Envelope2D extends Rectangl
             throws MismatchedDimensionException
     {
         super(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); // Really 'super',
not 'this'.
-        ensureDimensionMatches("crs", 2, crs);
+        ensureDimensionMatches("crs", DIMENSION, crs);
         this.crs = crs;
     }
 
@@ -248,7 +260,7 @@ public class Envelope2D extends Rectangl
             final double width, final double height) throws MismatchedDimensionException
     {
         super(x, y, width, height); // Really 'super', not 'this'.
-        ensureDimensionMatches("crs", 2, crs);
+        ensureDimensionMatches("crs", DIMENSION, crs);
         this.crs = crs;
     }
 
@@ -271,16 +283,18 @@ public class Envelope2D extends Rectangl
      * @param crs The new coordinate reference system, or {@code null}.
      */
     public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs) {
-        ensureDimensionMatches("crs", 2, crs);
+        ensureDimensionMatches("crs", DIMENSION, crs);
         this.crs = crs;
     }
 
     /**
      * Returns the number of dimensions, which is always 2.
+     *
+     * @return Always 2 for bi-dimensional objects.
      */
     @Override
     public final int getDimension() {
-        return 2;
+        return DIMENSION;
     }
 
     /**
@@ -501,11 +515,11 @@ public class Envelope2D extends Rectangl
      * (@linkplain #height} is considered as a non-empty area if the corresponding
      * axis has the {@linkplain org.opengis.referencing.cs.RangeMeaning#WRAPAROUND
      * wraparound} range meaning.
-     * <p>
-     * Note that if the {@linkplain #width} or {@linkplain #height} value is
+     *
+     * <p>Note that if the {@linkplain #width} or {@linkplain #height} value is
      * {@link java.lang.Double#NaN NaN}, then the envelope is considered empty.
      * This is different than the default {@link java.awt.geom.Rectangle2D.Double#isEmpty()}
-     * implementation, which doesn't check for {@code NaN} values.
+     * implementation, which doesn't check for {@code NaN} values.</p>
      */
     @Override
     public boolean isEmpty() {
@@ -514,6 +528,99 @@ public class Envelope2D extends Rectangl
     }
 
     /**
+     * Returns this envelope as non-empty Java2D rectangle objects. This method returns an
array of length 0, 1,
+     * 2 or 4 depending on whether the envelope crosses the anti-meridian or the limit of
any other axis having
+     * {@linkplain org.opengis.referencing.cs.RangeMeaning#WRAPAROUND wraparound} range meaning.
+     * More specifically:
+     *
+     * <ul>
+     *   <li>If this envelope {@linkplain #isEmpty() is empty}, then this method returns
an empty array.</li>
+     *   <li>If this envelope does not have any wraparound behavior, then this method
returns a copy
+     *       of this envelope as an instance of {@code Rectangle2D.Double} in an array of
length 1.</li>
+     *   <li>If this envelope crosses the <cite>anti-meridian</cite> (a.k.a.
<cite>date line</cite>)
+     *       then this method represents this envelope as two separated rectangles.
+     *   <li>While uncommon, the envelope could theoretically crosses the limit of
other axis having
+     *       wraparound range meaning. If wraparound occur along the two axes, then this
method
+     *       represents this envelope as four separated rectangles.
+     * </ul>
+     *
+     * @return A representation of this envelope as an array of non-empty Java2D rectangles.
+     *         The array never contains {@code this}.
+     *
+     * @see GeneralEnvelope#toSimpleEnvelopes()
+     *
+     * @since 0.4
+     */
+    public Rectangle2D.Double[] toRectangles() {
+        int isWrapAround = 0; // A bitmask of the dimensions having a "wrap around" behavior.
+        for (int i=0; i!=DIMENSION; i++) {
+            final double span = (i == 0) ? width : height;
+            if (!(span > 0)) { // Use '!' for catching NaN.
+                if (!isNegative(span) || !isWrapAround(crs, i)) {
+                    return EMPTY;
+                }
+                isWrapAround |= (1 << i);
+            }
+        }
+        /*
+         * The number of rectangles is 2ⁿ where n is the number of wraparound found.
+         */
+        final Rectangle2D.Double[] rect = new Rectangle2D.Double[1 << Integer.bitCount(isWrapAround)];
+        for (int i=0; i<rect.length; i++) {
+            rect[i] = new Rectangle2D.Double(x, y, width, height);
+        }
+        if ((isWrapAround & 1) != 0) {
+            /*
+             *  (x+width)   (x)
+             *          ↓   ↓
+             *    ──────┐   ┌───────
+             *    …next │   │ start…
+             *    ──────┘   └───────
+             */
+            final CoordinateSystemAxis axis = getAxis(crs, 0);
+            final Rectangle2D.Double start = rect[0];
+            final Rectangle2D.Double next  = rect[1];
+            start.width = axis.getMaximumValue() - x;
+            next.x      = axis.getMinimumValue();
+            next.width += x - next.x;
+        }
+        if ((isWrapAround & 2) != 0) {
+            /*
+             *              │   ⋮   │
+             *              │ start │
+             * (y)        → └───────┘
+             * (y+height) → ┌───────┐
+             *              │ next  │
+             *              │   ⋮   │
+             */
+            final CoordinateSystemAxis axis = getAxis(crs, 1);
+            final Rectangle2D.Double start = rect[0];
+            final Rectangle2D.Double next  = rect[isWrapAround - 1]; // == 1 if y is the
only wraparound axis, or 2 otherwise.
+            start.height = axis.getMaximumValue() - y;
+            next.y       = axis.getMinimumValue();
+            next.height += y - next.y;
+        }
+        if (isWrapAround == 3) {
+            /*
+             * If there is a wraparound along both axes, copy the values.
+             * The (x) and (y) labels indicate which values to copy.
+             *
+             *      (y) R1 │   │ R0
+             *    ─────────┘   └─────────
+             *    ─────────┐   ┌─────────
+             *    (x,y) R3 │   │ R2 (x)
+             */
+            rect[1].height = rect[0].height;
+            rect[2].width  = rect[0].width;
+            rect[3].x      = rect[1].x;
+            rect[3].width  = rect[1].width;
+            rect[3].y      = rect[2].y;
+            rect[3].height = rect[2].height;
+        }
+        return rect;
+    }
+
+    /**
      * Tests if a specified coordinate is inside the boundary of this envelope. If it least
one
      * of the given ordinate value is {@link java.lang.Double#NaN NaN}, then this method
returns
      * {@code false}.
@@ -580,7 +687,7 @@ public class Envelope2D extends Rectangl
      */
     @Override
     public boolean contains(final double rx, final double ry, final double rw, final double
rh) {
-        for (int i=0; i!=2; i++) {
+        for (int i=0; i!=DIMENSION; i++) {
             final double min0, min1, span0, span1;
             if (i == 0) {
                 min0 =  x;  span0 = width;
@@ -649,7 +756,7 @@ public class Envelope2D extends Rectangl
      */
     @Override
     public boolean intersects(final double rx, final double ry, final double rw, final double
rh) {
-        for (int i=0; i!=2; i++) {
+        for (int i=0; i!=DIMENSION; i++) {
             final double min0, min1, span0, span1;
             if (i == 0) {
                 min0 =  x;  span0 = width;
@@ -693,7 +800,7 @@ public class Envelope2D extends Rectangl
     public Envelope2D createIntersection(final Rectangle2D rect) {
         final Envelope2D env = (rect instanceof Envelope2D) ? (Envelope2D) rect : null;
         final Envelope2D inter = new Envelope2D(crs, NaN, NaN, NaN, NaN);
-        for (int i=0; i!=2; i++) {
+        for (int i=0; i!=DIMENSION; i++) {
             final double min0, min1, span0, span1;
             if (i == 0) {
                 min0  = x;
@@ -779,7 +886,7 @@ public class Envelope2D extends Rectangl
     @Override
     public void add(final Rectangle2D rect) {
         final Envelope2D env = (rect instanceof Envelope2D) ? (Envelope2D) rect : null;
-        for (int i=0; i!=2; i++) {
+        for (int i=0; i!=DIMENSION; i++) {
             final double min0, min1, span0, span1;
             if (i == 0) {
                 min0  = x;

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/Envelope2DTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/Envelope2DTest.java?rev=1507311&r1=1507310&r2=1507311&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/Envelope2DTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/Envelope2DTest.java
[UTF-8] Fri Jul 26 13:48:39 2013
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.geometry;
 
+import java.awt.geom.Rectangle2D;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -27,13 +29,14 @@ import static org.apache.sis.geometry.Ab
 
 /**
  * Tests the {@link Envelope2D} class.
- * Most of tests are actually performed by {@link AbstractEnvelopeTest}, which compare
+ * Most tests are actually performed by {@link AbstractEnvelopeTest}, which compare
  * {@link GeneralEnvelope} results with {@code Envelope2D} results for ensuring consistency.
  * This class adds only some tests that are specific to {@code Envelope2D} instances.
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Ross Laidlaw
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @DependsOn(AbstractEnvelopeTest.class)
@@ -48,4 +51,60 @@ public final strictfp class Envelope2DTe
         assertNotSame(e1, e2);
         validate(e2);
     }
+
+    /**
+     * Tests {@link Envelope2D#toRectangles()} on an empty envelope.
+     *
+     * @since 0.4
+     */
+    @Test
+    public void testToRectanglesOnEmptyEnvelope() {
+        final Envelope2D envelope = new Envelope2D(WGS84, 0, 0, 0, 0);
+        assertEquals(0, envelope.toRectangles().length);
+    }
+
+    /**
+     * Tests {@link Envelope2D#toRectangles()} on a simple envelope having no wraparound
axis.
+     *
+     * @since 0.4
+     */
+    @Test
+    public void testToRectanglesOnSimpleEnvelope() {
+        final Envelope2D envelope = new Envelope2D(WGS84, -20, -10, 50, 40);
+        final Rectangle2D[] rectangles = envelope.toRectangles();
+        assertEquals(1, rectangles.length);
+        final Rectangle2D r = rectangles[0];
+        assertNotSame("toRectangles() shall copy the envelope.", envelope, r);
+        assertEquals(-20.0, r.getX(),      0.0);
+        assertEquals(-10.0, r.getY(),      0.0);
+        assertEquals( 50.0, r.getWidth(),  0.0);
+        assertEquals( 40.0, r.getHeight(), 0.0);
+    }
+
+    /**
+     * Tests {@link Envelope2D#toRectangles()} on an envelope crossing the anti-meridian.
+     * The longitude range in this test is [155 … -150].
+     *
+     * @since 0.4
+     */
+    @Test
+    @DependsOnMethod("testToRectanglesOnSimpleEnvelope")
+    @org.junit.Ignore("Needs implementation of WGS84 CRS.")
+    public void testToRectanglesOverAntiMeridian() {
+        final Envelope2D envelope = new Envelope2D(WGS84, 155, 0, -150 - 155, 50);
+        final Rectangle2D[] rectangles = envelope.toRectangles();
+        assertEquals(2, rectangles.length);
+        final Rectangle2D r0 = rectangles[0];
+        final Rectangle2D r1 = rectangles[1];
+
+        assertEquals( 155.0, r0.getX(),      0.0);
+        assertEquals(   0.0, r0.getY(),      0.0);
+        assertEquals(  25.0, r0.getWidth(),  0.0);
+        assertEquals(  50.0, r0.getHeight(), 0.0);
+
+        assertEquals(-180.0, r1.getX(),      0.0);
+        assertEquals(   0.0, r1.getY(),      0.0);
+        assertEquals(  30.0, r1.getWidth(),  0.0);
+        assertEquals(  50.0, r1.getHeight(), 0.0);
+    }
 }



Mime
View raw message