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 01af1418e07eefd503fd21b8ebe846c24f34307c Merge: 0e0cde0 4f07986 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Feb 21 13:02:13 2022 +0100 Merge branch 'geoapi-3.1' .../coverage/grid/FractionalGridCoordinates.java | 2 +- .../apache/sis/coverage/grid/GridCoverage2D.java | 6 +- .../apache/sis/coverage/grid/GridDerivation.java | 65 ++-- .../apache/sis/coverage/grid/GridEvaluator.java | 215 ++++++++++- .../apache/sis/coverage/grid/ReshapedImage.java | 77 ++-- .../java/org/apache/sis/filter/LeafExpression.java | 15 +- .../sis/internal/coverage/j2d/TilePlaceholder.java | 3 - .../sis/internal/coverage/j2d/TiledImage.java | 23 +- .../sis/coverage/grid/GridCoverage2DTest.java | 37 +- .../sis/coverage/grid/GridDerivationTest.java | 2 +- .../coverage/grid/ResampledGridCoverageTest.java | 2 +- .../apache/sis/test/suite/FeatureTestSuite.java | 1 - .../apache/sis/geometry}/WraparoundAdjustment.java | 409 ++++++++++++++------- .../apache/sis/internal/referencing/RTreeNode.java | 26 +- .../internal/referencing/WraparoundApplicator.java | 2 +- .../internal/referencing/WraparoundAxesFinder.java | 86 +++++ .../operation/projection/ObliqueStereographic.java | 9 +- .../transform/SpecializableTransform.java | 11 +- .../sis/geometry}/WraparoundAdjustmentTest.java | 80 ++-- .../projection/ObliqueStereographicTest.java | 38 +- .../sis/test/suite/ReferencingTestSuite.java | 1 + .../sis/util/collection/WeakValueHashMap.java | 140 ++++++- .../sis/internal/converter/AngleConverterTest.java | 4 +- .../test/java/org/apache/sis/util/NumbersTest.java | 5 +- .../org/apache/sis/util/collection/CacheTest.java | 18 +- .../org/apache/sis/util/collection/IntObject.java | 65 ++++ .../sis/util/collection/WeakHashSetTest.java | 14 +- .../sis/util/collection/WeakValueHashMapTest.java | 96 +++-- pom.xml | 4 +- .../org/apache/sis/storage/geotiff/DataCube.java | 2 +- .../apache/sis/storage/geotiff/GeoTiffStore.java | 4 +- .../apache/sis/internal/netcdf/RasterResource.java | 39 +- .../sis/internal/storage/AbstractGridResource.java | 60 ++- .../sis/internal/storage/AbstractResource.java | 58 +++ .../org/apache/sis/internal/storage/Resources.java | 5 + .../sis/internal/storage/Resources.properties | 1 + .../sis/internal/storage/Resources_fr.properties | 1 + .../sis/internal/storage/TiledGridCoverage.java | 55 ++- .../org/apache/sis/storage/CoverageSubset.java | 6 +- .../apache/sis/test/storage/SubsampledImage.java | 7 +- 40 files changed, 1297 insertions(+), 397 deletions(-) diff --cc core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java index a5fe607,f246d44..8a38c1a --- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java +++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridEvaluator.java @@@ -24,13 -26,17 +26,17 @@@ import org.opengis.referencing.operatio import org.opengis.referencing.operation.TransformException; import org.opengis.referencing.operation.CoordinateOperation; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.coverage.CannotEvaluateException; -import org.opengis.coverage.PointOutsideCoverageException; import org.apache.sis.coverage.SampleDimension; import org.apache.sis.internal.coverage.j2d.ImageUtilities; - import org.apache.sis.referencing.CRS; + import org.apache.sis.internal.referencing.DirectPositionView; + import org.apache.sis.internal.referencing.WraparoundAxesFinder; import org.apache.sis.referencing.operation.transform.MathTransforms; + import org.apache.sis.referencing.CRS; + import org.apache.sis.internal.system.Modules; import org.apache.sis.util.ArgumentChecks; + import org.apache.sis.util.logging.Logging; +import org.apache.sis.coverage.CannotEvaluateException; +import org.apache.sis.coverage.PointOutsideCoverageException; /** diff --cc core/sis-feature/src/main/java/org/apache/sis/filter/LeafExpression.java index 2ab4039,fee716d..14819e8 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/LeafExpression.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/LeafExpression.java @@@ -134,14 -135,17 +134,17 @@@ abstract class LeafExpression<R,V> exte * @return builder of the added property. */ @Override - public PropertyTypeBuilder expectedType(FeatureType ignored, final FeatureTypeBuilder addTo) { + public PropertyTypeBuilder expectedType(DefaultFeatureType ignored, final FeatureTypeBuilder addTo) { final Class<?> valueType = getValueClass(); - DefaultAttributeType<?> propertyType = TYPES.get(valueType); - if (propertyType == null) { - final Class<?> standardType = Classes.getStandardType(valueType); - propertyType = TYPES.computeIfAbsent(standardType, Literal::newType); - if (valueType != standardType) { - TYPES.put(valueType, propertyType); - AttributeType<?> propertyType; ++ DefaultAttributeType<?> propertyType; + synchronized (TYPES) { + propertyType = TYPES.get(valueType); + if (propertyType == null) { + final Class<?> standardType = Classes.getStandardType(valueType); + propertyType = TYPES.computeIfAbsent(standardType, Literal::newType); + if (valueType != standardType) { + TYPES.put(valueType, propertyType); + } } } return addTo.addProperty(propertyType); diff --cc core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java index 8209562,bf19bde..597742d --- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java @@@ -27,7 -27,9 +27,8 @@@ import java.awt.image.WritableRaster import java.awt.image.WritableRenderedImage; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; -import org.opengis.coverage.PointOutsideCoverageException; import org.opengis.referencing.operation.MathTransform1D; + import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.datum.PixelInCell; import org.apache.sis.coverage.SampleDimension; import org.apache.sis.geometry.DirectPosition2D; diff --cc core/sis-referencing/src/main/java/org/apache/sis/geometry/WraparoundAdjustment.java index 32017c2,505b5f5..fb3d4c5 --- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/WraparoundAdjustment.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/WraparoundAdjustment.java @@@ -128,21 -169,105 +169,105 @@@ public class WraparoundAdjustment } /** - * If the coordinate reference system is a projected CRS, replaces it by another CRS where wraparound axes can - * be identified. The wraparound axes are identifiable in base geographic CRS. If such replacement is applied, - * remember that we may need to transform the result later. + * Finds a coordinate operation from the given source CRS to target CRS. + * This method is invoked by all codes that need to find a coordinate operation. * - * @return whether the replacement has been done. If {@code true}, then {@link #geographicToAOI} is non-null. + * @param source the source CRS of the desired coordinate operation. + * @param target the target CRS of the desired coordinate operation. + * @return operation from {@code source} to {@code target}. + * @throws TransformException if the operation can not be computed. */ - private boolean replaceCRS() { - if (crs instanceof ProjectedCRS) { - final ProjectedCRS p = (ProjectedCRS) crs; - crs = p.getBaseCRS(); // Geographic, so a wraparound axis certainly exists. - geographicToAOI = p.getConversionFromBase().getMathTransform(); - return true; - } else { - return false; + private CoordinateOperation findOperation(final CoordinateReferenceSystem source, + final CoordinateReferenceSystem target) + throws TransformException + { + /* + * The (source ≉ target) condition is a quick check for avoiding + * unnecessary calculation of `geographicDomain` in common cases. + */ + if (!geographicDomainKnown && !Utilities.equalsIgnoreMetadata(source, target)) try { + geographicDomainKnown = true; // Shall be set even in case of failure. + geographicDomain = ReferencingServices.getInstance().setBounds(domainOfValidity, null, null); + } catch (TransformException e) { + Logging.ignorableException(Logging.getLogger(Loggers.COORDINATE_OPERATION), WraparoundAdjustment.class, "<init>", e); + // No more attempt will be done. + } + try { + return CRS.findOperation(source, target, geographicDomain); + } catch (FactoryException e) { - throw new TransformException(e); ++ throw new TransformException(e.getMessage(), e); + } + } + + /** + * Initializes this {@code WraparoundAdjustment} for an AOI or POI having the given coordinate reference system. + * If the given CRS is the same than the CRS given in last call to this method, then this method does nothing as + * this {@code WraparoundAdjustment} is assumed already initialized. Otherwise this method performs those steps: + * + * <ul> + * <li>If the given coordinate reference system is a projected CRS, + * replaces it by another CRS where wraparound axes can be identified.</li> + * <li>Set {@link #shiftableDomain} to an envelope in above CRS.</li> + * <li>Set {@link #periods} to an array with the periods of wraparound axes.</li> + * <li>Set {@link #inputToResult} to the final transform to apply in {@code shift(…)} methods.</li> + * </ul> + * + * @return whether there is at least one wraparound axis. + */ + private boolean initialize(CoordinateReferenceSystem crs) throws TransformException { + if (crs == null) { + crs = domainOfValidity.getCoordinateReferenceSystem(); + if (crs == null && domainToInput == null) { + /* + * If `inputCRS` is also null, `inputToResult` will not be initialized by next block. + * Initialize here with the assumption that following CRS as same as domain CRS: + * + * - Input CRS, as specified in `shift(…)` method contract. + * - Result CRS, as specified in constructor contract. + * + * Note that this field is considered modifiable only if `domainToInput` is null (see its javadoc). + */ + inputToResult = MathTransforms.identity(domainOfValidity.getDimension()); + } + } + if (crs != inputCRS) { + inputCRS = crs; + periods = null; + inputToShiftable = null; // Will not be used if `crs` is null. + shiftableToResult = null; + shiftableDomain = domainOfValidity; + /* + * Get the transform from input CRS (before replacement by "shiftable" CRS) + * to the CRS of all results. It will be needed by all `shift(…)` methods. + * Note that by convention, `inputToResult` is considered modifiable only + * if `domainToInput` is null (see its javadoc). + */ + if (domainToInput == null) { + if (crs != null && resultCRS != null) { + inputToResult = findOperation(crs, resultCRS).getMathTransform(); + } else { + inputToResult = MathTransforms.identity( + (crs != null) ? ReferencingUtilities.getDimension(crs) + : domainOfValidity.getDimension()); + } + } + /* + * At this point we got a CRS which may have wraparound axes. Search for those axes. + * The `periods` array will become non-null only if we find at least one such axis. + */ + if (crs != null) { + /* + * Replace the input CRS by an intermediate CRS where wraparound axes can be found. + * We try to select a CRS as close as possible (simplest transform) to the input. + */ + final WraparoundAxesFinder f = new WraparoundAxesFinder(crs); + inputToShiftable = f.preferredToSpecified.inverse(); + if ((periods = f.periods()) != null) { + transformDomain(f.preferredCRS); + } + } } + return (periods != null); } /** diff --cc core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java index c57d4c7,f705115..1eaa2da --- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java +++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java @@@ -211,6 -223,42 +222,27 @@@ public final strictfp class ObliqueSter } /** - * Tests the <cite>Oblique Stereographic</cite> case (EPSG:9809). - * This test is defined in GeoAPI conformance test suite. - * - * @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#testObliqueStereographic() - */ - @Test - @DependsOnMethod({"testTransform", "testInverseTransform"}) - public void testObliqueStereographic() throws FactoryException, TransformException { - createGeoApiTest(new org.apache.sis.internal.referencing.provider.ObliqueStereographic()).testObliqueStereographic(); - } - - /** + * Tests consistency between forward and inverse projection using a point that was known to fail. + * + * @throws FactoryException if an error occurred while creating the map projection. + * @throws TransformException if an error occurred while projecting a coordinate. + * + * @see <a href="https://issues.apache.org/jira/browse/SIS-537">SIS-537</a> + */ + @Test + public void testObliqueStereographicConsistency() throws FactoryException, TransformException { + final OperationMethod op = new org.apache.sis.internal.referencing.provider.ObliqueStereographic(); + final ParameterValueGroup p = op.getParameters().createValue(); + p.parameter("semi_major").setValue(WGS84_A); + p.parameter("semi_minor").setValue(WGS84_B); + p.parameter("Latitude of natural origin") .setValue( 45, Units.DEGREE); + p.parameter("Longitude of natural origin").setValue(-70, Units.DEGREE); + createCompleteTransform(op, p); + tolerance = Formulas.ANGULAR_TOLERANCE; - verifyInverse(30, 45); ++ verifyInverse(new double[] {30, 45}); + } + + /** * Verifies the consistency of spherical formulas with the elliptical formulas. * This test transforms the point given in the EPSG guide and takes the result * of the elliptical implementation as a reference.