This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 550ee271a91e817b81f928ad5f6ede55496cbc57 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Jul 24 16:05:54 2024 +0200 Implement geodetic and vertical DynamicReferenceFrame classes. The coordinate operation factory has not yet been updated for taking the frame reference epoch in account. --- .../sis/referencing/datum/AbstractDatum.java | 58 +++++++- .../sis/referencing/datum/BursaWolfParameters.java | 20 +-- .../referencing/datum/DefaultGeodeticDatum.java | 152 ++++++++++++++++----- .../referencing/datum/DefaultVerticalDatum.java | 83 +++++++++++ .../referencing/factory/GeodeticObjectFactory.java | 71 +++++++++- geoapi/snapshot | 2 +- 6 files changed, 334 insertions(+), 52 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java index 56c14ae7c9..ed1d8e6b57 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/AbstractDatum.java @@ -47,6 +47,7 @@ import static org.apache.sis.util.Utilities.deepEquals; import static org.apache.sis.util.collection.Containers.property; // Specific to the geoapi-3.1 and geoapi-4.0 branches: +import org.opengis.referencing.datum.DynamicReferenceFrame; import org.opengis.metadata.Identifier; // Specific to the geoapi-4.0 branch: @@ -311,6 +312,17 @@ public class AbstractDatum extends AbstractIdentifiedObject implements Datum { return Optional.ofNullable(anchorEpoch); } + /** + * Returns the frame reference epoch if this datum is dynamic, or {@code null} if this datum is static. + * This method is overridden with public access in Apache SIS {@code Dynamic} subclasses. + * The default implementation should be suitable for non-SIS implementations. + * + * @return the reference epoch if this datum is dynamic, or {@code null} if this datum is static. + */ + Temporal getFrameReferenceEpoch() { + return (this instanceof DynamicReferenceFrame) ? ((DynamicReferenceFrame) this).getFrameReferenceEpoch() : null; + } + /** * Returns the date on which the datum definition was published. * @@ -395,6 +407,12 @@ public class AbstractDatum extends AbstractIdentifiedObject implements Datum { * {@linkplain #getAnchorDefinition() anchor definition}, {@linkplain #getAnchorEpoch() anchor epoch}, * and the {@linkplain #getDomains() domains}. * + * <h4>Static versus dynamic datum</h4> + * If this datum implements the {@link DynamicReferenceFrame} interface, then the given object needs + * to also implement that interfaces and provide the same reference epoch for being considered equal. + * Conversely, if this datum does not implement {@link DynamicReferenceFrame}, then the given object + * also need to <em>not</em> implement that interface for being considered equal. + * * @param object the object to compare to {@code this}. * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only @@ -409,13 +427,18 @@ public class AbstractDatum extends AbstractIdentifiedObject implements Datum { switch (mode) { case STRICT: { final var that = (AbstractDatum) object; - return Objects.equals(anchorEpoch, that.anchorEpoch) && - Objects.equals(anchorDefinition, that.anchorDefinition); + return Objects.equals(anchorEpoch, that.anchorEpoch) && + Objects.equals(anchorDefinition, that.anchorDefinition) && + Objects.equals(publicationDate, that.publicationDate) && + Objects.equals(conventionalRS, that.conventionalRS); } case BY_CONTRACT: { - final Datum that = (Datum) object; - return deepEquals(getAnchorEpoch(), that.getAnchorEpoch(), mode) && - deepEquals(getAnchorDefinition(), that.getAnchorDefinition(), mode); + final var that = (Datum) object; + return compareDynamicReferenceFrames(that, mode) && + deepEquals(getAnchorEpoch(), that.getAnchorEpoch(), mode) && + deepEquals(getAnchorDefinition(), that.getAnchorDefinition(), mode) && + deepEquals(getPublicationDate(), that.getPublicationDate(), mode) && + deepEquals(getConventionalRS(), that.getConventionalRS(), mode); } default: { /* @@ -428,6 +451,9 @@ public class AbstractDatum extends AbstractIdentifiedObject implements Datum { * and parameters. We extend this rule to datum as well. */ final var that = (Datum) object; + if (!compareDynamicReferenceFrames(that, mode)) { + return false; + } final Boolean match = Identifiers.hasCommonIdentifier(getIdentifiers(), that.getIdentifiers()); if (match != null) { return match; @@ -438,17 +464,35 @@ public class AbstractDatum extends AbstractIdentifiedObject implements Datum { } } + /** + * Checks whether this datum and the other datum are both static or both dynamic. + * In the latter case, checks also whether the two datum have the same reference epoch. + * + * @param that the other datum to compare with this datum. + * @param mode the comparison mode. + * @return whether the two reference frames are equal in their static versus dynamic aspect. + */ + private boolean compareDynamicReferenceFrames(final Datum that, final ComparisonMode mode) { + final Temporal frameReferenceEpoch = getFrameReferenceEpoch(); + if (frameReferenceEpoch != null) { + return (that instanceof DynamicReferenceFrame) && + deepEquals(frameReferenceEpoch, ((DynamicReferenceFrame) that).getFrameReferenceEpoch(), mode); + } else { + return !(that instanceof DynamicReferenceFrame); + } + } + /** * Invoked by {@code hashCode()} for computing the hash code when first needed. * See {@link org.apache.sis.referencing.AbstractIdentifiedObject#computeHashCode()} * for more information. * * @return the hash code value. This value may change in any future Apache SIS version. - * @hidden because not useful. + * @hidden because nothing new to said. */ @Override protected long computeHashCode() { - return super.computeHashCode() + Objects.hash(anchorDefinition, anchorEpoch); + return super.computeHashCode() + Objects.hash(anchorDefinition, anchorEpoch, publicationDate, conventionalRS); } /** diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/BursaWolfParameters.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/BursaWolfParameters.java index 4a41244b4e..a38bd2c7d8 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/BursaWolfParameters.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/BursaWolfParameters.java @@ -412,7 +412,7 @@ public class BursaWolfParameters extends FormattableObject implements Cloneable, /** * Returns the parameter at the given index. If this {@code BursaWolfParameters} is time-dependent, - * then the returned value shall be corrected the time elapsed since the reference time. + * then the returned value shall be corrected for the time elapsed since the reference time. * * The {@code factor} argument shall be the value computed by {@link #period(Temporal)}, * multiplied by 1000 for all {@code index} values except 6. @@ -498,17 +498,17 @@ public class BursaWolfParameters extends FormattableObject implements Cloneable, DoubleDouble RS = DoubleDouble.SECONDS_TO_RADIANS; DoubleDouble S = param(6, period).divide(PPM).add(1); // S = 1 + dS / PPM; RS = RS.multiply(S); // RS = toRadians(1″) * S; - final DoubleDouble rX = param(3, mp).multiply(RS); - final DoubleDouble rY = param(4, mp).multiply(RS); - final DoubleDouble rZ = param(5, mp).multiply(RS); - final DoubleDouble mX = rX.negate(); - final DoubleDouble mY = rY.negate(); - final DoubleDouble mZ = rZ.negate(); + final DoubleDouble pX = param(3, mp).multiply(RS); + final DoubleDouble pY = param(4, mp).multiply(RS); + final DoubleDouble pZ = param(5, mp).multiply(RS); + final DoubleDouble mX = pX.negate(); + final DoubleDouble mY = pY.negate(); + final DoubleDouble mZ = pZ.negate(); final Integer O = 0; // Fetch Integer instance only once. return Matrices.create(4, 4, new Number[] { - S, mZ, rY, param(0, mp), - rZ, S, mX, param(1, mp), - mY, rX, S, param(2, mp), + S, mZ, pY, param(0, mp), + pZ, S, mX, param(1, mp), + mY, pX, S, param(2, mp), O, O, O, 1}); } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java index c2e72fb9b4..37d1e44f38 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java @@ -19,7 +19,6 @@ package org.apache.sis.referencing.datum; import java.util.Map; import java.util.Arrays; import java.util.Objects; -import java.util.logging.Logger; import java.time.temporal.Temporal; import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.XmlElement; @@ -46,7 +45,6 @@ import org.apache.sis.referencing.internal.AnnotatedMatrix; import org.apache.sis.util.ComparisonMode; import org.apache.sis.util.CharSequences; import org.apache.sis.util.privy.CollectionsExt; -import org.apache.sis.system.Loggers; import org.apache.sis.util.logging.Logging; import org.apache.sis.io.wkt.Formatter; import static org.apache.sis.util.Utilities.deepEquals; @@ -55,6 +53,7 @@ import static org.apache.sis.util.ArgumentChecks.ensureNonNullElement; import static org.apache.sis.referencing.privy.WKTUtilities.toFormattable; // Specific to the geoapi-3.1 and geoapi-4.0 branches: +import org.opengis.referencing.datum.DynamicReferenceFrame; import org.opengis.metadata.Identifier; @@ -129,7 +128,7 @@ import org.opengis.metadata.Identifier; * constants. * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 1.4 + * @version 1.5 * * @see DefaultEllipsoid * @see DefaultPrimeMeridian @@ -144,13 +143,6 @@ import org.opengis.metadata.Identifier; }) @XmlRootElement(name = "GeodeticDatum") public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum { - /** - * The logger for coordinate operations. - * - * @see #getPositionVectorTransformation(GeodeticDatum, Extent) - */ - private static final Logger LOGGER = Logger.getLogger(Loggers.COORDINATE_OPERATION); - /** * Serial number for inter-operability with different versions. */ @@ -306,8 +298,13 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum * given object itself), or {@code null} if the argument was null. */ public static DefaultGeodeticDatum castOrCopy(final GeodeticDatum object) { - return (object == null) || (object instanceof DefaultGeodeticDatum) - ? (DefaultGeodeticDatum) object : new DefaultGeodeticDatum(object); + if (object == null || object instanceof DefaultGeodeticDatum) { + return (DefaultGeodeticDatum) object; + } + if (object instanceof DynamicReferenceFrame) { + return new Dynamic(object); + } + return new DefaultGeodeticDatum(object); } /** @@ -435,7 +432,8 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum * is defined in such a way that matrix should always be invertible. If it happen anyway, * returning `null` is allowed by this method's contract. */ - Logging.unexpectedException(LOGGER, DefaultGeodeticDatum.class, "getPositionVectorTransformation", e); + Logging.unexpectedException(CoordinateOperations.LOGGER, + DefaultGeodeticDatum.class, "getPositionVectorTransformation", e); } /* * No direct tranformation found. Search for a path through an intermediate datum. @@ -468,7 +466,8 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum Matrix m = MatrixSIS.castOrCopy(step2).inverse().multiply(step1); return AnnotatedMatrix.indirect(m, useAOI); } catch (NoninvertibleMatrixException e) { - Logging.unexpectedException(LOGGER, DefaultGeodeticDatum.class, "getPositionVectorTransformation", e); + Logging.unexpectedException(CoordinateOperations.LOGGER, + DefaultGeodeticDatum.class, "getPositionVectorTransformation", e); } } } @@ -481,21 +480,6 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum return null; } - /** - * Invokes {@link BursaWolfParameters#getPositionVectorTransformation(Temporal)} for a date calculated from - * the temporal elements on the given extent. This method chooses an instant located midway between the - * start and end time. - */ - private static Matrix createTransformation(final BursaWolfParameters bursaWolf, final Extent areaOfInterest) { - /* - * Implementation note: we know that we do not need to compute an instant if the parameters is - * not a subclass of BursaWolfParameters. This optimisation covers the vast majority of cases. - */ - return bursaWolf.getPositionVectorTransformation(bursaWolf.getClass() != BursaWolfParameters.class ? - Extents.getInstant(areaOfInterest, null, 0.5).orElse(null) : null); - // 0.5 is for choosing the instant midway between start and end. - } - /** * Returns the best parameters matching the given criteria, or {@code null} if none. */ @@ -511,6 +495,112 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum return selector.best(); } + /** + * Returns the position vector transformation (geocentric domain) as an affine transform. + * If this datum is dynamic, the frame reference epoch is used. + * Otherwise, a time is computed from the temporal area of interest. + * + * @see DynamicReferenceFrame#getFrameReferenceEpoch() + * @see BursaWolfParameters#getPositionVectorTransformation(Temporal) + */ + private Matrix createTransformation(final BursaWolfParameters bursaWolf, final Extent areaOfInterest) { + Temporal epoch = null; + /* + * Implementation note: we know that we do not need to compute an instant if the parameters is + * not a subclass of BursaWolfParameters. This optimisation covers the vast majority of cases. + */ + if (bursaWolf.getClass() != BursaWolfParameters.class) { + epoch = getFrameReferenceEpoch(); + if (epoch == null) { + epoch = Extents.getInstant(areaOfInterest, null, 0.5).orElse(null); + // 0.5 is for choosing the instant midway between start and end. + } + } + return bursaWolf.getPositionVectorTransformation(epoch); + } + + /** + * A geodetic reference frame in which some of the defining parameters have time dependency. + * The parameter values are valid at the time given by the + * {@linkplain #getFrameReferenceEpoch() frame reference epoch}. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 1.5 + */ + public static class Dynamic extends DefaultGeodeticDatum implements DynamicReferenceFrame { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 6117199873814779662L; + + /** + * The epoch to which the definition of the dynamic reference frame is referenced. + */ + @SuppressWarnings("serial") // Standard Java implementations are serializable. + private final Temporal frameReferenceEpoch; + + /** + * Creates a dynamic reference frame from the given properties. + * See super-class constructor for more information. + * + * @param properties the properties to be given to the identified object. + * @param ellipsoid the ellipsoid. + * @param primeMeridian the prime meridian. + * @param epoch the epoch to which the definition of the dynamic reference frame is referenced. + */ + public Dynamic(Map<String,?> properties, Ellipsoid ellipsoid, PrimeMeridian primeMeridian, Temporal epoch) { + super(properties, ellipsoid, primeMeridian); + frameReferenceEpoch = Objects.requireNonNull(epoch); + } + + /** + * Creates a new datum with the same values as the specified datum, which must be dynamic. + * + * @param datum the datum to copy. + * @throws ClassCastException if the given datum is not an instance of {@link DynamicReferenceFrame}. + * + * @see #castOrCopy(GeodeticDatum) + */ + protected Dynamic(final GeodeticDatum datum) { + super(datum); + frameReferenceEpoch = Objects.requireNonNull(((DynamicReferenceFrame) datum).getFrameReferenceEpoch()); + } + + /** + * Returns the epoch to which the coordinates of stations defining the dynamic reference frame are referenced. + * The type of the returned object depends on the epoch accuracy and the calendar in use. + * It may be merely a {@link java.time.Year}. + * + * @return the epoch to which the definition of the dynamic reference frame is referenced. + */ + @Override + public Temporal getFrameReferenceEpoch() { + return frameReferenceEpoch; + } + + /** + * Compares the specified object with this datum for equality. + * + * @hidden because nothing new to said. + */ + @Override + public boolean equals(final Object object, final ComparisonMode mode) { + return super.equals(object) && (mode != ComparisonMode.STRICT || + frameReferenceEpoch.equals(((Dynamic) object).frameReferenceEpoch)); + } + + /** + * Invoked by {@code hashCode()} for computing the hash code when first needed. + * + * @hidden because nothing new to said. + */ + @Override + protected long computeHashCode() { + return super.computeHashCode() + 31 * frameReferenceEpoch.hashCode(); + } + } + /** * Returns {@code true} if either the {@linkplain #getName() primary name} or at least * one {@linkplain #getAlias() alias} matches the given string according heuristic rules. @@ -580,13 +670,13 @@ public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum } switch (mode) { case STRICT: { - final DefaultGeodeticDatum that = (DefaultGeodeticDatum) object; + final var that = (DefaultGeodeticDatum) object; return Objects.equals(this.ellipsoid, that.ellipsoid) && Objects.equals(this.primeMeridian, that.primeMeridian) && Arrays.equals(this.bursaWolf, that.bursaWolf); } default: { - final GeodeticDatum that = (GeodeticDatum) object; + final var that = (GeodeticDatum) object; return deepEquals(getEllipsoid(), that.getEllipsoid(), mode) && deepEquals(getPrimeMeridian(), that.getPrimeMeridian(), mode); /* diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java index 6bbcdd48d0..b1fef4a79f 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultVerticalDatum.java @@ -18,6 +18,7 @@ package org.apache.sis.referencing.datum; import java.util.Map; import java.util.Objects; +import java.time.temporal.Temporal; import jakarta.xml.bind.annotation.XmlType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; @@ -34,6 +35,7 @@ import org.apache.sis.metadata.privy.ImplementationHelper; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import java.util.Optional; +import org.opengis.referencing.datum.DynamicReferenceFrame; import org.opengis.referencing.datum.RealizationMethod; import org.opengis.metadata.Identifier; @@ -211,6 +213,87 @@ public class DefaultVerticalDatum extends AbstractDatum implements VerticalDatum return Optional.ofNullable(method); } + /** + * A vertical reference frame in which some of the defining parameters have time dependency. + * The parameter values are valid at the time given by the + * {@linkplain #getFrameReferenceEpoch() frame reference epoch}. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 1.5 + */ + public static class Dynamic extends DefaultVerticalDatum implements DynamicReferenceFrame { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -2047994195060747008L; + + /** + * The epoch to which the definition of the dynamic reference frame is referenced. + */ + @SuppressWarnings("serial") // Standard Java implementations are serializable. + private final Temporal frameReferenceEpoch; + + /** + * Creates a dynamic reference frame from the given properties. + * See super-class constructor for more information. + * + * @param properties the properties to be given to the identified object. + * @param epoch the epoch to which the definition of the dynamic reference frame is referenced. + */ + public Dynamic(Map<String,?> properties, RealizationMethod method, Temporal epoch) { + super(properties, method); + frameReferenceEpoch = Objects.requireNonNull(epoch); + } + + /** + * Creates a new datum with the same values as the specified datum, which must be dynamic. + * + * @param datum the datum to copy. + * @param method the realization method (geoid, tidal, <i>etc.</i>), or {@code null} if unspecified. + * @throws ClassCastException if the given datum is not an instance of {@link DynamicReferenceFrame}. + * + * @see #castOrCopy(VerticalDatum) + */ + protected Dynamic(final VerticalDatum datum) { + super(datum); + frameReferenceEpoch = Objects.requireNonNull(((DynamicReferenceFrame) datum).getFrameReferenceEpoch()); + } + + /** + * Returns the epoch to which the coordinates of stations defining the dynamic reference frame are referenced. + * The type of the returned object depends on the epoch accuracy and the calendar in use. + * It may be merely a {@link java.time.Year}. + * + * @return the epoch to which the definition of the dynamic reference frame is referenced. + */ + @Override + public Temporal getFrameReferenceEpoch() { + return frameReferenceEpoch; + } + + /** + * Compares the specified object with this datum for equality. + * + * @hidden because nothing new to said. + */ + @Override + public boolean equals(final Object object, final ComparisonMode mode) { + return super.equals(object) && (mode != ComparisonMode.STRICT || + frameReferenceEpoch.equals(((Dynamic) object).frameReferenceEpoch)); + } + + /** + * Invoked by {@code hashCode()} for computing the hash code when first needed. + * + * @hidden because nothing new to said. + */ + @Override + protected long computeHashCode() { + return super.computeHashCode() + 31 * frameReferenceEpoch.hashCode(); + } + } + /** * Compares this vertical datum with the specified object for equality. * diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java index 51d03bcb17..623e89a925 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java @@ -65,6 +65,7 @@ import org.apache.sis.xml.XML; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import java.time.temporal.Temporal; +import org.opengis.referencing.datum.DynamicReferenceFrame; /** @@ -611,9 +612,9 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory } /** - * Creates a geodetic reference frame from ellipsoid and (optionally) Bursa-Wolf parameters. + * Creates a static geodetic reference frame from ellipsoid and (optionally) Bursa-Wolf parameters. * Geodetic reference frame defines the location and orientation of an ellipsoid that approximates the shape of the earth. - * This datum can be used with geographic, geocentric and engineering CRS. + * This datum can be used with geographic and geocentric <abbr>CRS</abbr>. * * <h4>Dependencies</h4> * The components needed by this method can be created by the following methods: @@ -650,6 +651,39 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory return unique("createGeodeticDatum", datum); } + /** + * Creates a dynamic geodetic reference frame from ellipsoid and frame reference epoch. + * The arguments are the same as for the {@linkplain #createGeodeticDatum(Map, Ellipsoid, + * PrimeMeridian) static datum}, with the addition of a mandatory frame reference epoch. + * The returned object implements the {@link DynamicReferenceFrame} interface. + * + * @param properties name and other properties to give to the new object. + * @param ellipsoid the ellipsoid to use in new geodetic reference frame. + * @param primeMeridian the prime meridian to use in new geodetic reference frame. + * @param epoch the epoch to which the definition of the dynamic reference frame is referenced. + * @throws FactoryException if the object creation failed. + * + * @see DefaultGeodeticDatum.Dynamic#Dynamic(Map, Ellipsoid, PrimeMeridian, Temporal) + * @see GeodeticAuthorityFactory#createGeodeticDatum(String) + * + * @since 1.5 + */ + @Override + public GeodeticDatum createGeodeticDatum(final Map<String,?> properties, + final Ellipsoid ellipsoid, + final PrimeMeridian primeMeridian, + final Temporal epoch) + throws FactoryException + { + final DefaultGeodeticDatum datum; + try { + datum = new DefaultGeodeticDatum.Dynamic(complete(properties), ellipsoid, primeMeridian, epoch); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createGeodeticDatum", datum); + } + /** * Creates a prime meridian, relative to Greenwich. * Defines the origin from which longitude values are determined. @@ -998,7 +1032,7 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory } /** - * Creates a vertical datum from a realization method. + * Creates a static vertical datum from a realization method. * The default implementation creates a {@link DefaultVerticalDatum} instance. * * @param properties name and other properties to give to the new object. @@ -1024,6 +1058,37 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory return unique("createVerticalDatum", datum); } + /** + * Creates a dynamic vertical datum from a realization method and a frame reference epoch. + * The arguments are the same as for the {@linkplain #createVerticalDatum(Map, RealizationMethod) + * static datum}, with the addition of a mandatory frame reference epoch. + * The returned object implements the {@link DynamicReferenceFrame} interface. + * + * @param properties name and other properties to give to the new object. + * @param method the realization method of the vertical datum, or {@code null} if none. + * @param epoch the epoch to which the definition of the dynamic reference frame is referenced. + * @throws FactoryException if the object creation failed. + * + * @see DefaultVerticalDatum.Dynamic#Dynamic(Map, RealizationMethod, Temporal) + * @see GeodeticAuthorityFactory#createVerticalDatum(String) + * + * @since 2.0 (temporary version number until this branch is released) + */ + @Override + public VerticalDatum createVerticalDatum(final Map<String,?> properties, + final RealizationMethod method, + final Temporal epoch) + throws FactoryException + { + final DefaultVerticalDatum datum; + try { + datum = new DefaultVerticalDatum.Dynamic(complete(properties), method, epoch); + } catch (IllegalArgumentException exception) { + throw new InvalidGeodeticParameterException(exception); + } + return unique("createVerticalDatum", datum); + } + /** * Creates a vertical coordinate system. * This coordinate system can be used with vertical and derived CRS. diff --git a/geoapi/snapshot b/geoapi/snapshot index 8281380030..367366e67f 160000 --- a/geoapi/snapshot +++ b/geoapi/snapshot @@ -1 +1 @@ -Subproject commit 828138003047cb68d25fb162732435be54ef2891 +Subproject commit 367366e67f7f860e100e0e8dafa3a03f34162e71