This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 681836128c5c95151e7e887aa8f98cf005f68413 Author: Martin Desruisseaux <[email protected]> AuthorDate: Wed Jun 24 20:59:29 2026 +0200 Add a way to create an `EngineeringCRS` for a grid geometry which contains only an extent. --- .../apache/sis/coverage/grid/GridCRSBuilder.java | 36 ++++++++++++++++------ .../org/apache/sis/coverage/grid/GridExtent.java | 33 +++++++++++++++++++- .../org/apache/sis/coverage/grid/GridGeometry.java | 8 +++-- .../apache/sis/referencing/NamedIdentifier.java | 6 ++-- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java index 224c90b68a..38682be486 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java @@ -186,9 +186,9 @@ final class GridCRSBuilder extends ReferencingFactoryContainer { private GridGeometry fullGrid; /** - * The cell part (center or corner) to map. + * The cell part (center or corner) to map, or {@code null} if this information is not needed. */ - private final PixelInCell anchor; + private PixelInCell anchor; /** * A helper tool for separating the "<abbr>CRS</abbr> to grid" transform for each component. @@ -213,11 +213,8 @@ final class GridCRSBuilder extends ReferencingFactoryContainer { /** * Creates a new helper class for building a grid coordinate reference system. - * - * @param anchor the cell part to map (center or corner). */ - GridCRSBuilder(final PixelInCell anchor) { - this.anchor = anchor; + GridCRSBuilder() { properties = new HashMap<>(8); if (LOCALE != null) { properties.put(DefiningConversion.LOCALE_KEY, LOCALE); @@ -237,15 +234,17 @@ final class GridCRSBuilder extends ReferencingFactoryContainer { * May return a compound <abbr>CRS</abbr> if the grid geometry has, for example, a temporal component. * * @param grid grid geometry of the coverage. + * @param anchor the cell part to map (center or corner). * @param derived whether to force {@link DerivedCRS} instances. * @param name name of the derived or engineering <abbr>CRS</abbr> to create. * @return a derived, engineering or compound <abbr>CRS</abbr> for cell indices associated to the grid extent. * @throws InvalidGeodeticParameterException if characteristics of the grid geometry disallow this operation. * @throws FactoryException if another error occurred during the use of a referencing factory. */ - final CoordinateReferenceSystem forCoverage(final GridGeometry grid, final boolean derived, final Identifier name) + final CoordinateReferenceSystem forCoverage(final GridGeometry grid, final PixelInCell anchor, final boolean derived, final Identifier name) throws FactoryException { + this.anchor = anchor; properties.put(DefiningConversion.NORMALIZED_KEY, Boolean.FALSE); properties.put(ObjectDomain.SCOPE_KEY, SCOPE); grid.getGeographicExtent().ifPresent((domain) -> { @@ -263,10 +262,27 @@ final class GridCRSBuilder extends ReferencingFactoryContainer { * We cannot create a derived CRS. Fallback on an engineering CRS with no * relationship to any other CRS. */ - final int dimension = grid.getDimension(); + return forExtent(name, grid.getDimension(), grid.isDefined(GridGeometry.EXTENT) ? grid.getExtent() : null); + } + + /** + * Creates an engineering <abbr>CRS</abbr> for grid coordinates with no relationship to real world coordinates. + * The {@code name} argument is important because it is the only way to determine whether a coordinate operation + * is possible between two engineering <abbr>CRS</abbr>s. It is recommended to use an identifier which is unique + * for the grid. It may be, for example, derived from the resource identifier. + * + * @param name name of the engineering datum. + * @param dimension number of dimensions. + * @param extent extent, or {@code null} if none. + * @return an engineering <abbr>CRS</abbr> for cell indices associated to the grid extent. + * @throws FactoryException if an error occurred during the use of a referencing factory. + */ + final EngineeringCRS forExtent(final Identifier name, final int dimension, final GridExtent extent) + throws FactoryException + { final DimensionNameType[] dimensionNames; - if (grid.isDefined(GridGeometry.EXTENT)) { - dimensionNames = Arrays.copyOf(grid.getExtent().getAxisTypes(), dimension); + if (extent != null) { + dimensionNames = Arrays.copyOf(extent.getAxisTypes(), dimension); } else { dimensionNames = new DimensionNameType[dimension]; } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java index 45b5d7e4bf..6f181ebc24 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridExtent.java @@ -36,11 +36,13 @@ import org.opengis.util.FactoryException; import org.opengis.util.InternationalString; import org.opengis.geometry.Envelope; import org.opengis.geometry.DirectPosition; +import org.opengis.metadata.Identifier; import org.opengis.metadata.spatial.DimensionNameType; import org.opengis.referencing.cs.AxisDirection; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.crs.EngineeringCRS; import org.opengis.referencing.operation.Matrix; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; @@ -53,6 +55,7 @@ import org.apache.sis.util.logging.Logging; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.collection.WeakValueHashMap; +import org.apache.sis.util.collection.BackingStoreException; import org.apache.sis.util.internal.shared.Numerics; import org.apache.sis.util.internal.shared.Strings; import org.apache.sis.util.internal.shared.DoubleDouble; @@ -1320,7 +1323,7 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable final GeneralEnvelope envelope = toEnvelope(cornerToCRS, false, cornerToCRS, null); try { final Matrix derivative = derivativeAtPOI(cornerToCRS, PixelInCell.CELL_CORNER); - final var builder = new GridCRSBuilder(PixelInCell.CELL_CORNER); + final var builder = new GridCRSBuilder(); builder.forExtentAlone(derivative, getAxisTypes()).ifPresent(envelope::setCoordinateReferenceSystem); } catch (FactoryException | TransformException e) { Logging.ignorableException(LOGGER, GridExtent.class, "toEnvelope", e); @@ -2351,6 +2354,34 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable } } + /** + * Creates a coordinate reference system for cell indices in this extent. + * The {@code name} argument will be the name of the engineering datum. + * Coordinate operations between two <abbr>CRS</abbr>s created by this method + * will be possible only if they were created with the same {@code name} argument. + * It is recommended to use an identifier which is unique for the grid. It may be, for example, derived + * from the {@linkplain org.apache.sis.storage.GridCoverageResource#getIdentifier() resource identifier}. + * + * <p>This engineering <abbr>CRS</abbr> may be used when no "grid to <abbr>CRS</abbr>" information is available. + * Otherwise, {@link GridGeometry#createGridCRS(Identifier, PixelInCell)} should be preferred.</p> + * + * @param name name of the engineering datum. + * @return an engineering <abbr>CRS</abbr> for cell indices associated to this grid extent. + * + * @see GridGeometry#createGridCRS(Identifier, PixelInCell) + * + * @since 1.7 + */ + public EngineeringCRS createGridCRS(final Identifier name) { + ArgumentChecks.ensureNonNull("name", name); + try { + return new GridCRSBuilder().forExtent(name, getDimension(), this); + } catch (FactoryException e) { + // Should never happen because `GridCRSBuilder` uses known implementations. + throw new BackingStoreException(e); + } + } + /** * Compares the specified object with this grid extent for equality. * This method delegates to {@code equals(object, ComparisonMode.STRICT)}. diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java index 10a3778369..3edd2a913b 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridGeometry.java @@ -753,7 +753,8 @@ public class GridGeometry implements LenientComparable, Serializable { } /** - * Creates a grid geometry with only an envelope. + * Creates a grid geometry with only an envelope and its coordinate reference system. + * The grid geometry has no "grid to <abbr>CRS</abbr>" transform. * * @param envelope the envelope together with CRS of the "real world" coordinates. * @throws IllegalArgumentException if the envelope has no CRS and only NaN coordinate values. @@ -1882,7 +1883,7 @@ public class GridGeometry implements LenientComparable, Serializable { final var id = new org.apache.sis.referencing.ImmutableIdentifier(null, null, name); try { // Note: the `true` boolean argument can be removed after the removal of this method. - final CoordinateReferenceSystem crs = new GridCRSBuilder(anchor).forCoverage(this, true, id); + final CoordinateReferenceSystem crs = new GridCRSBuilder().forCoverage(this, anchor, true, id); return (DerivedCRS) org.apache.sis.referencing.CRS.getSingleComponents(crs).get(0); } catch (FactoryException e) { throw new BackingStoreException(e); @@ -1920,13 +1921,14 @@ public class GridGeometry implements LenientComparable, Serializable { * @throws FactoryException if another error occurred during the use of a referencing factory. * * @see #createTransformTo(GridGeometry, PixelInCell) + * @see GridExtent#createGridCRS(Identifier) * * @since 1.7 */ public CoordinateReferenceSystem createGridCRS(final Identifier name, final PixelInCell anchor) throws FactoryException { ArgumentChecks.ensureNonNull("name", name); ArgumentChecks.ensureNonNull("anchor", anchor); - return new GridCRSBuilder(anchor).forCoverage(this, false, name); + return new GridCRSBuilder().forCoverage(this, anchor, false, name); } /** diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java index 6fc54e9b88..8979a5a1f4 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/NamedIdentifier.java @@ -39,7 +39,7 @@ import org.apache.sis.util.iso.DefaultNameFactory; /** - * An identification of a CRS object which is both a {@link Identifier} and a {@link GenericName}. + * An identification of a <abbr>CRS</abbr> object which is both an {@link Identifier} and a {@link GenericName}. * This class implements both interfaces in order to allow usage of the same instance either as an object * {@linkplain AbstractIdentifiedObject#getName() name} or {@linkplain AbstractIdentifiedObject#getAlias() alias}. * This flexibility make easier to uses object's names in two different models: @@ -200,7 +200,7 @@ public class NamedIdentifier extends ImmutableIdentifier implements GenericName * @throws InvalidParameterValueException if a property has an invalid value. * @throws IllegalArgumentException if a property is invalid for some other reason. */ - public NamedIdentifier(final Map<String,?> properties) throws IllegalArgumentException { + public NamedIdentifier(final Map<String, ?> properties) throws IllegalArgumentException { super(properties); name = (GenericName) properties.get("name"); isNameSupplied = (name != null); @@ -563,6 +563,8 @@ public class NamedIdentifier extends ImmutableIdentifier implements GenericName /** * Returns a hash code value for this object. + * + * @return a hash code value for this object. */ @Override public int hashCode() {
