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.nio.FloatBuffer;
021import java.nio.DoubleBuffer;
022import java.awt.geom.AffineTransform;
023import org.opengis.geometry.DirectPosition;
024import org.opengis.coordinate.CoordinateSet;
025import org.opengis.coordinate.MismatchedDimensionException;
026import org.opengis.annotation.UML;
027
028import static org.opengis.annotation.Specification.*;
029
030
031/**
032 * Transforms multi-dimensional coordinate points. A {@code MathTransform} is an object
033 * that actually does the work of applying a {@linkplain Formula formula} to coordinate values.
034 * The math transform does not know or care how the coordinates relate to positions in the real world.
035 * For example, the affine transform applies a matrix to the coordinates without knowing how what it is doing
036 * relates to the real world. So if the matrix scales <var>z</var> values by a factor of 1000,
037 * then it could be converting metres into millimetres, or it could be converting kilometres into metres.
038 *
039 * <p>Because they have low semantic value (but high mathematical value), {@link MathTransform}s can be used
040 * in applications that have nothing to do with GIS coordinates. For example, a math transform could be used
041 * to map color coordinates between different color spaces, such as converting (red, green, blue) colors into
042 * (hue, light, saturation) colors.</p>
043 *
044 * <h2>Application to coordinate operations</h2>
045 * When used for coordinate operations, this interface transforms coordinate value for a point given in the
046 * {@linkplain CoordinateOperation#getSourceCRS() source coordinate reference system} to coordinate value for
047 * the same point in the {@linkplain CoordinateOperation#getTargetCRS() target coordinate reference system}.
048 *
049 * <ul>
050 *   <li>In a {@linkplain Conversion conversion}, the transformation is accurate to within the
051 *     limitations of the computer making the calculations.</li>
052 *   <li>In a {@linkplain Transformation transformation}, where some of the operational parameters
053 *     are derived from observations, the transformation is accurate to within the limitations of
054 *     those observations.</li>
055 * </ul>
056 *
057 * If a client application wishes to query the source and target
058 * {@linkplain org.opengis.referencing.crs.CoordinateReferenceSystem coordinate reference systems}
059 * of an operation, then it should keep hold of the {@link CoordinateOperation} interface,
060 * and use the contained math transform object whenever it wishes to perform a transform.
061 *
062 * @author  Martin Desruisseaux (IRD, Geomatys)
063 * @version 3.1
064 * @since   1.0
065 *
066 * @see AffineTransform
067 * @see MathTransformFactory
068 * @see Formula
069 * @see CoordinateOperation#getMathTransform()
070 */
071@UML(identifier="CT_MathTransform", specification=OGC_01009)
072public interface MathTransform {
073    /**
074     * Returns the number of dimensions of input points.
075     *
076     * @return the number of dimensions of input points.
077     */
078    @UML(identifier="getDimSource", specification=OGC_01009)
079    int getSourceDimensions();
080
081    /**
082     * Returns the number of dimensions of output points.
083     *
084     * @return the number of dimensions of output points.
085     */
086    @UML(identifier="getDimTarget", specification=OGC_01009)
087    int getTargetDimensions();
088
089    /**
090     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
091     * If {@code ptDst} is {@code null}, a new {@link DirectPosition} object is allocated
092     * and then the result of the transformation is stored in this object. In either case,
093     * {@code ptDst}, which contains the transformed point, is returned for convenience.
094     * If {@code ptSrc} and {@code ptDst} are the same object,
095     * the input point is correctly overwritten with the transformed point.
096     *
097     * @param  ptSrc the specified coordinate point to be transformed.
098     * @param  ptDst the specified coordinate point that stores the result of transforming
099     *         {@code ptSrc}, or {@code null}.
100     * @return the coordinate point after transforming {@code ptSrc} and storing the result
101     *         in {@code ptDst}, or a newly created point if {@code ptDst} was null.
102     * @throws MismatchedDimensionException if {@code ptSrc} or
103     *         {@code ptDst} doesn't have the expected dimension.
104     * @throws TransformException if the point cannot be transformed.
105     */
106    @UML(identifier="transform", specification=OGC_01009)
107    DirectPosition transform(DirectPosition ptSrc, DirectPosition ptDst)
108            throws MismatchedDimensionException, TransformException;
109
110    /**
111     * Transforms an array of double-precision coordinate tuples.
112     * This method is provided for efficiently transforming many points.
113     * The supplied array will contain packed coordinate tuples.
114     * For example, if the source dimension is 3, then the coordinates will be packed in this order:
115     *
116     * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
117     *  <var>x₁</var>,<var>y₁</var>,<var>z₁</var> …).
118     *
119     * @param  srcPts the array containing the source coordinate tuples.
120     * @param  srcOff the offset to the first tuple to be transformed in the source array.
121     * @param  dstPts the array into which the transformed coordinate tuples are stored.
122     *                May be the same array as {@code srcPts}.
123     * @param  dstOff the offset to the first transformed coordinate that is stored in the destination array.
124     * @param  numPts the number of coordinate <em>tuples</em> to be transformed.
125     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
126     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
127     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
128     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
129     *
130     * @see #transform(DoubleBuffer, DoubleBuffer)
131     * @see AffineTransform#transform(double[], int, double[], int, int)
132     */
133    @UML(identifier="transformList", specification=OGC_01009)
134    void transform(double[] srcPts, int srcOff,
135                   double[] dstPts, int dstOff, int numPts) throws TransformException;
136
137    /**
138     * Transforms an array of single-precision coordinate tuples.
139     * This method is provided for efficiently transforming many points.
140     * The supplied array will contain packed coordinate tuples.
141     * For example, if the source dimension is 3, then the coordinates will be packed in this order:
142     *
143     * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
144     *  <var>x₁</var>,<var>y₁</var>,<var>z₁</var> …).
145     *
146     * <p>Note: while the source and destination arrays use single-precision floating point numbers,
147     * implementation should perform intermediate calculations in double-precision.</p>
148     *
149     * @param  srcPts the array containing the source coordinate tuples.
150     * @param  srcOff the offset to the first tuple to be transformed in the source array.
151     * @param  dstPts the array into which the transformed coordinate tuples are stored.
152     *                May be the same array as {@code srcPts}.
153     * @param  dstOff the offset to the first transformed coordinate that is stored in the destination array.
154     * @param  numPts the number of coordinate <em>tuples</em> to be transformed.
155     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
156     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
157     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
158     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
159     *
160     * @see #transform(FloatBuffer, FloatBuffer)
161     * @see AffineTransform#transform(float[], int, float[], int, int)
162     */
163    void transform(float[] srcPts, int srcOff,
164                   float[] dstPts, int dstOff, int numPts) throws TransformException;
165
166    /**
167     * Converts an array of single-precision coordinate tuples to double precision, then transform.
168     * This method is provided for efficiently transforming many points.
169     * The supplied array will contain packed coordinate tuples.
170     * For example, if the source dimension is 3, then the coordinates will be packed in this order:
171     *
172     * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
173     *  <var>x₁</var>,<var>y₁</var>,<var>z₁</var> …).
174     *
175     * @param  srcPts the array containing the source coordinate tuples.
176     * @param  srcOff the offset to the first tuple to be transformed in the source array.
177     * @param  dstPts the array into which the transformed coordinate tuples are stored.
178     *                May be the same array as {@code srcPts}.
179     * @param  dstOff the offset to the first transformed coordinate that is stored in the destination array.
180     * @param  numPts the number of coordinate <em>tuples</em> to be transformed.
181     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
182     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
183     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
184     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
185     *
186     * @see #transform(FloatBuffer, DoubleBuffer)
187     * @see AffineTransform#transform(float[], int, double[], int, int)
188     */
189    void transform(float [] srcPts, int srcOff,
190                   double[] dstPts, int dstOff, int numPts) throws TransformException;
191
192    /**
193     * Transforms an array of double-precision coordinate tuples, then converts to single-precision.
194     * This method is provided for efficiently transforming many points.
195     * The supplied array will contain packed coordinate tuples.
196     * For example, if the source dimension is 3, then the coordinates will be packed in this order:
197     *
198     * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
199     *  <var>x₁</var>,<var>y₁</var>,<var>z₁</var> …).
200     *
201     * @param  srcPts the array containing the source coordinate tuples.
202     * @param  srcOff the offset to the first tuple to be transformed in the source array.
203     * @param  dstPts the array into which the transformed coordinate tuples are stored.
204     *                May be the same array as {@code srcPts}.
205     * @param  dstOff the offset to the first transformed coordinate that is stored in the destination array.
206     * @param  numPts the number of coordinate <em>tuples</em> to be transformed.
207     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
208     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
209     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
210     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
211     *
212     * @see #transform(DoubleBuffer, FloatBuffer)
213     * @see AffineTransform#transform(double[], int, float[], int, int)
214     */
215    void transform(double[] srcPts, int srcOff,
216                   float [] dstPts, int dstOff, int numPts) throws TransformException;
217
218    /**
219     * Transforms a buffer of double-precision coordinate tuples.
220     * This method is provided for efficiently transforming many points,
221     * either in Java heap or in the memory of native applications (e.g. C/C++).
222     * The supplied buffer will contain packed coordinate tuples.
223     * For example, if the source dimension is 3, then the coordinates will be packed in this order:
224     *
225     * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
226     *  <var>x₁</var>,<var>y₁</var>,<var>z₁</var> …).
227     *
228     * <p>The first coordinate to transform is read at index {@code srcPts.position()} and
229     * the first transformed coordinate will be stored at index {@code dstPts.position()}.
230     * The maximal number of coordinate <em>tuples</em> to transform is:</p>
231     *
232     * {@snippet lang="java" :
233     * int numPts = Math.min(srcPts.remaining() / getSourceDimensions(),
234     *                       dstPts.remaining() / getTargetDimensions());
235     * }
236     *
237     * <p>If above maximum is zero, then this method returns 0.
238     * Otherwise, this method <em>shall</em> transform at least one coordinate tuple.
239     * It may transform any number of coordinate tuples between 1 and the above-cited maximum,
240     * at implementation choice. On success, the position of the source and destination buffer
241     * will be set to the index after the last coordinate read and stored respectively.
242     * If an exception has been thrown, then the buffer positions are undetermined.</p>
243     *
244     * <h4>Default implementation</h4>
245     * The default implementation delegates to {@link #transform(double[], int, double[], int, int)}.
246     * Therefore, the default implementation supports only buffers on Java heap.
247     * Implementations should override this method if they want to support native heaps.
248     *
249     * @param  srcPts the buffer containing the source coordinate tuples.
250     * @param  dstPts the buffer into which the transformed coordinate tuples are stored.
251     *                May be the same buffer as {@code srcPts}.
252     * @return number of coordinate <em>tuples</em> actually transformed.
253     * @throws UnsupportedOperationException if this implementation supports only buffers backed
254     *         by accessible Java arrays, and at least one buffer is backed by native memory.
255     * @throws java.nio.ReadOnlyBufferException if the destination buffer is read-only.
256     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
257     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
258     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
259     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
260     *
261     * @see #transform(double[], int, double[], int, int)
262     * @see CoordinateSet#asDoubleBuffers()
263     *
264     * @since 3.1
265     */
266    default int transform(final DoubleBuffer srcPts, final DoubleBuffer dstPts) throws TransformException {
267        // The source code looks identical in the 4 variants of this method, but the compiled code differs.
268        // Trying to factorize this code actually make the `MathTransform.class` file bigger.
269        final int srcDim = getSourceDimensions();
270        final int tgtDim = getTargetDimensions();
271        final int srcOff = srcPts.position();
272        final int dstOff = dstPts.position();
273        final int numPts = Math.min(srcPts.remaining() / srcDim,
274                                    dstPts.remaining() / tgtDim);
275        transform(srcPts.array(), srcPts.arrayOffset() + srcOff,
276                  dstPts.array(), dstPts.arrayOffset() + dstOff, numPts);
277        srcPts.position(srcOff + numPts * srcDim);
278        dstPts.position(dstOff + numPts * tgtDim);      // Must be last.
279        return numPts;
280    }
281
282    /**
283     * Transforms a buffer of single-precision coordinate tuples.
284     * This method follows the same contract as {@link #transform(DoubleBuffer, DoubleBuffer)},
285     * except that the floating-point precision of source and destination buffers are different.
286     * See the double-precision variant of this method for details.
287     *
288     * <h4>Default implementation</h4>
289     * The default implementation delegates to {@link #transform(float[], int, float[], int, int)}.
290     * Therefore, the default implementation supports only buffers on Java heap.
291     * Implementations should override this method if they want to support native heaps.
292     *
293     * @param  srcPts the buffer containing the source coordinate tuples.
294     * @param  dstPts the buffer into which the transformed coordinate tuples are stored.
295     *                May be the same buffer as {@code srcPts}.
296     * @return number of coordinate <em>tuples</em> actually transformed.
297     * @throws UnsupportedOperationException if this implementation supports only buffers backed
298     *         by accessible Java arrays, and at least one buffer is backed by native memory.
299     * @throws java.nio.ReadOnlyBufferException if the destination buffer is read-only.
300     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
301     *         while some other implementations may fill the untransformable points with {@linkplain Float#NaN} values,
302     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
303     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
304     *
305     * @see #transform(float[], int, float[], int, int)
306     * @see CoordinateSet#asFloatBuffers()
307     *
308     * @since 3.1
309     */
310    default int transform(final FloatBuffer srcPts, final FloatBuffer dstPts) throws TransformException {
311        // The source code looks identical in the 4 variants of this method, but the compiled code differs.
312        // Trying to factorize this code actually make the `MathTransform.class` file bigger.
313        final int srcDim = getSourceDimensions();
314        final int tgtDim = getTargetDimensions();
315        final int srcOff = srcPts.position();
316        final int dstOff = dstPts.position();
317        final int numPts = Math.min(srcPts.remaining() / srcDim,
318                                    dstPts.remaining() / tgtDim);
319        transform(srcPts.array(), srcPts.arrayOffset() + srcOff,
320                  dstPts.array(), dstPts.arrayOffset() + dstOff, numPts);
321        srcPts.position(srcOff + numPts * srcDim);
322        dstPts.position(dstOff + numPts * tgtDim);      // Must be last.
323        return numPts;
324    }
325
326    /**
327     * Converts simple-precision coordinate tuples to double-precision and transform them.
328     * This method follows the same contract as {@link #transform(DoubleBuffer, DoubleBuffer)},
329     * except that the floating-point precision of the source buffer is different.
330     * See the double-precision variant of this method for details.
331     *
332     * <h4>Default implementation</h4>
333     * The default implementation delegates to {@link #transform(float[], int, double[], int, int)}.
334     * Therefore, the default implementation supports only buffers on Java heap.
335     * Implementations should override this method if they want to support native heaps.
336     *
337     * @param  srcPts the buffer containing the source coordinate tuples.
338     * @param  dstPts the buffer into which the transformed coordinate tuples are stored.
339     *                May be the same buffer as {@code srcPts}.
340     * @return number of coordinate <em>tuples</em> actually transformed.
341     * @throws UnsupportedOperationException if this implementation supports only buffers backed
342     *         by accessible Java arrays, and at least one buffer is backed by native memory.
343     * @throws java.nio.ReadOnlyBufferException if the destination buffer is read-only.
344     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
345     *         while some other implementations may fill the untransformable points with {@linkplain Double#NaN} values,
346     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
347     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
348     *
349     * @see #transform(float[], int, double[], int, int)
350     * @see CoordinateSet#asFloatBuffers()
351     *
352     * @since 3.1
353     */
354    default int transform(final FloatBuffer srcPts, final DoubleBuffer dstPts) throws TransformException {
355        // The source code looks identical in the 4 variants of this method, but the compiled code differs.
356        // Trying to factorize this code actually make the `MathTransform.class` file bigger.
357        final int srcDim = getSourceDimensions();
358        final int tgtDim = getTargetDimensions();
359        final int srcOff = srcPts.position();
360        final int dstOff = dstPts.position();
361        final int numPts = Math.min(srcPts.remaining() / srcDim,
362                                    dstPts.remaining() / tgtDim);
363        transform(srcPts.array(), srcPts.arrayOffset() + srcOff,
364                  dstPts.array(), dstPts.arrayOffset() + dstOff, numPts);
365        srcPts.position(srcOff + numPts * srcDim);
366        dstPts.position(dstOff + numPts * tgtDim);      // Must be last.
367        return numPts;
368    }
369
370    /**
371     * Transforms coordinate tuples and converts the result to single-precision.
372     * This method follows the same contract as {@link #transform(DoubleBuffer, DoubleBuffer)},
373     * except that the floating-point precision of the destination buffer is different.
374     * See the double-precision variant of this method for details.
375     *
376     * <h4>Default implementation</h4>
377     * The default implementation delegates to {@link #transform(double[], int, float[], int, int)}.
378     * Therefore, the default implementation supports only buffers on Java heap.
379     * Implementations should override this method if they want to support native heaps.
380     *
381     * @param  srcPts the buffer containing the source coordinate tuples.
382     * @param  dstPts the buffer into which the transformed coordinate tuples are stored.
383     *                May be the same buffer as {@code srcPts}.
384     * @return number of coordinate <em>tuples</em> actually transformed.
385     * @throws UnsupportedOperationException if this implementation supports only buffers backed
386     *         by accessible Java arrays, and at least one buffer is backed by native memory.
387     * @throws java.nio.ReadOnlyBufferException if the destination buffer is read-only.
388     * @throws TransformException if a point cannot be transformed. Some implementations may stop at the first failure,
389     *         while some other implementations may fill the untransformable points with {@linkplain Float#NaN} values,
390     *         continue and throw the exception only at end. Implementations that fall in the latter case should set the
391     *         {@linkplain TransformException#getLastCompletedTransform last completed transform} to {@code this}.
392     *
393     * @see #transform(double[], int, float[], int, int)
394     * @see CoordinateSet#asDoubleBuffers()
395     *
396     * @since 3.1
397     */
398    default int transform(final DoubleBuffer srcPts, final FloatBuffer dstPts) throws TransformException {
399        // The source code looks identical in the 4 variants of this method, but the compiled code differs.
400        // Trying to factorize this code actually make the `MathTransform.class` file bigger.
401        final int srcDim = getSourceDimensions();
402        final int tgtDim = getTargetDimensions();
403        final int srcOff = srcPts.position();
404        final int dstOff = dstPts.position();
405        final int numPts = Math.min(srcPts.remaining() / srcDim,
406                                    dstPts.remaining() / tgtDim);
407        transform(srcPts.array(), srcPts.arrayOffset() + srcOff,
408                  dstPts.array(), dstPts.arrayOffset() + dstOff, numPts);
409        srcPts.position(srcOff + numPts * srcDim);
410        dstPts.position(dstOff + numPts * tgtDim);      // Must be last.
411        return numPts;
412    }
413
414    /**
415     * Gets the derivative of this transform at a point.
416     * The derivative is the matrix of the non-translating portion of the approximate affine map at the point.
417     * The matrix will have dimensions corresponding to the source and target coordinate systems.
418     * If the input dimension is <var>M</var>, and the output dimension is <var>N</var>,
419     * then the matrix will have size <var>N</var>×<var>M</var>.
420     * The elements of the matrix
421     *
422     *              {e<sub>n,m</sub> : <var>n</var>=0 … (<var>N</var>-1)}
423     *
424     * form a vector in the output space which is parallel to the displacement
425     * caused by a small change in the <var>m</var>'th coordinate in the input space.
426     *
427     * <p>For example, if the input dimension is 4 and the output dimension is 3,
428     * then a small displacement
429     *
430     * (<var>x₀</var>, <var>x₁</var>, <var>x₂</var>, <var>x₃</var>)
431     *
432     * in the input space will result in a displacement
433     *
434     * (<var>y₀</var>, <var>y₁</var>, <var>y₂</var>)
435     *
436     * in the output space computed as below (e<sub>n,m</sub> are the matrix elements):
437     *
438     * <pre>
439     *┌    ┐     ┌                    ┐ ┌    ┐
440     *│ y₀ │     │ e₀₀  e₀₁  e₀₂  e₀₃ │ │ x₀ │
441     *│ y₁ │  =  │ e₁₀  e₁₁  e₁₂  e₁₃ │ │ x₁ │
442     *│ y₂ │     │ e₂₀  e₂₁  e₂₂  e₂₃ │ │ x₂ │
443     *└    ┘     └                    ┘ │ x₃ │
444     *                                  └    ┘</pre>
445     *
446     * @param  point the coordinate point where to evaluate the derivative. Null
447     *         value is accepted only if the derivative is the same everywhere.
448     *         For example, affine transform accept null value since they produces
449     *         identical derivative no matter the coordinate value.
450     *         But most map projection will requires a non-null value.
451     * @return the derivative at the specified point (never {@code null}).
452     *         This method never returns an internal object: changing the matrix
453     *         will not change the state of this math transform.
454     * @throws NullPointerException if the derivative depends on coordinate and {@code point} is {@code null}.
455     * @throws MismatchedDimensionException if {@code point} does not have the expected dimension.
456     * @throws TransformException if the derivative cannot be evaluated at the specified point.
457     */
458    @UML(identifier="derivative", specification=OGC_01009)
459    Matrix derivative(DirectPosition point)
460            throws MismatchedDimensionException, TransformException;
461
462    /**
463     * Returns the inverse transform of this object. The target of the inverse transform
464     * is the source of the original. The source of the inverse transform is the target
465     * of the original. Using the original transform followed by the inverse's transform
466     * will result in an identity map on the source coordinate space, when allowances for
467     * error are made. This method may fail if the transform is not one to one. However,
468     * all cartographic projections should succeed.
469     *
470     * @return the inverse transform.
471     * @throws NoninvertibleTransformException if the transform cannot be inverted.
472     *
473     * @see AffineTransform#createInverse()
474     */
475    @UML(identifier="inverse", specification=OGC_01009)
476    default MathTransform inverse() throws NoninvertibleTransformException {
477        if (isIdentity()) {
478            return this;
479        }
480        throw new NoninvertibleTransformException();
481    }
482
483    /**
484     * Tests whether this transform does not move any points.
485     *
486     * @return {@code true} if this {@code MathTransform} is
487     *         an identity transform; {@code false} otherwise.
488     *
489     * @see AffineTransform#isIdentity()
490     */
491    @UML(identifier="isIdentity", specification=OGC_01009)
492    boolean isIdentity();
493
494    /**
495     * Returns a <i>Well-Known Text</i> (WKT) for this object.
496     * Version 1 of Well-Know Text is defined in {@linkplain org.opengis.annotation.Specification#OGC_01009 OGC 01-009}.
497     * This operation may fail if unsupported or if this instance contains elements that do not have WKT representation.
498     *
499     * @return the Well-Known Text (WKT) for this object.
500     * @throws UnsupportedOperationException if this object cannot be formatted as WKT.
501     *
502     * @see MathTransformFactory#createFromWKT(String)
503     */
504    @UML(identifier="getWKT", specification=OGC_01009)
505    default String toWKT() {
506        throw new UnsupportedOperationException();
507    }
508}