LCOV - code coverage report
Current view: directory - ogr - ogrct.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 268 215 80.2 %
Date: 2010-01-09 Functions: 17 15 88.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrct.cpp 18035 2009-11-15 23:33:45Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  The OGRSCoordinateTransformation class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Frank Warmerdam
      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 "ogr_spatialref.h"
      31                 : #include "cpl_port.h"
      32                 : #include "cpl_error.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : #include "cpl_multiproc.h"
      36                 : 
      37                 : #ifdef PROJ_STATIC
      38                 : #include "proj_api.h"
      39                 : #endif
      40                 : 
      41                 : CPL_CVSID("$Id: ogrct.cpp 18035 2009-11-15 23:33:45Z rouault $");
      42                 : 
      43                 : /* ==================================================================== */
      44                 : /*      PROJ.4 interface stuff.                                         */
      45                 : /* ==================================================================== */
      46                 : #ifndef PROJ_STATIC
      47                 : typedef struct { double u, v; } projUV;
      48                 : 
      49                 : #define projPJ void *
      50                 : 
      51                 : #define RAD_TO_DEG      57.29577951308232
      52                 : #define DEG_TO_RAD      .0174532925199432958
      53                 : 
      54                 : #endif
      55                 : 
      56                 : static void *hPROJMutex = NULL;
      57                 : 
      58                 : static projPJ       (*pfn_pj_init_plus)(const char *) = NULL;
      59                 : static projPJ       (*pfn_pj_init)(int, char**) = NULL;
      60                 : static projUV       (*pfn_pj_fwd)(projUV, projPJ) = NULL;
      61                 : static projUV       (*pfn_pj_inv)(projUV, projPJ) = NULL;
      62                 : static void     (*pfn_pj_free)(projPJ) = NULL;
      63                 : static int      (*pfn_pj_transform)(projPJ, projPJ, long, int, 
      64                 :                                     double *, double *, double * ) = NULL;
      65                 : static int         *(*pfn_pj_get_errno_ref)(void) = NULL;
      66                 : static char        *(*pfn_pj_strerrno)(int) = NULL;
      67                 : static char        *(*pfn_pj_get_def)(projPJ,int) = NULL;
      68                 : static void         (*pfn_pj_dalloc)(void *) = NULL;
      69                 : 
      70                 : #if (defined(WIN32) || defined(WIN32CE)) && !defined(__MINGW32__)
      71                 : #  define LIBNAME      "proj.dll"
      72                 : #elif defined(__CYGWIN__) || defined(__MINGW32__)
      73                 : // XXX: If PROJ.4 library was properly built using libtool in Cygwin or MinGW
      74                 : // environments it has the interface version number embedded in the file name
      75                 : // (it is CURRENT-AGE number). If DLL came somewhere else (e.g. from MSVC
      76                 : // build) it can be named either way, so use PROJSO environment variable to
      77                 : // specify the right library name. By default assume that in Cygwin/MinGW all
      78                 : // components were buit in the same way.
      79                 : #  define LIBNAME      "libproj-0.dll"
      80                 : #elif defined(__APPLE__)
      81                 : #  define LIBNAME      "libproj.dylib"
      82                 : #else
      83                 : #  define LIBNAME      "libproj.so"
      84                 : #endif
      85                 : 
      86                 : /************************************************************************/
      87                 : /*                              OGRProj4CT                              */
      88                 : /************************************************************************/
      89                 : 
      90                 : class OGRProj4CT : public OGRCoordinateTransformation
      91                 : {
      92                 :     OGRSpatialReference *poSRSSource;
      93                 :     void        *psPJSource;
      94                 :     int         bSourceLatLong;
      95                 :     double      dfSourceToRadians;
      96                 :     double      dfSourceFromRadians;
      97                 :     int         bSourceWrap;
      98                 :     double      dfSourceWrapLong;
      99                 :     
     100                 : 
     101                 :     OGRSpatialReference *poSRSTarget;
     102                 :     void        *psPJTarget;
     103                 :     int         bTargetLatLong;
     104                 :     double      dfTargetToRadians;
     105                 :     double      dfTargetFromRadians;
     106                 :     int         bTargetWrap;
     107                 :     double      dfTargetWrapLong;
     108                 : 
     109                 :     int         nErrorCount;
     110                 :     
     111                 :     int         bCheckWithInvertProj;
     112                 :     double      dfThreshold;
     113                 : 
     114                 : public:
     115                 :                 OGRProj4CT();
     116                 :     virtual     ~OGRProj4CT();
     117                 : 
     118                 :     int         Initialize( OGRSpatialReference *poSource, 
     119                 :                             OGRSpatialReference *poTarget );
     120                 : 
     121                 :     virtual OGRSpatialReference *GetSourceCS();
     122                 :     virtual OGRSpatialReference *GetTargetCS();
     123                 :     virtual int Transform( int nCount, 
     124                 :                            double *x, double *y, double *z = NULL );
     125                 :     virtual int TransformEx( int nCount, 
     126                 :                              double *x, double *y, double *z = NULL,
     127                 :                              int *panSuccess = NULL );
     128                 : 
     129                 : };
     130                 : 
     131                 : /************************************************************************/
     132                 : /*                        GetProjLibraryName()                          */
     133                 : /************************************************************************/
     134                 : 
     135              23 : static const char* GetProjLibraryName()
     136                 : {
     137              23 :     const char *pszLibName = LIBNAME;
     138                 : #if !defined(WIN32CE)
     139              23 :     if( CPLGetConfigOption("PROJSO",NULL) != NULL )
     140               0 :         pszLibName = CPLGetConfigOption("PROJSO",NULL);
     141                 : #endif
     142              23 :     return pszLibName;
     143                 : }
     144                 : 
     145                 : /************************************************************************/
     146                 : /*                          LoadProjLibrary()                           */
     147                 : /************************************************************************/
     148                 : 
     149             165 : static int LoadProjLibrary()
     150                 : 
     151                 : {
     152             165 :     CPLMutexHolderD( &hPROJMutex );
     153                 :     static int  bTriedToLoad = FALSE;
     154                 :     const char *pszLibName;
     155                 :     
     156             165 :     if( bTriedToLoad )
     157             142 :         return( pfn_pj_transform != NULL );
     158                 : 
     159              23 :     bTriedToLoad = TRUE;
     160                 : 
     161              23 :     pszLibName = GetProjLibraryName();
     162                 : 
     163                 : #ifdef PROJ_STATIC
     164                 :     pfn_pj_init = pj_init;
     165                 :     pfn_pj_init_plus = pj_init_plus;
     166                 :     pfn_pj_fwd = pj_fwd;
     167                 :     pfn_pj_inv = pj_inv;
     168                 :     pfn_pj_free = pj_free;
     169                 :     pfn_pj_transform = pj_transform;
     170                 :     pfn_pj_get_errno_ref = (int *(*)(void)) pj_get_errno_ref;
     171                 :     pfn_pj_strerrno = pj_strerrno;
     172                 :     pfn_pj_dalloc = pj_dalloc;
     173                 : #if PJ_VERSION >= 446
     174                 :     pfn_pj_get_def = pj_get_def;
     175                 : #endif    
     176                 : #else
     177              23 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     178                 : 
     179                 :     pfn_pj_init = (projPJ (*)(int, char**)) CPLGetSymbol( pszLibName,
     180              23 :                                                        "pj_init" );
     181              23 :     CPLPopErrorHandler();
     182                 :     
     183              23 :     if( pfn_pj_init == NULL )
     184               0 :        return( FALSE );
     185                 : 
     186                 :     pfn_pj_init_plus = (projPJ (*)(const char *)) 
     187              23 :         CPLGetSymbol( pszLibName, "pj_init_plus" );
     188                 :     pfn_pj_fwd = (projUV (*)(projUV,projPJ)) 
     189              23 :         CPLGetSymbol( pszLibName, "pj_fwd" );
     190                 :     pfn_pj_inv = (projUV (*)(projUV,projPJ)) 
     191              23 :         CPLGetSymbol( pszLibName, "pj_inv" );
     192                 :     pfn_pj_free = (void (*)(projPJ)) 
     193              23 :         CPLGetSymbol( pszLibName, "pj_free" );
     194                 :     pfn_pj_transform = (int (*)(projPJ,projPJ,long,int,double*,
     195                 :                                 double*,double*))
     196              23 :                         CPLGetSymbol( pszLibName, "pj_transform" );
     197                 :     pfn_pj_get_errno_ref = (int *(*)(void))
     198              23 :         CPLGetSymbol( pszLibName, "pj_get_errno_ref" );
     199                 :     pfn_pj_strerrno = (char *(*)(int))
     200              23 :         CPLGetSymbol( pszLibName, "pj_strerrno" );
     201                 : 
     202              23 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     203                 :     pfn_pj_get_def = (char *(*)(projPJ,int))
     204              23 :         CPLGetSymbol( pszLibName, "pj_get_def" );
     205                 :     pfn_pj_dalloc = (void (*)(void*))
     206              23 :         CPLGetSymbol( pszLibName, "pj_dalloc" );
     207              23 :     CPLPopErrorHandler();
     208                 : 
     209                 : #endif
     210                 : 
     211              23 :     if( pfn_pj_transform == NULL )
     212                 :     {
     213                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     214                 :                   "Attempt to load %s, but couldn't find pj_transform.\n"
     215                 :                   "Please upgrade to PROJ 4.1.2 or later.", 
     216               0 :                   pszLibName );
     217                 : 
     218               0 :         return FALSE;
     219                 :     }
     220                 : 
     221              23 :     return( TRUE );
     222                 : }
     223                 : 
     224                 : /************************************************************************/
     225                 : /*                         OCTProj4Normalize()                          */
     226                 : /*                                                                      */
     227                 : /*      This function is really just here since we already have all     */
     228                 : /*      the code to load libproj.so.  It is intended to "normalize"     */
     229                 : /*      a proj.4 definition, expanding +init= definitions and so        */
     230                 : /*      forth as possible.                                              */
     231                 : /************************************************************************/
     232                 : 
     233              25 : char *OCTProj4Normalize( const char *pszProj4Src )
     234                 : 
     235                 : {
     236                 :     char        *pszNewProj4Def, *pszCopy;
     237              25 :     projPJ      psPJSource = NULL;
     238              25 :     CPLMutexHolderD( &hPROJMutex );
     239                 : 
     240              25 :     if( !LoadProjLibrary() || pfn_pj_dalloc == NULL || pfn_pj_get_def == NULL )
     241               0 :         return CPLStrdup( pszProj4Src );
     242                 : 
     243              25 :     psPJSource = pfn_pj_init_plus( pszProj4Src );
     244                 : 
     245              25 :     if( psPJSource == NULL )
     246               1 :         return CPLStrdup( pszProj4Src );
     247                 : 
     248              24 :     pszNewProj4Def = pfn_pj_get_def( psPJSource, 0 );
     249                 : 
     250              24 :     pfn_pj_free( psPJSource );
     251                 : 
     252              24 :     if( pszNewProj4Def == NULL )
     253               0 :         return CPLStrdup( pszProj4Src );
     254                 : 
     255              24 :     pszCopy = CPLStrdup( pszNewProj4Def );
     256              24 :     pfn_pj_dalloc( pszNewProj4Def );
     257                 : 
     258              24 :     return pszCopy;
     259                 : }
     260                 : 
     261                 : /************************************************************************/
     262                 : /*                 OCTDestroyCoordinateTransformation()                 */
     263                 : /************************************************************************/
     264                 : 
     265                 : /**
     266                 :  * \brief OGRCoordinateTransformation destructor. 
     267                 :  *
     268                 :  * This function is the same as OGRCoordinateTransformation::DestroyCT()
     269                 :  *
     270                 :  * @param hCT the object to delete
     271                 :  */
     272                 :  
     273                 : void CPL_STDCALL
     274              30 : OCTDestroyCoordinateTransformation( OGRCoordinateTransformationH hCT )
     275                 : 
     276                 : {
     277              30 :     delete (OGRCoordinateTransformation *) hCT;
     278              30 : }
     279                 : 
     280                 : /************************************************************************/
     281                 : /*                             DestroyCT()                              */
     282                 : /************************************************************************/
     283                 : 
     284                 : /**
     285                 :  * \brief OGRCoordinateTransformation destructor. 
     286                 :  *
     287                 :  * This function is the same as OGRCoordinateTransformation::~OGRCoordinateTransformation()
     288                 :  * and OCTDestroyCoordinateTransformation()
     289                 :  *
     290                 :  * This static method will destroy a OGRCoordinateTransformation.  It is
     291                 :  * equivalent to calling delete on the object, but it ensures that the
     292                 :  * deallocation is properly executed within the OGR libraries heap on
     293                 :  * platforms where this can matter (win32).  
     294                 :  *
     295                 :  * @param poCT the object to delete
     296                 :  *
     297                 :  * @since GDAL 1.7.0
     298                 :  */
     299                 :  
     300              24 : void OGRCoordinateTransformation::DestroyCT(OGRCoordinateTransformation* poCT)
     301                 : {
     302              24 :     delete poCT;
     303              24 : }
     304                 : 
     305                 : /************************************************************************/
     306                 : /*                 OGRCreateCoordinateTransformation()                  */
     307                 : /************************************************************************/
     308                 : 
     309                 : /**
     310                 :  * Create transformation object.
     311                 :  *
     312                 :  * This is the same as the C function OCTNewCoordinateTransformation().
     313                 :  *
     314                 :  * Input spatial reference system objects are assigned 
     315                 :  * by copy (calling clone() method) and no ownership transfer occurs.
     316                 :  *
     317                 :  * The delete operator, or OCTDestroyCoordinateTransformation() should
     318                 :  * be used to destroy transformation objects. 
     319                 :  *
     320                 :  * The PROJ.4 library must be available at run-time.
     321                 :  *
     322                 :  * @param poSource source spatial reference system. 
     323                 :  * @param poTarget target spatial reference system. 
     324                 :  * @return NULL on failure or a ready to use transformation object.
     325                 :  */
     326                 : 
     327                 : OGRCoordinateTransformation*  
     328             140 : OGRCreateCoordinateTransformation( OGRSpatialReference *poSource, 
     329                 :                                    OGRSpatialReference *poTarget )
     330                 : 
     331                 : {
     332                 :     OGRProj4CT  *poCT;
     333                 : 
     334             140 :     if( !LoadProjLibrary() )
     335                 :     {
     336                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     337                 :                   "Unable to load PROJ.4 library (%s), creation of\n"
     338                 :                   "OGRCoordinateTransformation failed.",
     339               0 :                   GetProjLibraryName() );
     340               0 :         return NULL;
     341                 :     }
     342                 : 
     343             140 :     poCT = new OGRProj4CT();
     344                 :     
     345             140 :     if( !poCT->Initialize( poSource, poTarget ) )
     346                 :     {
     347               0 :         delete poCT;
     348               0 :         return NULL;
     349                 :     }
     350                 :     else
     351                 :     {
     352             140 :         return poCT;
     353                 :     }
     354                 : }
     355                 : 
     356                 : /************************************************************************/
     357                 : /*                   OCTNewCoordinateTransformation()                   */
     358                 : /************************************************************************/
     359                 : 
     360                 : OGRCoordinateTransformationH CPL_STDCALL 
     361              30 : OCTNewCoordinateTransformation(
     362                 :     OGRSpatialReferenceH hSourceSRS, OGRSpatialReferenceH hTargetSRS )
     363                 : 
     364                 : {
     365                 :     return (OGRCoordinateTransformationH) 
     366                 :         OGRCreateCoordinateTransformation( 
     367                 :             (OGRSpatialReference *) hSourceSRS,
     368              30 :             (OGRSpatialReference *) hTargetSRS );
     369                 : }
     370                 : 
     371                 : /************************************************************************/
     372                 : /*                             OGRProj4CT()                             */
     373                 : /************************************************************************/
     374                 : 
     375             140 : OGRProj4CT::OGRProj4CT()
     376                 : 
     377                 : {
     378             140 :     poSRSSource = NULL;
     379             140 :     poSRSTarget = NULL;
     380             140 :     psPJSource = NULL;
     381             140 :     psPJTarget = NULL;
     382                 :     
     383             140 :     nErrorCount = 0;
     384                 :     
     385             140 :     bCheckWithInvertProj = FALSE;
     386             140 :     dfThreshold = 0;
     387             140 : }
     388                 : 
     389                 : /************************************************************************/
     390                 : /*                            ~OGRProj4CT()                             */
     391                 : /************************************************************************/
     392                 : 
     393             280 : OGRProj4CT::~OGRProj4CT()
     394                 : 
     395                 : {
     396             140 :     if( poSRSSource != NULL )
     397                 :     {
     398             140 :         if( poSRSSource->Dereference() <= 0 )
     399             140 :             delete poSRSSource;
     400                 :     }
     401                 : 
     402             140 :     if( poSRSTarget != NULL )
     403                 :     {
     404             140 :         if( poSRSTarget->Dereference() <= 0 )
     405             138 :             delete poSRSTarget;
     406                 :     }
     407                 : 
     408             140 :     CPLMutexHolderD( &hPROJMutex );
     409                 : 
     410             140 :     if( psPJSource != NULL )
     411             140 :         pfn_pj_free( psPJSource );
     412                 : 
     413             140 :     if( psPJTarget != NULL )
     414             140 :         pfn_pj_free( psPJTarget );
     415             280 : }
     416                 : 
     417                 : /************************************************************************/
     418                 : /*                             Initialize()                             */
     419                 : /************************************************************************/
     420                 : 
     421             140 : int OGRProj4CT::Initialize( OGRSpatialReference * poSourceIn, 
     422                 :                             OGRSpatialReference * poTargetIn )
     423                 : 
     424                 : {
     425             140 :     CPLMutexHolderD( &hPROJMutex );
     426                 : 
     427             140 :     if( poSourceIn == NULL || poTargetIn == NULL )
     428               0 :         return FALSE;
     429                 : 
     430             140 :     poSRSSource = poSourceIn->Clone();
     431             140 :     poSRSTarget = poTargetIn->Clone();
     432                 : 
     433             140 :     bSourceLatLong = poSRSSource->IsGeographic();
     434             140 :     bTargetLatLong = poSRSTarget->IsGeographic();
     435                 : 
     436                 : /* -------------------------------------------------------------------- */
     437                 : /*      Setup source and target translations to radians for lat/long    */
     438                 : /*      systems.                                                        */
     439                 : /* -------------------------------------------------------------------- */
     440             140 :     dfSourceToRadians = DEG_TO_RAD;
     441             140 :     dfSourceFromRadians = RAD_TO_DEG;
     442             140 :     bSourceWrap = FALSE;
     443             140 :     dfSourceWrapLong = 0.0;
     444                 : 
     445             140 :     if( bSourceLatLong )
     446                 :     {
     447              71 :         OGR_SRSNode *poUNITS = poSRSSource->GetAttrNode( "GEOGCS|UNIT" );
     448              71 :         if( poUNITS && poUNITS->GetChildCount() >= 2 )
     449                 :         {
     450              71 :             dfSourceToRadians = atof(poUNITS->GetChild(1)->GetValue());
     451              71 :             if( dfSourceToRadians == 0.0 )
     452               0 :                 dfSourceToRadians = DEG_TO_RAD;
     453                 :             else
     454              71 :                 dfSourceFromRadians = 1 / dfSourceToRadians;
     455                 :         }
     456                 :     }
     457                 : 
     458             140 :     dfTargetToRadians = DEG_TO_RAD;
     459             140 :     dfTargetFromRadians = RAD_TO_DEG;
     460             140 :     bTargetWrap = FALSE;
     461             140 :     dfTargetWrapLong = 0.0;
     462                 : 
     463             140 :     if( bTargetLatLong )
     464                 :     {
     465              62 :         OGR_SRSNode *poUNITS = poSRSTarget->GetAttrNode( "GEOGCS|UNIT" );
     466              62 :         if( poUNITS && poUNITS->GetChildCount() >= 2 )
     467                 :         {
     468              62 :             dfTargetToRadians = atof(poUNITS->GetChild(1)->GetValue());
     469              62 :             if( dfTargetToRadians == 0.0 )
     470               0 :                 dfTargetToRadians = DEG_TO_RAD;
     471                 :             else
     472              62 :                 dfTargetFromRadians = 1 / dfTargetToRadians;
     473                 :         }
     474                 :     }
     475                 : 
     476                 : /* -------------------------------------------------------------------- */
     477                 : /*      Preliminary logic to setup wrapping.                            */
     478                 : /* -------------------------------------------------------------------- */
     479                 :     const char *pszCENTER_LONG;
     480                 : 
     481             140 :     if( CPLGetConfigOption( "CENTER_LONG", NULL ) != NULL )
     482                 :     {
     483               0 :         bSourceWrap = bTargetWrap = TRUE;
     484                 :         dfSourceWrapLong = dfTargetWrapLong = 
     485               0 :             atof(CPLGetConfigOption( "CENTER_LONG", "" ));
     486               0 :         CPLDebug( "OGRCT", "Wrap at %g.", dfSourceWrapLong );
     487                 :     }
     488                 : 
     489             140 :     pszCENTER_LONG = poSRSSource->GetExtension( "GEOGCS", "CENTER_LONG" );
     490             140 :     if( pszCENTER_LONG != NULL )
     491                 :     {
     492              30 :         dfSourceWrapLong = atof(pszCENTER_LONG);
     493              30 :         bSourceWrap = TRUE;
     494              30 :         CPLDebug( "OGRCT", "Wrap source at %g.", dfSourceWrapLong );
     495                 :     }
     496                 : 
     497             140 :     pszCENTER_LONG = poSRSTarget->GetExtension( "GEOGCS", "CENTER_LONG" );
     498             140 :     if( pszCENTER_LONG != NULL )
     499                 :     {
     500              30 :         dfTargetWrapLong = atof(pszCENTER_LONG);
     501              30 :         bTargetWrap = TRUE;
     502              30 :         CPLDebug( "OGRCT", "Wrap target at %g.", dfTargetWrapLong );
     503                 :     }
     504                 :     
     505             140 :     bCheckWithInvertProj = CSLTestBoolean(CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", "NO" ));
     506                 :     
     507                 :     /* The threshold is rather experimental... Works well with the cases of ticket #2305 */
     508             140 :     if (bSourceLatLong)
     509              71 :         dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", ".1" ));
     510                 :     else
     511                 :         /* 1 works well for most projections, except for +proj=aeqd that requires */
     512                 :         /* a tolerance of 10000 */
     513              69 :         dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", "10000" ));
     514                 : 
     515                 : /* -------------------------------------------------------------------- */
     516                 : /*      Establish PROJ.4 handle for source if projection.               */
     517                 : /* -------------------------------------------------------------------- */
     518                 :     // OGRThreadSafety: The following variable is not a thread safety issue 
     519                 :     // since the only issue is incrementing while accessing which at worse 
     520                 :     // means debug output could be one "increment" late. 
     521                 :     static int   nDebugReportCount = 0;
     522                 : 
     523             140 :     char        *pszProj4Defn = NULL;
     524                 : 
     525             140 :     if( poSRSSource->exportToProj4( &pszProj4Defn ) != OGRERR_NONE )
     526                 :     {
     527               0 :         CPLFree( pszProj4Defn );
     528               0 :         return FALSE;
     529                 :     }
     530                 : 
     531             140 :     if( strlen(pszProj4Defn) == 0 )
     532                 :     {
     533               0 :         CPLFree( pszProj4Defn );
     534                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     535                 :                   "No PROJ.4 translation for source SRS, coordinate\n"
     536               0 :                   "transformation initialization has failed." );
     537               0 :         return FALSE;
     538                 :     }
     539                 : 
     540             140 :     psPJSource = pfn_pj_init_plus( pszProj4Defn );
     541                 :     
     542             140 :     if( psPJSource == NULL )
     543                 :     {
     544               0 :         if( pfn_pj_get_errno_ref != NULL
     545                 :             && pfn_pj_strerrno != NULL )
     546                 :         {
     547               0 :             int *p_pj_errno = pfn_pj_get_errno_ref();
     548                 : 
     549                 :             CPLError( CE_Failure, CPLE_NotSupported, 
     550                 :                       "Failed to initialize PROJ.4 with `%s'.\n%s", 
     551               0 :                       pszProj4Defn, pfn_pj_strerrno(*p_pj_errno) );
     552                 :         }
     553                 :         else
     554                 :         {
     555                 :             CPLError( CE_Failure, CPLE_NotSupported, 
     556                 :                       "Failed to initialize PROJ.4 with `%s'.\n", 
     557               0 :                       pszProj4Defn );
     558                 :         }
     559                 :     }
     560                 :     
     561             140 :     if( nDebugReportCount < 10 )
     562              69 :         CPLDebug( "OGRCT", "Source: %s", pszProj4Defn );
     563                 :     
     564             140 :     CPLFree( pszProj4Defn );
     565                 : 
     566             140 :     if( psPJSource == NULL )
     567               0 :         return FALSE;
     568                 : 
     569                 : /* -------------------------------------------------------------------- */
     570                 : /*      Establish PROJ.4 handle for target if projection.               */
     571                 : /* -------------------------------------------------------------------- */
     572             140 :     pszProj4Defn = NULL;
     573                 : 
     574             140 :     if( poSRSTarget->exportToProj4( &pszProj4Defn ) != OGRERR_NONE )
     575                 :     {
     576               0 :         CPLFree( pszProj4Defn );
     577               0 :         return FALSE;
     578                 :     }
     579                 : 
     580             140 :     if( strlen(pszProj4Defn) == 0 )
     581                 :     {
     582               0 :         CPLFree( pszProj4Defn );
     583                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     584                 :                   "No PROJ.4 translation for destination SRS, coordinate\n"
     585               0 :                   "transformation initialization has failed." );
     586               0 :         return FALSE;
     587                 :     }
     588                 : 
     589             140 :     psPJTarget = pfn_pj_init_plus( pszProj4Defn );
     590                 :     
     591             140 :     if( psPJTarget == NULL )
     592                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     593                 :                   "Failed to initialize PROJ.4 with `%s'.", 
     594               0 :                   pszProj4Defn );
     595                 :     
     596             140 :     if( nDebugReportCount < 10 )
     597                 :     {
     598              69 :         CPLDebug( "OGRCT", "Target: %s", pszProj4Defn );
     599              69 :         nDebugReportCount++;
     600                 :     }
     601                 : 
     602             140 :     CPLFree( pszProj4Defn );
     603                 :     
     604             140 :     if( psPJTarget == NULL )
     605               0 :         return FALSE;
     606                 : 
     607             140 :     return TRUE;
     608                 : }
     609                 : 
     610                 : /************************************************************************/
     611                 : /*                            GetSourceCS()                             */
     612                 : /************************************************************************/
     613                 : 
     614               0 : OGRSpatialReference *OGRProj4CT::GetSourceCS()
     615                 : 
     616                 : {
     617               0 :     return poSRSSource;
     618                 : }
     619                 : 
     620                 : /************************************************************************/
     621                 : /*                            GetTargetCS()                             */
     622                 : /************************************************************************/
     623                 : 
     624              26 : OGRSpatialReference *OGRProj4CT::GetTargetCS()
     625                 : 
     626                 : {
     627              26 :     return poSRSTarget;
     628                 : }
     629                 : 
     630                 : /************************************************************************/
     631                 : /*                             Transform()                              */
     632                 : /*                                                                      */
     633                 : /*      This is a small wrapper for the extended transform version.     */
     634                 : /************************************************************************/
     635                 : 
     636              83 : int OGRProj4CT::Transform( int nCount, double *x, double *y, double *z )
     637                 : 
     638                 : {
     639              83 :     int *pabSuccess = (int *) CPLMalloc(sizeof(int) * nCount );
     640                 :     int bOverallSuccess, i;
     641                 : 
     642              83 :     bOverallSuccess = TransformEx( nCount, x, y, z, pabSuccess );
     643                 : 
     644             407 :     for( i = 0; i < nCount; i++ )
     645                 :     {
     646             324 :         if( !pabSuccess[i] )
     647                 :         {
     648               0 :             bOverallSuccess = FALSE;
     649               0 :             break;
     650                 :         }
     651                 :     }
     652                 : 
     653              83 :     CPLFree( pabSuccess );
     654                 : 
     655              83 :     return bOverallSuccess;
     656                 : }
     657                 : 
     658                 : /************************************************************************/
     659                 : /*                            OCTTransform()                            */
     660                 : /************************************************************************/
     661                 : 
     662              55 : int CPL_STDCALL OCTTransform( OGRCoordinateTransformationH hTransform,
     663                 :                               int nCount, double *x, double *y, double *z )
     664                 : 
     665                 : {
     666                 :     return ((OGRCoordinateTransformation*) hTransform)->
     667              55 :         Transform( nCount, x, y,z );
     668                 : }
     669                 : 
     670                 : /************************************************************************/
     671                 : /*                            TransformEx()                             */
     672                 : /************************************************************************/
     673                 : 
     674           27246 : int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z,
     675                 :                              int *pabSuccess )
     676                 : 
     677                 : {
     678                 :     int   err, i;
     679                 : 
     680                 : /* -------------------------------------------------------------------- */
     681                 : /*      Potentially transform to radians.                               */
     682                 : /* -------------------------------------------------------------------- */
     683           27246 :     if( bSourceLatLong )
     684                 :     {
     685            5582 :         if( bSourceWrap )
     686                 :         {
     687           14246 :             for( i = 0; i < nCount; i++ )
     688                 :             {
     689           10278 :                 if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     690                 :                 {
     691            9621 :                     if( x[i] < dfSourceWrapLong - 180.0 )
     692               0 :                         x[i] += 360.0;
     693            9621 :                     else if( x[i] > dfSourceWrapLong + 180 )
     694               0 :                         x[i] -= 360.0;
     695                 :                 }
     696                 :             }
     697                 :         }
     698                 : 
     699         1490329 :         for( i = 0; i < nCount; i++ )
     700                 :         {
     701         1484747 :             if( x[i] != HUGE_VAL )
     702                 :             {
     703         1484090 :                 x[i] *= dfSourceToRadians;
     704         1484090 :                 y[i] *= dfSourceToRadians;
     705                 :             }
     706                 :         }
     707                 :     }
     708                 :     
     709                 : /* -------------------------------------------------------------------- */
     710                 : /*      Do the transformation using PROJ.4.                             */
     711                 : /* -------------------------------------------------------------------- */
     712           27246 :     CPLMutexHolderD( &hPROJMutex );
     713                 :         
     714           27246 :     if (bCheckWithInvertProj)
     715                 :     {
     716                 :         /* For some projections, we cannot detect if we are trying to reproject */
     717                 :         /* coordinates outside the validity area of the projection. So let's do */
     718                 :         /* the reverse reprojection and compare with the source coordinates */
     719                 :         
     720            5714 :         double *ori_x = NULL;
     721            5714 :         double *ori_y = NULL;
     722            5714 :         double *ori_z = NULL;
     723            5714 :         ori_x = (double*)CPLMalloc(sizeof(double)*nCount);
     724            5714 :         memcpy(ori_x, x, sizeof(double)*nCount);
     725            5714 :         ori_y = (double*)CPLMalloc(sizeof(double)*nCount);
     726            5714 :         memcpy(ori_y, y, sizeof(double)*nCount);
     727            5714 :         if (z)
     728                 :         {
     729            5714 :             ori_z = (double*)CPLMalloc(sizeof(double)*nCount);
     730            5714 :             memcpy(ori_z, z, sizeof(double)*nCount);
     731                 :         }
     732            5714 :         err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z );
     733            5714 :         if (err == 0)
     734                 :         {
     735            5714 :             double* target_x = (double*)CPLMalloc(sizeof(double)*nCount);
     736            5714 :             double* target_y = (double*)CPLMalloc(sizeof(double)*nCount);
     737            5714 :             double* target_z = NULL;
     738            5714 :             memcpy(target_x, x, sizeof(double)*nCount);
     739            5714 :             memcpy(target_y, y, sizeof(double)*nCount);
     740            5714 :             if (z)
     741                 :             {
     742            5714 :                 target_z = (double*)CPLMalloc(sizeof(double)*nCount);
     743            5714 :                 memcpy(target_z, z, sizeof(double)*nCount);
     744                 :             }
     745                 :             
     746                 :             err = pfn_pj_transform( psPJTarget, psPJSource , nCount, 1,
     747            5714 :                                     target_x, target_y, target_z );
     748            5714 :             if (err == 0)
     749                 :             {
     750          751074 :                 for( i = 0; i < nCount; i++ )
     751                 :                 {
     752         2076673 :                     if ( x[i] != HUGE_VAL && y[i] != HUGE_VAL &&
     753          744618 :                         (fabs(target_x[i] - ori_x[i]) > dfThreshold ||
     754          586695 :                          fabs(target_y[i] - ori_y[i]) > dfThreshold) )
     755                 :                     {
     756          158266 :                         x[i] = HUGE_VAL;
     757          158266 :                         y[i] = HUGE_VAL;
     758                 :                     }
     759                 :                 }
     760                 :             }
     761                 :             
     762            5714 :             CPLFree(target_x);
     763            5714 :             CPLFree(target_y);
     764            5714 :             CPLFree(target_z);
     765                 :         }
     766            5714 :         CPLFree(ori_x);
     767            5714 :         CPLFree(ori_y);
     768            5714 :         CPLFree(ori_z);
     769                 :     }
     770                 :     else
     771                 :     {
     772           21532 :         err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z );
     773                 :     }
     774                 : 
     775                 : /* -------------------------------------------------------------------- */
     776                 : /*      Try to report an error through CPL.  Get proj.4 error string    */
     777                 : /*      if possible.  Try to avoid reporting thousands of error         */
     778                 : /*      ... supress further error reporting on this OGRProj4CT if we    */
     779                 : /*      have already reported 20 errors.                                */
     780                 : /* -------------------------------------------------------------------- */
     781           27246 :     if( err != 0 )
     782                 :     {
     783               0 :         if( pabSuccess )
     784               0 :             memset( pabSuccess, 0, sizeof(int) * nCount );
     785                 : 
     786               0 :         if( ++nErrorCount < 20 )
     787                 :         {
     788               0 :             const char *pszError = NULL;
     789               0 :             if( pfn_pj_strerrno != NULL )
     790               0 :                 pszError = pfn_pj_strerrno( err );
     791                 :             
     792               0 :             if( pszError == NULL )
     793                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     794                 :                           "Reprojection failed, err = %d", 
     795               0 :                           err );
     796                 :             else
     797               0 :                 CPLError( CE_Failure, CPLE_AppDefined, "%s", pszError );
     798                 :         }
     799               0 :         else if( nErrorCount == 20 )
     800                 :         {
     801                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     802                 :                       "Reprojection failed, err = %d, further errors will be supressed on the transform object.", 
     803               0 :                       err );
     804                 :         }
     805                 : 
     806               0 :         return FALSE;
     807                 :     }
     808                 : 
     809                 : /* -------------------------------------------------------------------- */
     810                 : /*      Potentially transform back to degrees.                          */
     811                 : /* -------------------------------------------------------------------- */
     812           27246 :     if( bTargetLatLong )
     813                 :     {
     814         2227298 :         for( i = 0; i < nCount; i++ )
     815                 :         {
     816         2219726 :             if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     817                 :             {
     818         2061970 :                 x[i] *= dfTargetFromRadians;
     819         2061970 :                 y[i] *= dfTargetFromRadians;
     820                 :             }
     821                 :         }
     822                 : 
     823            7572 :         if( bTargetWrap )
     824                 :         {
     825         2226951 :             for( i = 0; i < nCount; i++ )
     826                 :             {
     827         2219433 :                 if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     828                 :                 {
     829         2061677 :                     if( x[i] < dfTargetWrapLong - 180.0 )
     830             812 :                         x[i] += 360.0;
     831         2060865 :                     else if( x[i] > dfTargetWrapLong + 180 )
     832               4 :                         x[i] -= 360.0;
     833                 :                 }
     834                 :             }
     835                 :         }
     836                 :     }
     837                 : 
     838                 : /* -------------------------------------------------------------------- */
     839                 : /*      Establish error information if pabSuccess provided.             */
     840                 : /* -------------------------------------------------------------------- */
     841           27246 :     if( pabSuccess )
     842                 :     {
     843         2303363 :         for( i = 0; i < nCount; i++ )
     844                 :         {
     845         2435391 :             if( x[i] == HUGE_VAL || y[i] == HUGE_VAL )
     846          159274 :                 pabSuccess[i] = FALSE;
     847                 :             else
     848         2116843 :                 pabSuccess[i] = TRUE;
     849                 :         }
     850                 :     }
     851                 : 
     852           27246 :     return TRUE;
     853                 : }
     854                 : 
     855                 : /************************************************************************/
     856                 : /*                           OCTTransformEx()                           */
     857                 : /************************************************************************/
     858                 : 
     859               0 : int CPL_STDCALL OCTTransformEx( OGRCoordinateTransformationH hTransform,
     860                 :                                 int nCount, double *x, double *y, double *z,
     861                 :                                 int *pabSuccess )
     862                 : 
     863                 : {
     864                 :     return ((OGRCoordinateTransformation*) hTransform)->
     865               0 :         TransformEx( nCount, x, y, z, pabSuccess );
     866                 : }
     867                 : 

Generated by: LCOV version 1.7