sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1786756 - in /sis/branches/JDK8/core: sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/ sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/ sis-referencing/src/main/java/org/a...
Date Mon, 13 Mar 2017 18:40:33 GMT
Author: desruisseaux
Date: Mon Mar 13 18:40:33 2017
New Revision: 1786756

URL: http://svn.apache.org/viewvc?rev=1786756&view=rev
Log:
Fix the polar cases of MGRS iterators and add tests.

Modified:
    sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
    sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/LocationViewer.java
    sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java

Modified: sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java?rev=1786756&r1=1786755&r2=1786756&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
[UTF-8] Mon Mar 13 18:40:33 2017
@@ -32,6 +32,7 @@ import org.opengis.referencing.crs.Coord
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransform2D;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.internal.referencing.provider.TransverseMercator;
@@ -595,6 +596,13 @@ public class MilitaryGridReferenceSystem
          * If the CRS is geographic, the envelope is allowed to span the anti-meridian.
          * The MGRS references may be returned in any iteration order.
          *
+         * <div class="note"><b>Possible evolution:</b>
+         * current implementation does not clip the cells to UPS/UTM valid areas before to
test for intersection
+         * with {@code areaOfInterest}. Consequently the iterator may return slightly more
cells than expected.
+         * A future version may filter the cells more accurately. If an application needs
the same set of cells
+         * than what current the implementation returns, it can invoke <code>{@linkplain
#setClipToValidArea
+         * setClipToValidArea}(false)</code> for preserving current behavior in future
Apache SIS versions.</div>
+         *
          * @param  areaOfInterest  envelope of desired MGRS references.
          * @return an iterator over MGRS references intersecting the given area of interest.
          * @throws TransformException if an error occurred while transforming the area of
interest.
@@ -614,6 +622,13 @@ public class MilitaryGridReferenceSystem
          * If the CRS is geographic, the envelope is allowed to span the anti-meridian.
          * The MGRS references may be returned in any order.
          *
+         * <div class="note"><b>Possible evolution:</b>
+         * current implementation does not clip the cells to UPS/UTM valid areas before to
test for intersection
+         * with {@code areaOfInterest}. Consequently the iterator may return slightly more
cells than expected.
+         * A future version may filter the cells more accurately. If an application needs
the same set of cells
+         * than what current the implementation returns, it can invoke <code>{@linkplain
#setClipToValidArea
+         * setClipToValidArea}(false)</code> for preserving current behavior in future
Apache SIS versions.</div>
+         *
          * @param  areaOfInterest  envelope of desired MGRS references.
          * @param  parallel        {@code true} for a parallel stream, or {@code false} for
a sequential stream.
          * @return a stream of MGRS references intersecting the given area of interest.
