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);
+ }
}
|