You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2017/02/22 18:58:36 UTC
svn commit: r1784054 - in /sis/branches/JDK8/core/sis-referencing/src:
main/java/org/apache/sis/internal/referencing/provider/
main/java/org/apache/sis/referencing/gazetteer/
test/java/org/apache/sis/referencing/gazetteer/
Author: desruisseaux
Date: Wed Feb 22 18:58:36 2017
New Revision: 1784054
URL: http://svn.apache.org/viewvc?rev=1784054&view=rev
Log:
Implement MGRS encoding of polar coordinates.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java?rev=1784054&r1=1784053&r2=1784054&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PolarStereographicA.java [UTF-8] Wed Feb 22 18:58:36 2017
@@ -110,6 +110,11 @@ public final class PolarStereographicA e
}
/**
+ * False Easting and false Northing value used in Universal Polar Stereographic (UPS) projections.
+ */
+ public static final double UPS_SHIFT = 2000000;
+
+ /**
* Sets the parameter values for a Universal Polar Stereographic projection
* and returns a suggested conversion name.
*
@@ -132,10 +137,10 @@ public final class PolarStereographicA e
*/
public static String setParameters(final ParameterValueGroup group, final boolean north) {
group.parameter(Constants.LATITUDE_OF_ORIGIN).setValue(north ? Latitude.MAX_VALUE : Latitude.MIN_VALUE, Units.DEGREE);
- group.parameter(Constants.CENTRAL_MERIDIAN) .setValue(0, Units.DEGREE);
- group.parameter(Constants.SCALE_FACTOR) .setValue(0.994, Units.UNITY);
- group.parameter(Constants.FALSE_EASTING) .setValue(2000000, Units.METRE);
- group.parameter(Constants.FALSE_NORTHING) .setValue(2000000, Units.METRE);
+ group.parameter(Constants.CENTRAL_MERIDIAN) .setValue(0, Units.DEGREE);
+ group.parameter(Constants.SCALE_FACTOR) .setValue(0.994, Units.UNITY);
+ group.parameter(Constants.FALSE_EASTING) .setValue(UPS_SHIFT, Units.METRE);
+ group.parameter(Constants.FALSE_NORTHING) .setValue(UPS_SHIFT, Units.METRE);
return "Universal Polar Stereographic " + (north ? "North" : "South");
}
@@ -145,16 +150,15 @@ public final class PolarStereographicA e
* responsibility to verify that the operation method is {@value #NAME}.
*
* @param group the Transverse Mercator projection parameters.
- * @return zone number (positive if North, negative if South),
- * or 0 if the given parameters are not for a zoned projection.
+ * @return +1 if UPS north, -1 if UPS south, or 0 if the given parameters are not for a UPS projection.
*
* @since 0.8
*/
public static int isUPS(final ParameterValueGroup group) {
- if (Numerics.epsilonEqual(group.parameter(Constants.SCALE_FACTOR) .doubleValue(Units.UNITY), 0.994, Numerics.COMPARISON_THRESHOLD) &&
- Numerics.epsilonEqual(group.parameter(Constants.FALSE_EASTING) .doubleValue(Units.METRE), 2000000, Formulas.LINEAR_TOLERANCE) &&
- Numerics.epsilonEqual(group.parameter(Constants.FALSE_NORTHING) .doubleValue(Units.METRE), 2000000, Formulas.LINEAR_TOLERANCE) &&
- Numerics.epsilonEqual(group.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(Units.DEGREE), 0, Formulas.ANGULAR_TOLERANCE))
+ if (Numerics.epsilonEqual(group.parameter(Constants.SCALE_FACTOR) .doubleValue(Units.UNITY), 0.994, Numerics.COMPARISON_THRESHOLD) &&
+ Numerics.epsilonEqual(group.parameter(Constants.FALSE_EASTING) .doubleValue(Units.METRE), UPS_SHIFT, Formulas.LINEAR_TOLERANCE) &&
+ Numerics.epsilonEqual(group.parameter(Constants.FALSE_NORTHING) .doubleValue(Units.METRE), UPS_SHIFT, Formulas.LINEAR_TOLERANCE) &&
+ Numerics.epsilonEqual(group.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(Units.DEGREE), 0, Formulas.ANGULAR_TOLERANCE))
{
final double \u03c6 = group.parameter(Constants.LATITUDE_OF_ORIGIN).doubleValue(Units.DEGREE);
if (Numerics.epsilonEqual(\u03c6, Latitude.MAX_VALUE, Formulas.ANGULAR_TOLERANCE)) return +1;
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java?rev=1784054&r1=1784053&r2=1784054&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java [UTF-8] Wed Feb 22 18:58:36 2017
@@ -116,6 +116,19 @@ public class MilitaryGridReferenceSystem
private static final char EXCLUDE_O = 'O';
/**
+ * The column letters used in Polar Stereographic Projections.
+ * They are letters A to Z but omitting I, O, D, E, M, N, V, W.
+ */
+ private static final byte[] POLAR_COLUMNS = {
+ 'A','B','C','F','G','H','J','K','L','P','Q','R','S','T','U','X','Y','Z'
+ };
+
+ /**
+ * Military Grid Reference System (MGRS) instance using the WGS84 datum.
+ */
+ public static final MilitaryGridReferenceSystem WGS84 = new MilitaryGridReferenceSystem(CommonCRS.WGS84);
+
+ /**
* The datum to which to transform the coordinate before formatting the MGRS reference.
* Only the datums enumerated in {@link CommonCRS} are currently supported.
*/
@@ -128,12 +141,18 @@ public class MilitaryGridReferenceSystem
final boolean avoidDatumChange;
/**
- * Creates a new Military Grid Reference System (MGRS) using the WGS84 datum.
+ * Value to add to the row number in order to have the "A" letter on the northernmost value on Greenwich meridian of
+ * the Universal Polar Stereographic (UPS) South projection. Value is initially zero and computed when first needed.
+ * This is derived from the bottom of the 100\u2009000-metres square labeled "A" in Grid Zone Designations A and B.
*/
- public MilitaryGridReferenceSystem() {
- datum = CommonCRS.WGS84;
- avoidDatumChange = false;
- }
+ private transient short southOffset;
+
+ /**
+ * Value to add to the row number in order to have the "A" letter on the southernmost value on Greenwich meridian of
+ * the Universal Polar Stereographic (UPS) North projection. Value is initially zero and computed when first needed.
+ * This is derived from the bottom of the 100\u2009000-metres square labeled "A" in Grid Zone Designations Y and Z.
+ */
+ private transient short northOffset;
/**
* Creates a new Military Grid Reference System (MGRS) using the specified datum.
@@ -148,6 +167,39 @@ public class MilitaryGridReferenceSystem
}
/**
+ * Returns the value to add to the row number in order to have the "A" letter on the southernmost or
+ * northernmost value on Greenwich meridian of the Universal Polar Stereographic (UPS) projection.
+ * If {@code south} is {@code true}, then this is computed from the northernmost value of UPS South;
+ * otherwise this is computed from the southernmost value of UPS North. This value is derived from
+ * the bottom of the 100\u2009000-metres square labeled "A" in Grid Zone Designations A, B, Y and Z.
+ */
+ final int polarOffset(final boolean south) throws TransformException {
+ // No need to synchronized; not a big deal if computed twice.
+ short origin = south ? southOffset : northOffset;
+ if (origin == 0) {
+ final DirectPosition2D position = new DirectPosition2D(
+ south ? TransverseMercator.Zoner.SOUTH_BOUNDS
+ : TransverseMercator.Zoner.NORTH_BOUNDS, 0);
+ double northing = datum.universal(position.x * 1.01, position.y).getConversionFromBase()
+ .getMathTransform().transform(position, position).getOrdinate(1);
+ if (south) {
+ northing = 2*PolarStereographicA.UPS_SHIFT - northing;
+ }
+ northing = Math.floor(northing / GRID_SQUARE_SIZE);
+ origin = (short) northing;
+ if (origin != northing) { // Paranoiac check (should never happen).
+ throw new GazetteerException();
+ }
+ if (south) {
+ southOffset = origin;
+ } else {
+ northOffset = origin;
+ }
+ }
+ return origin;
+ }
+
+ /**
* Returns a new object performing conversions between {@code DirectPosition} and MGRS references.
* The returned object is <strong>not</strong> thread-safe; a new instance must be created for
* each thread, or synchronization must be applied by the caller.
@@ -196,10 +248,10 @@ public class MilitaryGridReferenceSystem
private final Map<CoordinateReferenceSystem,Encoder> encoders;
/**
- * Temporary positions used by {@link Encoder}�only. References are kept for avoiding to
- * recreate those temporary objects for every reference to format.
+ * Temporary positions used for encoding and decoding. References are kept for avoiding
+ * to recreate those temporary objects for every reference to parse or format.
*/
- DirectPosition normalized, geographic;
+ transient DirectPosition normalized, geographic;
/**
* A buffer where to create reference, to be reused for each new reference.
@@ -289,6 +341,13 @@ public class MilitaryGridReferenceSystem
}
/**
+ * Bridge to {@link MilitaryGridReferenceSystem#polarOffset(boolean)} for the {@link Encoder} class.
+ */
+ final int polarOffset(final boolean south) throws TransformException {
+ return MilitaryGridReferenceSystem.this.polarOffset(south);
+ }
+
+ /**
* Returns the encoder for the given coordinate reference system.
*
* @throws IllegalArgumentException if the given CRS do not use one of the supported datums.
@@ -485,20 +544,20 @@ public class MilitaryGridReferenceSystem
*/
if (hasSquareIdentification) {
final MathTransform inverse = projection.inverse();
- DirectPosition check = inverse.transform(position, null);
- double \u03c6 = check.getOrdinate(0);
+ geographic = inverse.transform(position, geographic);
+ double \u03c6 = geographic.getOrdinate(0);
double delta = truncateLastLatitudeBand(\u03c6) - \u03c6s;
if ((\u03c6s >= 0) ? (delta < 0) : (delta > LATITUDE_BAND_HEIGHT)) {
position.y += Math.signum(\u03c6s) * (GRID_SQUARE_SIZE * GRID_ROW_COUNT);
- check = inverse.transform(position, check);
- delta = truncateLastLatitudeBand(\u03c6 = check.getOrdinate(0)) - \u03c6s;
+ geographic = inverse.transform(position, geographic);
+ delta = truncateLastLatitudeBand(\u03c6 = geographic.getOrdinate(0)) - \u03c6s;
}
/*
* Verification. We allow a tolerance on the UTM zone number for latitudes close to a pole
* because not all users may apply the UTM special rules for Norway and Svalbard. Anyway,
* using the neighbor zone at those high latitudes is less significant.
*/
- final int actual = TransverseMercator.Zoner.UTM.zone(\u03c6, check.getOrdinate(1));
+ final int actual = TransverseMercator.Zoner.UTM.zone(\u03c6, geographic.getOrdinate(1));
final boolean isHighLat = Math.abs(\u03c6) >= TransverseMercator.Zoner.NORWAY_BOUNDS;
final boolean isZoneValid = Math.abs(actual - zone) <= (isHighLat ? 1 : 0);
final boolean isBandValid = delta >= 0 && delta <= LATITUDE_BAND_HEIGHT;
@@ -639,14 +698,10 @@ public class MilitaryGridReferenceSystem
*/
static final class Encoder {
/**
- * Special {@link #crsZone} value for the UPS South (Universal Polar Stereographic) projection.
- */
- private static final int SOUTH_POLE = -1000;
-
- /**
- * Special {@link #crsZone} value for the UPS North (Universal Polar Stereographic) projection.
+ * Special {@link #crsZone} value for the UPS (Universal Polar Stereographic) projection.
+ * Positive value is used for North pole and negative value for South pole.
*/
- private static final int NORTH_POLE = 1000;
+ private static final int POLE = 100;
/**
* The datum to which to transform the coordinate before formatting the MGRS reference.
@@ -655,7 +710,7 @@ public class MilitaryGridReferenceSystem
private final CommonCRS datum;
/**
- * UTM zone of position CRS (negative for South hemisphere), or {@value #NORTH_POLE} or {@value #SOUTH_POLE}
+ * UTM zone of position CRS (negative for South hemisphere), or {@value #POLE} (negative of positive)
* if the CRS is a Universal Polar Stereographic projection, or 0 if the CRS is not a recognized projection.
* Note that this is not necessarily the same zone than the one to use for formatting any given coordinate in
* that projected CRS, since the {@link #zone(double, char)} method has special rules for some latitudes.
@@ -721,7 +776,7 @@ public class MilitaryGridReferenceSystem
if (IdentifiedObjects.isHeuristicMatchForName(method, TransverseMercator.NAME)) {
crsZone = TransverseMercator.Zoner.UTM.zone(projection.getParameterValues());
} else if (IdentifiedObjects.isHeuristicMatchForName(method, PolarStereographicA.NAME)) {
- crsZone = NORTH_POLE * PolarStereographicA.isUPS(projection.getParameterValues());
+ crsZone = POLE * PolarStereographicA.isUPS(projection.getParameterValues());
} else {
crsZone = 0; // Neither UTM or UPS projection.
}
@@ -797,43 +852,58 @@ public class MilitaryGridReferenceSystem
owner.normalized = position = toNormalized.transform(position, owner.normalized);
}
final DirectPosition geographic = toGeographic.transform(position, owner.geographic);
- owner.geographic = geographic; // For reuse in next method calls.
- final double \u03c6 = geographic.getOrdinate(0);
- if (\u03c6 >= TransverseMercator.Zoner.SOUTH_BOUNDS &&
- \u03c6 < TransverseMercator.Zoner.NORTH_BOUNDS)
- {
- /*
- * Universal Transverse Mercator (UTM) case.
- */
- final double \u03bb = geographic.getOrdinate(1);
- final int zone = TransverseMercator.Zoner.UTM.zone(\u03c6, \u03bb);
- final int sz = MathFunctions.isNegative(\u03c6) ? -zone : zone;
- if (sz == 0) {
- // Zero value at this point is the result of NaN of infinite ordinate value.
- throw new GazetteerException(Errors.format(Errors.Keys.NotANumber_1, "longitude"));
- }
- if (sz != crsZone) {
- if (sz != actualZone) {
- actualZone = 0; // In case an exception is thrown on the next line.
- toActualZone = CRS.findOperation(datum.geographic(), datum.universal(\u03c6, \u03bb), null).getMathTransform();
- actualZone = sz;
- }
- owner.normalized = position = toActualZone.transform(geographic, owner.normalized);
+ owner.geographic = geographic; // For reuse in next method calls.
+ final double \u03bb = geographic.getOrdinate(1);
+ final double \u03c6 = geographic.getOrdinate(0);
+ final boolean isUTM = \u03c6 >= TransverseMercator.Zoner.SOUTH_BOUNDS &&
+ \u03c6 < TransverseMercator.Zoner.NORTH_BOUNDS;
+ final int zone = isUTM ? TransverseMercator.Zoner.UTM.zone(\u03c6, \u03bb) : POLE;
+ final int signedZone = MathFunctions.isNegative(\u03c6) ? -zone : zone;
+ if (signedZone == 0) {
+ // Zero value at this point is the result of NaN of infinite ordinate value.
+ throw new GazetteerException(Errors.format(Errors.Keys.NotANumber_1, "longitude"));
+ }
+ /*
+ * If the DirectPosition given to this method is not in the expected Coordinate Reference System,
+ * transform it now. This may happen because the UTM zone computed above is not the same UTM zone
+ * than the coordinate one, or because the coordinate is geographic instead than projected.
+ */
+ if (signedZone != crsZone) {
+ if (signedZone != actualZone) {
+ actualZone = 0; // In case an exception is thrown on the next line.
+ toActualZone = CRS.findOperation(datum.geographic(), datum.universal(\u03c6, \u03bb), null).getMathTransform();
+ actualZone = signedZone;
}
- buffer.setLength(0);
+ owner.normalized = position = toActualZone.transform(geographic, owner.normalized);
+ }
+ /*
+ * Grid Zone Designator (GZD).
+ */
+ buffer.setLength(0);
+ if (isUTM) {
buffer.append(zone).append(separator).append(latitudeBand(\u03c6));
- if (digits >= 0) {
+ } else {
+ char z = (signedZone < 0) ? 'A' : 'Y';
+ if (\u03bb >= 0) z++;
+ buffer.append(z);
+ }
+ /*
+ * 100\u2009000-metres square identification.
+ */
+ if (digits >= 0) {
+ final double x = position.getOrdinate(0);
+ final double y = position.getOrdinate(1);
+ final double cx = Math.floor(x / GRID_SQUARE_SIZE);
+ final double cy = Math.floor(y / GRID_SQUARE_SIZE);
+ int col = (int) cx;
+ int row = (int) cy;
+ if (isUTM) {
/*
* Specification said that 100,000-meters columns are lettered from A through Z (omitting I and O)
* starting at the 180� meridian, proceeding easterly for 18�, and repeating for each 18� intervals.
* Since a UTM zone is 6� width, a 18� interval is exactly 3 standard UTM zones. Columns in zone 1
* are A-H, zone 2 are J-R (skipping O), zone 3 are S-Z, then repeating every 3 zones.
*/
- final double x = position.getOrdinate(0);
- final double y = position.getOrdinate(1);
- final double cx = Math.floor(x / GRID_SQUARE_SIZE);
- final double cy = Math.floor(y / GRID_SQUARE_SIZE);
- int col = (int) cx;
if (col < 1 || col > 8) {
/*
* UTM northing values at the equator range from 166021 to 833979 meters approximatively
@@ -852,37 +922,60 @@ public class MilitaryGridReferenceSystem
* Rows in even zones are FGHJKLMNPQRSTUVABCDE
* Those 20 letters are repeated in a cycle.
*/
- int row = (int) cy;
if ((zone & 1) == 0) {
row += ('F' - 'A');
}
- row = 'A' + (row % GRID_ROW_COUNT);
- if (row >= EXCLUDE_I && ++row >= EXCLUDE_O) row++;
- buffer.append(separator).append((char) col).append((char) row);
+ row %= GRID_ROW_COUNT;
+ // Row calculation to be completed after the 'else' block.
+ } else {
/*
- * Numerical location at the given precision.
- * The specification requires us to truncate the number, not to round it.
+ * Universal Polar Stereographic (UPS) case. Row letters go from A to Z, omitting I and O.
+ * The column letters go from A to Z, omitting I, O, D, E, M, N, V, W. Rightmost column in
+ * grid zones A and Y has column letter Z, and the next column in grid zones B and Z starts
+ * over with column letter A.
*/
- if (digits > 0) {
- final double precision = MathFunctions.pow10(METRE_PRECISION_DIGITS - digits);
- append(buffer.append(separator), (int) ((x - cx * GRID_SQUARE_SIZE) / precision), digits);
- append(buffer.append(separator), (int) ((y - cy * GRID_SQUARE_SIZE) / precision), digits);
+ final byte[] columns = POLAR_COLUMNS;
+ col -= (int) (PolarStereographicA.UPS_SHIFT / GRID_SQUARE_SIZE);
+ if (!(\u03bb >= 0)) { // Same condition than in GZD block. Use of ! is for NaN.
+ col += columns.length; // Letters Z to A from right to left.
+ }
+ if (col < 0 || col >= columns.length) {
+ throw new GazetteerException(Errors.format(Errors.Keys.OutsideDomainOfValidity));
}
+ col = columns[col];
+ row -= owner.polarOffset(signedZone < 0);
}
- } else {
+ row += 'A';
+ if (row >= EXCLUDE_I && ++row >= EXCLUDE_O) row++;
+ buffer.append(separator).append(letter(col)).append(letter(row));
/*
- * Universal Polar Stereographic (UPS) case.
+ * Numerical location at the given precision.
+ * The specification requires us to truncate the number, not to round it.
*/
- return null; // TODO
+ if (digits > 0) {
+ final double precision = MathFunctions.pow10(METRE_PRECISION_DIGITS - digits);
+ append(buffer.append(separator), (int) ((x - cx * GRID_SQUARE_SIZE) / precision), digits);
+ append(buffer.append(separator), (int) ((y - cy * GRID_SQUARE_SIZE) / precision), digits);
+ }
}
return buffer.toString();
}
/**
+ * Returns the given character as a {@code char} if it is a letter, or throws an exception otherwise.
+ * The exception should never happen, unless the the encoder is used for a planet larger than Earth
+ * for which we do not have enough letters.
+ */
+ private static char letter(final int c) throws GazetteerException {
+ if (c >= 'A' && c <= 'Z') return (char) c;
+ throw new GazetteerException(Errors.format(Errors.Keys.OutsideDomainOfValidity));
+ }
+
+ /**
* Appends the given value in the given buffer, padding with zero digits in order to get
* the specified total amount of digits.
*/
- private static void append(final StringBuilder buffer, final int value, int digits) throws TransformException {
+ private static void append(final StringBuilder buffer, final int value, int digits) throws GazetteerException {
if (value >= 0) {
final int p = buffer.length();
digits -= (buffer.append(value).length() - p);
@@ -891,7 +984,7 @@ public class MilitaryGridReferenceSystem
return;
}
}
- throw new TransformException(Errors.format(Errors.Keys.OutsideDomainOfValidity));
+ throw new GazetteerException(Errors.format(Errors.Keys.OutsideDomainOfValidity));
}
}
}
Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java?rev=1784054&r1=1784053&r2=1784054&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystemTest.java [UTF-8] Wed Feb 22 18:58:36 2017
@@ -46,7 +46,7 @@ public final strictfp class MilitaryGrid
* Returns a coder instance to test.
*/
private MilitaryGridReferenceSystem.Coder coder() {
- return new MilitaryGridReferenceSystem().createCoder();
+ return new MilitaryGridReferenceSystem(CommonCRS.WGS84).createCoder();
}
/**
@@ -91,13 +91,13 @@ public final strictfp class MilitaryGrid
}
/**
- * Tests encoding of various coordinates.
+ * Tests encoding of various coordinates in Universal Transverse Mercator (UTM) projection.
*
* @throws TransformException if an error occurred while computing the MGRS label.
*/
@Test
@DependsOnMethod({"verifyInvariants", "testLatitudeBand"})
- public void testEncoding() throws TransformException {
+ public void testEncodingUTM() throws TransformException {
final MilitaryGridReferenceSystem.Coder coder = coder();
final DirectPosition2D position = new DirectPosition2D();
/*
@@ -142,13 +142,14 @@ public final strictfp class MilitaryGrid
}
/**
- * Tests decoding of various coordinates, all at the same resolution.
+ * Tests decoding of various coordinates in Universal Transverse Mercator (UTM) projection,
+ * all at the same resolution.
*
* @throws TransformException if an error occurred while computing the coordinate.
*/
@Test
@DependsOnMethod("verifyInvariants")
- public void testDecoding() throws TransformException {
+ public void testDecodingUTM() throws TransformException {
final MilitaryGridReferenceSystem.Coder coder = coder();
DirectPosition position;
@@ -179,12 +180,50 @@ public final strictfp class MilitaryGrid
}
/**
+ * Tests encoding of various coordinates in Universal Polar Stereographic (UPS) projection.
+ *
+ * @throws TransformException if an error occurred while computing the MGRS label.
+ */
+ @Test
+ @DependsOnMethod("verifyInvariants")
+ public void testEncodingUPS() throws TransformException {
+ final MilitaryGridReferenceSystem.Coder coder = coder();
+ final DirectPosition2D position = new DirectPosition2D();
+ /*
+ * South case.
+ */
+ position.setCoordinateReferenceSystem(CommonCRS.WGS84.universal(-90, 0));
+ position.x = 2000010;
+ position.y = 2000010;
+ assertEquals("BAN0001000010", coder.encode(position));
+ position.x = 1999990;
+ position.y = 1999990;
+ assertEquals("AZM9999099990", coder.encode(position));
+ position.x = 2806727;
+ position.y = 1602814;
+ assertEquals("BLJ0672702814", coder.encode(position));
+ /*
+ * North case.
+ */
+ position.setCoordinateReferenceSystem(CommonCRS.WGS84.universal(90, 0));
+ position.x = 2000010;
+ position.y = 2000010;
+ assertEquals("ZAH0001000010", coder.encode(position));
+ position.x = 1999990;
+ position.y = 1999990;
+ assertEquals("YZG9999099990", coder.encode(position));
+ position.x = 1386727;
+ position.y = 2202814;
+ assertEquals("YRK8672702814", coder.encode(position));
+ }
+
+ /**
* Tests encoding of the same coordinate at various precision.
*
* @throws TransformException if an error occurred while computing the MGRS label.
*/
@Test
- @DependsOnMethod("testEncoding")
+ @DependsOnMethod("testEncodingUTM")
public void testPrecision() throws TransformException {
final MilitaryGridReferenceSystem.Coder coder = coder();
final DirectPosition2D position = new DirectPosition2D(CommonCRS.WGS84.universal(13, 103));
@@ -243,7 +282,7 @@ public final strictfp class MilitaryGrid
* @throws TransformException if an error occurred while computing the coordinate.
*/
@Test
- @DependsOnMethod("testDecoding")
+ @DependsOnMethod("testDecodingUTM")
public void testDecodingVariants() throws TransformException {
final MilitaryGridReferenceSystem.Coder coder = coder();
coder.setSeparator(" / ");
@@ -276,7 +315,7 @@ public final strictfp class MilitaryGrid
* @throws TransformException if an error occurred while computing the coordinate.
*/
@Test
- @DependsOnMethod("testDecoding")
+ @DependsOnMethod("testDecodingUTM")
public void testErrorDetection() throws TransformException {
final MilitaryGridReferenceSystem.Coder coder = coder();
try {
@@ -305,13 +344,13 @@ public final strictfp class MilitaryGrid
}
/**
- * Encode random coordinates, decode them and verifies that the results are approximatively equals
+ * Encodes random coordinates, decodes them and verifies that the results are approximatively equal
* to the original coordinates.
*
* @throws TransformException if an error occurred while computing the coordinate.
*/
@Test
- @DependsOnMethod({"testEncoding", "testDecoding"})
+ @DependsOnMethod({"testEncodingUTM", "testDecodingUTM"})
public void verifyConsistency() throws TransformException {
final Random random = TestUtilities.createRandomNumberGenerator();
final MilitaryGridReferenceSystem.Coder coder = coder();