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}