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 6ec7df4c02 Concatenated operation handle automatically the change of coordinate system in the last step. For example, if the target CRS of the last `SingleOperation` uses a CartesianCS but the target CRS of the `ConcatenatedOperation` uses a SphericalCS, a conversion will be added automatically. 6ec7df4c02 is described below commit 6ec7df4c0263d91bdf92d60c589b607ed490c5f3 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Jan 15 19:42:19 2024 +0100 Concatenated operation handle automatically the change of coordinate system in the last step. For example, if the target CRS of the last `SingleOperation` uses a CartesianCS but the target CRS of the `ConcatenatedOperation` uses a SphericalCS, a conversion will be added automatically. --- .../main/org/apache/sis/referencing/CommonCRS.java | 13 ++-- .../operation/DefaultConcatenatedOperation.java | 14 +++- .../transform/CoordinateSystemTransform.java | 88 ++++++++++++++++++++-- .../transform/DefaultMathTransformFactory.java | 6 +- 4 files changed, 105 insertions(+), 16 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java index 6a436a84fb..136ff858a3 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java @@ -22,7 +22,6 @@ import java.util.HashMap; import java.util.logging.Level; import java.util.logging.LogRecord; import java.time.Instant; -import static java.util.Collections.singletonMap; import javax.measure.Unit; import javax.measure.quantity.Time; import org.opengis.metadata.Identifier; @@ -1919,7 +1918,7 @@ public enum CommonCRS { * <tr><th>Unit:</th> <td>{@link Units#UNITY}</td></tr> * </table></blockquote> */ - GRID(new DefaultEngineeringDatum(singletonMap(EngineeringDatum.NAME_KEY, "Cell indices"))), + GRID(new DefaultEngineeringDatum(Map.of(EngineeringDatum.NAME_KEY, "Cell indices"))), /** * A single-dimensional coordinate system for time in seconds since an unknown epoch. @@ -1936,7 +1935,7 @@ public enum CommonCRS { * * @see Temporal */ - TIME(new DefaultEngineeringDatum(singletonMap(EngineeringDatum.NAME_KEY, "Time"))); + TIME(new DefaultEngineeringDatum(Map.of(EngineeringDatum.NAME_KEY, "Time"))); /** * The datum. @@ -1964,7 +1963,7 @@ public enum CommonCRS { if (crs == null) { final String x, y; final AxisDirection dx, dy; - final Map<String,Object> pcs = singletonMap(CartesianCS.NAME_KEY, datum.getName()); + final Map<String,Object> pcs = Map.of(CartesianCS.NAME_KEY, datum.getName()); final Map<String,Object> properties = new HashMap<>(pcs); CoordinateSystem cs = null; switch (this) { @@ -1988,15 +1987,15 @@ public enum CommonCRS { x = y = "t"; dx = dy = AxisDirection.FUTURE; cs = new DefaultTimeCS(pcs, new DefaultCoordinateSystemAxis( - singletonMap(TimeCS.NAME_KEY, x), x, dx, Units.SECOND)); + Map.of(TimeCS.NAME_KEY, x), x, dx, Units.SECOND)); break; } default: throw new AssertionError(this); } if (cs == null) { cs = new DefaultCartesianCS(pcs, - new DefaultCoordinateSystemAxis(singletonMap(CartesianCS.NAME_KEY, x), x, dx, Units.PIXEL), - new DefaultCoordinateSystemAxis(singletonMap(CartesianCS.NAME_KEY, y), y, dy, Units.PIXEL)); + new DefaultCoordinateSystemAxis(Map.of(CartesianCS.NAME_KEY, x), x, dx, Units.PIXEL), + new DefaultCoordinateSystemAxis(Map.of(CartesianCS.NAME_KEY, y), y, dy, Units.PIXEL)); } crs = new DefaultEngineeringCRS(properties, datum, cs); } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java index 9fb03672f2..519fb54e7f 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java @@ -38,6 +38,7 @@ import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactor import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; import org.apache.sis.referencing.util.PositionalAccuracyConstant; import org.apache.sis.referencing.util.CoordinateOperations; +import org.apache.sis.referencing.util.ReferencingUtilities; import org.apache.sis.referencing.internal.Resources; import org.apache.sis.util.Utilities; import org.apache.sis.util.ComparisonMode; @@ -167,8 +168,16 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp final List<CoordinateOperation> flattened = new ArrayList<>(operations.length); final CoordinateReferenceSystem crs = initialize(properties, operations, flattened, mtFactory, sourceCRS, (sourceCRS == null), (coordinateOperationAccuracy == null)); + if (targetCRS == null) { targetCRS = crs; + } else if (mtFactory instanceof DefaultMathTransformFactory) { + final var dmf = (DefaultMathTransformFactory) mtFactory; + final MathTransform t = dmf.createCoordinateSystemChange( + crs.getCoordinateSystem(), + targetCRS.getCoordinateSystem(), + ReferencingUtilities.getEllipsoid(crs)); + transform = dmf.createConcatenatedTransform(transform, t); } /* * At this point we should have flattened.size() >= 2, except if some operations @@ -305,7 +314,10 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp } } } - verifyStepChaining(properties, operations.length, target, targetCRS, null); + if (!(mtFactory instanceof DefaultMathTransformFactory)) { + verifyStepChaining(properties, operations.length, target, targetCRS, null); + // Else verification will be done by the caller. + } return previous; } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java index d133e7756e..95d51daa4d 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java @@ -17,6 +17,8 @@ package org.apache.sis.referencing.operation.transform; import java.util.Map; +import java.util.List; +import java.util.ArrayList; import javax.measure.IncommensurableException; import org.opengis.util.FactoryException; import org.opengis.parameter.ParameterValueGroup; @@ -38,6 +40,7 @@ import org.apache.sis.metadata.iso.citation.Citations; import org.apache.sis.parameter.DefaultParameterDescriptorGroup; import org.apache.sis.referencing.cs.AxesConvention; import org.apache.sis.referencing.cs.CoordinateSystems; +import org.apache.sis.referencing.cs.DefaultCompoundCS; import org.apache.sis.referencing.operation.DefaultOperationMethod; @@ -182,12 +185,87 @@ abstract class CoordinateSystemTransform extends AbstractMathTransform { } /** - * Implementation of {@link DefaultMathTransformFactory#createCoordinateSystemChange(CoordinateSystem, - * CoordinateSystem, Ellipsoid)}, defined here for reducing the {@code DefaultMathTransformFactory} - * weight in the common case where the conversions handled by this class are not needed. + * Adds the components of the given coordinate system in the specified list. + * This method may invoke itself recursively if there is nested compound CS. + * The returned list is always a copy and can be safely modified. */ - static MathTransform create(final MathTransformFactory factory, final CoordinateSystem source, - final CoordinateSystem target, final ThreadLocal<OperationMethod> lastMethod) throws FactoryException + private static void getComponents(final CoordinateSystem cs, final List<CoordinateSystem> addTo) { + if (cs instanceof DefaultCompoundCS) { + addTo.addAll(((DefaultCompoundCS) cs).getComponents()); + } else { + addTo.add(cs); + } + } + + /** + * Implementation of {@code createCoordinateSystemChange(…)}, defined here for reducing the + * {@link DefaultMathTransformFactory} weight in the common case where the conversions handled + * by this class are not needed. + * + * @todo Handle the case where coordinate system components are not in the same order. + * + * @param factory the factory to use for creating math transforms. + * @param source the source coordinate system. + * @param target the target coordinate system. + * @param lastMethod where to set the coordinate operation method used. + * @return the transform from the given source CS to the given target CS. + * @throws FactoryException if an error occurred while creating a transform. + */ + static MathTransform create(final MathTransformFactory factory, + final CoordinateSystem source, + final CoordinateSystem target, + final ThreadLocal<OperationMethod> lastMethod) + throws FactoryException + { + final var sources = new ArrayList<CoordinateSystem>(3); getComponents(source, sources); + final var targets = new ArrayList<CoordinateSystem>(3); getComponents(target, targets); + final int count = sources.size(); + /* + * Current implementation expects the same number of components, in the same order + * and with the same number of dimensions in each component. A future version will + * need to improve on that. + */ + MathTransform result = null; + if (count == targets.size()) { + final int dimension = source.getDimension(); + int firstAffectedCoordinate = 0; + for (int i=0; i<count; i++) { + final CoordinateSystem s = sources.get(i); + final CoordinateSystem t = targets.get(i); + final int sd = s.getDimension(); + if (t.getDimension() != sd) { + result = null; + break; + } + final MathTransform subTransform = factory.createPassThroughTransform( + firstAffectedCoordinate, + single(factory, s, t, lastMethod), + dimension - (firstAffectedCoordinate + sd)); + if (result == null) { + result = subTransform; + } else { + result = factory.createConcatenatedTransform(result, subTransform); + } + firstAffectedCoordinate += sd; + } + } + // If we couldn't process components separately, try with the compound CS as a whole. + if (result == null) { + result = single(factory, source, target, lastMethod); + } + return result; + } + + /** + * Implementation of {@code create(…)} for a single component. + * This implementation performs can handle changes of coordinate system type between + * {@link CartesianCS}, {@link SphericalCS}, {@link CylindricalCS} and {@link PolarCS}. + */ + private static MathTransform single(final MathTransformFactory factory, + final CoordinateSystem source, + final CoordinateSystem target, + final ThreadLocal<OperationMethod> lastMethod) + throws FactoryException { int passthrough = 0; CoordinateSystemTransform kernel = null; 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 3afd8d1f4b..4ac8bd5642 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 @@ -163,7 +163,7 @@ import org.apache.sis.util.resources.Errors; * There is typically only one {@code MathTransformFactory} instance for the whole application. * * @author Martin Desruisseaux (Geomatys, IRD) - * @version 1.4 + * @version 1.5 * * @see MathTransformProvider * @see AbstractMathTransform @@ -729,7 +729,7 @@ public class DefaultMathTransformFactory extends AbstractFactory implements Math * </ul> * * This method is invoked by {@link DefaultMathTransformFactory#swapAndScaleAxes(MathTransform, Context)}. - * Users an override this method if they need to customize the normalization process. + * Users can override this method if they need to customize the normalization process. * * @param role whether the normalization or denormalization matrix is desired. * @return the requested matrix, or {@code null} if this {@code Context} has no information about the coordinate system. @@ -1296,7 +1296,7 @@ public class DefaultMathTransformFactory extends AbstractFactory implements Math * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis orientations. * * <h4>Controlling the normalization process</h4> - * Users who need a different normalized space than the default one way find more convenient to + * Users who need a different normalized space than the default one may find more convenient to * override the {@link Context#getMatrix Context.getMatrix(ContextualParameters.MatrixRole)} method. * * @param parameterized a transform for normalized input and output coordinates.