@@ -889,7 +904,7 @@ public class MilitaryGridReferenceSystem
          * The first <var>northing</var> value to use in iteration.
          * The {@link #gridY} value will need to be reset to this value for each new column.
          */
-        private final int yStart;
+        private int yStart;
 
         /**
          * The {@link #gridY} values where to stop iteration, exclusive. Invariants:
@@ -1050,7 +1065,7 @@ public class MilitaryGridReferenceSystem
              * Now we can project that area to the CRS managed by this iterator. All values
after projection
              * should be positive (because UPS and UTM are designed that way).
              */
-            final MathTransform2D op = (MathTransform2D) CRS.findOperation(sourceCRS, targetCRS,
null).getMathTransform();
+            final CoordinateOperation op = CRS.findOperation(sourceCRS, targetCRS, null);
             final Rectangle2D bounds = Shapes2D.transform(op, areaOfInterest, null);
             gridX = (((int)          (bounds.getMinX() / step))) * step;                
   // Inclusive
             gridY = (((int)          (bounds.getMinY() / step))) * step;
@@ -1064,7 +1079,8 @@ public class MilitaryGridReferenceSystem
             if (zone != Encoder.POLE) {
                 downward = (encoder.crsZone < 0);           // Upward in UTM North zones,
downward in UTM South zones.
             } else {
-                downward = gridY < PolarStereographicA.UPS_SHIFT;    // Upward ONLY if
AOI is fully in the upper half.
+                downward = yEnd <= PolarStereographicA.UPS_SHIFT;  // Downward only if
AOI is fully in the lower half.
+                isSpecialCase = (gridX < PolarStereographicA.UPS_SHIFT);         // Can
not optimize left side of UPS.
             }
             if (downward) {
                 final int y = gridY;
@@ -1072,7 +1088,7 @@ public class MilitaryGridReferenceSystem
                 yEnd  = y    - step;
             }
             yStart    = gridY;
-            gridToAOI = op.inverse();
+            gridToAOI = (MathTransform2D) op.getMathTransform().inverse();
             /*
              * To be strict, we should also test that the region of interest does not intersect
both the upper half
              * and lower half of Universal Polar Stereographic (UPS) projection domain. We
do not check that because
@@ -1083,8 +1099,8 @@ public class MilitaryGridReferenceSystem
         }
 
         /**
-         * Creates an iterator for the upper half of a Universal Polar Stereographic (UPS)
projection,
-         * and modifies the given iterator for restricting it to the lower half of UPS projection.
+         * Creates an iterator for the lower half of a Universal Polar Stereographic (UPS)
projection,
+         * and modifies the given iterator for restricting it to the upper half of UPS projection.
          * This method is for {@link #trySplit()} usage only.
          */
         private IteratorOneZone(final IteratorOneZone other) {
@@ -1095,24 +1111,25 @@ public class MilitaryGridReferenceSystem
             optimize       = other.optimize;
             step           = other.step;
             gridX          = other.gridX;
-            gridY          = other.gridY;
             xCenter        = other.xCenter;
             xEnd           = other.xEnd;
-            yEnd           = other.yEnd;
-            yStart         = 0;                 // This iterator will be for the upper half.
-            other.yEnd     = 0;                 // Other iterator will be for the lower half.
-            downward       = false;
-            assert other.downward;              // Fail if the other iterator is not for
lower half.
+            yEnd           = other.yStart - step;                   // Bottom of the zone
to iterate, exclusive.
+            yStart         = PolarStereographicA.UPS_SHIFT - step;  // Top of the zone to
iterate, inclusive.
+            other.yStart   = PolarStereographicA.UPS_SHIFT;         // Other iterator will
be for the upper half.
+            other.gridY    = other.yStart;
+            gridY          = yStart;
+            downward       = true;
+            assert !other.downward;                                 // Fail if the other
iterator is not for upper half.
         }
 
         /**
          * If this iterator intersects both the upper and lower half on UPS domain, returns
an iterator for the
-         * upper half and modify this iterator for the lower half. This method <strong>must</strong>
be invoked
+         * lower half and modifies this iterator for the upper half. This method <strong>must</strong>
be invoked
          * before {@code IteratorOneZone} can be used.
          */
         @Override
         public Spliterator<String> trySplit() {
-            if (downward && Math.abs(encoder.crsZone) == Encoder.POLE &&
gridY >= PolarStereographicA.UPS_SHIFT) {
+            if (!downward && Math.abs(encoder.crsZone) == Encoder.POLE &&
gridY < PolarStereographicA.UPS_SHIFT) {
                 return new IteratorOneZone(this);
             }
             return null;
@@ -1194,13 +1211,11 @@ public class MilitaryGridReferenceSystem
                     cell.setRect(Shapes2D.transform(gridToAOI, cell, cell));
                     if (cell.intersects(areaOfInterest)) {          // Must be invoked on
Envelope2D implementation.
                         int x = gridX;
-                        if (x < xCenter) {
-                            // Use the 'x' value closest to projection center (see above
comment for explanation),
-                            // minus one metre for preventing the position to be considered
as part of next cell.
-                            x += step - 1;
-                        }
+                        int y = gridY;
+                        if (x < xCenter) x += step - 1;
+                        if (downward)    y += step - 1;
                         normalized.setOrdinate(0, x);
-                        normalized.setOrdinate(1, gridY);
+                        normalized.setOrdinate(1, y);
                         String ref = encoder.encode(this, normalized, false, separator, digits);
                         if (ref != null) {
                             /*
@@ -1212,12 +1227,7 @@ public class MilitaryGridReferenceSystem
                             latitudeBand = encoder.latitudeBand;
                             if (latitudeBand != previous && previous != 0) {
                                 pending = ref;
-                                int y = gridY - 1;
-                                if (downward) {
-                                    y += step;              // If iterating downward, the
previous cell is upward.
-                                    previous = latitudeBand;
-                                }
-                                normalized.setOrdinate(1, y);
+                                normalized.setOrdinate(1, y + (downward ? +1 : -1));
                                 ref = encoder.encode(this, normalized, false, separator,
digits);
                                 if (ref == null || encoder.latitudeBand == previous) {
                                     ref = pending;  // No result or same result than previous
iteration - cancel.
@@ -1273,8 +1283,8 @@ public class MilitaryGridReferenceSystem
         @Debug
         @Override
         public String toString() {
-            return org.apache.sis.internal.util.Utilities.toString(getClass(),
-                    "zone", encoder.crsZone, "gridX", gridX, "gridY", gridY);
+            return org.apache.sis.internal.util.Utilities.toString(getClass(), "zone", encoder.crsZone,
+                    "downward", downward, "yStart", yStart, "yEnd", yEnd, "gridX", gridX,
"xEnd", xEnd);
         }
     }
 

Modified: sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/LocationViewer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/LocationViewer.java?rev=1786756&r1=1786755&r2=1786756&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/LocationViewer.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/LocationViewer.java
[UTF-8] Mon Mar 13 18:40:33 2017
@@ -56,7 +56,7 @@ import org.apache.sis.util.Debug;
 @SuppressWarnings("serial")
 public final class LocationViewer extends JPanel {
     /**
-     * Shows the locations tested by {@link MilitaryGridReferenceSystemTest#testIteratorNorthUTM()}.
+     * Shows the locations tested by {@code MilitaryGridReferenceSystemTest.testIterator()}
methods.
      *
      * @param  args  ignored.
      * @throws Exception if an error occurred while transforming an envelope to the display
CRS.
@@ -70,14 +70,16 @@ public final class LocationViewer extend
              * Include the Norway special case: in latitude band V, zone 32 is widened at
the expense of zone 31.
              */
             case 1: {
-                show(coder, new Envelope2D(CommonCRS.defaultGeographic(), 5, 47, 8, 10),
CommonCRS.WGS84.universal(1, 9));
+                show("UTM zones 31, 32 and 33 North", coder,
+                     new Envelope2D(CommonCRS.defaultGeographic(), 5, 47, 8, 10), CommonCRS.WGS84.universal(1,
9));
                 break;
             }
             /*
              * UTM South: 3 zones (31, 32 and 33) and 2 latitude bands (G and H).
              */
             case 2: {
-                show(coder, new Envelope2D(CommonCRS.defaultGeographic(), 5, -42, 8, 4),
CommonCRS.WGS84.universal(1, 9));
+                show("UTM zones 31, 32 and 33 South", coder,
+                     new Envelope2D(CommonCRS.defaultGeographic(), 5, -42, 8, 4), CommonCRS.WGS84.universal(1,
9));
                 break;
             }
             /*
@@ -87,14 +89,40 @@ public final class LocationViewer extend
                 final GeneralEnvelope ge = new GeneralEnvelope(CommonCRS.defaultGeographic());
                 ge.setRange(0, 170, -175);
                 ge.setRange(1,  40,   42);
-                show(coder, ge, null);
+                show("15° of longitude spanning the anti-meridian", coder, ge, null);
                 break;
             }
             /*
-             * Polar case.
+             * Complete North pole case surrounded by part of V latitude band.
+             * This include the Svalbard special case in zones 31 to 37.
              */
             case 4: {
-                show(coder, new Envelope2D(CommonCRS.defaultGeographic(), -180, 80, 360,
10), CommonCRS.WGS84.universal(90, 9));
+                show("North pole surrounded by V latitude band", coder,
+                     new Envelope2D(CommonCRS.defaultGeographic(), -180, 80, 360, 10), CommonCRS.WGS84.universal(90,
0));
+                break;
+            }
+            /*
+             * Complete South pole case surrounded by one latitude band.
+             */
+            case 5: {
+                show("South pole surrounded by C latitude band",
+                     coder, new Envelope2D(CommonCRS.defaultGeographic(), -180, -90, 360,
12), CommonCRS.WGS84.universal(-90, 0));
+                break;
+            }
+            /*
+             * Partial North pole case.
+             */
+            case 6: {
+                show("10°W to 70°E close to North pole", coder,
+                     new Envelope2D(CommonCRS.defaultGeographic(), -10, 85, 80, 5), CommonCRS.WGS84.universal(90,
0));
+                break;
+            }
+            /*
+             * Partial South pole case with zone UTM zones.
+             */
+            case 7: {
+                show("70°W to 120°W close to South pole", coder,
+                     new Envelope2D(CommonCRS.defaultGeographic(), -120, -83, 50, 5), CommonCRS.WGS84.universal(-90,
0));
                 break;
             }
         }
@@ -135,13 +163,14 @@ public final class LocationViewer extend
     /**
      * Shows all locations in the given area of interest.
      *
+     * @param  title           the window title.
      * @param  coder           the encoder to use for computing locations and their envelopes.
      * @param  areaOfInterest  the geographic or projected area where to get locations.
      * @param  displayCRS      the CRS to use for displaying the location shapes, or {@code
null} for the envelope CRS.
      * @throws FactoryException if a transformation to the display CRS can not be obtained.
      * @throws TransformException if an error occurred while transforming an envelope.
      */
-    public static void show(final MilitaryGridReferenceSystem.Coder coder, final Envelope
areaOfInterest,
+    public static void show(final String title, final MilitaryGridReferenceSystem.Coder coder,
final Envelope areaOfInterest,
             SingleCRS displayCRS) throws FactoryException, TransformException
     {
         if (displayCRS == null) {
@@ -149,7 +178,7 @@ public final class LocationViewer extend
         }
         final LocationViewer viewer = new LocationViewer(displayCRS);
         viewer.addLocations(coder, areaOfInterest);
-        final JFrame frame = new JFrame("Locations viewer (debug)");
+        final JFrame frame = new JFrame(title);
         frame.getContentPane().add(viewer);
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setSize(600, 600);

Modified: sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java?rev=1786756&r1=1786755&r2=1786756&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing-by-identifiers/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
[UTF-8] Mon Mar 13 18:40:33 2017
@@ -704,6 +704,7 @@ public final strictfp class MilitaryGrid
      * @throws TransformException if an error occurred while computing the coordinate.
      */
     @Test
+    @DependsOnMethod("testEncodeUTM")
     public void testIteratorOverAntiMeridian() throws TransformException {
         final GeneralEnvelope areaOfInterest = new GeneralEnvelope(CommonCRS.defaultGeographic());
         areaOfInterest.setRange(0, 170, -175);
@@ -716,10 +717,60 @@ public final strictfp class MilitaryGrid
     }
 
     /**
+     * Tests iterating over part of North pole, in an area between 10°W to 70°E.
+     * This area is restricted to the lower part of UPS projection, which allow
+     * {@code IteratorAllZones} to simplify to a single {@code IteratorOneZone}.
+     *
+     * <div class="note"><b>Tip:</b> in case of test failure, see {@link
LocationViewer} as a debugging tool.</div>
+     *
+     * @throws TransformException if an error occurred while computing the coordinate.
+     */
+    @Test
+    @DependsOnMethod("testEncodeUPS")
+    public void testIteratorNorthPole() throws TransformException {
+        testIterator(new Envelope2D(CommonCRS.defaultGeographic(), -10, 85, 80, 5), Arrays.asList(
+            "YZG", "ZAG", "ZBG", "ZCG",
+            "YZF", "ZAF", "ZBF", "ZCF", "ZFF", "ZGF", "ZHF",
+            "YZE", "ZAE", "ZBE", "ZCE", "ZFE", "ZGE", "ZHE",
+            "YZD", "ZAD", "ZBD", "ZCD", "ZFD", "ZGD",
+            "YZC", "ZAC", "ZBC", "ZCC", "ZFC",
+            "YZB", "ZAB", "ZBB", "ZCB"));
+    }
+
+    /**
+     * Tests iterating over part of South pole, both lower and upper parts of UPS projection
+     * together with some UTM zones. This is a test mixing a bit of everything together.
+     *
+     * <div class="note"><b>Tip:</b> in case of test failure, see {@link
LocationViewer} as a debugging tool.</div>
+     *
+     * @throws TransformException if an error occurred while computing the coordinate.
+     */
+    @Test
+    @DependsOnMethod({"testEncodeUPS", "testEncodeUTM"})
+    public void testIteratorSouthPole() throws TransformException {
+        testIterator(new Envelope2D(CommonCRS.defaultGeographic(), -120, -83, 50, 5), Arrays.asList(
+                   "AKR", "ALR", "APR",
+                   "AKQ", "ALQ", "APQ", "AQQ",
+            "AJP", "AKP", "ALP", "APP", "AQP",
+            "AJN", "AKN", "ALN", "APN", "AQN",
+            "AJM", "AKM", "ALM", "APM", "AQM",
+            "AJL", "AKL", "ALL", "APL", "AQL",
+                   "AKK", "ALK", "APK", "AQK",
+                   "AKJ", "ALJ", "APJ", "AQJ", "ARJ",
+                   "AKH", "ALH", "APH", "AQH", "ARH",
+                          "ALG", "APG",
+
+            "11CMP", "11CNP", "12CVU", "12CWU", "13CDP", "13CEP", "14CMU", "14CNU", "15CVP",
"15CWP", "16CDU", "16CEU", "17CMP", "17CNP", "18CVU", "18CWU", "19CDP",
+            "11CMN", "11CNN", "12CVT", "12CWT", "13CDN", "13CEN", "14CMT", "14CNT", "15CVN",
"15CWN", "16CDT", "16CET", "17CMN", "17CNN", "18CVT", "18CWT", "19CDN",
+            "11CMM", "11CNM", "12CVS", "12CWS", "13CDM", "13CEM", "14CMS", "14CNS", "15CVM",
"15CWM", "16CDS", "16CES", "17CMM", "17CNM", "18CVS", "18CWS", "19CDM"));
+    }
+
+    /**
      * Implementation of {@link #testIteratorUTM()}.
      */
     private static void testIterator(final Envelope areaOfInterest, final List<String>
expected) throws TransformException {
         final MilitaryGridReferenceSystem.Coder coder = coder();
+        coder.setClipToValidArea(false);
         coder.setPrecision(100000);
         /*
          * Test sequential iteration using iterator.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java?rev=1786756&r1=1786755&r2=1786756&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/Shapes2D.java
[UTF-8] Mon Mar 13 18:40:33 2017
@@ -386,6 +386,7 @@ public final class Shapes2D extends Stat
      * @see #transform(MathTransform2D, Rectangle2D, Rectangle2D)
      * @see Envelopes#transform(CoordinateOperation, Envelope)
      */
+    @SuppressWarnings("null")
     public static Rectangle2D transform(final CoordinateOperation operation,
                                         final Rectangle2D         envelope,
                                               Rectangle2D         destination)



Mime
View raw message