Author: desruisseaux Date: Fri Mar 3 11:28:20 2017 New Revision: 1785268 URL: http://svn.apache.org/viewvc?rev=1785268&view=rev Log: MGRS decode returns cell center instead than lower-left corner.
Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/AbstractLocation.java 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/MilitaryGridReferenceSystemTest.java sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java?rev=1785268&r1=1785267&r2=1785268&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] Fri Mar 3 11:28:20 2017 @@ -22,6 +22,7 @@ import java.util.Collections; import javax.measure.Unit; import javax.measure.UnitConverter; import javax.measure.IncommensurableException; +import org.opengis.geometry.DirectPosition; import org.opengis.metadata.extent.GeographicBoundingBox; import org.apache.sis.measure.Units; import org.apache.sis.measure.MeasurementRange; @@ -149,4 +150,26 @@ public final strictfp class ExtentsTest assertTrue(DefaultGeographicBoundingBoxTest.isSpanningAntiMeridian(box)); assertEquals(9845438, Extents.area(box) / 1E6, 1); // Compare in km² } + + /** + * Tests the {@link Extents#centroid(GeographicBoundingBox)} method. This method is defined here but executed from + * the {@link org.apache.sis.internal.referencing.ServicesForMetadataTest} class in {@code sis-referencing} module. + * This method can not be executed in the {@code sis-metadata} module because it has a dependency to a referencing + * implementation class. + * + * @since 0.8 + */ + public static void testCentroid() { + final DefaultGeographicBoundingBox bbox = new DefaultGeographicBoundingBox(140, 160, 30, 50); + DirectPosition pos = Extents.centroid(bbox); + assertEquals("longitude", 150, pos.getOrdinate(0), STRICT); + assertEquals("latitude", 40, pos.getOrdinate(1), STRICT); + /* + * Test crossing anti-meridian. + */ + bbox.setEastBoundLongitude(-160); + pos = Extents.centroid(bbox); + assertEquals("longitude", 170, pos.getOrdinate(0), STRICT); + assertEquals("latitude", 40, pos.getOrdinate(1), STRICT); + } } Modified: sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/AbstractLocation.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/AbstractLocation.java?rev=1785268&r1=1785267&r2=1785268&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/AbstractLocation.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/AbstractLocation.java [UTF-8] Fri Mar 3 11:28:20 2017 @@ -29,7 +29,7 @@ import org.opengis.referencing.gazetteer import org.opengis.util.InternationalString; import org.apache.sis.util.iso.Types; import org.apache.sis.geometry.Envelope2D; -import org.apache.sis.metadata.iso.extent.Extents; +import org.apache.sis.geometry.GeneralDirectPosition; /** @@ -165,18 +165,25 @@ public abstract class AbstractLocation i /** * Returns coordinates of a representative point for the location instance. - * This is often the centroid of the location instance, but not necessarily; - * another typical value is the lower-left corner. + * This is typically (but not necessarily) the centroid of the location instance. * - * <p>The default implementation returns the centroid of the {@linkplain #getGeographicExtent() - * geographic extent} if that extent is geographic bounding box.</p> + * <p>The default implementation returns the {@linkplain #getEnvelope()} median position.</p> * * @return coordinates of a representative point for the location instance, or {@code null} if none. */ @Override public Position getPosition() { - final GeographicExtent extent = getGeographicExtent(); - return (extent instanceof GeographicBoundingBox) ? Extents.centroid((GeographicBoundingBox) extent) : null; + final Envelope envelope = getEnvelope(); + if (envelope == null) { + return null; + } + final int dimension = envelope.getDimension(); + final GeneralDirectPosition pos = new GeneralDirectPosition(dimension); + pos.setCoordinateReferenceSystem(envelope.getCoordinateReferenceSystem()); + for (int i=0; i<dimension; i++) { + pos.setOrdinate(i, envelope.getMedian(i)); + } + return pos; } /** 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=1785268&r1=1785267&r2=1785268&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] Fri Mar 3 11:28:20 2017 @@ -885,7 +885,7 @@ public class MilitaryGridReferenceSystem /** * The position decoded from the MGRS reference given to the constructor. - * This is the lower-left corner of a cell of size {@link #sx} × {@link #sy} + * This is the center of a cell of size {@link #sx} × {@link #sy}. * The CRS of that position will be a UTM or UPS projected CRS. * * @see #getPosition() @@ -1144,8 +1144,16 @@ parse: switch (part) { } position.x += x; position.y += y; + } else if (hasSquareIdentification) { + sx = sy = GRID_SQUARE_SIZE; } else { - sx = sy = (hasSquareIdentification ? GRID_SQUARE_SIZE : GRID_SQUARE_SIZE * 10); + /* + * Not used for scaling anymore. Choose value that will cause the point to be in zone zenter. + * The '- GRID_SQUARE_SIZE' in 'sx' is because the westernmost 100-km grid squares are in the + * column at index 1 (the column at index 0 is outside the UTM zone). + */ + sx = (ZONER.easting - GRID_SQUARE_SIZE) * 2; + sy = ZONER.northing; } /* * At this point we finished computing the position. Now perform error detection, by verifying @@ -1157,51 +1165,49 @@ parse: switch (part) { * tolerance threshold for the upper bound because the coordinate that we are testing is the * lower-left corner of the cell area. */ - if (hasSquareIdentification) { + if (hasSquareIdentification && isValid) { + final MathTransform inverse = crs.getConversionFromBase().getMathTransform().inverse(); + DirectPosition geographic = owner.geographic; + geographic = inverse.transform(position, geographic); + final double λ = geographic.getOrdinate(1); + final double φ = geographic.getOrdinate(0); + owner.geographic = geographic; // For future reuse. + isValid = (φ >= φs - LATITUDE_BAND_HEIGHT/2) && (φ < upperBounds(φs)); // See above comment. if (isValid) { - final MathTransform inverse = crs.getConversionFromBase().getMathTransform().inverse(); - DirectPosition geographic = owner.geographic; - geographic = inverse.transform(position, geographic); - final double λ = geographic.getOrdinate(1); - final double φ = geographic.getOrdinate(0); - owner.geographic = geographic; // For future reuse. - isValid = (φ >= φs - LATITUDE_BAND_HEIGHT/2) && (φ < upperBounds(φs)); // See above comment. - if (isValid) { - /* - * Verification of UTM zone. We allow a tolerance 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. For other latitudes, - * we allow a tolerance if the point is close to a line of zone change. - */ - int zoneError = ZONER.zone(φ, λ) - zone; - if (zoneError != 0) { - final int zc = ZONER.zoneCount(); - if (zoneError > zc/2) zoneError -= zc; - if (ZONER.isSpecialCase(zone, φ)) { - isValid = Math.abs(zoneError) == 1; // Tolerance in zone numbers for high latitudes. - } else { - final double rλ = Math.IEEEremainder(λ - ZONER.origin, ZONER.width); // Distance to closest zone change, in degrees of longitude. - final double cv = (position.x - ZONER.easting) / (λ - λ0); // Approximative conversion factor from degrees to metres. - isValid = (Math.abs(rλ) * cv <= sx); // Be tolerant if distance in metres is less than resolution. - if (isValid) { - isValid = (zoneError == (rλ < 0 ? -1 : +1)); // Verify also that the error is on the side of the zone change. - } + /* + * Verification of UTM zone. We allow a tolerance 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. For other latitudes, + * we allow a tolerance if the point is close to a line of zone change. + */ + int zoneError = ZONER.zone(φ, λ) - zone; + if (zoneError != 0) { + final int zc = ZONER.zoneCount(); + if (zoneError > zc/2) zoneError -= zc; + if (ZONER.isSpecialCase(zone, φ)) { + isValid = Math.abs(zoneError) == 1; // Tolerance in zone numbers for high latitudes. + } else { + final double rλ = Math.IEEEremainder(λ - ZONER.origin, ZONER.width); // Distance to closest zone change, in degrees of longitude. + final double cv = (position.x - ZONER.easting) / (λ - λ0); // Approximative conversion factor from degrees to metres. + isValid = (Math.abs(rλ) * cv <= sx); // Be tolerant if distance in metres is less than resolution. + if (isValid) { + isValid = (zoneError == (rλ < 0 ? -1 : +1)); // Verify also that the error is on the side of the zone change. } } } } - if (!isValid) { - position.x += sx/2; - position.y += sy/2; - final String gzd; - try { - gzd = owner.encoder(crs).encode(owner, position, "", 0); - } catch (IllegalArgumentException | FactoryException e) { - throw new GazetteerException(e.getLocalizedMessage(), e); - } - final CharSequence ref = reference.subSequence(base, end); - throw new ReferenceVerifyException(Resources.format(Resources.Keys.InconsistentWithGZD_2, ref, gzd)); + } + position.x += sx/2; + position.y += sy/2; + if (!isValid) { + final String gzd; + try { + gzd = owner.encoder(crs).encode(owner, position, "", 0); + } catch (IllegalArgumentException | FactoryException e) { + throw new GazetteerException(e.getLocalizedMessage(), e); } + final CharSequence ref = reference.subSequence(base, end); + throw new ReferenceVerifyException(Resources.format(Resources.Keys.InconsistentWithGZD_2, ref, gzd)); } } 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=1785268&r1=1785267&r2=1785268&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] Fri Mar 3 11:28:20 2017 @@ -262,28 +262,28 @@ public final strictfp class MilitaryGrid position = coder.decode("32TNL8410239239"); assertSame("crs", CommonCRS.WGS84.universal(41, 10), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 584102, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4539239, position.getOrdinate(1), STRICT); + assertEquals("Easting", 584102.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 4539239.5, position.getOrdinate(1), STRICT); position = coder.decode("29XMM8446304963"); assertSame("crs", CommonCRS.WGS84.universal(82, -10), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 484463, position.getOrdinate(0), STRICT); - assertEquals("Northing", 9104963, position.getOrdinate(1), STRICT); + assertEquals("Easting", 484463.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 9104963.5, position.getOrdinate(1), STRICT); position = coder.decode("32GNV8410260761"); assertSame("crs", CommonCRS.WGS84.universal(-41, 10), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 584102, position.getOrdinate(0), STRICT); - assertEquals("Northing", 5460761, position.getOrdinate(1), STRICT); + assertEquals("Easting", 584102.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 5460761.5, position.getOrdinate(1), STRICT); position = coder.decode("33XVM2240708183"); assertSame("crs", CommonCRS.WGS84.universal(82, 10), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 422407, position.getOrdinate(0), STRICT); - assertEquals("Northing", 9108183, position.getOrdinate(1), STRICT); + assertEquals("Easting", 422407.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 9108183.5, position.getOrdinate(1), STRICT); position = coder.decode("32FNL9360826322"); assertSame("crs", CommonCRS.WGS84.universal(-49.4, 10.3), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 593608, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4526322, position.getOrdinate(1), STRICT); + assertEquals("Easting", 593608.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 4526322.5, position.getOrdinate(1), STRICT); } /** @@ -301,23 +301,23 @@ public final strictfp class MilitaryGrid position = coder.decode("19JBK"); // South hemisphere assertSame("crs", CommonCRS.WGS84.universal(-10, -69), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 200000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 6900000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 250000, position.getOrdinate(0), STRICT); + assertEquals("Northing", 6950000, position.getOrdinate(1), STRICT); position = coder.decode("1VCK"); // North of Norway latitude band assertSame("crs", CommonCRS.WGS84.universal(62, -180), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 300000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 6900000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 350000, position.getOrdinate(0), STRICT); + assertEquals("Northing", 6950000, position.getOrdinate(1), STRICT); position = coder.decode("57KTP"); assertSame("crs", CommonCRS.WGS84.universal(-24, 156), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 200000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 7300000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 250000, position.getOrdinate(0), STRICT); + assertEquals("Northing", 7350000, position.getOrdinate(1), STRICT); position = coder.decode("56VPH"); assertSame("crs", CommonCRS.WGS84.universal(55, 154), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 600000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 6200000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 650000, position.getOrdinate(0), STRICT); + assertEquals("Northing", 6250000, position.getOrdinate(1), STRICT); } /** @@ -374,35 +374,35 @@ public final strictfp class MilitaryGrid */ position = coder.decode("BAN0001000010"); assertSame("crs", CommonCRS.WGS84.universal(-90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 2000010, position.getOrdinate(0), STRICT); - assertEquals("Northing", 2000010, position.getOrdinate(1), STRICT); + assertEquals("Easting", 2000010.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 2000010.5, position.getOrdinate(1), STRICT); position = coder.decode("AZM9999099990"); assertSame("crs", CommonCRS.WGS84.universal(-90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 1999990, position.getOrdinate(0), STRICT); - assertEquals("Northing", 1999990, position.getOrdinate(1), STRICT); + assertEquals("Easting", 1999990.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 1999990.5, position.getOrdinate(1), STRICT); position = coder.decode("BLJ0672702814"); assertSame("crs", CommonCRS.WGS84.universal(-90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 2806727, position.getOrdinate(0), STRICT); - assertEquals("Northing", 1602814, position.getOrdinate(1), STRICT); + assertEquals("Easting", 2806727.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 1602814.5, position.getOrdinate(1), STRICT); /* * North case. */ position = coder.decode("ZAH0001000010"); assertSame("crs", CommonCRS.WGS84.universal(90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 2000010, position.getOrdinate(0), STRICT); - assertEquals("Northing", 2000010, position.getOrdinate(1), STRICT); + assertEquals("Easting", 2000010.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 2000010.5, position.getOrdinate(1), STRICT); position = coder.decode("YZG9999099990"); assertSame("crs", CommonCRS.WGS84.universal(90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 1999990, position.getOrdinate(0), STRICT); - assertEquals("Northing", 1999990, position.getOrdinate(1), STRICT); + assertEquals("Easting", 1999990.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 1999990.5, position.getOrdinate(1), STRICT); position = coder.decode("YRK8672702814"); assertSame("crs", CommonCRS.WGS84.universal(90, 0), position.getCoordinateReferenceSystem()); - assertEquals("Easting", 1386727, position.getOrdinate(0), STRICT); - assertEquals("Northing", 2202814, position.getOrdinate(1), STRICT); + assertEquals("Easting", 1386727.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 2202814.5, position.getOrdinate(1), STRICT); } /** @@ -478,23 +478,23 @@ public final strictfp class MilitaryGrid position = coder.decode("32TNL8410239239"); assertEquals("32TNL8410239239", position, coder.decode("32/T/NL/84102/39239")); - assertEquals("Easting", 584102, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4539239, position.getOrdinate(1), STRICT); + assertEquals("Easting", 584102.5, position.getOrdinate(0), STRICT); + assertEquals("Northing", 4539239.5, position.getOrdinate(1), STRICT); position = coder.decode("32TNL8439"); assertEquals("32TNL8439", position, coder.decode("32/T/NL/84/39")); - assertEquals("Easting", 584000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4539000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 584500.0, position.getOrdinate(0), STRICT); + assertEquals("Northing", 4539500.0, position.getOrdinate(1), STRICT); position = coder.decode("32TNL"); assertEquals("32TNL", position, coder.decode("32/T/NL")); - assertEquals("Easting", 500000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4500000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 550000.0, position.getOrdinate(0), STRICT); + assertEquals("Northing", 4550000.0, position.getOrdinate(1), STRICT); position = coder.decode("32T"); assertEquals("32T", position, coder.decode("32/T")); - assertEquals("Easting", 100000, position.getOrdinate(0), STRICT); - assertEquals("Northing", 4000000, position.getOrdinate(1), STRICT); + assertEquals("Easting", 500000.0, position.getOrdinate(0), STRICT); + assertEquals("Northing", 9000000.0, position.getOrdinate(1), STRICT); } /** Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java?rev=1785268&r1=1785267&r2=1785268&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java [UTF-8] Fri Mar 3 11:28:20 2017 @@ -50,7 +50,7 @@ import static org.apache.sis.test.TestUt * * @author Martin Desruisseaux (Geomatys) * @since 0.5 - * @version 0.7 + * @version 0.8 * @module */ @DependsOn({ @@ -213,4 +213,14 @@ public final strictfp class ServicesForM ((CoordinateReferenceSystem) components[1]).getCoordinateSystem(), AxisDirection.UP, AxisDirection.NORTH, AxisDirection.EAST); } + + /** + * Tests {@link org.apache.sis.metadata.iso.extent.Extents#centroid(GeographicBoundingBox)}. + * + * @since 0.8 + */ + @Test + public void testGeographicBoundingBoxCentroid() { + org.apache.sis.metadata.iso.extent.ExtentsTest.testCentroid(); + } }