LCOV - code coverage report
Current view: directory - alg - gdal_rpc.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 408 204 50.0 %
Date: 2012-04-28 Functions: 11 7 63.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdal_rpc.cpp 24099 2012-03-09 09:24:57Z bishop $
       3                 :  *
       4                 :  * Project:  Image Warper
       5                 :  * Purpose:  Implements a rational polynomail (RPC) based transformer. 
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_priv.h"
      31                 : #include "gdal_alg.h"
      32                 : #include "ogr_spatialref.h"
      33                 : #include "cpl_minixml.h"
      34                 : 
      35                 : CPL_CVSID("$Id: gdal_rpc.cpp 24099 2012-03-09 09:24:57Z bishop $");
      36                 : 
      37                 : CPL_C_START
      38                 : CPLXMLNode *GDALSerializeRPCTransformer( void *pTransformArg );
      39                 : void *GDALDeserializeRPCTransformer( CPLXMLNode *psTree );
      40                 : CPL_C_END
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                            RPCInfoToMD()                             */
      44                 : /*                                                                      */
      45                 : /*      Turn an RPCInfo structure back into it's metadata format.       */
      46                 : /************************************************************************/
      47                 : 
      48               0 : static char ** RPCInfoToMD( GDALRPCInfo *psRPCInfo )
      49                 : 
      50                 : {
      51               0 :     char **papszMD = NULL;
      52               0 :     CPLString osField, osMultiField;
      53                 :     int i;
      54                 : 
      55               0 :     osField.Printf( "%.15g", psRPCInfo->dfLINE_OFF );
      56               0 :     papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
      57                 : 
      58               0 :     osField.Printf( "%.15g", psRPCInfo->dfSAMP_OFF );
      59               0 :     papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
      60                 : 
      61               0 :     osField.Printf( "%.15g", psRPCInfo->dfLAT_OFF );
      62               0 :     papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
      63                 : 
      64               0 :     osField.Printf( "%.15g", psRPCInfo->dfLONG_OFF );
      65               0 :     papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
      66                 : 
      67               0 :     osField.Printf( "%.15g", psRPCInfo->dfHEIGHT_OFF );
      68               0 :     papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
      69                 : 
      70               0 :     osField.Printf( "%.15g", psRPCInfo->dfLINE_SCALE );
      71               0 :     papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
      72                 : 
      73               0 :     osField.Printf( "%.15g", psRPCInfo->dfSAMP_SCALE );
      74               0 :     papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
      75                 : 
      76               0 :     osField.Printf( "%.15g", psRPCInfo->dfLAT_SCALE );
      77               0 :     papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
      78                 : 
      79               0 :     osField.Printf( "%.15g", psRPCInfo->dfLONG_SCALE );
      80               0 :     papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
      81                 : 
      82               0 :     osField.Printf( "%.15g", psRPCInfo->dfHEIGHT_SCALE );
      83               0 :     papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
      84                 : 
      85               0 :     osField.Printf( "%.15g", psRPCInfo->dfMIN_LONG );
      86               0 :     papszMD = CSLSetNameValue( papszMD, "MIN_LONG", osField );
      87                 : 
      88               0 :     osField.Printf( "%.15g", psRPCInfo->dfMIN_LAT );
      89               0 :     papszMD = CSLSetNameValue( papszMD, "MIN_LAT", osField );
      90                 : 
      91               0 :     osField.Printf( "%.15g", psRPCInfo->dfMAX_LONG );
      92               0 :     papszMD = CSLSetNameValue( papszMD, "MAX_LONG", osField );
      93                 : 
      94               0 :     osField.Printf( "%.15g", psRPCInfo->dfMAX_LAT );
      95               0 :     papszMD = CSLSetNameValue( papszMD, "MAX_LAT", osField );
      96                 : 
      97               0 :     for( i = 0; i < 20; i++ )
      98                 :     {
      99               0 :         osField.Printf( "%.15g", psRPCInfo->adfLINE_NUM_COEFF[i] );
     100               0 :         if( i > 0 )
     101               0 :             osMultiField += " ";
     102                 :         else
     103               0 :             osMultiField = "";
     104               0 :         osMultiField += osField;
     105                 :     }
     106               0 :     papszMD = CSLSetNameValue( papszMD, "LINE_NUM_COEFF", osMultiField );
     107                 : 
     108               0 :     for( i = 0; i < 20; i++ )
     109                 :     {
     110               0 :         osField.Printf( "%.15g", psRPCInfo->adfLINE_DEN_COEFF[i] );
     111               0 :         if( i > 0 )
     112               0 :             osMultiField += " ";
     113                 :         else
     114               0 :             osMultiField = "";
     115               0 :         osMultiField += osField;
     116                 :     }
     117               0 :     papszMD = CSLSetNameValue( papszMD, "LINE_DEN_COEFF", osMultiField );
     118                 : 
     119               0 :     for( i = 0; i < 20; i++ )
     120                 :     {
     121               0 :         osField.Printf( "%.15g", psRPCInfo->adfSAMP_NUM_COEFF[i] );
     122               0 :         if( i > 0 )
     123               0 :             osMultiField += " ";
     124                 :         else
     125               0 :             osMultiField = "";
     126               0 :         osMultiField += osField;
     127                 :     }
     128               0 :     papszMD = CSLSetNameValue( papszMD, "SAMP_NUM_COEFF", osMultiField );
     129                 : 
     130               0 :     for( i = 0; i < 20; i++ )
     131                 :     {
     132               0 :         osField.Printf( "%.15g", psRPCInfo->adfSAMP_DEN_COEFF[i] );
     133               0 :         if( i > 0 )
     134               0 :             osMultiField += " ";
     135                 :         else
     136               0 :             osMultiField = "";
     137               0 :         osMultiField += osField;
     138                 :     }
     139               0 :     papszMD = CSLSetNameValue( papszMD, "SAMP_DEN_COEFF", osMultiField );
     140                 : 
     141               0 :     return papszMD;
     142                 : }
     143                 : 
     144                 : /************************************************************************/
     145                 : /*                          RPCComputeTerms()                           */
     146                 : /************************************************************************/
     147                 : 
     148              56 : static void RPCComputeTerms( double dfLong, double dfLat, double dfHeight,
     149                 :                              double *padfTerms )
     150                 : 
     151                 : {
     152              56 :     padfTerms[0] = 1.0;
     153              56 :     padfTerms[1] = dfLong;
     154              56 :     padfTerms[2] = dfLat;
     155              56 :     padfTerms[3] = dfHeight;
     156              56 :     padfTerms[4] = dfLong * dfLat;
     157              56 :     padfTerms[5] = dfLong * dfHeight;
     158              56 :     padfTerms[6] = dfLat * dfHeight;
     159              56 :     padfTerms[7] = dfLong * dfLong;
     160              56 :     padfTerms[8] = dfLat * dfLat;
     161              56 :     padfTerms[9] = dfHeight * dfHeight;
     162                 : 
     163              56 :     padfTerms[10] = dfLong * dfLat * dfHeight;
     164              56 :     padfTerms[11] = dfLong * dfLong * dfLong;
     165              56 :     padfTerms[12] = dfLong * dfLat * dfLat;
     166              56 :     padfTerms[13] = dfLong * dfHeight * dfHeight;
     167              56 :     padfTerms[14] = dfLong * dfLong * dfLat;
     168              56 :     padfTerms[15] = dfLat * dfLat * dfLat;
     169              56 :     padfTerms[16] = dfLat * dfHeight * dfHeight;
     170              56 :     padfTerms[17] = dfLong * dfLong * dfHeight;
     171              56 :     padfTerms[18] = dfLat * dfLat * dfHeight;
     172              56 :     padfTerms[19] = dfHeight * dfHeight * dfHeight;
     173              56 : }
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                            RPCEvaluate()                             */
     177                 : /************************************************************************/
     178                 : 
     179             224 : static double RPCEvaluate( double *padfTerms, double *padfCoefs )
     180                 : 
     181                 : {
     182             224 :     double dfSum = 0.0;
     183                 :     int i;
     184                 : 
     185            4704 :     for( i = 0; i < 20; i++ )
     186            4480 :         dfSum += padfTerms[i] * padfCoefs[i];
     187                 : 
     188             224 :     return dfSum;
     189                 : }
     190                 : 
     191                 : /************************************************************************/
     192                 : /*                         RPCTransformPoint()                          */
     193                 : /************************************************************************/
     194                 : 
     195              56 : static void RPCTransformPoint( GDALRPCInfo *psRPC, 
     196                 :                                double dfLong, double dfLat, double dfHeight, 
     197                 :                                double *pdfPixel, double *pdfLine )
     198                 : 
     199                 : {
     200                 :     double dfResultX, dfResultY;
     201                 :     double adfTerms[20];
     202                 :    
     203                 :     RPCComputeTerms( 
     204                 :         (dfLong   - psRPC->dfLONG_OFF) / psRPC->dfLONG_SCALE, 
     205                 :         (dfLat    - psRPC->dfLAT_OFF) / psRPC->dfLAT_SCALE, 
     206                 :         (dfHeight - psRPC->dfHEIGHT_OFF) / psRPC->dfHEIGHT_SCALE,
     207              56 :         adfTerms );
     208                 :     
     209                 :     dfResultX = RPCEvaluate( adfTerms, psRPC->adfSAMP_NUM_COEFF )
     210              56 :         / RPCEvaluate( adfTerms, psRPC->adfSAMP_DEN_COEFF );
     211                 :     
     212                 :     dfResultY = RPCEvaluate( adfTerms, psRPC->adfLINE_NUM_COEFF )
     213              56 :         / RPCEvaluate( adfTerms, psRPC->adfLINE_DEN_COEFF );
     214                 :     
     215              56 :     *pdfPixel = dfResultX * psRPC->dfSAMP_SCALE + psRPC->dfSAMP_OFF;
     216              56 :     *pdfLine = dfResultY * psRPC->dfLINE_SCALE + psRPC->dfLINE_OFF;
     217              56 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /* ==================================================================== */
     221                 : /*           GDALRPCTransformer                         */
     222                 : /* ==================================================================== */
     223                 : /************************************************************************/
     224                 : 
     225                 : /*! DEM Resampling Algorithm */
     226                 : typedef enum {
     227                 :   /*! Nearest neighbour (select on one input pixel) */ DRA_NearestNeighbour=0,
     228                 :   /*! Bilinear (2x2 kernel) */                         DRA_Bilinear=1,
     229                 :   /*! Cubic Convolution Approximation (4x4 kernel) */  DRA_Cubic=2
     230                 : } DEMResampleAlg;
     231                 : 
     232                 : typedef struct {
     233                 : 
     234                 :     GDALTransformerInfo sTI;
     235                 : 
     236                 :     GDALRPCInfo sRPC;
     237                 : 
     238                 :     double      adfPLToLatLongGeoTransform[6];
     239                 : 
     240                 :     int         bReversed;
     241                 : 
     242                 :     double      dfPixErrThreshold;
     243                 : 
     244                 :     double      dfHeightOffset;
     245                 : 
     246                 :     double      dfHeightScale;
     247                 : 
     248                 :     char        *pszDEMPath;
     249                 : 
     250                 :     DEMResampleAlg eResampleAlg;
     251                 : 
     252                 :     int         bHasTriedOpeningDS;
     253                 :     GDALDataset *poDS;
     254                 : 
     255                 :     OGRCoordinateTransformation *poCT;
     256                 : 
     257                 :     double      adfGeoTransform[6];
     258                 :     double      adfReverseGeoTransform[6];
     259                 : } GDALRPCTransformInfo;
     260                 : 
     261                 : /************************************************************************/
     262                 : /*                      GDALCreateRPCTransformer()                      */
     263                 : /************************************************************************/
     264                 : 
     265                 : /**
     266                 :  * Create an RPC based transformer. 
     267                 :  *
     268                 :  * The geometric sensor model describing the physical relationship between 
     269                 :  * image coordinates and ground coordinate is known as a Rigorous Projection 
     270                 :  * Model. A Rigorous Projection Model expresses the mapping of the image space 
     271                 :  * coordinates of rows and columns (r,c) onto the object space reference 
     272                 :  * surface geodetic coordinates (long, lat, height).
     273                 :  * 
     274                 :  * RPC supports a generic description of the Rigorous Projection Models. The 
     275                 :  * approximation used by GDAL (RPC00) is a set of rational polynomials exp 
     276                 :  * ressing the normalized row and column values, (rn , cn), as a function of
     277                 :  *  normalized geodetic latitude, longitude, and height, (P, L, H), given a 
     278                 :  * set of normalized polynomial coefficients (LINE_NUM_COEF_n, LINE_DEN_COEF_n,
     279                 :  *  SAMP_NUM_COEF_n, SAMP_DEN_COEF_n). Normalized values, rather than actual 
     280                 :  * values are used in order to minimize introduction of errors during the 
     281                 :  * calculations. The transformation between row and column values (r,c), and 
     282                 :  * normalized row and column values (rn, cn), and between the geodetic 
     283                 :  * latitude, longitude, and height and normalized geodetic latitude, 
     284                 :  * longitude, and height (P, L, H), is defined by a set of normalizing 
     285                 :  * translations (offsets) and scales that ensure all values are contained i 
     286                 :  * the range -1 to +1.
     287                 :  *
     288                 :  * This function creates a GDALTransformFunc compatible transformer 
     289                 :  * for going between image pixel/line and long/lat/height coordinates 
     290                 :  * using RPCs.  The RPCs are provided in a GDALRPCInfo structure which is
     291                 :  * normally read from metadata using GDALExtractRPCInfo().  
     292                 :  *
     293                 :  * GDAL RPC Metadata has the following entries (also described in GDAL RFC 22
     294                 :  * and the GeoTIFF RPC document http://geotiff.maptools.org/rpc_prop.html.  
     295                 :  *
     296                 :  * <ul>
     297                 :  * <li>ERR_BIAS: Error - Bias. The RMS bias error in meters per horizontal axis of all points in the image (-1.0 if unknown)
     298                 :  * <li>ERR_RAND: Error - Random. RMS random error in meters per horizontal axis of each point in the image (-1.0 if unknown)
     299                 :  * <li>LINE_OFF: Line Offset
     300                 :  * <li>SAMP_OFF: Sample Offset
     301                 :  * <li>LAT_OFF: Geodetic Latitude Offset
     302                 :  * <li>LONG_OFF: Geodetic Longitude Offset
     303                 :  * <li>HEIGHT_OFF: Geodetic Height Offset
     304                 :  * <li>LINE_SCALE: Line Scale
     305                 :  * <li>SAMP_SCALE: Sample Scale
     306                 :  * <li>LAT_SCALE: Geodetic Latitude Scale
     307                 :  * <li>LONG_SCALE: Geodetic Longitude Scale
     308                 :  * <li>HEIGHT_SCALE: Geodetic Height Scale
     309                 :  * <li>LINE_NUM_COEFF (1-20): Line Numerator Coefficients. Twenty coefficients for the polynomial in the Numerator of the rn equation. (space separated)
     310                 :  * <li>LINE_DEN_COEFF (1-20): Line Denominator Coefficients. Twenty coefficients for the polynomial in the Denominator of the rn equation. (space separated)
     311                 :  * <li>SAMP_NUM_COEFF (1-20): Sample Numerator Coefficients. Twenty coefficients for the polynomial in the Numerator of the cn equation. (space separated)
     312                 :  * <li>SAMP_DEN_COEFF (1-20): Sample Denominator Coefficients. Twenty coefficients for the polynomial in the Denominator of the cn equation. (space separated)
     313                 :  * </ul>
     314                 :  *
     315                 :  * The transformer normally maps from pixel/line/height to long/lat/height space
     316                 :  * as a forward transformation though in RPC terms that would be considered
     317                 :  * an inverse transformation (and is solved by iterative approximation using
     318                 :  * long/lat/height to pixel/line transformations).  The default direction can
     319                 :  * be reversed by passing bReversed=TRUE.  
     320                 :  * 
     321                 :  * The iterative solution of pixel/line
     322                 :  * to lat/long/height is currently run for up to 10 iterations or until 
     323                 :  * the apparent error is less than dfPixErrThreshold pixels.  Passing zero
     324                 :  * will not avoid all error, but will cause the operation to run for the maximum
     325                 :  * number of iterations. 
     326                 :  *
     327                 :  * Additional options to the transformer can be supplied in papszOptions.
     328                 :  *
     329                 :  * Options:
     330                 :  * 
     331                 :  * <ul>
     332                 :  * <li> RPC_HEIGHT: a fixed height offset to be applied to all points passed
     333                 :  * in.  In this situation the Z passed into the transformation function is
     334                 :  * assumed to be height above ground, and the RPC_HEIGHT is assumed to be
     335                 :  * an average height above sea level for ground in the target scene. 
     336                 :  *
     337                 :  * <li> RPC_HEIGHT_SCALE: a factor used to multiply heights above ground.
     338                 :  * Usefull when elevation offsets of the DEM are not expressed in meters. (GDAL >= 1.8.0)
     339                 :  *
     340                 :  * <li> RPC_DEM: the name of a GDAL dataset (a DEM file typically) used to
     341                 :  * extract elevation offsets from. In this situation the Z passed into the
     342                 :  * transformation function is assumed to be height above ground. This option
     343                 :  * should be used in replacement of RPC_HEIGHT to provide a way of defining
     344                 :  * a non uniform ground for the target scene (GDAL >= 1.8.0)
     345                 :  *
     346                 :  * <li> RPC_DEMINTERPOLATION: the DEM interpolation (near, bilinear or cubic)
     347                 :  * </ul>
     348                 :  *
     349                 :  * @param psRPCInfo Definition of the RPC parameters.
     350                 :  *
     351                 :  * @param bReversed If true "forward" transformation will be lat/long to pixel/line instead of the normal pixel/line to lat/long.
     352                 :  *
     353                 :  * @param dfPixErrThreshold the error (measured in pixels) allowed in the 
     354                 :  * iterative solution of pixel/line to lat/long computations (the other way
     355                 :  * is always exact given the equations). 
     356                 :  *
     357                 :  * @param papszOptions Other transformer options (ie. RPC_HEIGHT=<z>). 
     358                 :  *
     359                 :  * @return transformer callback data (deallocate with GDALDestroyTransformer()).
     360                 :  */
     361                 : 
     362               6 : void *GDALCreateRPCTransformer( GDALRPCInfo *psRPCInfo, int bReversed, 
     363                 :                                 double dfPixErrThreshold,
     364                 :                                 char **papszOptions )
     365                 : 
     366                 : {
     367                 :     GDALRPCTransformInfo *psTransform;
     368                 : 
     369                 : /* -------------------------------------------------------------------- */
     370                 : /*      Initialize core info.                                           */
     371                 : /* -------------------------------------------------------------------- */
     372                 :     psTransform = (GDALRPCTransformInfo *) 
     373               6 :         CPLCalloc(sizeof(GDALRPCTransformInfo),1);
     374                 : 
     375               6 :     memcpy( &(psTransform->sRPC), psRPCInfo, sizeof(GDALRPCInfo) );
     376               6 :     psTransform->bReversed = bReversed;
     377               6 :     psTransform->dfPixErrThreshold = dfPixErrThreshold;
     378               6 :     psTransform->dfHeightOffset = 0.0;
     379               6 :     psTransform->dfHeightScale = 1.0;
     380                 : 
     381               6 :     strcpy( psTransform->sTI.szSignature, "GTI" );
     382               6 :     psTransform->sTI.pszClassName = "GDALRPCTransformer";
     383               6 :     psTransform->sTI.pfnTransform = GDALRPCTransform;
     384               6 :     psTransform->sTI.pfnCleanup = GDALDestroyRPCTransformer;
     385               6 :     psTransform->sTI.pfnSerialize = GDALSerializeRPCTransformer;
     386                 :    
     387                 : /* -------------------------------------------------------------------- */
     388                 : /*      Do we have a "average height" that we want to consider all      */
     389                 : /*      elevations to be relative to?                                   */
     390                 : /* -------------------------------------------------------------------- */
     391               6 :     const char *pszHeight = CSLFetchNameValue( papszOptions, "RPC_HEIGHT" );
     392               6 :     if( pszHeight != NULL )
     393               2 :         psTransform->dfHeightOffset = CPLAtof(pszHeight);
     394                 : 
     395                 : /* -------------------------------------------------------------------- */
     396                 : /*                       The "height scale"                             */
     397                 : /* -------------------------------------------------------------------- */
     398               6 :     const char *pszHeightScale = CSLFetchNameValue( papszOptions, "RPC_HEIGHT_SCALE" );
     399               6 :     if( pszHeightScale != NULL )
     400               2 :         psTransform->dfHeightScale = CPLAtof(pszHeightScale);
     401                 : 
     402                 : /* -------------------------------------------------------------------- */
     403                 : /*                       The DEM file name                              */
     404                 : /* -------------------------------------------------------------------- */
     405               6 :     const char *pszDEMPath = CSLFetchNameValue( papszOptions, "RPC_DEM" );
     406               6 :     if( pszDEMPath != NULL )
     407               2 :         psTransform->pszDEMPath = CPLStrdup(pszDEMPath);
     408                 : 
     409                 : /* -------------------------------------------------------------------- */
     410                 : /*                      The DEM interpolation                           */
     411                 : /* -------------------------------------------------------------------- */
     412               6 :     const char *pszDEMInterpolation = CSLFetchNameValueDef( papszOptions, "RPC_DEMINTERPOLATION", "bilinear" );
     413               6 :     if(EQUAL(pszDEMInterpolation, "near" ))
     414               0 :         psTransform->eResampleAlg = DRA_NearestNeighbour;
     415               6 :     else if(EQUAL(pszDEMInterpolation, "bilinear" ))
     416               6 :         psTransform->eResampleAlg = DRA_Bilinear;
     417               0 :     else if(EQUAL(pszDEMInterpolation, "cubic" ))
     418               0 :         psTransform->eResampleAlg = DRA_Cubic;
     419                 :     else
     420               0 :         psTransform->eResampleAlg = DRA_Bilinear;
     421                 :        
     422                 : /* -------------------------------------------------------------------- */
     423                 : /*      Establish a reference point for calcualating an affine          */
     424                 : /*      geotransform approximate transformation.                        */
     425                 : /* -------------------------------------------------------------------- */
     426               6 :     double adfGTFromLL[6], dfRefPixel = -1.0, dfRefLine = -1.0;
     427               6 :     double dfRefLong = 0.0, dfRefLat = 0.0;
     428                 : 
     429               6 :     if( psRPCInfo->dfMIN_LONG != -180 || psRPCInfo->dfMAX_LONG != 180 )
     430                 :     {
     431               0 :         dfRefLong = (psRPCInfo->dfMIN_LONG + psRPCInfo->dfMAX_LONG) * 0.5;
     432               0 :         dfRefLat  = (psRPCInfo->dfMIN_LAT  + psRPCInfo->dfMAX_LAT ) * 0.5;
     433                 : 
     434                 :         RPCTransformPoint( psRPCInfo, dfRefLong, dfRefLat, 0.0, 
     435               0 :                            &dfRefPixel, &dfRefLine );
     436                 :     }
     437                 : 
     438                 :     // Try with scale and offset if we don't can't use bounds or
     439                 :     // the results seem daft. 
     440               6 :     if( dfRefPixel < 0.0 || dfRefLine < 0.0
     441                 :         || dfRefPixel > 100000 || dfRefLine > 100000 )
     442                 :     {
     443               6 :         dfRefLong = psRPCInfo->dfLONG_OFF;
     444               6 :         dfRefLat  = psRPCInfo->dfLAT_OFF;
     445                 : 
     446                 :         RPCTransformPoint( psRPCInfo, dfRefLong, dfRefLat, 0.0, 
     447               6 :                            &dfRefPixel, &dfRefLine );
     448                 :     }
     449                 : 
     450                 : /* -------------------------------------------------------------------- */
     451                 : /*      Transform nearby locations to establish affine direction        */
     452                 : /*      vectors.                                                        */
     453                 : /* -------------------------------------------------------------------- */
     454               6 :     double dfRefPixelDelta, dfRefLineDelta, dfLLDelta = 0.0001;
     455                 :     
     456                 :     RPCTransformPoint( psRPCInfo, dfRefLong+dfLLDelta, dfRefLat, 0.0, 
     457               6 :                        &dfRefPixelDelta, &dfRefLineDelta );
     458               6 :     adfGTFromLL[1] = (dfRefPixelDelta - dfRefPixel) / dfLLDelta;
     459               6 :     adfGTFromLL[2] = (dfRefLineDelta - dfRefLine) / dfLLDelta;
     460                 :     
     461                 :     RPCTransformPoint( psRPCInfo, dfRefLong, dfRefLat+dfLLDelta, 0.0, 
     462               6 :                        &dfRefPixelDelta, &dfRefLineDelta );
     463               6 :     adfGTFromLL[4] = (dfRefPixelDelta - dfRefPixel) / dfLLDelta;
     464               6 :     adfGTFromLL[5] = (dfRefLineDelta - dfRefLine) / dfLLDelta;
     465                 : 
     466                 :     adfGTFromLL[0] = dfRefPixel 
     467               6 :         - adfGTFromLL[1] * dfRefLong - adfGTFromLL[2] * dfRefLat;
     468                 :     adfGTFromLL[3] = dfRefLine 
     469               6 :         - adfGTFromLL[4] * dfRefLong - adfGTFromLL[5] * dfRefLat;
     470                 : 
     471               6 :     GDALInvGeoTransform( adfGTFromLL, psTransform->adfPLToLatLongGeoTransform);
     472                 :     
     473               6 :     return psTransform;
     474                 : }
     475                 : 
     476                 : /************************************************************************/
     477                 : /*                 GDALDestroyReprojectionTransformer()                 */
     478                 : /************************************************************************/
     479                 : 
     480               6 : void GDALDestroyRPCTransformer( void *pTransformAlg )
     481                 : 
     482                 : {
     483               6 :     GDALRPCTransformInfo *psTransform = (GDALRPCTransformInfo *) pTransformAlg;
     484                 : 
     485               6 :     CPLFree( psTransform->pszDEMPath );
     486                 : 
     487               6 :     if(psTransform->poDS)
     488               2 :         GDALClose(psTransform->poDS);
     489               6 :     if(psTransform->poCT)
     490               2 :         OCTDestroyCoordinateTransformation((OGRCoordinateTransformationH)psTransform->poCT);
     491                 : 
     492               6 :     CPLFree( pTransformAlg );
     493               6 : }
     494                 : 
     495                 : /************************************************************************/
     496                 : /*                      RPCInverseTransformPoint()                      */
     497                 : /************************************************************************/
     498                 : 
     499                 : static void 
     500              10 : RPCInverseTransformPoint( GDALRPCTransformInfo *psTransform,
     501                 :                           double dfPixel, double dfLine, double dfHeight, 
     502                 :                           double *pdfLong, double *pdfLat )
     503                 : 
     504                 : {
     505                 :     double dfResultX, dfResultY;
     506                 :     int    iIter;
     507              10 :     GDALRPCInfo *psRPC = &(psTransform->sRPC);
     508                 : 
     509                 : /* -------------------------------------------------------------------- */
     510                 : /*      Compute an initial approximation based on linear                */
     511                 : /*      interpolation from our reference point.                         */
     512                 : /* -------------------------------------------------------------------- */
     513              10 :     dfResultX = psTransform->adfPLToLatLongGeoTransform[0]
     514              10 :         + psTransform->adfPLToLatLongGeoTransform[1] * dfPixel
     515              10 :         + psTransform->adfPLToLatLongGeoTransform[2] * dfLine;
     516                 : 
     517              10 :     dfResultY = psTransform->adfPLToLatLongGeoTransform[3]
     518              10 :         + psTransform->adfPLToLatLongGeoTransform[4] * dfPixel
     519              10 :         + psTransform->adfPLToLatLongGeoTransform[5] * dfLine;
     520                 : 
     521                 : /* -------------------------------------------------------------------- */
     522                 : /*      Now iterate, trying to find a closer LL location that will      */
     523                 : /*      back transform to the indicated pixel and line.                 */
     524                 : /* -------------------------------------------------------------------- */
     525              10 :     double dfPixelDeltaX=0.0, dfPixelDeltaY=0.0;
     526                 : 
     527              30 :     for( iIter = 0; iIter < 10; iIter++ )
     528                 :     {
     529                 :         double dfBackPixel, dfBackLine;
     530                 : 
     531                 :         RPCTransformPoint( psRPC, dfResultX, dfResultY, dfHeight, 
     532              30 :                            &dfBackPixel, &dfBackLine );
     533                 : 
     534              30 :         dfPixelDeltaX = dfBackPixel - dfPixel;
     535              30 :         dfPixelDeltaY = dfBackLine - dfLine;
     536                 : 
     537                 :         dfResultX = dfResultX 
     538              30 :             - dfPixelDeltaX * psTransform->adfPLToLatLongGeoTransform[1]
     539              30 :             - dfPixelDeltaY * psTransform->adfPLToLatLongGeoTransform[2];
     540                 :         dfResultY = dfResultY 
     541              30 :             - dfPixelDeltaX * psTransform->adfPLToLatLongGeoTransform[4]
     542              30 :             - dfPixelDeltaY * psTransform->adfPLToLatLongGeoTransform[5];
     543                 : 
     544              30 :         if( ABS(dfPixelDeltaX) < psTransform->dfPixErrThreshold
     545                 :             && ABS(dfPixelDeltaY) < psTransform->dfPixErrThreshold )
     546                 :         {
     547              10 :             iIter = -1;
     548                 :             //CPLDebug( "RPC", "Converged!" );
     549              10 :             break;
     550                 :         }
     551                 : 
     552                 :     }
     553                 : 
     554              10 :     if( iIter != -1 )
     555                 :         CPLDebug( "RPC", "Iterations %d: Got: %g,%g  Offset=%g,%g", 
     556                 :                   iIter, 
     557                 :                   dfResultX, dfResultY,
     558               0 :                   dfPixelDeltaX, dfPixelDeltaY );
     559                 :     
     560              10 :     *pdfLong = dfResultX;
     561              10 :     *pdfLat = dfResultY;
     562              10 : }
     563                 : 
     564                 : 
     565               0 : double BiCubicKernel(double dfVal)
     566                 : {
     567               0 :   if ( dfVal > 2.0 )
     568               0 :     return 0.0;
     569                 :   
     570                 :   double a, b, c, d;
     571               0 :   double xm1 = dfVal - 1.0;
     572               0 :   double xp1 = dfVal + 1.0;
     573               0 :   double xp2 = dfVal + 2.0;
     574                 :   
     575               0 :   a = ( xp2 <= 0.0 ) ? 0.0 : xp2 * xp2 * xp2;
     576               0 :   b = ( xp1 <= 0.0 ) ? 0.0 : xp1 * xp1 * xp1;
     577               0 :   c = ( dfVal   <= 0.0 ) ? 0.0 : dfVal * dfVal * dfVal;
     578               0 :   d = ( xm1 <= 0.0 ) ? 0.0 : xm1 * xm1 * xm1;
     579                 :   
     580               0 :   return ( 0.16666666666666666667 * ( a - ( 4.0 * b ) + ( 6.0 * c ) - ( 4.0 * d ) ) );
     581                 : }
     582                 : 
     583                 : /************************************************************************/
     584                 : /*                          GDALRPCTransform()                          */
     585                 : /************************************************************************/
     586                 : 
     587              16 : int GDALRPCTransform( void *pTransformArg, int bDstToSrc, 
     588                 :                       int nPointCount, 
     589                 :                       double *padfX, double *padfY, double *padfZ,
     590                 :                       int *panSuccess )
     591                 : 
     592                 : {
     593              16 :     VALIDATE_POINTER1( pTransformArg, "GDALRPCTransform", 0 );
     594                 : 
     595              16 :     GDALRPCTransformInfo *psTransform = (GDALRPCTransformInfo *) pTransformArg;
     596              16 :     GDALRPCInfo *psRPC = &(psTransform->sRPC);
     597                 :     int i;
     598                 : 
     599              16 :     if( psTransform->bReversed )
     600               0 :         bDstToSrc = !bDstToSrc;
     601                 : 
     602              16 :     int bands[1] = {1};
     603              16 :     int nRasterXSize = 0, nRasterYSize = 0;
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Lazy opening of the optionnal DEM file.                         */
     607                 : /* -------------------------------------------------------------------- */
     608              16 :     if(psTransform->pszDEMPath != NULL &&
     609                 :        psTransform->bHasTriedOpeningDS == FALSE)
     610                 :     {
     611               2 :         int bIsValid = FALSE;
     612               2 :         psTransform->bHasTriedOpeningDS = TRUE;
     613                 :         psTransform->poDS = (GDALDataset *)
     614               2 :                                 GDALOpen( psTransform->pszDEMPath, GA_ReadOnly );
     615               2 :         if(psTransform->poDS != NULL && psTransform->poDS->GetRasterCount() >= 1)
     616                 :         {
     617               2 :             const char* pszSpatialRef = psTransform->poDS->GetProjectionRef();
     618               2 :             if (pszSpatialRef != NULL && pszSpatialRef[0] != '\0')
     619                 :             {
     620                 :                 OGRSpatialReference* poWGSSpaRef =
     621               2 :                         new OGRSpatialReference(SRS_WKT_WGS84);
     622                 :                 OGRSpatialReference* poDSSpaRef =
     623               4 :                         new OGRSpatialReference(pszSpatialRef);
     624               2 :                 if(!poWGSSpaRef->IsSame(poDSSpaRef))
     625                 :                     psTransform->poCT =OGRCreateCoordinateTransformation(
     626               2 :                                                     poWGSSpaRef, poDSSpaRef );
     627               2 :                 delete poWGSSpaRef;
     628               2 :                 delete poDSSpaRef;
     629                 :             }
     630                 : 
     631               4 :             if (psTransform->poDS->GetGeoTransform(
     632               2 :                                 psTransform->adfGeoTransform) == CE_None &&
     633                 :                 GDALInvGeoTransform( psTransform->adfGeoTransform,
     634                 :                                      psTransform->adfReverseGeoTransform ))
     635                 :             {
     636               2 :                 bIsValid = TRUE;
     637                 :             }
     638                 :         }
     639                 : 
     640               2 :         if (!bIsValid && psTransform->poDS != NULL)
     641                 :         {
     642               0 :             GDALClose(psTransform->poDS);
     643               0 :             psTransform->poDS = NULL;
     644                 :         }
     645                 :     }
     646              16 :     if (psTransform->poDS)
     647                 :     {
     648               4 :         nRasterXSize = psTransform->poDS->GetRasterXSize();
     649               4 :         nRasterYSize = psTransform->poDS->GetRasterYSize();
     650                 :     }
     651                 : 
     652                 : /* -------------------------------------------------------------------- */
     653                 : /*      The simple case is transforming from lat/long to pixel/line.    */
     654                 : /*      Just apply the equations directly.                              */
     655                 : /* -------------------------------------------------------------------- */
     656              16 :     if( bDstToSrc )
     657                 :     {
     658              16 :         for( i = 0; i < nPointCount; i++ )
     659                 :         {
     660               8 :             if(psTransform->poDS)
     661                 :             {
     662                 :                 double dfX, dfY;
     663                 :                 //check if dem is not in WGS84 and transform points padfX[i], padfY[i]
     664               2 :                 if(psTransform->poCT)
     665                 :                 {
     666               2 :                     double dfXOrig = padfX[i];
     667               2 :                     double dfYOrig = padfY[i];
     668               2 :                     double dfZOrig = padfZ[i];
     669               4 :                     if (!psTransform->poCT->Transform(
     670               2 :                                                 1, &dfXOrig, &dfYOrig, &dfZOrig))
     671                 :                     {
     672               0 :                         panSuccess[i] = FALSE;
     673               0 :                         continue;
     674                 :                     }
     675                 :                     GDALApplyGeoTransform( psTransform->adfReverseGeoTransform,
     676               2 :                                            dfXOrig, dfYOrig, &dfX, &dfY );
     677                 :                 }
     678                 :                 else
     679                 :                     GDALApplyGeoTransform( psTransform->adfReverseGeoTransform,
     680               0 :                                            padfX[i], padfY[i], &dfX, &dfY );
     681               2 :                 int dX = int(dfX);
     682               2 :                 int dY = int(dfY);
     683                 : 
     684               2 :                 if (!(dX >= 0 && dY >= 0 &&
     685                 :                       dX+2 <= nRasterXSize && dY+2 <= nRasterYSize))
     686                 :                 {
     687               0 :                     panSuccess[i] = FALSE;
     688               0 :                     continue;
     689                 :                 }
     690                 : 
     691               2 :                 double dfDEMH(0);
     692               2 :                 double dfDeltaX = dfX - dX;
     693               2 :                 double dfDeltaY = dfY - dY;
     694                 :                 
     695               2 :                 if(psTransform->eResampleAlg == DRA_Cubic)
     696                 :                 {
     697               0 :                     int dXNew = dX - 1;
     698               0 :                     int dYNew = dY - 1;
     699               0 :                     if (!(dXNew >= 0 && dYNew >= 0 && dXNew + 4 <= nRasterXSize && dYNew + 4 <= nRasterYSize))
     700                 :                     {
     701               0 :                         panSuccess[i] = FALSE;
     702               0 :                         continue;
     703                 :                     }
     704                 :                     //cubic interpolation
     705               0 :                     int adElevData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     706                 :                     CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4,
     707                 :                                                               &adElevData, 4, 4,
     708               0 :                                                               GDT_Int32, 1, bands, 0, 0, 0);
     709               0 :                     if(eErr != CE_None)
     710                 :                     {
     711               0 :                         panSuccess[i] = FALSE;
     712               0 :                         continue;
     713                 :                     }
     714                 : 
     715               0 :                     double dfSumH(0);
     716               0 :                     for ( int i = 0; i < 5; i++ )
     717                 :                     {
     718                 :                         // Loop across the X axis
     719               0 :                         for ( int j = 0; j < 5; j++ )
     720                 :                         {
     721                 :                             // Calculate the weight for the specified pixel according
     722                 :                             // to the bicubic b-spline kernel we're using for
     723                 :                             // interpolation
     724               0 :                             int dKernIndX = j - 1;
     725               0 :                             int dKernIndY = i - 1;
     726               0 :                             double dfPixelWeight = BiCubicKernel(dKernIndX - dfDeltaX) * BiCubicKernel(dKernIndY - dfDeltaY);
     727                 : 
     728                 :                             // Create a sum of all values
     729                 :                             // adjusted for the pixel's calculated weight
     730               0 :                             dfSumH += adElevData[j + i * 4] * dfPixelWeight;
     731                 :                         }
     732                 :                     }
     733               0 :                     dfDEMH = dfSumH;
     734                 :                 }
     735               2 :                 else if(psTransform->eResampleAlg == DRA_Bilinear)
     736                 :                 {
     737               2 :                     if (!(dX >= 0 && dY >= 0 && dX + 2 <= nRasterXSize && dY + 2 <= nRasterYSize))
     738                 :                     {
     739               0 :                         panSuccess[i] = FALSE;
     740               0 :                         continue;
     741                 :                     }
     742                 :                     //bilinear interpolation
     743               2 :                     int anElevData[4] = {0,0,0,0};
     744                 :                     CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2,
     745                 :                                                               &anElevData, 2, 2,
     746               2 :                                                               GDT_Int32, 1, bands, 0, 0, 0);
     747               2 :                     if(eErr != CE_None)
     748                 :                     {
     749               0 :                         panSuccess[i] = FALSE;
     750               0 :                         continue;
     751                 :                     }
     752               2 :                     double dfDeltaX1 = 1.0 - dfDeltaX;                
     753               2 :                     double dfDeltaY1 = 1.0 - dfDeltaY;
     754                 : 
     755               2 :                     double dfXZ1 = anElevData[0] * dfDeltaX1 + anElevData[1] * dfDeltaX;
     756               2 :                     double dfXZ2 = anElevData[2] * dfDeltaX1 + anElevData[3] * dfDeltaX;
     757               2 :                     double dfYZ = dfXZ1 * dfDeltaY1 + dfXZ2 * dfDeltaY;
     758               2 :                     dfDEMH = dfYZ;
     759                 :                 }
     760                 :                 else
     761                 :                 {
     762               0 :                     if (!(dX >= 0 && dY >= 0 && dX <= nRasterXSize && dY <= nRasterYSize))
     763                 :                     {
     764               0 :                         panSuccess[i] = FALSE;
     765               0 :                         continue;
     766                 :                     }
     767                 :                     CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1,
     768                 :                                                               &dfDEMH, 1, 1,
     769               0 :                                                               GDT_Int32, 1, bands, 0, 0, 0);
     770               0 :                     if(eErr != CE_None)
     771                 :                     {
     772               0 :                         panSuccess[i] = FALSE;
     773               0 :                         continue;
     774                 :                     }              
     775                 :                 }                
     776                 : 
     777                 :                 RPCTransformPoint( psRPC, padfX[i], padfY[i], 
     778               2 :                                    padfZ[i] + (psTransform->dfHeightOffset + dfDEMH) *
     779                 :                                                 psTransform->dfHeightScale, 
     780               4 :                                    padfX + i, padfY + i );
     781                 :             }
     782                 :             else
     783                 :                 RPCTransformPoint( psRPC, padfX[i], padfY[i], 
     784               6 :                                    padfZ[i] + psTransform->dfHeightOffset *
     785                 :                                               psTransform->dfHeightScale, 
     786              12 :                                    padfX + i, padfY + i );
     787               8 :             panSuccess[i] = TRUE;
     788                 :         }
     789                 : 
     790               8 :         return TRUE;
     791                 :     }
     792                 : 
     793                 : /* -------------------------------------------------------------------- */
     794                 : /*      Compute the inverse (pixel/line/height to lat/long).  This      */
     795                 : /*      function uses an iterative method from an initial linear        */
     796                 : /*      approximation.                                                  */
     797                 : /* -------------------------------------------------------------------- */
     798              16 :     for( i = 0; i < nPointCount; i++ )
     799                 :     {
     800                 :         double dfResultX, dfResultY;
     801                 : 
     802               8 :         if(psTransform->poDS)
     803                 :         {
     804                 :             RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], 
     805               2 :                       padfZ[i] + psTransform->dfHeightOffset *
     806                 :                                  psTransform->dfHeightScale,
     807               2 :                       &dfResultX, &dfResultY );
     808                 : 
     809                 :             double dfX, dfY;
     810                 :             //check if dem is not in WGS84 and transform points padfX[i], padfY[i]
     811               2 :             if(psTransform->poCT)
     812                 :             {
     813               2 :                 double dfZ = 0;
     814               2 :                 if (!psTransform->poCT->Transform(1, &dfResultX, &dfResultY, &dfZ))
     815                 :                 {
     816               0 :                     panSuccess[i] = FALSE;
     817               0 :                     continue;
     818                 :                 }
     819                 :             }
     820                 : 
     821                 :             GDALApplyGeoTransform( psTransform->adfReverseGeoTransform,
     822               2 :                                     dfResultX, dfResultY, &dfX, &dfY );
     823               2 :             int dX = int(dfX);
     824               2 :             int dY = int(dfY);
     825                 : 
     826               2 :             double dfDEMH(0);
     827               2 :             double dfDeltaX = dfX - dX;
     828               2 :             double dfDeltaY = dfY - dY;
     829                 : 
     830               2 :             if(psTransform->eResampleAlg == DRA_Cubic)
     831                 :             {
     832               0 :                 int dXNew = dX - 1;
     833               0 :                 int dYNew = dY - 1;
     834               0 :                 if (!(dXNew >= 0 && dYNew >= 0 && dXNew + 4 <= nRasterXSize && dYNew + 4 <= nRasterYSize))
     835                 :                 {
     836               0 :                     panSuccess[i] = FALSE;
     837               0 :                     continue;
     838                 :                 }
     839                 :                 //cubic interpolation
     840               0 :                 int adElevData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     841                 :                 CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4,
     842                 :                                                           &adElevData, 4, 4,
     843               0 :                                                           GDT_Int32, 1, bands, 0, 0, 0);
     844               0 :                 if(eErr != CE_None)
     845                 :                 {
     846               0 :                     panSuccess[i] = FALSE;
     847               0 :                     continue;
     848                 :                 }
     849                 : 
     850               0 :                 double dfSumH(0);
     851               0 :                 for ( int i = 0; i < 5; i++ )
     852                 :                 {
     853                 :                     // Loop across the X axis
     854               0 :                     for ( int j = 0; j < 5; j++ )
     855                 :                     {
     856                 :                         // Calculate the weight for the specified pixel according
     857                 :                         // to the bicubic b-spline kernel we're using for
     858                 :                         // interpolation
     859               0 :                         int dKernIndX = j - 1;
     860               0 :                         int dKernIndY = i - 1;
     861               0 :                         double dfPixelWeight = BiCubicKernel(dKernIndX - dfDeltaX) * BiCubicKernel(dKernIndY - dfDeltaY);
     862                 : 
     863                 :                         // Create a sum of all values
     864                 :                         // adjusted for the pixel's calculated weight
     865               0 :                         dfSumH += adElevData[j + i * 4] * dfPixelWeight;
     866                 :                     }
     867                 :                 }
     868               0 :                 dfDEMH = dfSumH;
     869                 :             }
     870               2 :             else if(psTransform->eResampleAlg == DRA_Bilinear)
     871                 :             {
     872               2 :                 if (!(dX >= 0 && dY >= 0 && dX + 2 <= nRasterXSize && dY + 2 <= nRasterYSize))
     873                 :                 {
     874               0 :                     panSuccess[i] = FALSE;
     875               0 :                     continue;
     876                 :                 }
     877                 :                 //bilinear interpolation
     878               2 :                 int adElevData[4] = {0,0,0,0};
     879                 :                 CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2,
     880                 :                                                           &adElevData, 2, 2,
     881               2 :                                                           GDT_Int32, 1, bands, 0, 0, 0);
     882               2 :                 if(eErr != CE_None)
     883                 :                 {
     884               0 :                     panSuccess[i] = FALSE;
     885               0 :                     continue;
     886                 :                 }
     887               2 :                 double dfDeltaX1 = 1.0 - dfDeltaX;                
     888               2 :                 double dfDeltaY1 = 1.0 - dfDeltaY;
     889                 : 
     890               2 :                 double dfXZ1 = adElevData[0] * dfDeltaX1 + adElevData[1] * dfDeltaX;
     891               2 :                 double dfXZ2 = adElevData[2] * dfDeltaX1 + adElevData[3] * dfDeltaX;
     892               2 :                 double dfYZ = dfXZ1 * dfDeltaY1 + dfXZ2 * dfDeltaY;
     893               2 :                 dfDEMH = dfYZ;
     894                 :             }
     895                 :             else
     896                 :             {
     897               0 :                 if (!(dX >= 0 && dY >= 0 && dX <= nRasterXSize && dY <= nRasterYSize))
     898                 :                 {
     899               0 :                     panSuccess[i] = FALSE;
     900               0 :                     continue;
     901                 :                 }
     902                 :                 CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1,
     903                 :                                                           &dfDEMH, 1, 1,
     904               0 :                                                           GDT_Int32, 1, bands, 0, 0, 0);
     905               0 :                 if(eErr != CE_None)
     906                 :                 {
     907               0 :                     panSuccess[i] = FALSE;
     908               0 :                     continue;
     909                 :                 }           
     910                 :             }
     911                 : 
     912                 :             RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], 
     913               2 :                                       padfZ[i] + (psTransform->dfHeightOffset + dfDEMH) *
     914                 :                                                   psTransform->dfHeightScale,
     915               2 :                                       &dfResultX, &dfResultY );
     916                 :         }
     917                 :         else
     918                 :         {
     919                 :             RPCInverseTransformPoint( psTransform, padfX[i], padfY[i], 
     920               6 :                                       padfZ[i] + psTransform->dfHeightOffset *
     921                 :                                                  psTransform->dfHeightScale,
     922               6 :                                       &dfResultX, &dfResultY );
     923                 : 
     924                 :         }
     925               8 :         padfX[i] = dfResultX;
     926               8 :         padfY[i] = dfResultY;
     927                 : 
     928               8 :         panSuccess[i] = TRUE;
     929                 :     }
     930                 : 
     931               8 :     return TRUE;
     932                 : }
     933                 : 
     934                 : /************************************************************************/
     935                 : /*                    GDALSerializeRPCTransformer()                     */
     936                 : /************************************************************************/
     937                 : 
     938               0 : CPLXMLNode *GDALSerializeRPCTransformer( void *pTransformArg )
     939                 : 
     940                 : {
     941               0 :     VALIDATE_POINTER1( pTransformArg, "GDALSerializeRPCTransformer", NULL );
     942                 : 
     943                 :     CPLXMLNode *psTree;
     944                 :     GDALRPCTransformInfo *psInfo = 
     945               0 :         (GDALRPCTransformInfo *)(pTransformArg);
     946                 : 
     947               0 :     psTree = CPLCreateXMLNode( NULL, CXT_Element, "RPCTransformer" );
     948                 : 
     949                 : /* -------------------------------------------------------------------- */
     950                 : /*      Serialize bReversed.                                            */
     951                 : /* -------------------------------------------------------------------- */
     952                 :     CPLCreateXMLElementAndValue( 
     953                 :         psTree, "Reversed", 
     954               0 :         CPLString().Printf( "%d", psInfo->bReversed ) );
     955                 : 
     956                 : /* -------------------------------------------------------------------- */
     957                 : /*      Serialize Height Offset.                                        */
     958                 : /* -------------------------------------------------------------------- */
     959                 :     CPLCreateXMLElementAndValue( 
     960                 :         psTree, "HeightOffset", 
     961               0 :         CPLString().Printf( "%.15g", psInfo->dfHeightOffset ) );
     962                 : 
     963                 : /* -------------------------------------------------------------------- */
     964                 : /*      Serialize Height Scale.                                         */
     965                 : /* -------------------------------------------------------------------- */
     966               0 :     if (psInfo->dfHeightScale != 1.0)
     967                 :         CPLCreateXMLElementAndValue( 
     968                 :             psTree, "HeightScale", 
     969               0 :             CPLString().Printf( "%.15g", psInfo->dfHeightScale ) );
     970                 : 
     971                 : /* -------------------------------------------------------------------- */
     972                 : /*      Serialize DEM path.                                             */
     973                 : /* -------------------------------------------------------------------- */
     974               0 :     if (psInfo->pszDEMPath != NULL)
     975                 :         CPLCreateXMLElementAndValue( 
     976                 :             psTree, "DEMPath", 
     977               0 :             CPLString().Printf( "%s", psInfo->pszDEMPath ) );
     978                 : 
     979                 : /* -------------------------------------------------------------------- */
     980                 : /*      Serialize DEM interpolation                                     */
     981                 : /* -------------------------------------------------------------------- */
     982               0 :     CPLString soDEMInterpolation;
     983               0 :     switch(psInfo->eResampleAlg)
     984                 :     {
     985                 :     case  DRA_NearestNeighbour:
     986               0 :         soDEMInterpolation = "near";
     987               0 :         break;
     988                 :     case DRA_Cubic:
     989               0 :         soDEMInterpolation = "cubic";
     990               0 :         break;
     991                 :     default:
     992                 :     case DRA_Bilinear:
     993               0 :         soDEMInterpolation = "bilinear";
     994                 :     }
     995                 :     CPLCreateXMLElementAndValue( 
     996               0 :         psTree, "DEMInterpolation", soDEMInterpolation );
     997                 : 
     998                 : /* -------------------------------------------------------------------- */
     999                 : /*      Serialize pixel error threshold.                                */
    1000                 : /* -------------------------------------------------------------------- */
    1001                 :     CPLCreateXMLElementAndValue( 
    1002                 :         psTree, "PixErrThreshold", 
    1003               0 :         CPLString().Printf( "%.15g", psInfo->dfPixErrThreshold ) );
    1004                 : 
    1005                 : /* -------------------------------------------------------------------- */
    1006                 : /*      RPC metadata.                                                   */
    1007                 : /* -------------------------------------------------------------------- */
    1008               0 :     char **papszMD = RPCInfoToMD( &(psInfo->sRPC) );
    1009                 :     CPLXMLNode *psMD= CPLCreateXMLNode( psTree, CXT_Element, 
    1010               0 :                                         "Metadata" );
    1011                 : 
    1012               0 :     for( int i = 0; papszMD != NULL && papszMD[i] != NULL; i++ )
    1013                 :     {
    1014                 :         const char *pszRawValue;
    1015                 :         char *pszKey;
    1016                 :         CPLXMLNode *psMDI;
    1017                 :                 
    1018               0 :         pszRawValue = CPLParseNameValue( papszMD[i], &pszKey );
    1019                 :                 
    1020               0 :         psMDI = CPLCreateXMLNode( psMD, CXT_Element, "MDI" );
    1021               0 :         CPLSetXMLValue( psMDI, "#key", pszKey );
    1022               0 :         CPLCreateXMLNode( psMDI, CXT_Text, pszRawValue );
    1023                 :                 
    1024               0 :         CPLFree( pszKey );
    1025                 :     }
    1026                 : 
    1027               0 :     CSLDestroy( papszMD );
    1028                 : 
    1029               0 :     return psTree;
    1030                 : }
    1031                 : 
    1032                 : /************************************************************************/
    1033                 : /*                   GDALDeserializeRPCTransformer()                    */
    1034                 : /************************************************************************/
    1035                 : 
    1036               0 : void *GDALDeserializeRPCTransformer( CPLXMLNode *psTree )
    1037                 : 
    1038                 : {
    1039                 :     void *pResult;
    1040               0 :     char **papszOptions = NULL;
    1041                 : 
    1042                 : /* -------------------------------------------------------------------- */
    1043                 : /*      Collect metadata.                                               */
    1044                 : /* -------------------------------------------------------------------- */
    1045               0 :     char **papszMD = NULL;
    1046                 :     CPLXMLNode *psMDI, *psMetadata;
    1047                 :     GDALRPCInfo sRPC;
    1048                 : 
    1049               0 :     psMetadata = CPLGetXMLNode( psTree, "Metadata" );
    1050                 : 
    1051               0 :     if( psMetadata == NULL
    1052                 :         || psMetadata->eType != CXT_Element
    1053                 :         || !EQUAL(psMetadata->pszValue,"Metadata") )
    1054               0 :         return NULL;
    1055                 :     
    1056               0 :     for( psMDI = psMetadata->psChild; psMDI != NULL; 
    1057                 :          psMDI = psMDI->psNext )
    1058                 :     {
    1059               0 :         if( !EQUAL(psMDI->pszValue,"MDI") 
    1060                 :             || psMDI->eType != CXT_Element 
    1061                 :             || psMDI->psChild == NULL 
    1062                 :             || psMDI->psChild->psNext == NULL 
    1063                 :             || psMDI->psChild->eType != CXT_Attribute
    1064                 :             || psMDI->psChild->psChild == NULL )
    1065               0 :             continue;
    1066                 :         
    1067                 :         papszMD = 
    1068                 :             CSLSetNameValue( papszMD, 
    1069                 :                              psMDI->psChild->psChild->pszValue, 
    1070               0 :                              psMDI->psChild->psNext->pszValue );
    1071                 :     }
    1072                 : 
    1073               0 :     if( !GDALExtractRPCInfo( papszMD, &sRPC ) )
    1074                 :     {
    1075                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1076               0 :                   "Failed to reconstitute RPC transformer." );
    1077               0 :         CSLDestroy( papszMD );
    1078               0 :         return NULL;
    1079                 :     }
    1080                 : 
    1081               0 :     CSLDestroy( papszMD );
    1082                 : 
    1083                 : /* -------------------------------------------------------------------- */
    1084                 : /*      Get other flags.                                                */
    1085                 : /* -------------------------------------------------------------------- */
    1086                 :     double dfPixErrThreshold;
    1087                 :     int bReversed;
    1088                 : 
    1089               0 :     bReversed = atoi(CPLGetXMLValue(psTree,"Reversed","0"));
    1090                 : 
    1091                 :     dfPixErrThreshold = 
    1092               0 :         CPLAtof(CPLGetXMLValue(psTree,"PixErrThreshold","0.25"));
    1093                 : 
    1094                 :     papszOptions = CSLSetNameValue( papszOptions, "RPC_HEIGHT",
    1095               0 :                                     CPLGetXMLValue(psTree,"HeightOffset","0"));
    1096                 :     papszOptions = CSLSetNameValue( papszOptions, "RPC_HEIGHT_SCALE",
    1097               0 :                                     CPLGetXMLValue(psTree,"HeightScale","1"));
    1098               0 :     const char* pszDEMPath = CPLGetXMLValue(psTree,"DEMPath",NULL);
    1099               0 :     if (pszDEMPath != NULL)
    1100                 :         papszOptions = CSLSetNameValue( papszOptions, "RPC_DEM",
    1101               0 :                                         pszDEMPath);
    1102                 : 
    1103               0 :     const char* pszDEMInterpolation = CPLGetXMLValue(psTree,"DEMInterpolation", "bilinear");
    1104               0 :     if (pszDEMInterpolation != NULL)
    1105                 :         papszOptions = CSLSetNameValue( papszOptions, "RPC_DEMINTERPOLATION",
    1106               0 :                                         pszDEMInterpolation);
    1107                 : 
    1108                 : /* -------------------------------------------------------------------- */
    1109                 : /*      Generate transformation.                                        */
    1110                 : /* -------------------------------------------------------------------- */
    1111                 :     pResult = GDALCreateRPCTransformer( &sRPC, bReversed, dfPixErrThreshold,
    1112               0 :                                         papszOptions );
    1113                 :     
    1114               0 :     CSLDestroy( papszOptions );
    1115                 : 
    1116               0 :     return pResult;
    1117                 : }

Generated by: LCOV version 1.7