sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1508383 - in /sis/branches/JDK7/core/sis-referencing/src: main/java/org/apache/sis/geometry/AbstractEnvelope.java test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java test/java/org/apache/sis/geometry/Envelope2DTest.java
Date Tue, 30 Jul 2013 10:48:57 GMT
Author: desruisseaux
Date: Tue Jul 30 10:48:57 2013
New Revision: 1508383

URL: http://svn.apache.org/r1508383
Log:
Implement AbstractEnvelope.toSimpleEnvelopes(), which is equivalent to Envelope2D.toRectangles()
in a more general way.

Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.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/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1508383&r1=1508382&r2=1508383&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
[UTF-8] Tue Jul 30 10:48:57 2013
@@ -82,6 +82,7 @@ import java.util.Objects;
  *   <li>{@link #getMaximum(int)}</li>
  *   <li>{@link #getMedian(int)}</li>
  *   <li>{@link #getSpan(int)}</li>
+ *   <li>{@link #toSimpleEnvelopes()}</li>
  *   <li>{@link #contains(DirectPosition)}</li>
  *   <li>{@link #contains(Envelope, boolean)}</li>
  *   <li>{@link #intersects(Envelope, boolean)}</li>
@@ -112,6 +113,12 @@ import java.util.Objects;
  */
 public abstract class AbstractEnvelope implements Envelope {
     /**
+     * An empty array of envelopes, to be returned by {@link #toSimpleEnvelopes()}
+     * when en envelope is empty.
+     */
+    private static final Envelope[] EMPTY = new Envelope[0];
+
+    /**
      * Constructs an envelope.
      */
     protected AbstractEnvelope() {
@@ -496,6 +503,111 @@ public abstract class AbstractEnvelope i
     }
 
     /**
+     * Returns this envelope as an array of simple (without wraparound) envelopes.
+     * The length of the returned array depends on the number of dimensions where a
+     * {@linkplain org.opengis.referencing.cs.RangeMeaning#WRAPAROUND wraparound} range is
found.
+     * Typically, wraparound occurs only in the range of longitude values, when the range
crosses
+     * the anti-meridian (a.k.a. date line). However this implementation will take in account
any
+     * axis having wraparound {@linkplain CoordinateSystemAxis#getRangeMeaning() range meaning}.
+     *
+     * <p>Special cases:</p>
+     *
+     * <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 {@code this}
+     *       in an array of length 1. This envelope is <strong>not</strong> cloned.</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 simple envelopes.
+     *   <li>While uncommon, the envelope could theoretically crosses the limit of
other axis having
+     *       wraparound range meaning. If wraparound occur along <var>n</var>
axes, then this method
+     *       represents this envelope as 2ⁿ separated simple envelopes.
+     * </ul>
+     *
+     * @return A representation of this envelope as an array of non-empty envelope.
+     *
+     * @see Envelope2D#toRectangles()
+     *
+     * @since 0.4
+     */
+    public Envelope[] toSimpleEnvelopes() {
+        long isWrapAround = 0; // A bitmask of the dimensions having a "wrap around" behavior.
+        CoordinateReferenceSystem crs = null;
+        final int dimension = getDimension();
+        for (int i=0; i!=dimension; i++) {
+            final double span = getUpper(i) - getLower(i); // Do not use getSpan(i).
+            if (!(span > 0)) { // Use '!' for catching NaN.
+                if (!isNegative(span)) {
+                    return EMPTY; // Span is positive zero.
+                }
+                if (crs == null) {
+                    crs = getCoordinateReferenceSystem();
+                }
+                if (!isWrapAround(crs, i)) {
+                    return EMPTY;
+                }
+                if (i >= Long.SIZE) {
+                    // Actually the limit in our current implementation is not the number
of axes, but the index of
+                    // axes where a wraparound has been found. However we consider that having
more than 64 axes in
+                    // a CRS is unusual enough for not being worth to make the distinction
in the error message.
+                    throw new IllegalStateException(Errors.format(Errors.Keys.ExcessiveListSize_2,
"axis", dimension));
+                }
+                isWrapAround |= (1L << i);
+            }
+        }
+        /*
+         * The number of simple envelopes is 2ⁿ where n is the number of wraparound found.
In most
+         * cases, isWrapAround == 0 so we have an array of length 1 containing only this
envelope.
+         */
+        final int bitCount = Long.bitCount(isWrapAround);
+        if (bitCount >= Integer.SIZE - 1) {
+            // Should be very unusual, but let be paranoiac.
+            throw new IllegalStateException(Errors.format(Errors.Keys.ExcessiveListSize_2,
"wraparound", bitCount));
+        }
+        final Envelope[] envelopes = new Envelope[1 << bitCount];
+        if (envelopes.length == 1) {
+            envelopes[0] = this;
+        } else {
+            /*
+             * Need to create at least 2 envelopes. Instantiate now all envelopes with ordinate
values
+             * initialized to a copy of this envelope. We will write directly in their internal
arrays later.
+             */
+            double[] c = new double[dimension * 2];
+            for (int i=0; i<dimension; i++) {
+                c[i            ] = getLower(i);
+                c[i + dimension] = getUpper(i);
+            }
+            final double[][] ordinates = new double[envelopes.length][];
+            for (int i=0; i<envelopes.length; i++) {
+                final GeneralEnvelope envelope = new GeneralEnvelope(i == 0 ? c : c.clone());
+                envelope.crs = crs;
+                envelopes[i] = envelope;
+                ordinates[i] = envelope.ordinates;
+            }
+            /*
+             * Assign the minimum and maximum ordinate values in the dimension where a wraparound
has been found.
+             * The 'for' loop below iterates only over the 'i' values for which the 'isWrapAround'
bit is set to 1.
+             */
+            int mask = 1; // For identifying whether we need to set the lower or the upper
ordinate.
+            final CoordinateSystem cs = crs.getCoordinateSystem(); // Should not be null
at this point.
+            for (int i; (i = Long.numberOfTrailingZeros(isWrapAround)) != Long.SIZE; isWrapAround
&= ~(1L << i)) {
+                final CoordinateSystemAxis axis = cs.getAxis(i);
+                final double min = axis.getMinimumValue();
+                final double max = axis.getMaximumValue();
+                for (int j=0; j<ordinates.length; j++) {
+                    c = ordinates[j];
+                    if ((j & mask) == 0) {
+                        c[i + dimension] = max;
+                    } else {
+                        c[i] = min;
+                    }
+                }
+                mask <<= 1;
+            }
+        }
+        return envelopes;
+    }
+
+    /**
      * Determines whether or not this envelope is empty. An envelope is non-empty only if
it has
      * at least one {@linkplain #getDimension() dimension}, and the {@linkplain #getSpan(int)
span}
      * is greater than 0 along all dimensions. Note that {@link #isAllNaN()} always returns

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java?rev=1508383&r1=1508382&r2=1508383&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
[UTF-8] Tue Jul 30 10:48:57 2013
@@ -20,6 +20,7 @@ import java.awt.geom.Rectangle2D;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.referencing.crs.GeographicCRS;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Ignore;
@@ -36,7 +37,7 @@ import static org.apache.sis.referencing
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-3.20)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @DependsOn(GeneralDirectPositionTest.class)
@@ -44,7 +45,7 @@ public final strictfp class AbstractEnve
     /**
      * Tolerance threshold for strict floating point comparisons.
      */
-    private static final double STRICT = 0;
+    static final double STRICT = 0;
 
     /**
      * Enumeration of implementations to be tested.
@@ -459,4 +460,71 @@ public final strictfp class AbstractEnve
             verifyInvariants(type, envelope);
         }
     }
+
+    /**
+     * Tests {@link AbstractEnvelope#toSimpleEnvelopes()} on an empty envelope.
+     *
+     * @since 0.4
+     */
+    @Test
+    public void testToSimpleEnvelopesOnEmptyEnvelope() {
+        for (int type=0; type<LAST; type++) {
+            if (type != RECTANGLE) {
+                final AbstractEnvelope envelope = (AbstractEnvelope) create(type, 0, 0, 0,
0);
+                assertEquals(0, envelope.toSimpleEnvelopes().length);
+            }
+        }
+    }
+
+    /**
+     * Tests {@link AbstractEnvelope#toSimpleEnvelopes()} on a simple envelope having no
wraparound axis.
+     *
+     * @since 0.4
+     */
+    @Test
+    @DependsOnMethod("testToSimpleEnvelopesOnEmptyEnvelope")
+    public void testToSimpleEnvelopesOnSimpleEnvelope() {
+        for (int type=0; type<LAST; type++) {
+            if (type != RECTANGLE) {
+                final AbstractEnvelope envelope = (AbstractEnvelope) create(type, -20, 30,
-10, 15);
+                final Envelope[] simples = envelope.toSimpleEnvelopes();
+                assertEquals(1, simples.length);
+                assertSame(envelope, simples[0]);
+            }
+        }
+    }
+
+    /**
+     * Tests {@link AbstractEnvelope#toSimpleEnvelopes()} on a simple envelope having no
wraparound axis.
+     *
+     * @since 0.4
+     */
+    @Test
+    @DependsOnMethod("testToSimpleEnvelopesOnEmptyEnvelope")
+    @Ignore("The tested envelope needs to be associated to CRS:84")
+    public void testToSimpleEnvelopesOverAntiMeridian() {
+        for (int type=0; type<LAST; type++) {
+            if (type != RECTANGLE) {
+                final AbstractEnvelope envelope = (AbstractEnvelope) create(type, 155, -150,
0, 50);
+                final Envelope[] simples = envelope.toSimpleEnvelopes();
+                assertEquals(2, simples.length);
+                final AbstractEnvelope e0 = (AbstractEnvelope) simples[0];
+                final AbstractEnvelope e1 = (AbstractEnvelope) simples[1];
+
+                assertEquals( 155.0, e0.getLower(0), STRICT);
+                assertEquals(   0.0, e0.getLower(1), STRICT);
+                assertEquals( 180.0, e0.getUpper(0), STRICT);
+                assertEquals(  50.0, e0.getUpper(1), STRICT);
+                assertEquals(  25.0, e0.getSpan (0), STRICT);
+                assertEquals(  50.0, e0.getSpan (1), STRICT);
+
+                assertEquals(-180.0, e1.getLower(0), STRICT);
+                assertEquals(   0.0, e1.getLower(1), STRICT);
+                assertEquals(-150.0, e1.getUpper(0), STRICT);
+                assertEquals(  50.0, e1.getUpper(1), STRICT);
+                assertEquals(  30.0, e1.getSpan (0), STRICT);
+                assertEquals(  50.0, e1.getSpan (1), STRICT);
+            }
+        }
+    }
 }

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=1508383&r1=1508382&r2=1508383&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] Tue Jul 30 10:48:57 2013
@@ -25,6 +25,7 @@ import org.junit.Test;
 import static org.opengis.test.Validators.*;
 import static org.apache.sis.referencing.Assert.*;
 import static org.apache.sis.geometry.AbstractEnvelopeTest.WGS84;
+import static org.apache.sis.geometry.AbstractEnvelopeTest.STRICT;
 
 
 /**
@@ -75,10 +76,10 @@ public final strictfp class Envelope2DTe
         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);
+        assertEquals(-20.0, r.getX(),      STRICT);
+        assertEquals(-10.0, r.getY(),      STRICT);
+        assertEquals( 50.0, r.getWidth(),  STRICT);
+        assertEquals( 40.0, r.getHeight(), STRICT);
     }
 
     /**
@@ -89,7 +90,7 @@ public final strictfp class Envelope2DTe
      */
     @Test
     @DependsOnMethod("testToRectanglesOnSimpleEnvelope")
-    @org.junit.Ignore("Needs implementation of WGS84 CRS.")
+    @org.junit.Ignore("The tested envelope needs to be associated to CRS:84")
     public void testToRectanglesOverAntiMeridian() {
         final Envelope2D envelope = new Envelope2D(WGS84, 155, 0, -150 - 155, 50);
         final Rectangle2D[] rectangles = envelope.toRectangles();
@@ -97,14 +98,14 @@ public final strictfp class Envelope2DTe
         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);
+        assertEquals( 155.0, r0.getX(),      STRICT);
+        assertEquals(   0.0, r0.getY(),      STRICT);
+        assertEquals(  25.0, r0.getWidth(),  STRICT);
+        assertEquals(  50.0, r0.getHeight(), STRICT);
+
+        assertEquals(-180.0, r1.getX(),      STRICT);
+        assertEquals(   0.0, r1.getY(),      STRICT);
+        assertEquals(  30.0, r1.getWidth(),  STRICT);
+        assertEquals(  50.0, r1.getHeight(), STRICT);
     }
 }



Mime
View raw message