LCOV - code coverage report
Current view: top level - alg - gdalgenericinverse.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 45 51 88.2 %
Date: 2024-11-21 22:18:42 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Generic method to compute inverse coordinate transformation from
       5             :  *           forward method
       6             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include <algorithm>
      15             : #include <cmath>
      16             : 
      17             : #include "gdalgenericinverse.h"
      18             : #include <cstdio>
      19             : 
      20             : /** Compute (xOut, yOut) corresponding to input (xIn, yIn) using
      21             :  * the provided forward transformation to emulate the reverse direction.
      22             :  *
      23             :  * Uses Newton-Raphson method, extended to 2D variables, that is using
      24             :  * inversion of the Jacobian 2D matrix of partial derivatives. The derivatives
      25             :  * are estimated numerically from the forward method evaluated at close points.
      26             :  *
      27             :  * Starts with initial guess provided by user in (guessedXOut, guessedYOut)
      28             :  *
      29             :  * It iterates at most for 15 iterations or as soon as we get below the specified
      30             :  * tolerance (on input coordinates)
      31             :  */
      32       70066 : bool GDALGenericInverse2D(double xIn, double yIn, double guessedXOut,
      33             :                           double guessedYOut,
      34             :                           GDALForwardCoordTransformer pfnForwardTranformer,
      35             :                           void *pfnForwardTranformerUserData, double &xOut,
      36             :                           double &yOut,
      37             :                           bool computeJacobianMatrixOnlyAtFirstIter,
      38             :                           double toleranceOnInputCoordinates,
      39             :                           double toleranceOnOutputCoordinates)
      40             : {
      41       70066 :     const double dfAbsValOut = std::max(fabs(guessedXOut), fabs(guessedYOut));
      42       70066 :     const double dfEps = dfAbsValOut > 0 ? dfAbsValOut * 1e-6 : 1e-6;
      43       70066 :     if (toleranceOnInputCoordinates == 0)
      44             :     {
      45       70066 :         const double dfAbsValIn = std::max(fabs(xIn), fabs(yIn));
      46       70066 :         toleranceOnInputCoordinates =
      47       70066 :             dfAbsValIn > 0 ? dfAbsValIn * 1e-12 : 1e-12;
      48             :     }
      49       70066 :     xOut = guessedXOut;
      50       70066 :     yOut = guessedYOut;
      51       70066 :     double deriv_lam_X = 0;
      52       70066 :     double deriv_lam_Y = 0;
      53       70066 :     double deriv_phi_X = 0;
      54       70066 :     double deriv_phi_Y = 0;
      55      333611 :     for (int i = 0; i < 15; i++)
      56             :     {
      57             :         double xApprox;
      58             :         double yApprox;
      59      333585 :         if (!pfnForwardTranformer(xOut, yOut, xApprox, yApprox,
      60             :                                   pfnForwardTranformerUserData))
      61       70040 :             return false;
      62      333585 :         const double deltaX = xApprox - xIn;
      63      333585 :         const double deltaY = yApprox - yIn;
      64      333585 :         if (fabs(deltaX) < toleranceOnInputCoordinates &&
      65       83854 :             fabs(deltaY) < toleranceOnInputCoordinates)
      66             :         {
      67       70040 :             return true;
      68             :         }
      69             : 
      70      263545 :         if (i == 0 || !computeJacobianMatrixOnlyAtFirstIter)
      71             :         {
      72             :             // Compute Jacobian matrix
      73       63865 :             double xTmp = xOut + dfEps;
      74       63865 :             double yTmp = yOut;
      75             :             double xTmpOut;
      76             :             double yTmpOut;
      77       63865 :             if (!pfnForwardTranformer(xTmp, yTmp, xTmpOut, yTmpOut,
      78             :                                       pfnForwardTranformerUserData))
      79           0 :                 return false;
      80       63865 :             const double deriv_X_lam = (xTmpOut - xApprox) / dfEps;
      81       63865 :             const double deriv_Y_lam = (yTmpOut - yApprox) / dfEps;
      82             : 
      83       63865 :             xTmp = xOut;
      84       63865 :             yTmp = yOut + dfEps;
      85       63865 :             if (!pfnForwardTranformer(xTmp, yTmp, xTmpOut, yTmpOut,
      86             :                                       pfnForwardTranformerUserData))
      87           0 :                 return false;
      88       63865 :             const double deriv_X_phi = (xTmpOut - xApprox) / dfEps;
      89       63865 :             const double deriv_Y_phi = (yTmpOut - yApprox) / dfEps;
      90             : 
      91             :             // Inverse of Jacobian matrix
      92       63865 :             const double det =
      93       63865 :                 deriv_X_lam * deriv_Y_phi - deriv_X_phi * deriv_Y_lam;
      94       63865 :             if (det != 0)
      95             :             {
      96       63865 :                 deriv_lam_X = deriv_Y_phi / det;
      97       63865 :                 deriv_lam_Y = -deriv_X_phi / det;
      98       63865 :                 deriv_phi_X = -deriv_Y_lam / det;
      99       63865 :                 deriv_phi_Y = deriv_X_lam / det;
     100             :             }
     101             :             else
     102             :             {
     103           0 :                 return false;
     104             :             }
     105             :         }
     106             : 
     107      263545 :         const double xOutDelta = deltaX * deriv_lam_X + deltaY * deriv_lam_Y;
     108      263545 :         const double yOutDelta = deltaX * deriv_phi_X + deltaY * deriv_phi_Y;
     109      263545 :         xOut -= xOutDelta;
     110      263545 :         yOut -= yOutDelta;
     111      263545 :         if (toleranceOnOutputCoordinates > 0 &&
     112           0 :             fabs(xOutDelta) < toleranceOnOutputCoordinates &&
     113           0 :             fabs(yOutDelta) < toleranceOnOutputCoordinates)
     114             :         {
     115           0 :             return true;
     116             :         }
     117             :     }
     118          26 :     return false;
     119             : }

Generated by: LCOV version 1.14