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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 3a6d0acf80 Deprecate
`DefaultMathTransformFactory.createParameterizedTransform(ParameterValueGroup,
Context)`. This is replaced by a builder.
3a6d0acf80 is described below
commit 3a6d0acf805e39a21eab1070eed03edf5cd14944
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Jun 30 05:00:29 2024 +0200
Deprecate
`DefaultMathTransformFactory.createParameterizedTransform(ParameterValueGroup,
Context)`.
This is replaced by a builder.
---
.../referencing/factory/sql/EPSGDataAccess.java | 3 +-
.../operation/AbstractSingleOperation.java | 4 +-
.../operation/CoordinateOperationFinder.java | 16 +-
.../operation/CoordinateOperationRegistry.java | 41 +-
.../referencing/operation/DefaultConversion.java | 42 +-
.../DefaultCoordinateOperationFactory.java | 3 +-
.../operation/MathTransformContext.java | 5 -
.../operation/projection/package-info.java | 5 +-
.../transform/DefaultMathTransformFactory.java | 512 ++++++++++++++-------
.../referencing/privy/ReferencingUtilities.java | 68 +--
.../operation/provider/GeographicOffsetsTest.java | 13 +-
.../transform/DefaultMathTransformFactoryTest.java | 18 +-
.../transform/MathTransformFactoryBase.java | 8 +
.../transform/MathTransformFactoryMock.java | 13 +
geoapi/snapshot | 2 +-
15 files changed, 451 insertions(+), 302 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 497646caba..f4694584cd 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -2950,7 +2950,8 @@ next: while (r.next()) {
*/
opProperties = new HashMap<>(opProperties);
// Because this class uses a shared map.
final MathTransformFactory mtFactory = owner.mtFactory;
- final MathTransform mt =
ReferencingUtilities.createBaseToDerived(mtFactory, sourceCRS, parameters,
targetCRS);
+ final MathTransform mt = ReferencingUtilities.builder(
+ mtFactory, parameters, sourceCRS,
targetCRS).create();
/*
* Give a hint to the factory about the type of the
coordinate operation. ISO 19111 defines
* Conversion and Transformation, but SIS also have
more specific sub-types. We begin with
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractSingleOperation.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractSingleOperation.java
index a721f0d225..de3287b2e1 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractSingleOperation.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractSingleOperation.java
@@ -468,8 +468,8 @@ class AbstractSingleOperation extends
AbstractCoordinateOperation implements Sin
final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
final CoordinateReferenceSystem targetCRS = super.getTargetCRS();
if (transform == null && sourceCRS != null && targetCRS != null &&
parameters != null) try {
- transform =
ReferencingUtilities.createBaseToDerived(DefaultMathTransformFactory.provider(),
- sourceCRS,
parameters, targetCRS);
+ transform =
ReferencingUtilities.builder(DefaultMathTransformFactory.provider(),
+ parameters, sourceCRS,
targetCRS).create();
} catch (FactoryException e) {
Context.warningOccured(Context.current(),
AbstractSingleOperation.class, "afterUnmarshal", e, true);
}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index 39a7d78e28..1c2313349b 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@ -513,6 +513,8 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
final GeodeticCRS
targetCRS)
throws FactoryException
{
+ final CoordinateSystem sourceCS = sourceCRS.getCoordinateSystem();
+ final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
final GeodeticDatum sourceDatum = sourceCRS.getDatum();
final GeodeticDatum targetDatum = targetCRS.getDatum();
Matrix datumShift = null;
@@ -525,8 +527,8 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
* prime meridians are not the same, then the target meridian must be
Greenwich.
*/
final DefaultMathTransformFactory.Context context = new
MathTransformContext(sourceDatum, targetDatum);
- context.setSource(sourceCRS);
- context.setTarget(targetCRS);
+ context.setSourceAxes(sourceCS, sourceDatum.getEllipsoid());
+ context.setTargetAxes(targetCS, targetDatum.getEllipsoid());
/*
* If both CRS use the same datum and the same prime meridian, then
the coordinate operation is only axis
* swapping, unit conversion or change of coordinate system type
(Ellipsoidal ↔ Cartesian ↔ Spherical).
@@ -536,8 +538,6 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
*/
Identifier identifier;
boolean isGeographicToGeocentric = false;
- final CoordinateSystem sourceCS = context.getSourceCS();
- final CoordinateSystem targetCS = context.getTargetCS();
if (equalsIgnoreMetadata(sourceDatum, targetDatum)) {
final boolean isGeocentricToGeographic;
isGeographicToGeocentric = (sourceCS instanceof EllipsoidalCS &&
targetCS instanceof CartesianCS);
@@ -612,8 +612,8 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
final CoordinateSystem normalized =
CommonCRS.WGS84.geocentric().getCoordinateSystem();
before = mtFactory.createCoordinateSystemChange(sourceCS,
normalized, sourceDatum.getEllipsoid());
after = mtFactory.createCoordinateSystemChange(normalized,
targetCS, targetDatum.getEllipsoid());
- context.setSource(normalized);
- context.setTarget(normalized);
+ context.setSourceAxes(normalized, null);
+ context.setTargetAxes(normalized, null);
/*
* The name of the `parameters` group determines the
`OperationMethod` later in this method.
* We cannot leave that name to "Affine" if `before` or
`after` transforms are not identity.
@@ -655,7 +655,7 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
*/
before = mtFactory.createCoordinateSystemChange(sourceCS,
targetCS,
(sourceCS instanceof EllipsoidalCS ? sourceDatum :
targetDatum).getEllipsoid());
- context.setSource(targetCS);
+ context.setSourceAxes(targetCS, null);
method = mtFactory.getLastMethodUsed();
}
}
@@ -675,7 +675,7 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
*/
MathTransform transform =
mtFactory.createParameterizedTransform(parameters, context);
if (method == null) {
- method = context.getMethodUsed();
+ method = context.getMethod().orElse(null);
}
if (before != null) {
parameters = null; // Providing parameters would be
misleading because they apply to only a step of the operation.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index 6bbb7f6814..c4aa7c3866 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -53,7 +53,6 @@ import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.cs.CoordinateSystems;
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.transform.MathTransforms;
-import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
import org.apache.sis.referencing.factory.UnavailableFactoryException;
@@ -1023,13 +1022,11 @@ class CoordinateOperationRegistry {
CoordinateReferenceSystem crs;
if (Utilities.equalsApproximately(sourceCRS, crs =
operation.getSourceCRS())) sourceCRS = crs;
if (Utilities.equalsApproximately(targetCRS, crs =
operation.getTargetCRS())) targetCRS = crs;
- final MathTransformFactory mtFactory =
factorySIS.getMathTransformFactory();
- if (mtFactory instanceof DefaultMathTransformFactory) {
- MathTransform mt = ((DefaultMathTransformFactory)
mtFactory).createParameterizedTransform(
- parameters,
ReferencingUtilities.createTransformContext(sourceCRS, targetCRS));
- return
factorySIS.createSingleOperation(IdentifiedObjects.getProperties(operation),
- sourceCRS, targetCRS, null, operation.getMethod(), mt);
- }
+ var builder = ReferencingUtilities.builder(
+ factorySIS.getMathTransformFactory(), parameters,
sourceCRS, targetCRS);
+ final MathTransform mt = builder.create(); // Must be before
`operation.getMethod()`.
+ return
factorySIS.createSingleOperation(IdentifiedObjects.getProperties(operation),
+ sourceCRS, targetCRS, null, operation.getMethod(), mt);
} else {
// Should never happen because parameters are mandatory, but let
be safe.
log(resources().getLogRecord(Level.WARNING,
Resources.Keys.MissingParameterValues_1,
@@ -1141,22 +1138,20 @@ class CoordinateOperationRegistry {
if (matrix == null) {
if (op instanceof SingleOperation) {
final MathTransformFactory mtFactory =
factorySIS.getMathTransformFactory();
- if (mtFactory instanceof DefaultMathTransformFactory) {
- if (forward) sourceCRS = toGeodetic3D(sourceCRS,
source3D);
- else targetCRS = toGeodetic3D(targetCRS,
target3D);
- final DefaultMathTransformFactory.Context context;
- final MathTransform mt;
- try {
- context =
ReferencingUtilities.createTransformContext(sourceCRS, targetCRS);
- mt = ((DefaultMathTransformFactory)
mtFactory).createParameterizedTransform(
- ((SingleOperation)
op).getParameterValues(), context);
- } catch (InvalidGeodeticParameterException e) {
- log(null, e);
- break;
- }
- operations.set(recreate(op, sourceCRS, targetCRS, mt,
context.getMethodUsed()));
- return true;
+ if (forward) sourceCRS = toGeodetic3D(sourceCRS, source3D);
+ else targetCRS = toGeodetic3D(targetCRS, target3D);
+ final MathTransform.Builder builder;
+ final MathTransform mt;
+ try {
+ final var parameters = ((SingleOperation)
op).getParameterValues();
+ builder = ReferencingUtilities.builder(mtFactory,
parameters, sourceCRS, targetCRS);
+ mt = builder.create();
+ } catch (InvalidGeodeticParameterException e) {
+ log(null, e);
+ break;
}
+ operations.set(recreate(op, sourceCRS, targetCRS, mt,
builder.getMethod().orElse(null)));
+ return true;
}
break;
}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
index b3d96d3e2a..f7358bb8d5 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
@@ -237,41 +237,31 @@ public class DefaultConversion extends
AbstractSingleOperation implements Conver
if (parameters == null) {
throw new
IllegalArgumentException(Resources.format(Resources.Keys.UnspecifiedParameterValues));
}
- if (factory instanceof DefaultMathTransformFactory) {
- /*
- * Apache SIS specific API (not yet defined in GeoAPI, but
could be proposed).
- * Note that setTarget(…) intentionally uses only the
CoordinateSystem instead of the full
- * CoordinateReferenceSystem because the targetCRS is
typically under construction when this
- * method in invoked, and attempts to use it can cause
NullPointerException.
- */
- final DefaultMathTransformFactory.Context context;
- if (target instanceof DerivedCRS) {
- context =
ReferencingUtilities.createTransformContext(source, null);
- context.setTarget(target.getCoordinateSystem()); //
Using `target` would be unsafe here.
- } else {
- context =
ReferencingUtilities.createTransformContext(source, target);
- }
- transform = ((DefaultMathTransformFactory)
factory).createParameterizedTransform(parameters, context);
+ /*
+ * Note that setTargetAxes(…) intentionally uses only the
CoordinateSystem instead of the full
+ * CoordinateReferenceSystem because the targetCRS is typically
under construction when this
+ * method in invoked, and attempts to use it can cause
NullPointerException.
+ */
+ final boolean isDerived = (target instanceof DerivedCRS);
+ var builder = ReferencingUtilities.builder(factory, parameters,
source, isDerived ? null : target);
+ if (isDerived) {
+ builder.setTargetAxes(target.getCoordinateSystem(), null);
+ }
+ transform = builder.create();
+ if (builder instanceof DefaultMathTransformFactory.Context) {
+ final var context = (DefaultMathTransformFactory.Context)
builder;
setParameterValues(context.getCompletedParameters(),
context.getContextualParameters());
- } else {
- /*
- * Fallback for non-SIS implementation. Equivalent to the
above code, except that we can
- * not get the parameters completed with semi-major and
semi-minor axis lengths. Most of
- * the code should work anyway.
- */
- transform = factory.createBaseToDerived(source, parameters,
target.getCoordinateSystem());
}
} else {
/*
* If the user specified explicitly a MathTransform, we may still
need to swap or scale axes.
* If this conversion is a defining conversion (which is usually
the case when creating a new
- * ProjectedCRS), then DefaultMathTransformFactory has a
specialized createBaseToDerived(…)
- * method for this job.
+ * ProjectedCRS), then MathTransformFactory has a specialized
builder(…) method for this job.
*/
if (sourceCRS == null && targetCRS == null && factory instanceof
DefaultMathTransformFactory) {
final var context = new DefaultMathTransformFactory.Context();
- context.setSource(source.getCoordinateSystem());
- context.setTarget(target.getCoordinateSystem()); // See
comment on the other setTarget(…) call.
+ context.setSourceAxes(source.getCoordinateSystem(), null);
+ context.setTargetAxes(target.getCoordinateSystem(), null);
// See comment on the other setTargetAxes(…) call.
transform = ((DefaultMathTransformFactory)
factory).swapAndScaleAxes(transform, context);
} else {
/*
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index 80e25bccd7..52c794c1cc 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -506,7 +506,8 @@ next: for (int i=components.size(); --i >= 0;) {
if (parameters == null) {
throw new
NullPointerException(Errors.format(Errors.Keys.NullArgument_1, "transform"));
}
- transform =
ReferencingUtilities.createBaseToDerived(getMathTransformFactory(), sourceCRS,
parameters, targetCRS);
+ transform = ReferencingUtilities.builder(
+ getMathTransformFactory(), parameters, sourceCRS,
targetCRS).create();
}
/*
* The "operationType" property is currently undocumented. The intent
is to help this factory method in
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
index 90b94e6f6d..350c25ed91 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
@@ -43,11 +43,6 @@ import org.apache.sis.measure.Units;
* @author Martin Desruisseaux (Geomatys)
*/
final class MathTransformContext extends Context {
- /**
- * For cross-version compatibility.
- */
- private static final long serialVersionUID = 8765209303733056283L;
-
/**
* The longitude of the source and target prime meridian, in number of
degrees East of Greenwich.
*/
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/package-info.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/package-info.java
index 69564d8421..7b28b53b7b 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/package-info.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/package-info.java
@@ -99,9 +99,8 @@
* The real axis flip is performed outside this projection package, upon
* {@linkplain org.opengis.referencing.cs.CoordinateSystemAxis coordinate
system axis} inspection,
* as a concatenation of the North oriented cartographic projection with an
affine transform.
- * Such axis analysis and transforms concatenation can be performed
automatically by the
- * {@link
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createBaseToDerived
- * createBaseToDerived(…)} method defined in the {@code MathTransformFactory}
interface.
+ * Such axis analysis and transforms concatenation can be performed
automatically by
+ * {@link
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.Context}.
* The same rule applies to the <cite>Krovak</cite> projection as well (at the
opposite of what ESRI does).
*
* <p>In order to reduce the risk of confusion, this package never defines
south oriented map projection.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 84e54a6232..d11a29a3e5 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.ServiceLoader;
import java.util.Objects;
+import java.util.Optional;
import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -29,7 +30,6 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.lang.reflect.Constructor;
-import java.io.Serializable;
import javax.measure.Unit;
import javax.measure.IncommensurableException;
import javax.measure.quantity.Length;
@@ -45,6 +45,7 @@ import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.SphericalCS;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
@@ -85,6 +86,9 @@ import org.apache.sis.util.iso.AbstractFactory;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.resources.Errors;
+// Specific to the geoapi-3.1 and geoapi-4.0 branches:
+import org.opengis.util.UnimplementedServiceException;
+
/**
* Low level factory for creating {@linkplain AbstractMathTransform math
transforms}.
@@ -476,6 +480,39 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
return method;
}
+ /**
+ * Returns a builder for a parameterized math transform using the
specified operation method.
+ * The {@code method} argument should be the name or identifier of an
{@link OperationMethod}
+ * instance returned by <code>{@link #getAvailableMethods(Class)
getAvailableMethods}(null)</code>.
+ *
+ * <p>The returned builder allows to specify not only the operation
parameter values,
+ * but also some contextual information such as the source and target axes.
+ * The builder uses these information for:</p>
+ *
+ * <ol>
+ * <li>Inferring the {@code "semi_major"}, {@code "semi_minor"}, {@code
"src_semi_major"},
+ * {@code "src_semi_minor"}, {@code "tgt_semi_major"} or {@code
"tgt_semi_minor"} parameter values
+ * from the {@link Ellipsoid} associated to the source or target
CRS, if these parameters are
+ * not explicitly given and if they are relevant for the coordinate
operation method.</li>
+ * <li>{@linkplain #createConcatenatedTransform Concatenating} the
parameterized transform
+ * with any other transforms required for performing units changes
and coordinates swapping.</li>
+ * </ol>
+ *
+ * The complete group of parameters, including {@code "semi_major"},
{@code "semi_minor"} or other
+ * calculated values, can be obtained by a call to {@link
Context#getCompletedParameters()}.
+ *
+ * @param method the case insensitive name or identifier of the desired
coordinate operation method.
+ * @return a builder for a meth transform implementing the formulas
identified by the given method.
+ * @throws NoSuchIdentifierException if there is no supported method for
the given name or identifier.
+ *
+ * @see #getAvailableMethods(Class)
+ * @since 1.5
+ */
+ @Override
+ public MathTransform.Builder builder(final String method) throws
NoSuchIdentifierException {
+ return new Context(this, getOperationMethod(method));
+ }
+
/**
* Returns the default parameter values for a math transform using the
given operation method.
* The {@code method} argument is the name of any {@code OperationMethod}
instance returned by
@@ -500,36 +537,16 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
}
/**
- * Creates a transform from a group of parameters.
- * The set of expected parameters varies for each operation.
- *
- * @param parameters the parameter values. The {@linkplain
ParameterDescriptorGroup#getName() parameter group name}
- * shall be the name of the desired {@linkplain
DefaultOperationMethod operation method}.
- * @return the transform created from the given parameters.
- * @throws NoSuchIdentifierException if there is no method for the given
parameter group name.
- * @throws FactoryException if the object creation failed. This exception
is thrown
- * if some required parameter has not been supplied, or has
illegal value.
- *
- * @deprecated Replaced by {@link
#createParameterizedTransform(ParameterValueGroup, Context)}
- * where the {@code Context} argument can be null.
- */
- @Override
- @Deprecated(since="0.7")
- public MathTransform createParameterizedTransform(final
ParameterValueGroup parameters)
- throws NoSuchIdentifierException, FactoryException
- {
- return createParameterizedTransform(parameters, null);
- }
-
- /**
- * Source and target coordinate systems for which a new parameterized
transform is going to be used.
+ * Builder of a parameterized math transform identified by a name or code.
+ * A builder can optionally contain the source and target coordinate
systems
+ * for which a new parameterized transform is going to be used.
* {@link DefaultMathTransformFactory} uses this information for:
*
* <ul>
* <li>Completing some parameters if they were not provided. In
particular, the {@linkplain #getSourceEllipsoid()
* source ellipsoid} can be used for providing values for the {@code
"semi_major"} and {@code "semi_minor"}
* parameters in map projections.</li>
- * <li>{@linkplain CoordinateSystems#swapAndScaleAxes Swapping and
scaling axes} if the source or the target
+ * <li>{@linkplain #swapAndScaleAxes Swapping and scaling axes} if the
source or the target
* coordinate systems are not {@linkplain AxesConvention#NORMALIZED
normalized}.</li>
* </ul>
*
@@ -538,25 +555,19 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* or anything else related to datum. Datum changes have dedicated {@link
OperationMethod},
* for example <q>Longitude rotation</q> (EPSG:9601) for changing the
prime meridian.
*
- * <h2>Scope</h2>
- * Instances of this class should be short-lived
- * (they exist only the time needed for creating a {@link MathTransform})
- * and should not be shared (because they provide no immutability
guarantees).
- * This class is not thread-safe.
+ * <p>Each instance is created by {@link #builder(String)} and should be
used only once.
+ * This class is <em>not</em> thread-safe.</p>
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.5
* @since 0.7
+ *
+ * @see #builder(String)
*/
- @SuppressWarnings("serial") // All field values are usually
serializable instances.
- public static class Context implements MathTransformProvider.Context,
Serializable {
- /**
- * For cross-version compatibility.
- */
- private static final long serialVersionUID = -239563539875674709L;
-
+ public static class Context implements MathTransform.Builder,
MathTransformProvider.Context {
/**
* The factory to use if the provider needs to create other math
transforms as operation steps.
+ * @todo Replace by non-static inner class after deprecated methods
have been removed.
*
* @see #getFactory()
*/
@@ -569,21 +580,23 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
/**
* The ellipsoid of the source or target ellipsoidal coordinate
system, or {@code null} if it does not apply.
- * Valid only if {@link #sourceCS} or {@link #targetCS} is an instance
of {@link EllipsoidalCS}.
*/
private Ellipsoid sourceEllipsoid, targetEllipsoid;
/**
* The provider that created the parameterized {@link MathTransform}
instance, or {@code null}
- * if this information does not apply. This field is used for
transferring information between
- * {@code createParameterizedTransform(…)} and {@code
swapAndScaleAxes(…)}.
+ * if this information does not apply. This is initially set to the
operation method specified
+ * in the call to {@link #builder(String)}, but may be modified by
{@link #create()}.
+ *
+ * @see #getMethod()
*/
private OperationMethod provider;
/**
* The parameters actually used.
+ * @todo Make final after the deprecated methods have been removed.
*
- * @see #getCompletedParameters()
+ * @see #parameters()
*/
private ParameterValueGroup parameters;
@@ -594,17 +607,47 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
*/
private final Map<String,Boolean> contextualParameters;
+ /**
+ * Whether the user-specified parameters have been completed with the
contextual parameters.
+ * This set to {@code true} the first time that {@link
#getCompletedParameters()} is invoked.
+ * After this flag became {@code true}, this {@code Context} should
not be modified anymore.
+ *
+ * @see #completeParameters()
+ */
+ private boolean completedParameters;
+
+ /**
+ * The warning that occurred during parameters completion, or {@code
null} if none.
+ * This warning is not necessarily fatal, but will be appended to the
suppressed exceptions
+ * of {@link FactoryException} if the {@link MathTransform} creation
nevertheless fail.
+ */
+ private RuntimeException warning;
+
/**
* Creates a new context with all properties initialized to {@code
null}.
+ *
+ * @deprecated Use {@link #builder(String)} instead.
*/
+ @Deprecated(since="1.5", forRemoval=true)
public Context() {
contextualParameters = new HashMap<>();
}
+ /**
+ * Creates a new context with all properties initialized to {@code
null}.
+ *
+ * @param method a method known to the enclosing factory.
+ */
+ Context(final DefaultMathTransformFactory factory, final
OperationMethod method) {
+ this.factory = factory;
+ provider = method;
+ parameters = method.getParameters().createValue();
+ contextualParameters = new HashMap<>();
+ }
+
/**
* Returns the factory to use if the provider needs to create other
math transforms as operation steps.
- * This is the factory on which {@link
#createParameterizedTransform(ParameterValueGroup, Context)} is
- * invoked, or the {@linkplain #provider() default factory} otherwise.
+ * This is the factory on which {@link #builder(String)} has been
invoked.
*
* @since 1.5
*/
@@ -613,15 +656,39 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
return (factory != null) ? factory : provider();
}
+ /**
+ * Gives hints about axis lengths and their orientations in input
coordinates.
+ * The {@code ellipsoid} argument is often provided together with an
{@link EllipsoidalCS}, but not only.
+ * For example, a two-dimensional {@link SphericalCS} may also require
information about the ellipsoid.
+ *
+ * <p>Each call to this method replaces the values of the previous
call.
+ * However, this method cannot be invoked anymore after {@link
#getCompletedParameters()} has been invoked.</p>
+ *
+ * @param cs the coordinate system defining source axis order and
units, or {@code null} if none.
+ * @param ellipsoid the ellipsoid providing source semi-axis
lengths, or {@code null} if none.
+ * @throws IllegalStateException if {@link #getCompletedParameters()}
has already been invoked.
+ *
+ * @since 1.5
+ */
+ @Override
+ public void setSourceAxes(CoordinateSystem cs, Ellipsoid ellipsoid) {
+ if (completedParameters) {
+ throw new
IllegalStateException(Errors.format(Errors.Keys.AlreadyInitialized_1,
"completedParameters"));
+ }
+ sourceCS = cs;
+ sourceEllipsoid = ellipsoid;
+ }
+
/**
* Sets the source coordinate system to the given value.
* The source ellipsoid is unconditionally set to {@code null}.
*
* @param cs the coordinate system to set as the source (can be
{@code null}).
+ * @deprecated Replaced by {@link #setSourceAxes(CoordinateSystem,
Ellipsoid)} for simplifying the API.
*/
+ @Deprecated(since="1.5", forRemoval=true)
public void setSource(final CoordinateSystem cs) {
- sourceCS = cs;
- sourceEllipsoid = null;
+ setSourceAxes(cs, null);
}
/**
@@ -636,15 +703,38 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* @param crs the coordinate system and ellipsoid to set as the
source, or {@code null}.
*
* @since 1.3
+ * @deprecated Replaced by {@link #setSourceAxes(CoordinateSystem,
Ellipsoid)} for simplifying the API.
*/
+ @Deprecated(since="1.5", forRemoval=true)
public void setSource(final GeodeticCRS crs) {
if (crs != null) {
- sourceCS = crs.getCoordinateSystem();
- sourceEllipsoid = crs.getDatum().getEllipsoid();
+ setSourceAxes(crs.getCoordinateSystem(),
crs.getDatum().getEllipsoid());
} else {
- sourceCS = null;
- sourceEllipsoid = null;
+ setSourceAxes(null, null);
+ }
+ }
+
+ /**
+ * Gives hints about axis lengths and their orientations in output
coordinates.
+ * The {@code ellipsoid} argument is often provided together with an
{@link EllipsoidalCS}, but not only.
+ * For example, a two-dimensional {@link SphericalCS} may also require
information about the ellipsoid.
+ *
+ * <p>Each call to this method replaces the values of the previous
call.
+ * However, this method cannot be invoked anymore after {@link
#getCompletedParameters()} has been invoked.</p>
+ *
+ * @param cs the coordinate system defining target axis order and
units, or {@code null} if none.
+ * @param ellipsoid the ellipsoid providing target semi-axis
lengths, or {@code null} if none.
+ * @throws IllegalStateException if {@link #getCompletedParameters()}
has already been invoked.
+ *
+ * @since 1.5
+ */
+ @Override
+ public void setTargetAxes(CoordinateSystem cs, Ellipsoid ellipsoid) {
+ if (completedParameters) {
+ throw new
IllegalStateException(Errors.format(Errors.Keys.AlreadyInitialized_1,
"completedParameters"));
}
+ targetCS = cs;
+ targetEllipsoid = ellipsoid;
}
/**
@@ -652,10 +742,11 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* The target ellipsoid is unconditionally set to {@code null}.
*
* @param cs the coordinate system to set as the target (can be
{@code null}).
+ * @deprecated Replaced by {@link #setTargetAxes(CoordinateSystem,
Ellipsoid)} for simplifying the API.
*/
+ @Deprecated(since="1.5", forRemoval=true)
public void setTarget(final CoordinateSystem cs) {
- targetCS = cs;
- targetEllipsoid = null;
+ setTargetAxes(cs, null);
}
/**
@@ -670,14 +761,14 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* @param crs the coordinate system and ellipsoid to set as the
target, or {@code null}.
*
* @since 1.3
+ * @deprecated Replaced by {@link #setTargetAxes(CoordinateSystem,
Ellipsoid)} for simplifying the API.
*/
+ @Deprecated(since="1.5", forRemoval=true)
public void setTarget(final GeodeticCRS crs) {
if (crs != null) {
- targetCS = crs.getCoordinateSystem();
- targetEllipsoid = crs.getDatum().getEllipsoid();
+ setTargetAxes(crs.getCoordinateSystem(),
crs.getDatum().getEllipsoid());
} else {
- targetCS = null;
- targetEllipsoid = null;
+ setTargetAxes(null, null);
}
}
@@ -691,10 +782,9 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
}
/**
- * Returns the ellipsoid of the source ellipsoidal coordinate system,
or {@code null} if it does not apply.
- * This information is valid only if {@link #getSourceCS()} returns an
instance of {@link EllipsoidalCS}.
+ * Returns the ellipsoid used together with the source coordinate
system, or {@code null} if none.
*
- * @return the ellipsoid of the source ellipsoidal coordinate system,
or {@code null} if it does not apply.
+ * @return the ellipsoid used together with the source coordinate
system, or {@code null} if none.
*/
public Ellipsoid getSourceEllipsoid() {
return sourceEllipsoid;
@@ -721,10 +811,9 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
}
/**
- * Returns the ellipsoid of the target ellipsoidal coordinate system,
or {@code null} if it does not apply.
- * This information is valid only if {@link #getTargetCS()} returns an
instance of {@link EllipsoidalCS}.
+ * Returns the ellipsoid used together with the target coordinate
system, or {@code null} if none.
*
- * @return the ellipsoid of the target ellipsoidal coordinate system,
or {@code null} if it does not apply.
+ * @return the ellipsoid used together with the target coordinate
system, or {@code null} if none.
*/
public Ellipsoid getTargetEllipsoid() {
return targetEllipsoid;
@@ -801,6 +890,21 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
}
}
+ /**
+ * Returns the operation method used for creating the math transform
from the parameter values.
+ * This is initially the operation method specified in the call to
{@link #builder(String)},
+ * but may change after the call to {@link #create()} if the method
has been adjusted because
+ * of the parameter values.
+ *
+ * @return the operation method used for creating the math transform
from the parameter values.
+ *
+ * @since 1.5
+ */
+ @Override
+ public Optional<OperationMethod> getMethod() {
+ return Optional.ofNullable(provider);
+ }
+
/**
* Returns the operation method used for the math transform creation.
* This is the same information as {@link #getLastMethodUsed()} but
more stable
@@ -810,10 +914,11 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* @throws IllegalStateException if {@link
#createParameterizedTransform(ParameterValueGroup, Context)}
* has not yet been invoked.
*
- * @see #getLastMethodUsed()
+ * @deprecated Replaced by {@link #getMethod()}.
*
* @since 1.3
*/
+ @Deprecated(since="1.5", forRemoval=true)
public OperationMethod getMethodUsed() {
if (provider != null) {
return provider;
@@ -821,6 +926,24 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
throw new
IllegalStateException(Resources.format(Resources.Keys.UnspecifiedParameterValues));
}
+ /**
+ * Returns the parameter values to modify for defining the transform
to create.
+ * Those parameters are initialized to default values, which are
{@linkplain #getMethod() method} depend.
+ * User-supplied values should be set directly in the returned
instance with codes like
+ *
<code>parameter(</code><var>name</var><code>).setValue(</code><var>value</var><code>)</code>.
+ *
+ * @return the parameter values to modify for defining the transform
to create.
+ *
+ * @since 1.5
+ */
+ @Override
+ public ParameterValueGroup parameters() {
+ if (parameters == null) {
+ parameters = provider.getParameters().createValue();
+ }
+ return parameters;
+ }
+
/**
* Returns the names of parameters that have been inferred from the
context.
* The set of keys can contain any of {@code "dim"},
@@ -831,15 +954,15 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* The parameters named in that set are included in the parameters
* returned by {@link #getCompletedParameters()}.
*
- * <h4>Associated boolean values</h4>
- * The associated boolean in the map tells whether the named parameter
value is really contextual.
- * The boolean is {@code FALSE} if the user explicitly specified a
value in the parameters given to
+ * <h4>Associated Boolean values</h4>
+ * The associated Boolean in the map tells whether the named parameter
value is really contextual.
+ * The Boolean is {@code FALSE} if the user explicitly specified a
value in the parameters given to
* the {@link #createParameterizedTransform(ParameterValueGroup,
Context)} method,
* and that value is different than the value inferred from the
context.
* Such inconsistencies are also logged at {@link Level#WARNING}.
* In all other cases
* (no value specified by the user, or a value was specified but is
consistent with the context),
- * the associated boolean in the map is {@code TRUE}.
+ * the associated Boolean in the map is {@code TRUE}.
*
* <h4>Mutability</h4>
* The returned map is modifiable for making easier for callers to
amend the contextual information.
@@ -858,15 +981,26 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
/**
* Returns the parameter values used for the math transform creation,
* including the parameters completed by the factory.
- * The parameters inferred from the context are listed by {@link
#getContextualParameters()}.
+ * This is the union of {@link #parameters()} with {@link
#getContextualParameters()}.
+ * The completed parameters may only have additional parameters
compared to the user-supplied parameters.
+ * {@linkplain #parameters() Parameter} values that were explicitly
set by the user are not overwritten.
+ *
+ * <p>After this method has been invoked, the {@link #setSourceAxes
setSourceAxes(…)}
+ * and {@link #setTargetAxes setTargetAxes(…)} methods can no longer
be invoked.</p>
*
* @return the parameter values used by the factory.
- * @throws IllegalStateException if {@link
#createParameterizedTransform(ParameterValueGroup, Context)}
- * has not yet been invoked.
*/
@Override
public ParameterValueGroup getCompletedParameters() {
if (parameters != null) {
+ /*
+ * If the user's parameters do not contain semi-major and
semi-minor axis lengths, infer
+ * them from the ellipsoid. We have to do that because those
parameters are often omitted,
+ * since the standard place where to provide this information
is in the ellipsoid object.
+ */
+ if (!completedParameters) {
+ warning = completeParameters();
+ }
return parameters;
}
throw new
IllegalStateException(Resources.format(Resources.Keys.UnspecifiedParameterValues));
@@ -885,6 +1019,8 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* @param writable {@code true} if this method should also check
that the parameters group is editable.
* @throws IllegalArgumentException if the copy cannot be performed
because a parameter has
* a unrecognized name or an illegal value.
+ *
+ * @todo We should be able to remove this method after we removed the
other deprecated methods.
*/
private void ensureCompatibleParameters(final boolean writable) throws
IllegalArgumentException {
final ParameterDescriptorGroup expected = provider.getParameters();
@@ -1053,41 +1189,16 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
/**
* Completes the parameter group with information about source and
target ellipsoid axis lengths,
* if available. This method writes semi-major and semi-minor
parameter values only if they do not
- * already exists in the given parameters.
+ * already exists in the current parameters.
*
- * <p>The given method and parameters are stored in the {@link
#provider} and {@link #parameters}
- * fields respectively. The actual stored values may differ from the
values given to this method.
- * The {@link #factory} field must be set before this method is
invoked.</p>
- *
- * @param method description of the transform to be created, or
{@code null} if unknown.
* @return the exception if the operation failed, or {@code null} if
none. This exception is not thrown now
* because the caller may succeed in creating the transform
anyway, or otherwise may produce a more
* informative exception.
- * @throws IllegalArgumentException if the operation fails because a
parameter has a unrecognized name or an
- * illegal value.
*
* @see #getCompletedParameters()
*/
- final RuntimeException completeParameters(OperationMethod method,
final ParameterValueGroup userParams)
- throws FactoryException, IllegalArgumentException
- {
- /*
- * The "Geographic/geocentric conversions" conversion (EPSG:9602)
can be either:
- *
- * - "Ellipsoid_To_Geocentric"
- * - "Geocentric_To_Ellipsoid"
- *
- * EPSG defines both by a single operation, but Apache SIS needs
to distinguish them.
- */
- if (method instanceof AbstractProvider) {
- final String alt = ((AbstractProvider)
method).resolveAmbiguity(this);
- if (alt != null) {
- method = factory.getOperationMethod(alt);
- }
- }
- provider = method;
- parameters = userParams;
- ensureCompatibleParameters(false); // Invoke only after we
set `provider` to its final instance.
+ private RuntimeException completeParameters() throws
IllegalArgumentException {
+ completedParameters = true; // Need to be first.
/*
* Get a mask telling us if we need to set parameters for the
source and/or target ellipsoid.
* This information should preferably be given by the provider.
But if the given provider is
@@ -1128,10 +1239,65 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
return failure;
}
+ /**
+ * Creates the parameterized transform. The operation method is given
by {@link #getMethod()}
+ * and the parameter values should have been set on the group returned
by {@link #parameters()}
+ * before to invoke this constructor.
+ *
+ * @return the parameterized transform.
+ * @throws FactoryException if the transform creation failed.
+ * This exception is thrown if some required parameters have not been
supplied, or have illegal values.
+ *
+ * @since 1.5
+ */
+ @Override
+ public MathTransform create() throws FactoryException {
+ try {
+ if (provider instanceof AbstractProvider) {
+ /*
+ * The "Geographic/geocentric conversions" conversion
(EPSG:9602) can be either:
+ *
+ * - "Ellipsoid_To_Geocentric"
+ * - "Geocentric_To_Ellipsoid"
+ *
+ * EPSG defines both by a single operation, but Apache SIS
needs to distinguish them.
+ */
+ final String method = ((AbstractProvider)
provider).resolveAmbiguity(this);
+ if (method != null) {
+ provider = factory.getOperationMethod(method);
+ }
+ }
+ final MathTransform transform;
+ if (provider instanceof MathTransformProvider) try {
+ transform = ((MathTransformProvider)
provider).createMathTransform(this);
+ } catch (IllegalArgumentException | IllegalStateException
exception) {
+ throw new
InvalidGeodeticParameterException(exception.getLocalizedMessage(), exception);
+ } else {
+ throw new UnimplementedServiceException(Errors.format(
+ Errors.Keys.UnsupportedImplementation_1,
Classes.getClass(provider)));
+ }
+ /*
+ * Make sure that the number of dimensions is compatible with
the OperationMethod instance.
+ * Then make final adjustment for axis directions and units of
measurement.
+ */
+ if (provider instanceof AbstractProvider) {
+ provider = ((AbstractProvider)
provider).variantFor(transform);
+ }
+ return factory.unique(factory.swapAndScaleAxes(transform,
this));
+ } catch (FactoryException exception) {
+ if (warning != null) {
+ exception.addSuppressed(warning);
+ }
+ throw exception;
+ } finally {
+ factory.lastMethod.set(provider);
+ }
+ }
+
/**
* Returns a string representation of this context for debugging
purposes.
- * Current implementation write the name of source/target coordinate
systems and ellipsoids.
- * If {@linkplain #getContextualParameters() contextual parameters}
have already been inferred,
+ * The current implementation writes the name of source/target
coordinate systems and ellipsoids.
+ * If the {@linkplain #getContextualParameters() contextual
parameters} have already been inferred,
* then their names are appended with inconsistent parameters (if any)
written on a separated line.
*
* @return a string representation of this context.
@@ -1186,32 +1352,11 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* }
*
* Sometimes the {@code "semi_major"} and {@code "semi_minor"} parameter
values are not explicitly provided,
- * but rather inferred from the {@linkplain
org.apache.sis.referencing.datum.DefaultGeodeticDatum geodetic
- * datum} of the source Coordinate Reference System. If the given {@code
context} argument is non-null,
- * then this method will use those contextual information for:
- *
- * <ol>
- * <li>Inferring the {@code "semi_major"}, {@code "semi_minor"}, {@code
"src_semi_major"},
- * {@code "src_semi_minor"}, {@code "tgt_semi_major"} or {@code
"tgt_semi_minor"} parameter values
- * from the {@linkplain
org.apache.sis.referencing.datum.DefaultEllipsoid ellipsoids} associated to
- * the source or target CRS, if those parameters are not explicitly
given and if they are relevant
- * for the coordinate operation method.</li>
- * <li>{@linkplain #createConcatenatedTransform Concatenating} the
parameterized transform
- * with any other transforms required for performing units changes
and coordinates swapping.</li>
- * </ol>
- *
- * The complete group of parameters, including {@code "semi_major"},
{@code "semi_minor"} or other calculated values,
- * can be obtained by a call to {@link Context#getCompletedParameters()}
after {@code createParameterizedTransform(…)}
- * returned. Note that the completed parameters may only have additional
parameters compared to the given parameter
- * group; existing parameter values should not be modified.
- *
- * <p>The {@code OperationMethod} instance used by this constructor can be
obtained by a call to
- * {@link #getLastMethodUsed()}.</p>
+ * but rather inferred from the {@linkplain
org.opengis.referencing.datum.GeodeticDatum geodetic
+ * reference frame} of the source Coordinate Reference System.
*
* @param parameters the parameter values. The {@linkplain
ParameterDescriptorGroup#getName() parameter group name}
- * shall be the name of the desired {@linkplain
DefaultOperationMethod operation method}.
- * @param context information about the context (for example source
and target coordinate systems)
- * in which the new transform is going to be used, or
{@code null} if none.
+ * shall be the name of the desired {@linkplain
DefaultOperationMethod operation method}.
* @return the transform created from the given parameters.
* @throws NoSuchIdentifierException if there is no method for the given
parameter group name.
* @throws FactoryException if the object creation failed. This exception
is thrown
@@ -1222,8 +1367,9 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* @see #getLastMethodUsed()
* @see
org.apache.sis.parameter.ParameterBuilder#createGroupForMapProjection(ParameterDescriptor...)
*/
- public MathTransform createParameterizedTransform(final
ParameterValueGroup parameters,
- final Context context) throws NoSuchIdentifierException,
FactoryException
+ @Override
+ public MathTransform createParameterizedTransform(final
ParameterValueGroup parameters)
+ throws NoSuchIdentifierException, FactoryException
{
OperationMethod method = null;
RuntimeException failure = null;
@@ -1247,50 +1393,30 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
} catch (NoSuchIdentifierException exception) {
if (methodIdentifier.equals(methodName)) {
throw exception;
+ } else try {
+ method = getOperationMethod(methodName);
+ } catch (NoSuchIdentifierException e) {
+ e.addSuppressed(exception);
+ throw e;
}
- method = getOperationMethod(methodName);
Logging.recoverableException(AbstractMathTransform.LOGGER,
DefaultMathTransformFactory.class,
"createParameterizedTransform", exception);
}
- if (!(method instanceof MathTransformProvider)) {
- throw new NoSuchIdentifierException(Errors.format( //
For now, handle like an unknown operation.
- Errors.Keys.UnsupportedImplementation_1,
Classes.getClass(method)), methodName);
- }
/*
* Will catch only exceptions that may be the result of improper
parameter usage (e.g. a value out
* of range). Do not catch exceptions caused by programming errors
(e.g. null pointer exception).
*/
- try {
- /*
- * If the user's parameters do not contain semi-major and
semi-minor axis lengths, infer
- * them from the ellipsoid. We have to do that because those
parameters are often omitted,
- * since the standard place where to provide this information
is in the ellipsoid object.
- */
- if (context != null) {
- context.factory = this;
- failure = context.completeParameters(method, parameters);
- method = context.provider;
- transform = ((MathTransformProvider)
method).createMathTransform(context);
- } else {
- transform = ((MathTransformProvider)
method).createMathTransform(this, parameters);
- }
+ if (method instanceof MathTransformProvider) try {
+ transform = ((MathTransformProvider)
method).createMathTransform(this, parameters);
} catch (IllegalArgumentException | IllegalStateException
exception) {
throw new
InvalidGeodeticParameterException(exception.getLocalizedMessage(), exception);
+ } else {
+ throw new UnimplementedServiceException(Errors.format(
+ Errors.Keys.UnsupportedImplementation_1,
Classes.getClass(method)));
}
- /*
- * Cache the transform that we just created and make sure that the
number of dimensions
- * is compatible with the OperationMethod instance. Then make
final adjustment for axis
- * directions and units of measurement.
- */
transform = unique(transform);
if (method instanceof AbstractProvider) {
method = ((AbstractProvider) method).variantFor(transform);
- if (context != null) {
- context.provider = method;
- }
- }
- if (context != null) {
- transform = swapAndScaleAxes(transform, context);
}
} catch (FactoryException e) {
if (failure != null) {
@@ -1303,6 +1429,52 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
return transform;
}
+ /**
+ * Creates a transform from a group of parameters and a context.
+ *
+ * @param parameters the parameter values.
+ * @param context information about the context, or {@code null} if
none.
+ * @return the transform created from the given parameters.
+ * @throws NoSuchIdentifierException if there is no method for the given
parameter group name.
+ * @throws FactoryException if the object creation failed.
+ * @deprecated Replaced by a builder pattern with {@link #builder(String)}.
+ */
+ @Deprecated(since="1.5", forRemoval=true)
+ public MathTransform createParameterizedTransform(final
ParameterValueGroup parameters,
+ final Context context) throws NoSuchIdentifierException,
FactoryException
+ {
+ // TODO: After the deprecated methods have been removed
+ // - Make the `Context.parameters` field final (initialized in
constructor).
+ // - Delete `Context.ensureCompatibleParameters(boolean)`.
+ // - Remove the null check on `Context.getCompletedParameters()`
method body.
+ if (context == null) {
+ return createParameterizedTransform(parameters);
+ }
+ final ParameterDescriptorGroup descriptor = parameters.getDescriptor();
+ final String methodName = descriptor.getName().getCode();
+ String methodIdentifier =
IdentifiedObjects.toString(IdentifiedObjects.getIdentifier(descriptor,
Citations.EPSG));
+ if (methodIdentifier == null) {
+ methodIdentifier = methodName;
+ }
+ OperationMethod method;
+ try {
+ method = getOperationMethod(methodIdentifier);
+ } catch (NoSuchIdentifierException exception) {
+ if (methodIdentifier.equals(methodName)) {
+ throw exception;
+ }
+ method = getOperationMethod(methodName);
+ Logging.recoverableException(AbstractMathTransform.LOGGER,
+ DefaultMathTransformFactory.class,
"createParameterizedTransform", exception);
+ }
+ context.factory = this;
+ context.provider = method;
+ context.parameters = parameters;
+ context.completedParameters = false;
+ context.ensureCompatibleParameters(false);
+ return context.create();
+ }
+
/**
* Given a transform between normalized spaces,
* creates a transform taking in account axis directions, units of
measurement and longitude rotation.
@@ -1509,9 +1681,9 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
ArgumentChecks.ensureNonNull("baseCRS", baseCRS);
ArgumentChecks.ensureNonNull("parameters", parameters);
ArgumentChecks.ensureNonNull("derivedCS", derivedCS);
- final Context context =
ReferencingUtilities.createTransformContext(baseCRS, null);
- context.setTarget(derivedCS);
- return createParameterizedTransform(parameters, context);
+ var builder = ReferencingUtilities.builder(this, parameters, baseCRS,
null);
+ builder.setTargetAxes(derivedCS, null);
+ return builder.create();
}
/**
@@ -1551,22 +1723,17 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
* EllipsoidalCS and SphericalCS or other coordinate systems.
*/
if ((isEllipsoidalSource ? target : source) instanceof
CartesianCS) {
- final Context context = new Context();
- final EllipsoidalCS cs;
- final String operation;
+ final var context = new Context(this, getOperationMethod(
+ isEllipsoidalSource ? GeographicToGeocentric.NAME
+ :
GeocentricToGeographic.NAME));
if (isEllipsoidalSource) {
- operation = GeographicToGeocentric.NAME;
- context.setSource(cs = (EllipsoidalCS) source);
- context.setTarget(target);
- context.sourceEllipsoid = ellipsoid;
+ context.setSourceAxes(source, ellipsoid);
+ context.setTargetAxes(target, null);
} else {
- operation = GeocentricToGeographic.NAME;
- context.setSource(source);
- context.setTarget(cs = (EllipsoidalCS) target);
- context.targetEllipsoid = ellipsoid;
+ context.setSourceAxes(source, null);
+ context.setTargetAxes(target, ellipsoid);
}
- final ParameterValueGroup pg =
getDefaultParameters(operation);
- return createParameterizedTransform(pg, context);
+ return context.create();
}
}
}
@@ -1764,8 +1931,11 @@ public class DefaultMathTransformFactory extends
AbstractFactory implements Math
*
* @see #createParameterizedTransform(ParameterValueGroup, Context)
* @see Context#getMethodUsed()
+ *
+ * @deprecated Replaced by {@link MathTransform.Builder#getMethod()}.
*/
@Override
+ @Deprecated(since = "1.5")
public OperationMethod getLastMethodUsed() {
return lastMethod.get();
}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
index 3179cdfb67..d7dc4b2150 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ReferencingUtilities.java
@@ -54,7 +54,8 @@ import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
import org.apache.sis.referencing.internal.VerticalDatumTypes;
import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
-import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.Context;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.apache.sis.parameter.Parameters;
/**
@@ -511,58 +512,35 @@ public final class ReferencingUtilities extends Static {
}
/**
- * Creates a context with source and target ellipsoids and coordinate
systems inferred from the given CRS.
+ * Creates a builder with source and target ellipsoids and coordinate
systems inferred from the given CRSs.
* The ellipsoids will be non-null only if the given CRS is geodetic
(geographic or geocentric).
*
- * @param sourceCRS the CRS from which to get the source coordinate
system and ellipsoid, or {@code null}.
- * @param targetCRS the CRS from which to get the target coordinate
system and ellipsoid, or {@code null}.
+ * @param factory the factory on which to create the builder.
+ * @param parameters the operation parameter value group.
+ * @param sourceCRS the CRS from which to get the source coordinate
system and ellipsoid, or {@code null}.
+ * @param targetCRS the CRS from which to get the target coordinate
system and ellipsoid, or {@code null}.
* @return the context to provides to math transform factory.
+ * @throws FactoryException if the builder cannot be created.
*/
- public static Context createTransformContext(final
CoordinateReferenceSystem sourceCRS,
- final
CoordinateReferenceSystem targetCRS)
+ public static MathTransform.Builder builder(
+ final MathTransformFactory factory,
+ final ParameterValueGroup parameters,
+ final CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS) throws FactoryException
{
- final Context context = new Context();
- if (sourceCRS instanceof GeodeticCRS) {
- context.setSource((GeodeticCRS) sourceCRS);
- } else if (sourceCRS != null) {
- context.setSource(sourceCRS.getCoordinateSystem());
+ final var builder =
factory.builder(parameters.getDescriptor().getName().getCode());
+ try {
+ Parameters.copy(parameters, builder.parameters());
+ } catch (IllegalArgumentException e) {
+ throw new InvalidGeodeticParameterException(e.getMessage(), e);
}
- if (targetCRS instanceof GeodeticCRS) {
- context.setTarget((GeodeticCRS) targetCRS);
- } else if (targetCRS != null) {
- context.setTarget(targetCRS.getCoordinateSystem());
+ if (sourceCRS != null) {
+ builder.setSourceAxes(sourceCRS.getCoordinateSystem(),
getEllipsoid(sourceCRS));
}
- return context;
- }
-
- /**
- * Substitute for the deprecated {@link
MathTransformFactory#createBaseToDerived createBaseToDerived(…)} method.
- * This substitute uses the full {@code targetCRS} instead of only the
coordinate system of the target.
- * This is needed for setting the {@code "tgt_semi_minor"} and {@code
"tgt_semi_major"} parameters of
- * Molodensky transformation for example.
- *
- * @param factory the factory to use for creating the transform.
- * @param sourceCRS the source (base) coordinate reference system.
- * @param parameters the parameter values for the transform.
- * @param targetCRS the target (derived) coordinate system.
- * @return the parameterized transform from {@code sourceCRS} to {@code
targetCRS},
- * including unit conversions and axis swapping.
- * @throws FactoryException if the object creation failed. This exception
is thrown
- * if some required parameter has not been supplied, or has
illegal value.
- *
- * @see <a href="https://issues.apache.org/jira/browse/SIS-512">SIS-512 on
issues tracker</a>
- */
- public static MathTransform createBaseToDerived(final MathTransformFactory
factory,
- final CoordinateReferenceSystem sourceCRS, final
ParameterValueGroup parameters,
- final CoordinateReferenceSystem targetCRS) throws FactoryException
- {
- if (factory instanceof DefaultMathTransformFactory) {
- return ((DefaultMathTransformFactory)
factory).createParameterizedTransform(
- parameters, createTransformContext(sourceCRS, targetCRS));
- } else {
- // Fallback for non-SIS implementations. Work for map projections
but not for Molodensky.
- return factory.createBaseToDerived(sourceCRS, parameters,
targetCRS.getCoordinateSystem());
+ if (targetCRS != null) {
+ builder.setTargetAxes(targetCRS.getCoordinateSystem(),
getEllipsoid(targetCRS));
}
+ return builder;
}
/**
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeographicOffsetsTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeographicOffsetsTest.java
index 94b9949288..755c275c6f 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeographicOffsetsTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeographicOffsetsTest.java
@@ -124,19 +124,18 @@ public final class GeographicOffsetsTest extends
TransformTestCase {
@Test
public void testCreateWithContext() throws FactoryException,
TransformException {
final DefaultMathTransformFactory factory =
DefaultMathTransformFactory.provider();
- final ParameterValueGroup pv = factory.getDefaultParameters("Vertical
Offset");
- pv.parameter("Vertical Offset").setValue(15.55, Units.FOOT);
/*
* Now create the MathTransform. But at the difference of the above
testVerticalOffset() method,
* we supply information about axis directions. The operation
parameter shall have the same sign
- * than in the EPSG database (which is positive), and the source and
target coordinates shall have
+ * as in the EPSG database (which is positive), and the source and
target coordinates shall have
* the same sign as in the EPSG example (positive too). However, we do
not test unit conversion
* in this method (EPSG sample point uses feet units), only axis
direction.
*/
- final DefaultMathTransformFactory.Context context = new
DefaultMathTransformFactory.Context();
- context.setSource(HardCodedCS.GRAVITY_RELATED_HEIGHT); // Direction
up, in metres.
- context.setTarget(HardCodedCS.DEPTH); // Direction
down, in metres.
- transform = factory.createParameterizedTransform(pv, context);
+ final var builder = factory.builder("Vertical Offset");
+ builder.parameters().parameter("Vertical Offset").setValue(15.55,
Units.FOOT);
+ builder.setSourceAxes(HardCodedCS.GRAVITY_RELATED_HEIGHT, null); //
Direction up, in metres.
+ builder.setTargetAxes(HardCodedCS.DEPTH, null); //
Direction down, in metres.
+ transform = builder.create();
tolerance = Formulas.LINEAR_TOLERANCE;
final double[] source = new double[transform.getSourceDimensions()];
final double[] target = new double[transform.getTargetDimensions()];
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
index 5a29446915..b75449db34 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
@@ -310,9 +310,9 @@ public final class DefaultMathTransformFactoryTest extends
TestCase {
@Test
public void testSwapAndScaleAxes() throws FactoryException {
final DefaultMathTransformFactory factory = factory();
- final DefaultMathTransformFactory.Context context = new
DefaultMathTransformFactory.Context();
- context.setSource(HardCodedCS.GEODETIC_3D);
- context.setTarget(HardCodedCS.CARTESIAN_3D);
+ final var context = new DefaultMathTransformFactory.Context();
+ context.setSourceAxes(HardCodedCS.GEODETIC_3D, null);
+ context.setTargetAxes(HardCodedCS.CARTESIAN_3D, null);
/*
* Simulate a case where the parameterized transform is a
two-dimensional map projection,
* but the input and output CRS are three-dimensional geographic and
projected CRS respectively.
@@ -324,8 +324,8 @@ public final class DefaultMathTransformFactoryTest extends
TestCase {
/*
* Transform from 3D to 2D. Height dimension is dropped.
*/
- context.setSource(HardCodedCS.GEODETIC_3D);
- context.setTarget(HardCodedCS.GEODETIC_2D);
+ context.setSourceAxes(HardCodedCS.GEODETIC_3D, null);
+ context.setTargetAxes(HardCodedCS.GEODETIC_2D, null);
mt = factory.swapAndScaleAxes(MathTransforms.identity(2), context);
var expected = Matrices.create(3, 4, new double[] {
1, 0, 0, 0,
@@ -337,8 +337,8 @@ public final class DefaultMathTransformFactoryTest extends
TestCase {
* Transform from 2D to 3D. Coordinate values in the height dimension
are unknown (NaN).
* This case happen when the third dimension is handled as a "pass
through" dimension.
*/
- context.setSource(HardCodedCS.GEODETIC_2D);
- context.setTarget(HardCodedCS.GEODETIC_3D);
+ context.setSourceAxes(HardCodedCS.GEODETIC_2D, null);
+ context.setTargetAxes(HardCodedCS.GEODETIC_3D, null);
mt = factory.swapAndScaleAxes(MathTransforms.identity(2), context);
expected = Matrices.create(4, 3, new double[] {
1, 0, 0,
@@ -362,8 +362,8 @@ public final class DefaultMathTransformFactoryTest extends
TestCase {
/*
* Test error message when adding a dimension that is not ellipsoidal
height.
*/
- context.setSource(HardCodedCS.CARTESIAN_2D);
- context.setTarget(HardCodedCS.CARTESIAN_3D);
+ context.setSourceAxes(HardCodedCS.CARTESIAN_2D, null);
+ context.setTargetAxes(HardCodedCS.CARTESIAN_3D, null);
var e = assertThrows(InvalidGeodeticParameterException.class,
() -> factory.swapAndScaleAxes(MathTransforms.identity(2),
context),
"Should not have accepted the given coordinate systems.");
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryBase.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryBase.java
index b8c252b7d0..84412badde 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryBase.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryBase.java
@@ -65,6 +65,7 @@ class MathTransformFactoryBase implements
MathTransformFactory {
/** Default implementation unconditionally returns {@code null}. */
@Override
+ @Deprecated
public OperationMethod getLastMethodUsed() {
return null;
}
@@ -77,10 +78,17 @@ class MathTransformFactoryBase implements
MathTransformFactory {
/** Default implementation throws an exception. */
@Override
+ @Deprecated
public MathTransform createBaseToDerived(CoordinateReferenceSystem
baseCRS, ParameterValueGroup parameters, CoordinateSystem derivedCS) throws
FactoryException {
throw new FactoryException(MESSAGE);
}
+ /** Default implementation throws an exception. */
+ @Override
+ public MathTransform.Builder builder(String code) throws
NoSuchIdentifierException {
+ throw new NoSuchIdentifierException(MESSAGE, code);
+ }
+
/** Default implementation throws an exception. */
@Override
public MathTransform createParameterizedTransform(ParameterValueGroup
parameters) throws FactoryException {
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
index 762fce44e2..f368841e2d 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
@@ -102,6 +102,7 @@ public final class MathTransformFactoryMock implements
MathTransformFactory {
* @return the method given at construction time.
*/
@Override
+ @Deprecated
public OperationMethod getLastMethodUsed() {
return method;
}
@@ -192,12 +193,24 @@ public final class MathTransformFactoryMock implements
MathTransformFactory {
* @return never returned.
*/
@Override
+ @Deprecated
public MathTransform createBaseToDerived(CoordinateReferenceSystem baseCRS,
ParameterValueGroup parameters, CoordinateSystem derivedCS)
{
throw new UnsupportedOperationException();
}
+ /**
+ * Unimplemented method.
+ *
+ * @param code ignored.
+ * @return never returned.
+ */
+ @Override
+ public MathTransform.Builder builder(String code) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Unimplemented method.
*
diff --git a/geoapi/snapshot b/geoapi/snapshot
index a0ae30dd67..e57e817bb1 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit a0ae30dd67b67a718b74bd8a90140ea0a559e8b6
+Subproject commit e57e817bb1965d241d4f16f498499d6bb304fddd