This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sis.git
commit e0503ad983d9a9e733b7dc8aff2c95f4db5841d9 Merge: 0beabad754 8f4b197bc6 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu May 5 16:04:04 2022 +0200 Merge branch 'geoapi-3.1' .../org/apache/sis/metadata/sql/Dispatcher.java | 2 +- .../MultiResolutionCoverageLoaderTest.java | 2 +- .../referencing/provider/AbstractMercator.java | 12 +- .../referencing/provider/CassiniSoldner.java | 9 +- ...Soldner.java => LambertAzimuthalEqualArea.java} | 108 ++++--- .../LambertAzimuthalEqualAreaSpherical.java | 77 +++++ .../provider/LambertCylindricalEqualArea.java | 9 +- .../internal/referencing/provider/Mercator1SP.java | 9 +- .../internal/referencing/provider/Mercator2SP.java | 9 +- .../provider/MercatorAuxiliarySphere.java | 85 +++++ .../referencing/provider/MillerCylindrical.java | 2 +- .../referencing/provider/ObliqueMercator.java | 6 +- .../referencing/provider/PseudoMercator.java | 2 +- .../java/org/apache/sis/referencing/Builder.java | 14 +- .../operation/projection/AlbersEqualArea.java | 24 +- ...AreaProjection.java => AuthalicConversion.java} | 122 +++++--- .../operation/projection/AuthalicMercator.java | 115 +++++++ .../operation/projection/AzimuthalEquidistant.java | 6 +- .../operation/projection/CassiniSoldner.java | 87 ++++-- .../operation/projection/ConformalProjection.java | 8 +- .../operation/projection/CylindricalEqualArea.java | 79 +++-- .../operation/projection/Initializer.java | 42 ++- .../projection/LambertAzimuthalEqualArea.java | 284 +++++++++++++++++ .../projection/LambertConicConformal.java | 95 +++--- .../referencing/operation/projection/Mercator.java | 135 +++++--- .../operation/projection/MeridianArcBased.java | 4 +- .../projection/ModifiedAzimuthalEquidistant.java | 6 +- .../operation/projection/Mollweide.java | 31 +- .../operation/projection/NormalizedProjection.java | 95 +++--- .../operation/projection/ObliqueMercator.java | 80 +++-- .../operation/projection/ObliqueStereographic.java | 10 +- .../operation/projection/Orthographic.java | 4 +- .../operation/projection/PolarStereographic.java | 83 +++-- .../operation/projection/Polyconic.java | 6 +- .../operation/projection/ProjectionVariant.java | 58 ++++ .../operation/projection/SatelliteTracking.java | 4 +- .../operation/projection/Sinusoidal.java | 6 +- .../operation/projection/TransverseMercator.java | 44 ++- .../operation/projection/ZonedGridSystem.java | 2 +- ...g.opengis.referencing.operation.OperationMethod | 3 + .../referencing/provider/ProvidersTest.java | 3 + ...ectionTest.java => AuthalicConversionTest.java} | 24 +- .../operation/projection/InitializerTest.java | 2 +- .../projection/LambertAzimuthalEqualAreaTest.java | 344 +++++++++++++++++++++ .../operation/projection/MercatorTest.java | 72 ++++- .../sis/referencing/operation/projection/NoOp.java | 4 +- .../projection/ProjectionResultComparator.java | 2 +- .../sis/test/suite/ReferencingTestSuite.java | 3 +- .../org/apache/sis/storage/landsat/BandGroup.java | 2 +- .../sis/internal/netcdf/DiscreteSampling.java | 2 +- .../apache/sis/internal/netcdf/RasterResource.java | 2 +- .../org/apache/sis/internal/netcdf/TestCase.java | 2 +- .../org/apache/sis/internal/sql/feature/Table.java | 4 +- .../sis/internal/storage/AggregatedFeatureSet.java | 2 +- .../sis/internal/storage/MemoryFeatureSet.java | 4 +- .../sis/internal/storage/MemoryGridResource.java | 2 +- .../sis/internal/storage/TiledGridResource.java | 2 +- .../org/apache/sis/internal/storage/csv/Store.java | 6 +- .../sis/internal/storage/image/FormatFilter.java | 23 +- .../sis/internal/storage/image/FormatFinder.java | 288 +++++++++++++++++ .../internal/storage/image/MultiImageStore.java | 62 ++++ .../internal/storage/image/SingleImageStore.java | 191 ++++++++++++ .../internal/storage/image/WorldFileResource.java | 16 +- .../sis/internal/storage/image/WorldFileStore.java | 116 +++---- .../storage/image/WorldFileStoreProvider.java | 67 +++- .../sis/internal/storage/image/WritableStore.java | 81 ++--- .../sis/internal/storage/io/ChannelData.java | 2 + .../storage/io/ChannelImageInputStream.java | 31 +- .../org/apache/sis/storage/AbstractFeatureSet.java | 20 +- .../sis/storage/AbstractGridCoverageResource.java | 20 +- .../org/apache/sis/storage/AbstractResource.java | 24 +- .../org/apache/sis/storage/CoverageSubset.java | 2 +- .../java/org/apache/sis/storage/DataStore.java | 2 +- .../java/org/apache/sis/storage/FeatureNaming.java | 1 + .../java/org/apache/sis/storage/FeatureSubset.java | 2 +- .../apache/sis/storage/event/StoreListeners.java | 2 +- .../sis/internal/storage/RangeArgumentTest.java | 2 +- .../storage/image/SelfConsistencyTest.java | 2 +- .../internal/storage/image/WorldFileStoreTest.java | 12 +- .../org/apache/sis/storage/GridResourceMock.java | 2 +- 80 files changed, 2578 insertions(+), 651 deletions(-) diff --cc core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java index b3e1bbb1e1,2fc5829ec5..335a4a4763 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java @@@ -21,8 -21,10 +21,9 @@@ import java.util.List import java.util.Map; import java.util.HashMap; import java.util.Objects; + import java.util.regex.Pattern; import java.io.Serializable; import java.lang.reflect.Modifier; -import org.opengis.metadata.Identifier; import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; @@@ -457,26 -455,22 +457,22 @@@ public abstract class NormalizedProject } /** - * Returns {@code true} if the projection specified by the given method has the given keyword or identifier. - * If non-null, the given identifier is presumed in the EPSG namespace and has precedence over the keyword. + * Returns the variant of the map projection described by the given operation method. + * Identifiers are tested first because they have precedence over operation names. * - * <div class="note"><b>Implementation note:</b> - * Since callers usually give a constant string for the {@code regex} argument, it would be more efficient to - * compile the {@link java.util.regex.Pattern} once for all. However the regular expression is used only as a - * fallback if the descriptor does not contain EPSG identifier, which should be rare. Usually, the regular - * expression will never be compiled.</div> - * - * @param method the user-specified projection method. - * @param regex the regular expression to use when using the operation name as the criterion. - * @param identifier the identifier to compare against the operation method name. - * @return {@code true} if the name of the given operation method contains the given keyword - * or has an EPSG identifier equals to the given identifier. + * @param method the user-specified projection method. + * @param variants possible variants for the map projection. + * @param defaultValue value to return if no match is found. + * @return the variant of the given operation method, or {@code defaultValue} if none. */ - static boolean identMatch(final OperationMethod method, final String regex, final String identifier) { - if (identifier != null) { - for (final ReferenceIdentifier id : method.getIdentifiers()) { - if (Constants.EPSG.equals(id.getCodeSpace())) { - return identifier.equals(id.getCode()); + static <V extends ProjectionVariant> V variant(final OperationMethod method, final V[] variants, final V defaultValue) { + for (final V variant : variants) { + final String identifier = variant.getIdentifier(); + if (identifier != null) { - for (final Identifier id : method.getIdentifiers()) { ++ for (final ReferenceIdentifier id : method.getIdentifiers()) { + if (Constants.EPSG.equals(id.getCodeSpace()) && identifier.equals(id.getCode())) { + return variant; + } } } } diff --cc core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualAreaTest.java index 0000000000,72427c2dac..3c46896b6b mode 000000,100644..100644 --- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualAreaTest.java +++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualAreaTest.java @@@ -1,0 -1,357 +1,344 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.sis.referencing.operation.projection; + + import org.opengis.util.FactoryException; + import org.opengis.referencing.operation.TransformException; + import org.apache.sis.referencing.operation.transform.CoordinateDomain; + import org.apache.sis.referencing.operation.transform.MathTransformFactoryMock; + import org.apache.sis.internal.referencing.provider.MapProjection; + import org.apache.sis.internal.metadata.ReferencingServices; + import org.apache.sis.parameter.Parameters; + import org.junit.Test; + + import static java.lang.Double.NaN; + import static java.lang.StrictMath.*; + import static org.apache.sis.math.MathFunctions.SQRT_2; + import static org.apache.sis.internal.referencing.Formulas.LINEAR_TOLERANCE; + import static org.apache.sis.internal.referencing.Formulas.ANGULAR_TOLERANCE; + import static org.junit.Assert.*; + + + /** + * Tests the {@link LambertAzimuthalEqualArea} class. We test using various values + * of the latitude of origin, which is the only parameter impacting the internal + * coefficients of that class (except for the eccentricity). + * + * @author Martin Desruisseaux (Geomatys) + * @author Rémi Maréchal (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ + public final strictfp class LambertAzimuthalEqualAreaTest extends MapProjectionTestCase { + /** + * The radius of the sphere used in sphere test cases. + */ + private static final double SPHERE_RADIUS = ReferencingServices.AUTHALIC_RADIUS; + + /** + * Returns the provider for the map projection to tesT. + */ + private static MapProjection provider(final boolean elliptical) { + return elliptical ? new org.apache.sis.internal.referencing.provider.LambertAzimuthalEqualArea() + : new org.apache.sis.internal.referencing.provider.LambertAzimuthalEqualAreaSpherical(); + } + + /** + * Creates and validates a new instance of {@link LambertAzimuthalEqualArea}. + * + * @param elliptical {@code false} for a sphere, or {@code true} for WGS84 ellipsoid. + * @param latitudeOfOrigin the latitude of origin. + * @param complete whether to create the full projection, working on degrees instead of radians. + * @throws FactoryException if an error occurred while creating the map projection. + */ + private void createProjection(final boolean elliptical, final double latitudeOfOrigin, final boolean complete) + throws FactoryException + { + final MapProjection provider = provider(elliptical); + final Parameters parameters = parameters(provider, elliptical); + parameters.parameter("latitude_of_origin").setValue(latitudeOfOrigin); + LambertAzimuthalEqualArea projection = new LambertAzimuthalEqualArea(provider, parameters); + if (complete) { + transform = projection.createMapProjection(new MathTransformFactoryMock(provider)); + } else { + transform = projection; + } + validate(); + } + + /** + * Tests oblique case with a point computed with PROJ. + * Command line was: + * + * <pre>cs2cs "EPSG:4326" +to +type=crs +proj=laea +no_defs +lat_0=90 +lon_0=0 +datum=WGS84 <<< "72 50"</pre> + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testPolar() throws FactoryException, TransformException { + tolerance = LINEAR_TOLERANCE; + createProjection(true, 90, true); + final double[] point = new double[] {50, 72}; + final double[] expected = new double[] {1533302.80, -1286593.82}; + verifyTransform(point, expected); + } + + /** + * Tests oblique case with a point computed with PROJ. + * Command line was: + * + * <pre>cs2cs "EPSG:4326" +to +type=crs +proj=laea +no_defs +lat_0=37 +lon_0=0 +datum=WGS84 <<< "25 -9"</pre> + * + * Note that {@link #runGeoapiTest()} performs a similar test. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testOblique() throws FactoryException, TransformException { + tolerance = LINEAR_TOLERANCE; + createProjection(true, 37, true); + final double[] point = new double[] {-9, 25}; + final double[] expected = new double[] {-911656.53, -1288191.92}; + verifyTransform(point, expected); + } + + /** + * Tests self-consistency of the unitary projection on a sphere. + * The projection works with radians on a sphere of radius 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testConsistencyOfUnitaryOnSphere() throws FactoryException, TransformException { + final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres. + derivativeDeltas = new double[] {delta, delta}; + tolerance = ANGULAR_TOLERANCE; + for (int φ = -90; φ <= 90; φ += 15) { + createProjection(false, φ, false); + verifyInDomain(CoordinateDomain.GEOGRAPHIC_RADIANS, 862247543); + } + } + + /** + * Tests self-consistency of the unitary projection on an ellipse. + * The projection works with radians on an ellipsoid of semi-major axis length 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testConsistencyOfUnitaryOnEllipse() throws FactoryException, TransformException { + final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres. + derivativeDeltas = new double[] {delta, delta}; + tolerance = ANGULAR_TOLERANCE; + for (int φ = -90; φ <= 90; φ += 15) { + createProjection(true, φ, false); + verifyInDomain(CoordinateDomain.GEOGRAPHIC_RADIANS, 484117986); + } + } + + /** + * Tests the projection at a few particular points in the oblique case. + * The particular points are the origin and the (almost) antipodal points. + * The projection works with radians on a sphere of radius 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testParticularPointsWithObliqueOnSphere() throws FactoryException, TransformException { + testParticularPointsWithOblique(false); + } + + /** + * Tests the projection at a few particular points in the oblique case. + * The particular points are the origin and the (almost) antipodal points. + * The projection works with degrees on an ellipsoid of semi-major axis length 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testParticularPointsWithObliqueOnEllipse() throws FactoryException, TransformException { + testParticularPointsWithOblique(true); + } + + /** + * Implementation of {@link #testParticularPointsWithObliqueOnSphere()} + * and {@link #testParticularPointsWithObliqueOnEllipse()}. + */ + private void testParticularPointsWithOblique(final boolean elliptical) throws FactoryException, TransformException { + tolerance = LINEAR_TOLERANCE; + createProjection(elliptical, 45, true); + + // Projects the origin. + final double[] point = new double[] {0, 45}; + final double[] expected = new double[] {0, 0}; + verifyTransform(point, expected); + + // Project the antipode. + point[0] = 180; + point[1] = -45; + transform.transform(point, 0, point, 0, 1); + assertEquals("E", NaN, point[0], tolerance); + assertEquals("N", NaN, point[1], tolerance); + + // Project the almost-antipode. + point[0] = 180; + point[1] = -44.999; + transform.transform(point, 0, point, 0, 1); + assertEquals("E", 0, point[0], tolerance); + assertEquals("N", 2*SPHERE_RADIUS, point[1], 0.002*SPHERE_RADIUS); + } + + /** + * Tests the projection at a few extreme points in the polar case. + * The projection works with radians on a sphere of radius 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testParticularPointsWithPolarOnSphere() throws FactoryException, TransformException { + testParticularPointsWithPolar(false); + } + + /** + * Tests the projection at a few extreme points in the polar case. + * The projection works with radians on an ellipsoid of semi-major axis length 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testParticularPointsWithPolarOnEllipse() throws FactoryException, TransformException { + testParticularPointsWithPolar(true); + } + + /** + * Implementation of {@link #testParticularPointsWithPolarOnSphere()} + * and {@link #testParticularPointsWithPolarOnEllipse()}. + */ + private void testParticularPointsWithPolar(final boolean elliptical) throws FactoryException, TransformException { + tolerance = LINEAR_TOLERANCE; + createProjection(elliptical, 90, true); + /* + * Project the origin. Result should be (0,0). Do not test the inverse projection + * because the longitude could be anything and still be the North pole. We test that + * by projecting again with an other longitude, set to 45°, and expect the same result. + */ + final double[] point = new double[] {0, 90}; + final double[] expected = new double[] {0, 0}; + isInverseTransformSupported = false; + verifyTransform(point, expected); + transform.inverse().transform(expected, 0, point, 0, 1); + assertEquals("λ", 0, point[0], 180); + assertEquals("φ", 90, point[1], ANGULAR_TOLERANCE); + /* + * Same point as above (i.e. projection origin), but using a different longitude value. + * Same expected result because longitude should have no effect at a pole. + */ + point[0] = 45; + point[1] = 90; + verifyTransform(point, expected); + transform.inverse().transform(expected, 0, point, 0, 1); + assertEquals("λ", 45, point[0], 180); + assertEquals("φ", 90, point[1], ANGULAR_TOLERANCE); + /* + * Project a point on the equator, at 0° and at 180° longitude. + * Result should be (0, √2) positive or negative depending on the longitude. + */ + point[0] = 0; expected[0] = 0; + point[1] = 0; expected[1] = -SQRT_2*SPHERE_RADIUS; + isInverseTransformSupported = true; + if (elliptical) tolerance = 0.5; // Because the use of `SPHERE_RADIUS` is approximate. + verifyTransform(point, expected); + + point[0] = 180; expected[0] = 0; + point[1] = 0; expected[1] = SQRT_2*SPHERE_RADIUS; + verifyTransform(point, expected); + /* + * Project the antipode. Result would be (0, -2) if this operation was allowed. + * Actually the formulas would work, but every points on a circle or radius 2 + * would be the pole so returning a single value may not be appropriate. + */ + point[0] = 0; + point[1] = -90; + transform.transform(point, 0, point, 0, 1); + assertEquals("E", NaN, point[0], tolerance); + assertEquals("N", NaN, point[1], tolerance); + } + + /** + * Tests consistency when converting a point forward then backward. + * The projection works with radians on a sphere of radius 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testRoundtrip() throws FactoryException, TransformException { + tolerance = ANGULAR_TOLERANCE; + createProjection(false, -75, false); + final double[] point = new double[] {toRadians(-90), toRadians(-8)}; + transform.transform(point, 0, point, 0, 1); + transform.inverse().transform(point, 0, point, 0, 1); + assertEquals(-90, toDegrees(point[0]), tolerance); + assertEquals( -8, toDegrees(point[1]), tolerance); + } + + /** + * Creates a projection and tests the derivatives at a few points. + * The projection works with radians on an ellipsoid of semi-major axis length 1. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + */ + @Test + public void testDerivative() throws FactoryException, TransformException { + tolerance = 1E-9; + final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres. + derivativeDeltas = new double[] {delta, delta}; + + // Polar projection. + createProjection(true, 90, false); + verifyDerivative(toRadians(-6), toRadians(80)); + + // Intentionally above the pole. + verifyDerivative(toRadians(-6), toRadians(100)); + + // Polar projection, spherical formulas. + createProjection(false, 90, false); + verifyDerivative(toRadians(-6), toRadians(85)); + + // Equatorial projection, spherical formulas. + createProjection(false, 0, false); + verifyDerivative(toRadians(3), toRadians(4)); + + // Oblique projection, ellipsoidal formulas. + createProjection(true, 8, false); + verifyDerivative(toRadians(-6), toRadians(2)); + + // Oblique projection, spherical formulas. + createProjection(false, 8, false); + verifyDerivative(toRadians(-6), toRadians(2)); + } - - /** - * Runs the test defined in the GeoAPI-conformance module. - * - * @throws FactoryException if an error occurred while creating the map projection. - * @throws TransformException if an error occurred while projecting a coordinate. - * - * @see org.opengis.test.referencing.ParameterizedTransformTest#testLambertAzimuthalEqualArea() - */ - @Test - public void runGeoapiTest() throws FactoryException, TransformException { - createGeoApiTest(provider(true)).testLambertAzimuthalEqualArea(); - } + } diff --cc core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java index f3e2b3c167,aa93ec41fd..b4de8e0248 --- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java +++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java @@@ -22,9 -23,14 +23,12 @@@ import org.apache.sis.internal.util.Con import org.apache.sis.internal.referencing.Formulas; import org.apache.sis.internal.referencing.provider.Mercator1SP; import org.apache.sis.internal.referencing.provider.Mercator2SP; -import org.apache.sis.internal.referencing.provider.MercatorSpherical; + import org.apache.sis.internal.referencing.provider.MercatorAuxiliarySphere; import org.apache.sis.internal.referencing.provider.PseudoMercator; import org.apache.sis.internal.referencing.provider.MillerCylindrical; -import org.apache.sis.internal.referencing.provider.RegionalMercator; import org.apache.sis.referencing.operation.transform.CoordinateDomain; + import org.apache.sis.referencing.operation.transform.MathTransformFactoryMock; + import org.apache.sis.parameter.Parameters; import org.apache.sis.test.DependsOnMethod; import org.apache.sis.test.DependsOn; import org.junit.Test; diff --cc storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java index b8079a82ce,6e5b40c17e..82d237c4af --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java @@@ -190,10 -191,10 +190,10 @@@ final class Table extends AbstractFeatu * * @todo This constructor is not yet used because it is an unfinished work. * We need to invent some mechanism for using a subset of the columns. - * A starting point is {@link org.apache.sis.storage.FeatureQuery#expectedType(FeatureType)}. + * A starting point is {@link org.apache.sis.storage.FeatureQuery#expectedType(DefaultFeatureType)}. */ Table(final Table parent) { - super(parent.listeners); + super(parent.listeners, false); database = parent.database; query = parent.query; name = parent.name; diff --cc storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java index f03d334266,7249bbbb6c..2ae3383eed --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java @@@ -59,10 -59,8 +59,10 @@@ public class MemoryFeatureSet extends A * @param type the type of all features in the given collection. * @param features collection of stored features. This collection will not be copied. */ - public MemoryFeatureSet(final StoreListeners parent, final FeatureType type, final Collection<Feature> features) { + public MemoryFeatureSet(final StoreListeners parent, + final DefaultFeatureType type, final Collection<AbstractFeature> features) - { - super(parent); ++ { + super(parent, false); ArgumentChecks.ensureNonNull("type", type); ArgumentChecks.ensureNonNull("features", features); this.type = type; diff --cc storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java index 84416bb946,50fd6de7b7..d3a4e61bfc --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java @@@ -576,13 -578,9 +576,9 @@@ final class Store extends URIDataStore } properties.add(createProperty(name, type, minOccurrence, maxOccurrence, characteristics)); } - String name = super.getDisplayName(); - final int s = name.lastIndexOf('.'); - if (s > 0) { // Exclude 0 because shall not be the first character. - name = name.substring(0, s); - } + final String name = IOUtilities.filenameWithoutExtension(super.getDisplayName()); return new DefaultFeatureType(Collections.singletonMap(DefaultFeatureType.NAME_KEY, name), - false, null, properties.toArray(new PropertyType[properties.size()])); + false, null, properties.toArray(new AbstractIdentifiedType[properties.size()])); } /** diff --cc storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java index 7ff00be156,9c174d5241..7e68d48a6e --- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java +++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/image/WorldFileStoreTest.java @@@ -76,10 -76,20 +76,18 @@@ public final strictfp class WorldFileSt public void testMetadata() throws DataStoreException { final WorldFileStoreProvider provider = new WorldFileStoreProvider(); try (WorldFileStore store = provider.open(testData())) { + /* + * Opportunistic check of store type. Should be read-only, + * and should have been simplified to the "single image" case. + */ assertFalse(store instanceof WritableStore); + assertTrue(store instanceof SingleImageStore); + /* + * Verify metadata content. + */ assertEquals("gradient", store.getIdentifier().get().toString()); final Metadata metadata = store.getMetadata(); - final Identification id = getSingleton(metadata.getIdentificationInfo()); - final String format = getSingleton(id.getResourceFormats()).getFormatSpecificationCitation().getTitle().toString(); - assertTrue(format, format.contains("PNG")); + final DataIdentification id = (DataIdentification) getSingleton(metadata.getIdentificationInfo()); assertEquals("WGS 84", getSingleton(metadata.getReferenceSystemInfo()).getName().getCode()); final GeographicBoundingBox bbox = (GeographicBoundingBox) getSingleton(getSingleton(id.getExtents()).getGeographicElements());