001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2004-2024 Open Geospatial Consortium, Inc.
004 *    http://www.geoapi.org
005 *
006 *    Licensed under the Apache License, Version 2.0 (the "License");
007 *    you may not use this file except in compliance with the License.
008 *    You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *    Unless required by applicable law or agreed to in writing, software
013 *    distributed under the License is distributed on an "AS IS" BASIS,
014 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *    See the License for the specific language governing permissions and
016 *    limitations under the License.
017 */
018package org.opengis.referencing.operation;
019
020import java.util.Set;
021import org.opengis.util.Factory;
022import org.opengis.util.FactoryException;
023import org.opengis.util.NoSuchIdentifierException;
024import org.opengis.referencing.cs.CoordinateSystem;
025import org.opengis.referencing.datum.Ellipsoid;
026import org.opengis.referencing.crs.*;                   // Contains some import for javadoc.
027import org.opengis.parameter.*;                         // Contains some import for javadoc.
028import org.opengis.annotation.UML;
029
030import static org.opengis.annotation.Obligation.*;
031import static org.opengis.annotation.Specification.*;
032
033
034/**
035 * Low level factory for creating {@code MathTransform} instances.
036 * Many high level GIS applications will never need to use this factory directly;
037 * they can use a {@linkplain CoordinateOperationFactory coordinate operation factory} instead.
038 * However, the {@code MathTransformFactory} interface can be used directly
039 * by applications that wish to transform other types of coordinates
040 * (e.g. color coordinates, or image pixel coordinates).
041 *
042 * <p>A {@link MathTransform} is an object that actually does the work of applying {@link Formula} to coordinate values.
043 * The math transform does not know or care how the coordinates relate to positions in the real world.
044 * This lack of semantics makes implementing {@code MathTransformFactory} significantly easier
045 * than it would be otherwise.</p>
046 *
047 * <p>For example, the affine transform applies a matrix to the coordinates
048 * without knowing how what it is doing relates to the real world.
049 * So if the matrix scales <var>z</var> values by a factor of 1000, then it could be
050 * converting metres into millimetres, or it could be converting kilometres into metres.</p>
051 *
052 * <p>Because {@link MathTransform}s have low semantic value (but high mathematical value),
053 * programmers who do not have much knowledge of how GIS applications use coordinate systems,
054 * or how those coordinate systems relate to the real world, can implement {@code MathTransformFactory}.
055 * The low semantic content of {@link MathTransform}s also means that they will be useful in applications
056 * that have nothing to do with GIS coordinates. For example, a math transform could be used to map color
057 * coordinates between different color spaces, such as converting (red, green, blue) colors into
058 * (hue, light, saturation) colors.</p>
059 *
060 * <p>Since a {@link MathTransform} does not know what its source and target coordinate systems mean,
061 * it is not necessary or desirable for a math transform object to keep information on its source and
062 * target coordinate systems.</p>
063 *
064 * @author  Martin Desruisseaux (IRD)
065 * @version 3.1
066 * @since   1.0
067 */
068@UML(identifier="CT_MathTransformFactory", specification=OGC_01009)
069public interface MathTransformFactory extends Factory {
070    /*
071     * NOTE FOR JAVADOC WRITER:
072     * The "method" word is ambiguous here, because it can be "Java method" or "coordinate operation method".
073     * In this interface, we reserve "method" for coordinate operation methods as much as possible. For Java
074     * methods, we rather use "constructor" or "function".
075     */
076
077    /**
078     * Returns a set of available methods for coordinate operations of the given type.
079     * For each element in this set, the {@linkplain OperationMethod#getName() operation method name}
080     * must be a valid argument for {@link #getDefaultParameters(String)}.
081     *
082     * <p>The {@code type} argument can be used for filtering the kind of operations described by the returned
083     * {@code OperationMethod}s. The argument is usually (but not restricted to) one of the following types:</p>
084     *
085     * <ul>
086     *   <li>{@link Conversion} for coordinate operations described by definitions (including map projections).</li>
087     *   <li>{@link Transformation} for coordinate operations described by empirically derived parameters.</li>
088     *   <li>{@link PointMotionOperation} for changes due to the motion of the point between two coordinate epochs.</li>
089     *   <li>{@link SingleOperation} for all coordinate operations, regardless of their type.</li>
090     * </ul>
091     *
092     * The returned set may conservatively contain more {@code OperationMethod} elements than requested
093     * if this {@code MathTransformFactory} does not support filtering by the given type.
094     *
095     * @param  type <code>{@linkplain SingleOperation}.class</code> for fetching all operation methods,
096     *         <code>{@linkplain Transformation}.class</code> for fetching only transformation methods, <i>etc</i>.
097     * @return methods available in this factory for coordinate operations of the given type.
098     *
099     * @departure extension
100     *   This method is not part of the OGC specification.
101     *   It has been added as a way to publish the capabilities of a factory.
102     *
103     * @see #getDefaultParameters(String)
104     * @see #createParameterizedTransform(ParameterValueGroup)
105     * @see CoordinateOperationFactory#getOperationMethod(String)
106     */
107    Set<OperationMethod> getAvailableMethods(Class<? extends SingleOperation> type);
108
109    /**
110     * Returns the operation method used by the latest call to a {@code create(…)} constructor,
111     * or {@code null} if not applicable.
112     *
113     * <p>Implementers should document how their implementation behave in a multi-threads environment.
114     * For example, some implementations use {@linkplain java.lang.ThreadLocal thread local variables},
115     * while other can choose to return {@code null} in all cases since {@code getLastMethodUsed()}
116     * is optional.</p>
117     *
118     * <p>Invoking {@code getLastMethodUsed()} can be useful after a call to
119     * {@link #createParameterizedTransform createParameterizedTransform(…)}, or after a call to another
120     * constructor that delegates its work to {@code createParameterizedTransform(…)}, for example
121     * {@link #createBaseToDerived createBaseToDerived(…)}.</p>
122     *
123     * @return the last method used by a {@code create(…)} constructor, or {@code null} if unknown of unsupported.
124     *
125     * @see #createParameterizedTransform(ParameterValueGroup)
126     *
127     * @departure extension
128     *   This method is not part of the OGC specification.
129     *   It has been added because this information appears to be important in some situations.
130     *   We did not defined a {{@code MathTransform}, {@code OperationMethod}} tuple in order
131     *   to keep {@code create(…)} simpler in the common case where the operation method is not needed,
132     *   and for historical reasons (conformance to OGC 01-009).
133     */
134    OperationMethod getLastMethodUsed();
135
136    /**
137     * Returns the default parameter values for a math transform using the given operation method.
138     * The {@code method} argument is the name of any {@code OperationMethod} instance returned by
139     * <code>{@link #getAvailableMethods(Class) getAvailableMethods}({@linkplain SingleOperation}.class)</code>.
140     * A typical example is "Transverse Mercator".
141     *
142     * <p>The {@linkplain ParameterDescriptorGroup#getName() parameter group name} shall be a method name or identifier
143     * that {@link #createParameterizedTransform(ParameterValueGroup)} can recognize without ambiguity.</p>
144     *
145     * <p>This function creates new parameter instances at every call.
146     * Parameters are intended to be modified by the user before to be given to the above-cited
147     * {@code createParameterizedTransform(…)} constructor.</p>
148     *
149     * @param  method  the case insensitive name of the coordinate operation method to search for.
150     * @return a new group of parameter values for the {@code OperationMethod} identified by the given name.
151     * @throws NoSuchIdentifierException if there is no method registered for the given name or identifier.
152     *
153     * @departure extension
154     *   This method is part of the GeoAPI mechanism for defining the math transform parameters
155     *   or deriving other transforms.
156     *
157     * @see #getAvailableMethods(Class)
158     * @see #createParameterizedTransform(ParameterValueGroup)
159     */
160    ParameterValueGroup getDefaultParameters(String method) throws NoSuchIdentifierException;
161
162    /**
163     * Creates a {@linkplain #createParameterizedTransform parameterized transform} from a base CRS
164     * to a derived CS. This convenience constructor {@linkplain #createConcatenatedTransform concatenates}
165     * the parameterized transform with any other transform required for performing units changes and
166     * coordinates swapping, as described in the {@linkplain #createParameterizedTransform note on
167     * cartographic projections}.
168     *
169     * <p>In addition, implementations are encouraged to infer the {@code "semi_major"} and
170     * {@code "semi_minor"} parameter values from the {@linkplain Ellipsoid ellipsoid}
171     * associated to the {@code baseCRS}, if those parameters are not explicitly given
172     * and if they are applicable (typically for cartographic projections).
173     * This inference is consistent with the EPSG database model.</p>
174     *
175     * @param  baseCRS     the source coordinate reference system.
176     * @param  parameters  the parameter values for the transform.
177     * @param  derivedCS   the target coordinate system.
178     * @return the parameterized transform from {@code baseCRS} to {@code derivedCS},
179     *         including unit conversions and axis swapping.
180     * @throws NoSuchIdentifierException if there is no transform registered for the coordinate operation method.
181     * @throws FactoryException if the transform creation failed.
182     *         This exception is thrown if some required parameter has not been supplied, or has illegal value.
183     *
184     * @departure extension
185     *   This method is part of the GeoAPI mechanism for defining the math transform parameters
186     *   or deriving other transforms.
187     */
188    MathTransform createBaseToDerived(CoordinateReferenceSystem baseCRS,
189                                      ParameterValueGroup       parameters,
190                                      CoordinateSystem          derivedCS)
191            throws NoSuchIdentifierException, FactoryException;
192
193    /**
194     * Creates a transform from a group of parameters. The {@link OperationMethod} name is inferred from
195     * the {@linkplain ParameterDescriptorGroup#getName() parameter group name}. Example:
196     *
197     * {@snippet lang="java" :
198     * ParameterValueGroup p = factory.getDefaultParameters("Transverse_Mercator");
199     * p.parameter("semi_major").setValue(6378137.000);
200     * p.parameter("semi_minor").setValue(6356752.314);
201     * MathTransform mt = factory.createParameterizedTransform(p);
202     * }
203     *
204     * <h4>Note on cartographic projections:</h4>
205     * Cartographic projection transforms are used by {@linkplain ProjectedCRS projected coordinate reference systems}
206     * to map geographic coordinates (e.g. <var>longitude</var> and <var>latitude</var>) into (<var>x</var>,<var>y</var>)
207     * coordinates. These (<var>x</var>,<var>y</var>) coordinates can be imagined to lie on a plane, such as a paper map
208     * or a screen. All cartographic projection transforms created through this constructor will have the following
209     * properties:
210     *
211     * <ul>
212     *   <li>Converts from (<var>longitude</var>,<var>latitude</var>) coordinates to (<var>x</var>,<var>y</var>).</li>
213     *   <li>All angles are assumed to be degrees, and all distances are assumed to be meters.</li>
214     *   <li>The domain shall be a subset of {[-180,180)×(-90,90)}.</li>
215     *   <li>Axis directions are usually ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST east},
216     *       {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH north}), but exceptions may exist
217     *       for some operation methods like <cite>Lambert Conic Conformal (West Orientated)</cite>
218     *       (EPSG:9826) or <cite>Transverse Mercator (South Orientated)</cite> (EPSG:9808).</li>
219     * </ul>
220     *
221     * Although all cartographic projection transforms must have the properties listed above, many projected coordinate
222     * reference systems have different properties. For example, in Europe some projected CRSs use grads instead of degrees,
223     * and often the {@linkplain ProjectedCRS#getBaseCRS() base geographic CRS} is (<var>latitude</var>, <var>longitude</var>)
224     * instead of (<var>longitude</var>, <var>latitude</var>). This means that the cartographic projected transform is often
225     * used as a single step in a series of transforms, where the other steps change units and swap coordinates.
226     *
227     * <p>When the change of axis directions is part of the map projection definition as in <cite>Transverse Mercator
228     * (South Orientated)</cite>, there is a conflict with the above-cited (<var>east</var>, <var>north</var>) directions.
229     * In such cases the {@code createParameterizedTransform(…)} behavior is implementation specific, since different
230     * libraries may resolve this conflict in different ways.
231     * Users can invoke {@link #createBaseToDerived createBaseToDerived(…)} instead for more determinist results.</p>
232     *
233     * @param  parameters  the parameter values.
234     * @return the parameterized transform.
235     * @throws NoSuchIdentifierException if there is no transform registered for the coordinate operation method.
236     * @throws FactoryException if the transform creation failed.
237     *         This exception is thrown if some required parameter has not been supplied, or has illegal value.
238     *
239     * @see #getDefaultParameters(String)
240     * @see #getAvailableMethods(Class)
241     * @see #getLastMethodUsed()
242     */
243    @UML(identifier="createParameterizedTransform", obligation=MANDATORY, specification=OGC_01009)
244    MathTransform createParameterizedTransform(ParameterValueGroup parameters)
245            throws NoSuchIdentifierException, FactoryException;
246
247    /**
248     * Creates an affine transform from a matrix.
249     * If the transform's input dimension is {@code M}, and output dimension is {@code N},
250     * then the matrix will have size {@code [N+1][M+1]}.
251     * The +1 in the matrix dimensions allows the matrix to do a shift, as well as a rotation.
252     * The {@code [M][j]} element of the matrix will be the <var>j</var>'th coordinate of the moved origin.
253     * The {@code [i][N]} element of the matrix will be 0 for <var>i</var> less than {@code M},
254     * and 1 for <var>i</var> equals {@code M}.
255     *
256     * @param  matrix  the matrix used to define the affine transform.
257     * @return the affine transform.
258     * @throws FactoryException if the transform creation failed.
259     */
260    @UML(identifier="createAffineTransform", obligation=MANDATORY, specification=OGC_01009)
261    MathTransform createAffineTransform(Matrix matrix) throws FactoryException;
262
263    /**
264     * Creates a matrix of size {@code numRow}&nbsp;×&nbsp;{@code numCol}.
265     * Elements on the diagonal (<var>j</var> == <var>i</var>) are set to 1.
266     *
267     * @param  numRow  number of rows.
268     * @param  numCol  number of columns.
269     * @return a new matrix of the given size.
270     * @throws FactoryException if the matrix creation failed.
271     *
272     * @since 3.1
273     */
274    Matrix createMatrix(int numRow, int numCol) throws FactoryException;
275
276    /**
277     * Creates a transform by concatenating two existing transforms.
278     * A concatenated transform acts in the same way as applying two
279     * transforms, one after the other.
280     *
281     * <p>The dimension of the output space of the first transform must match the dimension
282     * of the input space in the second transform. If you wish to concatenate more than two
283     * transforms, then you can repeatedly use this constructor.</p>
284     *
285     * @param  transform1  the first transform to apply to points.
286     * @param  transform2  the second transform to apply to points.
287     * @return the concatenated transform.
288     * @throws FactoryException if the transform creation failed.
289     */
290    @UML(identifier="createConcatenatedTransform", obligation=MANDATORY, specification=OGC_01009)
291    MathTransform createConcatenatedTransform(MathTransform transform1,
292                                              MathTransform transform2) throws FactoryException;
293
294    /**
295     * Creates a transform which passes through a subset of coordinates to another transform.
296     * This allows transforms to operate on a subset of coordinates. For example, giving
297     * (<var>latitude</var>, <var>longitude</var>, <var>height</var>) coordinates, a pass
298     * through transform can convert the height values from meters to feet without affecting
299     * the (<var>latitude</var>, <var>longitude</var>) values.
300     *
301     * @param  firstAffectedCoordinate  the lowest index of the affected coordinates.
302     * @param  subTransform             transform to use for affected coordinates.
303     * @param  numTrailingCoordinates   number of trailing coordinates to pass through.
304     *         Affected coordinates will range from {@code firstAffectedCoordinate}
305     *         inclusive to {@code dimTarget-numTrailingCoordinates} exclusive.
306     * @return a pass through transform with the following dimensions:<br>
307     *         <pre>
308     * Source: firstAffectedCoordinate + subTransform.getDimSource() + numTrailingCoordinates
309     * Target: firstAffectedCoordinate + subTransform.getDimTarget() + numTrailingCoordinates</pre>
310     * @throws FactoryException if the transform creation failed.
311     */
312    @UML(identifier="createPassThroughTransform", obligation=MANDATORY, specification=OGC_01009)
313    MathTransform createPassThroughTransform(int firstAffectedCoordinate,
314                                             MathTransform subTransform,
315                                             int numTrailingCoordinates) throws FactoryException;
316
317    /**
318     * Creates a math transform object from a XML string.
319     *
320     * @param  xml  math transform encoded in XML format.
321     * @return the math transform (never {@code null}).
322     * @throws FactoryException if the object creation failed.
323     *
324     * @deprecated This method was defined in OGC 01-009 in anticipation for future normative specification,
325     *             but no XML format for math transforms have been defined.
326     */
327    @Deprecated
328    @UML(identifier="createFromXML", obligation=MANDATORY, specification=OGC_01009)
329    default MathTransform createFromXML(String xml) throws FactoryException {
330        throw new FactoryException("No XML format defined for MathTransform.");
331    }
332
333    /**
334     * Creates a math transform object from a <i>Well-Known Text</i>.
335     * The WKT of math transforms is defined in {@linkplain org.opengis.annotation.Specification#OGC_01009 OGC 01-009}.
336     *
337     * @param  wkt  math transform encoded in Well-Known Text format.
338     * @return the math transform (never {@code null}).
339     * @throws FactoryException if the Well-Known Text cannot be parsed,
340     *         or if the math transform creation failed from some other reason.
341     *
342     * @see MathTransform#toWKT()
343     */
344    @UML(identifier="createFromWKT", obligation=MANDATORY, specification=OGC_01009)
345    MathTransform createFromWKT(String wkt) throws FactoryException;
346}