LCOV - code coverage report
Current view: directory - ogr - ogrct.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 313 234 74.8 %
Date: 2012-04-28 Functions: 20 16 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrct.cpp 20079 2010-07-16 21:28:02Z 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 20079 2010-07-16 21:28:02Z 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                 : #define projCtx void *
      51                 : #define RAD_TO_DEG      57.29577951308232
      52                 : #define DEG_TO_RAD      .0174532925199432958
      53                 : 
      54                 : #else
      55                 : 
      56                 : #if PJ_VERSION < 480
      57                 : #define projCtx void *
      58                 : #endif
      59                 : 
      60                 : #endif
      61                 : 
      62                 : static void *hPROJMutex = NULL;
      63                 : 
      64                 : static projPJ       (*pfn_pj_init_plus)(const char *) = NULL;
      65                 : static projPJ       (*pfn_pj_init)(int, char**) = NULL;
      66                 : static void     (*pfn_pj_free)(projPJ) = NULL;
      67                 : static int      (*pfn_pj_transform)(projPJ, projPJ, long, int, 
      68                 :                                     double *, double *, double * ) = NULL;
      69                 : static int         *(*pfn_pj_get_errno_ref)(void) = NULL;
      70                 : static char        *(*pfn_pj_strerrno)(int) = NULL;
      71                 : static char        *(*pfn_pj_get_def)(projPJ,int) = NULL;
      72                 : static void         (*pfn_pj_dalloc)(void *) = NULL;
      73                 : 
      74                 : static projPJ (*pfn_pj_init_plus_ctx)( projCtx, const char * ) = NULL;
      75                 : static int (*pfn_pj_ctx_get_errno)( projCtx ) = NULL;
      76                 : static projCtx (*pfn_pj_ctx_alloc)(void) = NULL;
      77                 : static void    (*pfn_pj_ctx_free)( projCtx ) = NULL;
      78                 : 
      79                 : #if (defined(WIN32) || defined(WIN32CE)) && !defined(__MINGW32__)
      80                 : #  define LIBNAME      "proj.dll"
      81                 : #elif defined(__MINGW32__)
      82                 : // XXX: If PROJ.4 library was properly built using libtool in Cygwin or MinGW
      83                 : // environments it has the interface version number embedded in the file name
      84                 : // (it is CURRENT-AGE number). If DLL came somewhere else (e.g. from MSVC
      85                 : // build) it can be named either way, so use PROJSO environment variable to
      86                 : // specify the right library name. By default assume that in Cygwin/MinGW all
      87                 : // components were buit in the same way.
      88                 : #  define LIBNAME      "libproj-0.dll"
      89                 : #elif defined(__CYGWIN__)
      90                 : #  define LIBNAME      "cygproj-0.dll"
      91                 : #elif defined(__APPLE__)
      92                 : #  define LIBNAME      "libproj.dylib"
      93                 : #else
      94                 : #  define LIBNAME      "libproj.so"
      95                 : #endif
      96                 : 
      97                 : /************************************************************************/
      98                 : /*                              OGRProj4CT                              */
      99                 : /************************************************************************/
     100                 : 
     101                 : class OGRProj4CT : public OGRCoordinateTransformation
     102                 : {
     103                 :     OGRSpatialReference *poSRSSource;
     104                 :     void        *psPJSource;
     105                 :     int         bSourceLatLong;
     106                 :     double      dfSourceToRadians;
     107                 :     double      dfSourceFromRadians;
     108                 :     int         bSourceWrap;
     109                 :     double      dfSourceWrapLong;
     110                 :     
     111                 : 
     112                 :     OGRSpatialReference *poSRSTarget;
     113                 :     void        *psPJTarget;
     114                 :     int         bTargetLatLong;
     115                 :     double      dfTargetToRadians;
     116                 :     double      dfTargetFromRadians;
     117                 :     int         bTargetWrap;
     118                 :     double      dfTargetWrapLong;
     119                 : 
     120                 :     int         nErrorCount;
     121                 :     
     122                 :     int         bCheckWithInvertProj;
     123                 :     double      dfThreshold;
     124                 :     
     125                 :     projCtx     pjctx;
     126                 : 
     127                 :     int         InitializeNoLock( OGRSpatialReference *poSource, 
     128                 :                                   OGRSpatialReference *poTarget );
     129                 : 
     130                 :     int         nMaxCount;
     131                 :     double     *padfOriX;
     132                 :     double     *padfOriY;
     133                 :     double     *padfOriZ;
     134                 :     double     *padfTargetX;
     135                 :     double     *padfTargetY;
     136                 :     double     *padfTargetZ;
     137                 : 
     138                 : public:
     139                 :                 OGRProj4CT();
     140                 :     virtual     ~OGRProj4CT();
     141                 : 
     142                 :     int         Initialize( OGRSpatialReference *poSource, 
     143                 :                             OGRSpatialReference *poTarget );
     144                 : 
     145                 :     virtual OGRSpatialReference *GetSourceCS();
     146                 :     virtual OGRSpatialReference *GetTargetCS();
     147                 :     virtual int Transform( int nCount, 
     148                 :                            double *x, double *y, double *z = NULL );
     149                 :     virtual int TransformEx( int nCount, 
     150                 :                              double *x, double *y, double *z = NULL,
     151                 :                              int *panSuccess = NULL );
     152                 : 
     153                 : };
     154                 : 
     155                 : /************************************************************************/
     156                 : /*                        GetProjLibraryName()                          */
     157                 : /************************************************************************/
     158                 : 
     159              68 : static const char* GetProjLibraryName()
     160                 : {
     161              68 :     const char *pszLibName = LIBNAME;
     162                 : #if !defined(WIN32CE)
     163              68 :     if( CPLGetConfigOption("PROJSO",NULL) != NULL )
     164               0 :         pszLibName = CPLGetConfigOption("PROJSO",NULL);
     165                 : #endif
     166              68 :     return pszLibName;
     167                 : }
     168                 : 
     169                 : /************************************************************************/
     170                 : /*                          LoadProjLibrary()                           */
     171                 : /************************************************************************/
     172                 : 
     173            1116 : static int LoadProjLibrary()
     174                 : 
     175                 : {
     176            1116 :     CPLMutexHolderD( &hPROJMutex );
     177                 :     static int  bTriedToLoad = FALSE;
     178                 :     const char *pszLibName;
     179                 :     
     180            1116 :     if( bTriedToLoad )
     181            1048 :         return( pfn_pj_transform != NULL );
     182                 : 
     183              68 :     bTriedToLoad = TRUE;
     184                 : 
     185              68 :     pszLibName = GetProjLibraryName();
     186                 : 
     187                 : #ifdef PROJ_STATIC
     188                 :     pfn_pj_init = pj_init;
     189                 :     pfn_pj_init_plus = pj_init_plus;
     190                 :     pfn_pj_free = pj_free;
     191                 :     pfn_pj_transform = pj_transform;
     192                 :     pfn_pj_get_errno_ref = (int *(*)(void)) pj_get_errno_ref;
     193                 :     pfn_pj_strerrno = pj_strerrno;
     194                 :     pfn_pj_dalloc = pj_dalloc;
     195                 : #if PJ_VERSION >= 446
     196                 :     pfn_pj_get_def = pj_get_def;
     197                 : #endif
     198                 : #if PJ_VERSION >= 480
     199                 :     pfn_pj_ctx_alloc = pj_ctx_alloc;
     200                 :     pfn_pj_ctx_free = pj_ctx_free;
     201                 :     pfn_pj_init_plus_ctx = pj_init_plus_ctx;
     202                 :     pfn_pj_ctx_get_errno = pj_ctx_get_errno;
     203                 : #endif
     204                 : #else
     205              68 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     206                 : 
     207                 :     pfn_pj_init = (projPJ (*)(int, char**)) CPLGetSymbol( pszLibName,
     208              68 :                                                        "pj_init" );
     209              68 :     CPLPopErrorHandler();
     210                 :     
     211              68 :     if( pfn_pj_init == NULL )
     212               0 :        return( FALSE );
     213                 : 
     214                 :     pfn_pj_init_plus = (projPJ (*)(const char *)) 
     215              68 :         CPLGetSymbol( pszLibName, "pj_init_plus" );
     216                 :     pfn_pj_free = (void (*)(projPJ)) 
     217              68 :         CPLGetSymbol( pszLibName, "pj_free" );
     218                 :     pfn_pj_transform = (int (*)(projPJ,projPJ,long,int,double*,
     219                 :                                 double*,double*))
     220              68 :                         CPLGetSymbol( pszLibName, "pj_transform" );
     221                 :     pfn_pj_get_errno_ref = (int *(*)(void))
     222              68 :         CPLGetSymbol( pszLibName, "pj_get_errno_ref" );
     223                 :     pfn_pj_strerrno = (char *(*)(int))
     224              68 :         CPLGetSymbol( pszLibName, "pj_strerrno" );
     225                 : 
     226              68 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     227                 :     pfn_pj_get_def = (char *(*)(projPJ,int))
     228              68 :         CPLGetSymbol( pszLibName, "pj_get_def" );
     229                 :     pfn_pj_dalloc = (void (*)(void*))
     230              68 :         CPLGetSymbol( pszLibName, "pj_dalloc" );
     231                 : 
     232                 :     /* PROJ 4.8.0 symbols */
     233                 :     pfn_pj_ctx_alloc = (projCtx (*)( void ))
     234              68 :         CPLGetSymbol( pszLibName, "pj_ctx_alloc" );
     235                 :     pfn_pj_ctx_free = (void (*)( projCtx ))
     236              68 :         CPLGetSymbol( pszLibName, "pj_ctx_free" );
     237                 :     pfn_pj_init_plus_ctx = (projPJ (*)( projCtx, const char * ))
     238              68 :         CPLGetSymbol( pszLibName, "pj_init_plus_ctx" );
     239                 :     pfn_pj_ctx_get_errno = (int (*)( projCtx ))
     240              68 :         CPLGetSymbol( pszLibName, "pj_ctx_get_errno" );
     241                 : 
     242              68 :     CPLPopErrorHandler();
     243              68 :     CPLErrorReset();
     244                 : #endif
     245                 : 
     246              68 :     if (pfn_pj_ctx_alloc != NULL &&
     247                 :         pfn_pj_ctx_free != NULL &&
     248                 :         pfn_pj_init_plus_ctx != NULL &&
     249                 :         pfn_pj_ctx_get_errno != NULL &&
     250                 :         CSLTestBoolean(CPLGetConfigOption("USE_PROJ_480_FEATURES", "YES")))
     251                 :     {
     252              68 :         CPLDebug("OGRCT", "PROJ >= 4.8.0 features enabled");
     253                 :     }
     254                 :     else
     255                 :     {
     256               0 :         pfn_pj_ctx_alloc = NULL;
     257               0 :         pfn_pj_ctx_free = NULL;
     258               0 :         pfn_pj_init_plus_ctx = NULL;
     259               0 :         pfn_pj_ctx_get_errno = NULL;
     260                 :     }
     261                 : 
     262              68 :     if( pfn_pj_transform == NULL )
     263                 :     {
     264                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     265                 :                   "Attempt to load %s, but couldn't find pj_transform.\n"
     266                 :                   "Please upgrade to PROJ 4.1.2 or later.", 
     267               0 :                   pszLibName );
     268                 : 
     269               0 :         return FALSE;
     270                 :     }
     271                 : 
     272              68 :     return( TRUE );
     273                 : }
     274                 : 
     275                 : /************************************************************************/
     276                 : /*                         OCTProj4Normalize()                          */
     277                 : /*                                                                      */
     278                 : /*      This function is really just here since we already have all     */
     279                 : /*      the code to load libproj.so.  It is intended to "normalize"     */
     280                 : /*      a proj.4 definition, expanding +init= definitions and so        */
     281                 : /*      forth as possible.                                              */
     282                 : /************************************************************************/
     283                 : 
     284            1062 : char *OCTProj4Normalize( const char *pszProj4Src )
     285                 : 
     286                 : {
     287                 :     char        *pszNewProj4Def, *pszCopy;
     288            1062 :     projPJ      psPJSource = NULL;
     289                 : 
     290            1062 :     CPLMutexHolderD( &hPROJMutex );
     291                 : 
     292            1062 :     if( !LoadProjLibrary() || pfn_pj_dalloc == NULL || pfn_pj_get_def == NULL )
     293               0 :         return CPLStrdup( pszProj4Src );
     294                 : 
     295            1062 :     psPJSource = pfn_pj_init_plus( pszProj4Src );
     296                 : 
     297            1062 :     if( psPJSource == NULL )
     298             816 :         return CPLStrdup( pszProj4Src );
     299                 : 
     300             246 :     pszNewProj4Def = pfn_pj_get_def( psPJSource, 0 );
     301                 : 
     302             246 :     pfn_pj_free( psPJSource );
     303                 : 
     304             246 :     if( pszNewProj4Def == NULL )
     305               0 :         return CPLStrdup( pszProj4Src );
     306                 : 
     307             246 :     pszCopy = CPLStrdup( pszNewProj4Def );
     308             246 :     pfn_pj_dalloc( pszNewProj4Def );
     309                 : 
     310             246 :     return pszCopy;
     311                 : }
     312                 : 
     313                 : /************************************************************************/
     314                 : /*                 OCTDestroyCoordinateTransformation()                 */
     315                 : /************************************************************************/
     316                 : 
     317                 : /**
     318                 :  * \brief OGRCoordinateTransformation destructor. 
     319                 :  *
     320                 :  * This function is the same as OGRCoordinateTransformation::DestroyCT()
     321                 :  *
     322                 :  * @param hCT the object to delete
     323                 :  */
     324                 :  
     325                 : void CPL_STDCALL
     326             190 : OCTDestroyCoordinateTransformation( OGRCoordinateTransformationH hCT )
     327                 : 
     328                 : {
     329             190 :     delete (OGRCoordinateTransformation *) hCT;
     330             190 : }
     331                 : 
     332                 : /************************************************************************/
     333                 : /*                             DestroyCT()                              */
     334                 : /************************************************************************/
     335                 : 
     336                 : /**
     337                 :  * \brief OGRCoordinateTransformation destructor. 
     338                 :  *
     339                 :  * This function is the same as OGRCoordinateTransformation::~OGRCoordinateTransformation()
     340                 :  * and OCTDestroyCoordinateTransformation()
     341                 :  *
     342                 :  * This static method will destroy a OGRCoordinateTransformation.  It is
     343                 :  * equivalent to calling delete on the object, but it ensures that the
     344                 :  * deallocation is properly executed within the OGR libraries heap on
     345                 :  * platforms where this can matter (win32).  
     346                 :  *
     347                 :  * @param poCT the object to delete
     348                 :  *
     349                 :  * @since GDAL 1.7.0
     350                 :  */
     351                 :  
     352             236 : void OGRCoordinateTransformation::DestroyCT(OGRCoordinateTransformation* poCT)
     353                 : {
     354             236 :     delete poCT;
     355             236 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                 OGRCreateCoordinateTransformation()                  */
     359                 : /************************************************************************/
     360                 : 
     361                 : /**
     362                 :  * Create transformation object.
     363                 :  *
     364                 :  * This is the same as the C function OCTNewCoordinateTransformation().
     365                 :  *
     366                 :  * Input spatial reference system objects are assigned 
     367                 :  * by copy (calling clone() method) and no ownership transfer occurs.
     368                 :  *
     369                 :  * The delete operator, or OCTDestroyCoordinateTransformation() should
     370                 :  * be used to destroy transformation objects. 
     371                 :  *
     372                 :  * The PROJ.4 library must be available at run-time.
     373                 :  *
     374                 :  * @param poSource source spatial reference system. 
     375                 :  * @param poTarget target spatial reference system. 
     376                 :  * @return NULL on failure or a ready to use transformation object.
     377                 :  */
     378                 : 
     379                 : OGRCoordinateTransformation*  
     380             800 : OGRCreateCoordinateTransformation( OGRSpatialReference *poSource, 
     381                 :                                    OGRSpatialReference *poTarget )
     382                 : 
     383                 : {
     384                 :     OGRProj4CT  *poCT;
     385                 : 
     386             800 :     if( pfn_pj_init == NULL && !LoadProjLibrary() )
     387                 :     {
     388                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     389                 :                   "Unable to load PROJ.4 library (%s), creation of\n"
     390                 :                   "OGRCoordinateTransformation failed.",
     391               0 :                   GetProjLibraryName() );
     392               0 :         return NULL;
     393                 :     }
     394                 : 
     395             800 :     poCT = new OGRProj4CT();
     396                 :     
     397             800 :     if( !poCT->Initialize( poSource, poTarget ) )
     398                 :     {
     399               0 :         delete poCT;
     400               0 :         return NULL;
     401                 :     }
     402                 :     else
     403                 :     {
     404             800 :         return poCT;
     405                 :     }
     406                 : }
     407                 : 
     408                 : /************************************************************************/
     409                 : /*                   OCTNewCoordinateTransformation()                   */
     410                 : /************************************************************************/
     411                 : 
     412                 : /**
     413                 :  * Create transformation object.
     414                 :  *
     415                 :  * This is the same as the C++ function OGRCreateCoordinateTransformation().
     416                 :  *
     417                 :  * Input spatial reference system objects are assigned 
     418                 :  * by copy (calling clone() method) and no ownership transfer occurs.
     419                 :  *
     420                 :  * OCTDestroyCoordinateTransformation() should
     421                 :  * be used to destroy transformation objects. 
     422                 :  *
     423                 :  * The PROJ.4 library must be available at run-time.
     424                 :  *
     425                 :  * @param hSourceSRS source spatial reference system. 
     426                 :  * @param hTargetSRS target spatial reference system. 
     427                 :  * @return NULL on failure or a ready to use transformation object.
     428                 :  */
     429                 :  
     430                 : OGRCoordinateTransformationH CPL_STDCALL 
     431             184 : OCTNewCoordinateTransformation(
     432                 :     OGRSpatialReferenceH hSourceSRS, OGRSpatialReferenceH hTargetSRS )
     433                 : 
     434                 : {
     435                 :     return (OGRCoordinateTransformationH) 
     436                 :         OGRCreateCoordinateTransformation( 
     437                 :             (OGRSpatialReference *) hSourceSRS,
     438             184 :             (OGRSpatialReference *) hTargetSRS );
     439                 : }
     440                 : 
     441                 : /************************************************************************/
     442                 : /*                             OGRProj4CT()                             */
     443                 : /************************************************************************/
     444                 : 
     445             800 : OGRProj4CT::OGRProj4CT()
     446                 : 
     447                 : {
     448             800 :     poSRSSource = NULL;
     449             800 :     poSRSTarget = NULL;
     450             800 :     psPJSource = NULL;
     451             800 :     psPJTarget = NULL;
     452                 :     
     453             800 :     nErrorCount = 0;
     454                 :     
     455             800 :     bCheckWithInvertProj = FALSE;
     456             800 :     dfThreshold = 0;
     457                 : 
     458             800 :     nMaxCount = 0;
     459             800 :     padfOriX = NULL;
     460             800 :     padfOriY = NULL;
     461             800 :     padfOriZ = NULL;
     462             800 :     padfTargetX = NULL;
     463             800 :     padfTargetY = NULL;
     464             800 :     padfTargetZ = NULL;
     465                 : 
     466             800 :     if (pfn_pj_ctx_alloc != NULL)
     467             800 :         pjctx = pfn_pj_ctx_alloc();
     468                 :     else
     469               0 :         pjctx = NULL;
     470             800 : }
     471                 : 
     472                 : /************************************************************************/
     473                 : /*                            ~OGRProj4CT()                             */
     474                 : /************************************************************************/
     475                 : 
     476             800 : OGRProj4CT::~OGRProj4CT()
     477                 : 
     478                 : {
     479             800 :     if( poSRSSource != NULL )
     480                 :     {
     481             800 :         if( poSRSSource->Dereference() <= 0 )
     482             800 :             delete poSRSSource;
     483                 :     }
     484                 : 
     485             800 :     if( poSRSTarget != NULL )
     486                 :     {
     487             800 :         if( poSRSTarget->Dereference() <= 0 )
     488             796 :             delete poSRSTarget;
     489                 :     }
     490                 : 
     491             800 :     if (pjctx != NULL)
     492                 :     {
     493             800 :         pfn_pj_ctx_free(pjctx);
     494                 : 
     495             800 :         if( psPJSource != NULL )
     496             800 :             pfn_pj_free( psPJSource );
     497                 : 
     498             800 :         if( psPJTarget != NULL )
     499             800 :             pfn_pj_free( psPJTarget );
     500                 :     }
     501                 :     else
     502                 :     {
     503               0 :         CPLMutexHolderD( &hPROJMutex );
     504                 : 
     505               0 :         if( psPJSource != NULL )
     506               0 :             pfn_pj_free( psPJSource );
     507                 : 
     508               0 :         if( psPJTarget != NULL )
     509               0 :             pfn_pj_free( psPJTarget );
     510                 :     }
     511                 : 
     512             800 :     CPLFree(padfOriX);
     513             800 :     CPLFree(padfOriY);
     514             800 :     CPLFree(padfOriZ);
     515             800 :     CPLFree(padfTargetX);
     516             800 :     CPLFree(padfTargetY);
     517             800 :     CPLFree(padfTargetZ);
     518             800 : }
     519                 : 
     520                 : /************************************************************************/
     521                 : /*                             Initialize()                             */
     522                 : /************************************************************************/
     523                 : 
     524             800 : int OGRProj4CT::Initialize( OGRSpatialReference * poSourceIn, 
     525                 :                             OGRSpatialReference * poTargetIn )
     526                 : 
     527                 : {
     528             800 :     if (pjctx != NULL)
     529                 :     {
     530             800 :         return InitializeNoLock(poSourceIn, poTargetIn);
     531                 :     }
     532                 : 
     533               0 :     CPLMutexHolderD( &hPROJMutex );
     534               0 :     return InitializeNoLock(poSourceIn, poTargetIn);
     535                 : }
     536                 : 
     537                 : /************************************************************************/
     538                 : /*                         InitializeNoLock()                           */
     539                 : /************************************************************************/
     540                 : 
     541             800 : int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn, 
     542                 :                                   OGRSpatialReference * poTargetIn )
     543                 : 
     544                 : {
     545             800 :     if( poSourceIn == NULL || poTargetIn == NULL )
     546               0 :         return FALSE;
     547                 : 
     548             800 :     poSRSSource = poSourceIn->Clone();
     549             800 :     poSRSTarget = poTargetIn->Clone();
     550                 : 
     551             800 :     bSourceLatLong = poSRSSource->IsGeographic();
     552             800 :     bTargetLatLong = poSRSTarget->IsGeographic();
     553                 : 
     554                 : /* -------------------------------------------------------------------- */
     555                 : /*      Setup source and target translations to radians for lat/long    */
     556                 : /*      systems.                                                        */
     557                 : /* -------------------------------------------------------------------- */
     558             800 :     dfSourceToRadians = DEG_TO_RAD;
     559             800 :     dfSourceFromRadians = RAD_TO_DEG;
     560             800 :     bSourceWrap = FALSE;
     561             800 :     dfSourceWrapLong = 0.0;
     562                 : 
     563             800 :     if( bSourceLatLong )
     564                 :     {
     565             466 :         OGR_SRSNode *poUNITS = poSRSSource->GetAttrNode( "GEOGCS|UNIT" );
     566             466 :         if( poUNITS && poUNITS->GetChildCount() >= 2 )
     567                 :         {
     568             466 :             dfSourceToRadians = atof(poUNITS->GetChild(1)->GetValue());
     569             466 :             if( dfSourceToRadians == 0.0 )
     570               0 :                 dfSourceToRadians = DEG_TO_RAD;
     571                 :             else
     572             466 :                 dfSourceFromRadians = 1 / dfSourceToRadians;
     573                 :         }
     574                 :     }
     575                 : 
     576             800 :     dfTargetToRadians = DEG_TO_RAD;
     577             800 :     dfTargetFromRadians = RAD_TO_DEG;
     578             800 :     bTargetWrap = FALSE;
     579             800 :     dfTargetWrapLong = 0.0;
     580                 : 
     581             800 :     if( bTargetLatLong )
     582                 :     {
     583             330 :         OGR_SRSNode *poUNITS = poSRSTarget->GetAttrNode( "GEOGCS|UNIT" );
     584             330 :         if( poUNITS && poUNITS->GetChildCount() >= 2 )
     585                 :         {
     586             330 :             dfTargetToRadians = atof(poUNITS->GetChild(1)->GetValue());
     587             330 :             if( dfTargetToRadians == 0.0 )
     588               0 :                 dfTargetToRadians = DEG_TO_RAD;
     589                 :             else
     590             330 :                 dfTargetFromRadians = 1 / dfTargetToRadians;
     591                 :         }
     592                 :     }
     593                 : 
     594                 : /* -------------------------------------------------------------------- */
     595                 : /*      Preliminary logic to setup wrapping.                            */
     596                 : /* -------------------------------------------------------------------- */
     597                 :     const char *pszCENTER_LONG;
     598                 : 
     599             800 :     if( CPLGetConfigOption( "CENTER_LONG", NULL ) != NULL )
     600                 :     {
     601               0 :         bSourceWrap = bTargetWrap = TRUE;
     602                 :         dfSourceWrapLong = dfTargetWrapLong = 
     603               0 :             atof(CPLGetConfigOption( "CENTER_LONG", "" ));
     604               0 :         CPLDebug( "OGRCT", "Wrap at %g.", dfSourceWrapLong );
     605                 :     }
     606                 : 
     607             800 :     pszCENTER_LONG = poSRSSource->GetExtension( "GEOGCS", "CENTER_LONG" );
     608             800 :     if( pszCENTER_LONG != NULL )
     609                 :     {
     610              72 :         dfSourceWrapLong = atof(pszCENTER_LONG);
     611              72 :         bSourceWrap = TRUE;
     612              72 :         CPLDebug( "OGRCT", "Wrap source at %g.", dfSourceWrapLong );
     613                 :     }
     614                 : 
     615             800 :     pszCENTER_LONG = poSRSTarget->GetExtension( "GEOGCS", "CENTER_LONG" );
     616             800 :     if( pszCENTER_LONG != NULL )
     617                 :     {
     618              72 :         dfTargetWrapLong = atof(pszCENTER_LONG);
     619              72 :         bTargetWrap = TRUE;
     620              72 :         CPLDebug( "OGRCT", "Wrap target at %g.", dfTargetWrapLong );
     621                 :     }
     622                 :     
     623             800 :     bCheckWithInvertProj = CSLTestBoolean(CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", "NO" ));
     624                 :     
     625                 :     /* The threshold is rather experimental... Works well with the cases of ticket #2305 */
     626             800 :     if (bSourceLatLong)
     627             466 :         dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", ".1" ));
     628                 :     else
     629                 :         /* 1 works well for most projections, except for +proj=aeqd that requires */
     630                 :         /* a tolerance of 10000 */
     631             334 :         dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", "10000" ));
     632                 : 
     633                 : /* -------------------------------------------------------------------- */
     634                 : /*      Establish PROJ.4 handle for source if projection.               */
     635                 : /* -------------------------------------------------------------------- */
     636                 :     // OGRThreadSafety: The following variable is not a thread safety issue 
     637                 :     // since the only issue is incrementing while accessing which at worse 
     638                 :     // means debug output could be one "increment" late. 
     639                 :     static int   nDebugReportCount = 0;
     640                 : 
     641             800 :     char        *pszProj4Defn = NULL;
     642                 : 
     643             800 :     if( poSRSSource->exportToProj4( &pszProj4Defn ) != OGRERR_NONE )
     644                 :     {
     645               0 :         CPLFree( pszProj4Defn );
     646               0 :         return FALSE;
     647                 :     }
     648                 : 
     649             800 :     if( strlen(pszProj4Defn) == 0 )
     650                 :     {
     651               0 :         CPLFree( pszProj4Defn );
     652                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     653                 :                   "No PROJ.4 translation for source SRS, coordinate\n"
     654               0 :                   "transformation initialization has failed." );
     655               0 :         return FALSE;
     656                 :     }
     657                 : 
     658             800 :     if (pjctx)
     659             800 :         psPJSource = pfn_pj_init_plus_ctx( pjctx, pszProj4Defn );
     660                 :     else
     661               0 :         psPJSource = pfn_pj_init_plus( pszProj4Defn );
     662                 :     
     663             800 :     if( psPJSource == NULL )
     664                 :     {
     665               0 :         if( pjctx != NULL)
     666                 :         {
     667               0 :             int pj_errno = pfn_pj_ctx_get_errno(pjctx);
     668                 : 
     669                 :             /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */
     670               0 :             CPLMutexHolderD(&hPROJMutex);
     671                 :             CPLError( CE_Failure, CPLE_NotSupported, 
     672                 :                       "Failed to initialize PROJ.4 with `%s'.\n%s", 
     673               0 :                       pszProj4Defn, pfn_pj_strerrno(pj_errno) );
     674                 :         }
     675               0 :         else if( pfn_pj_get_errno_ref != NULL
     676                 :             && pfn_pj_strerrno != NULL )
     677                 :         {
     678               0 :             int *p_pj_errno = pfn_pj_get_errno_ref();
     679                 : 
     680                 :             CPLError( CE_Failure, CPLE_NotSupported, 
     681                 :                       "Failed to initialize PROJ.4 with `%s'.\n%s", 
     682               0 :                       pszProj4Defn, pfn_pj_strerrno(*p_pj_errno) );
     683                 :         }
     684                 :         else
     685                 :         {
     686                 :             CPLError( CE_Failure, CPLE_NotSupported, 
     687                 :                       "Failed to initialize PROJ.4 with `%s'.\n", 
     688               0 :                       pszProj4Defn );
     689                 :         }
     690                 :     }
     691                 :     
     692             800 :     if( nDebugReportCount < 10 )
     693             178 :         CPLDebug( "OGRCT", "Source: %s", pszProj4Defn );
     694                 :     
     695             800 :     CPLFree( pszProj4Defn );
     696                 : 
     697             800 :     if( psPJSource == NULL )
     698               0 :         return FALSE;
     699                 : 
     700                 : /* -------------------------------------------------------------------- */
     701                 : /*      Establish PROJ.4 handle for target if projection.               */
     702                 : /* -------------------------------------------------------------------- */
     703             800 :     pszProj4Defn = NULL;
     704                 : 
     705             800 :     if( poSRSTarget->exportToProj4( &pszProj4Defn ) != OGRERR_NONE )
     706                 :     {
     707               0 :         CPLFree( pszProj4Defn );
     708               0 :         return FALSE;
     709                 :     }
     710                 : 
     711             800 :     if( strlen(pszProj4Defn) == 0 )
     712                 :     {
     713               0 :         CPLFree( pszProj4Defn );
     714                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     715                 :                   "No PROJ.4 translation for destination SRS, coordinate\n"
     716               0 :                   "transformation initialization has failed." );
     717               0 :         return FALSE;
     718                 :     }
     719                 : 
     720             800 :     if (pjctx)
     721             800 :         psPJTarget = pfn_pj_init_plus_ctx( pjctx, pszProj4Defn );
     722                 :     else
     723               0 :         psPJTarget = pfn_pj_init_plus( pszProj4Defn );
     724                 :     
     725             800 :     if( psPJTarget == NULL )
     726                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     727                 :                   "Failed to initialize PROJ.4 with `%s'.", 
     728               0 :                   pszProj4Defn );
     729                 :     
     730             800 :     if( nDebugReportCount < 10 )
     731                 :     {
     732             178 :         CPLDebug( "OGRCT", "Target: %s", pszProj4Defn );
     733             178 :         nDebugReportCount++;
     734                 :     }
     735                 : 
     736             800 :     CPLFree( pszProj4Defn );
     737                 :     
     738             800 :     if( psPJTarget == NULL )
     739               0 :         return FALSE;
     740                 : 
     741             800 :     return TRUE;
     742                 : }
     743                 : 
     744                 : /************************************************************************/
     745                 : /*                            GetSourceCS()                             */
     746                 : /************************************************************************/
     747                 : 
     748              56 : OGRSpatialReference *OGRProj4CT::GetSourceCS()
     749                 : 
     750                 : {
     751              56 :     return poSRSSource;
     752                 : }
     753                 : 
     754                 : /************************************************************************/
     755                 : /*                            GetTargetCS()                             */
     756                 : /************************************************************************/
     757                 : 
     758             148 : OGRSpatialReference *OGRProj4CT::GetTargetCS()
     759                 : 
     760                 : {
     761             148 :     return poSRSTarget;
     762                 : }
     763                 : 
     764                 : /************************************************************************/
     765                 : /*                             Transform()                              */
     766                 : /*                                                                      */
     767                 : /*      This is a small wrapper for the extended transform version.     */
     768                 : /************************************************************************/
     769                 : 
     770            1740 : int OGRProj4CT::Transform( int nCount, double *x, double *y, double *z )
     771                 : 
     772                 : {
     773            1740 :     int *pabSuccess = (int *) CPLMalloc(sizeof(int) * nCount );
     774                 :     int bOverallSuccess, i;
     775                 : 
     776            1740 :     bOverallSuccess = TransformEx( nCount, x, y, z, pabSuccess );
     777                 : 
     778            3484 :     for( i = 0; i < nCount; i++ )
     779                 :     {
     780            1744 :         if( !pabSuccess[i] )
     781                 :         {
     782               0 :             bOverallSuccess = FALSE;
     783               0 :             break;
     784                 :         }
     785                 :     }
     786                 : 
     787            1740 :     CPLFree( pabSuccess );
     788                 : 
     789            1740 :     return bOverallSuccess;
     790                 : }
     791                 : 
     792                 : /************************************************************************/
     793                 : /*                            OCTTransform()                            */
     794                 : /************************************************************************/
     795                 : 
     796             644 : int CPL_STDCALL OCTTransform( OGRCoordinateTransformationH hTransform,
     797                 :                               int nCount, double *x, double *y, double *z )
     798                 : 
     799                 : {
     800                 :     return ((OGRCoordinateTransformation*) hTransform)->
     801             644 :         Transform( nCount, x, y,z );
     802                 : }
     803                 : 
     804                 : /************************************************************************/
     805                 : /*                            TransformEx()                             */
     806                 : /************************************************************************/
     807                 : 
     808           75072 : int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z,
     809                 :                              int *pabSuccess )
     810                 : 
     811                 : {
     812                 :     int   err, i;
     813                 : 
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Potentially transform to radians.                               */
     816                 : /* -------------------------------------------------------------------- */
     817           75072 :     if( bSourceLatLong )
     818                 :     {
     819           20652 :         if( bSourceWrap )
     820                 :         {
     821           29652 :             for( i = 0; i < nCount; i++ )
     822                 :             {
     823           21022 :                 if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     824                 :                 {
     825           19708 :                     if( x[i] < dfSourceWrapLong - 180.0 )
     826               0 :                         x[i] += 360.0;
     827           19708 :                     else if( x[i] > dfSourceWrapLong + 180 )
     828               0 :                         x[i] -= 360.0;
     829                 :                 }
     830                 :             }
     831                 :         }
     832                 : 
     833         7587402 :         for( i = 0; i < nCount; i++ )
     834                 :         {
     835         7566750 :             if( x[i] != HUGE_VAL )
     836                 :             {
     837         7565436 :                 x[i] *= dfSourceToRadians;
     838         7565436 :                 y[i] *= dfSourceToRadians;
     839                 :             }
     840                 :         }
     841                 :     }
     842                 :     
     843                 : /* -------------------------------------------------------------------- */
     844                 : /*      Do the transformation using PROJ.4.                             */
     845                 : /* -------------------------------------------------------------------- */
     846           75072 :     if (pjctx == NULL)
     847                 :     {
     848                 :         /* The mutex has already been created */
     849               0 :         CPLAssert(hPROJMutex != NULL);
     850               0 :         CPLAcquireMutex(hPROJMutex, 1000.0);
     851                 :     }
     852                 :         
     853           75072 :     if (bCheckWithInvertProj)
     854                 :     {
     855                 :         /* For some projections, we cannot detect if we are trying to reproject */
     856                 :         /* coordinates outside the validity area of the projection. So let's do */
     857                 :         /* the reverse reprojection and compare with the source coordinates */
     858           11234 :         if (nCount > nMaxCount)
     859                 :         {
     860              42 :             nMaxCount = nCount;
     861              42 :             padfOriX = (double*) CPLRealloc(padfOriX, sizeof(double)*nCount);
     862              42 :             padfOriY = (double*) CPLRealloc(padfOriY, sizeof(double)*nCount);
     863              42 :             padfOriZ = (double*) CPLRealloc(padfOriZ, sizeof(double)*nCount);
     864              42 :             padfTargetX = (double*) CPLRealloc(padfTargetX, sizeof(double)*nCount);
     865              42 :             padfTargetY = (double*) CPLRealloc(padfTargetY, sizeof(double)*nCount);
     866              42 :             padfTargetZ = (double*) CPLRealloc(padfTargetZ, sizeof(double)*nCount);
     867                 :         }
     868           11234 :         memcpy(padfOriX, x, sizeof(double)*nCount);
     869           11234 :         memcpy(padfOriY, y, sizeof(double)*nCount);
     870           11234 :         if (z)
     871                 :         {
     872           11234 :             memcpy(padfOriZ, z, sizeof(double)*nCount);
     873                 :         }
     874           11234 :         err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z );
     875           11234 :         if (err == 0)
     876                 :         {
     877           11234 :             memcpy(padfTargetX, x, sizeof(double)*nCount);
     878           11234 :             memcpy(padfTargetY, y, sizeof(double)*nCount);
     879           11234 :             if (z)
     880                 :             {
     881           11234 :                 memcpy(padfTargetZ, z, sizeof(double)*nCount);
     882                 :             }
     883                 :             
     884                 :             err = pfn_pj_transform( psPJTarget, psPJSource , nCount, 1,
     885           11234 :                                     padfTargetX, padfTargetY, (z) ? padfTargetZ : NULL);
     886           11234 :             if (err == 0)
     887                 :             {
     888         1500880 :                 for( i = 0; i < nCount; i++ )
     889                 :                 {
     890         4150108 :                     if ( x[i] != HUGE_VAL && y[i] != HUGE_VAL &&
     891         1488162 :                         (fabs(padfTargetX[i] - padfOriX[i]) > dfThreshold ||
     892         1172300 :                          fabs(padfTargetY[i] - padfOriY[i]) > dfThreshold) )
     893                 :                     {
     894          316548 :                         x[i] = HUGE_VAL;
     895          316548 :                         y[i] = HUGE_VAL;
     896                 :                     }
     897                 :                 }
     898                 :             }
     899                 :         }
     900                 :     }
     901                 :     else
     902                 :     {
     903           63838 :         err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z );
     904                 :     }
     905                 : 
     906                 : /* -------------------------------------------------------------------- */
     907                 : /*      Try to report an error through CPL.  Get proj.4 error string    */
     908                 : /*      if possible.  Try to avoid reporting thousands of error         */
     909                 : /*      ... supress further error reporting on this OGRProj4CT if we    */
     910                 : /*      have already reported 20 errors.                                */
     911                 : /* -------------------------------------------------------------------- */
     912           75072 :     if( err != 0 )
     913                 :     {
     914               0 :         if( pabSuccess )
     915               0 :             memset( pabSuccess, 0, sizeof(int) * nCount );
     916                 : 
     917               0 :         if( ++nErrorCount < 20 )
     918                 :         {
     919               0 :             if (pjctx != NULL)
     920                 :                 /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */
     921               0 :                 CPLAcquireMutex(hPROJMutex, 1000.0);
     922                 : 
     923               0 :             const char *pszError = NULL;
     924               0 :             if( pfn_pj_strerrno != NULL )
     925               0 :                 pszError = pfn_pj_strerrno( err );
     926                 :             
     927               0 :             if( pszError == NULL )
     928                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     929                 :                           "Reprojection failed, err = %d", 
     930               0 :                           err );
     931                 :             else
     932               0 :                 CPLError( CE_Failure, CPLE_AppDefined, "%s", pszError );
     933                 : 
     934               0 :             if (pjctx != NULL)
     935                 :                 /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */
     936               0 :                 CPLReleaseMutex(hPROJMutex);
     937                 :         }
     938               0 :         else if( nErrorCount == 20 )
     939                 :         {
     940                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     941                 :                       "Reprojection failed, err = %d, further errors will be supressed on the transform object.", 
     942               0 :                       err );
     943                 :         }
     944                 : 
     945               0 :         if (pjctx == NULL)
     946               0 :             CPLReleaseMutex(hPROJMutex);
     947               0 :         return FALSE;
     948                 :     }
     949                 : 
     950           75072 :     if (pjctx == NULL)
     951               0 :         CPLReleaseMutex(hPROJMutex);
     952                 : 
     953                 : /* -------------------------------------------------------------------- */
     954                 : /*      Potentially transform back to degrees.                          */
     955                 : /* -------------------------------------------------------------------- */
     956           75072 :     if( bTargetLatLong )
     957                 :     {
     958         7374776 :         for( i = 0; i < nCount; i++ )
     959                 :         {
     960         7347834 :             if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     961                 :             {
     962         7032322 :                 x[i] *= dfTargetFromRadians;
     963         7032322 :                 y[i] *= dfTargetFromRadians;
     964                 :             }
     965                 :         }
     966                 : 
     967           26942 :         if( bTargetWrap )
     968                 :         {
     969         7367706 :             for( i = 0; i < nCount; i++ )
     970                 :             {
     971         7343456 :                 if( x[i] != HUGE_VAL && y[i] != HUGE_VAL )
     972                 :                 {
     973         7027944 :                     if( x[i] < dfTargetWrapLong - 180.0 )
     974            1616 :                         x[i] += 360.0;
     975         7026328 :                     else if( x[i] > dfTargetWrapLong + 180 )
     976               0 :                         x[i] -= 360.0;
     977                 :                 }
     978                 :             }
     979                 :         }
     980                 :     }
     981                 : 
     982                 : /* -------------------------------------------------------------------- */
     983                 : /*      Establish error information if pabSuccess provided.             */
     984                 : /* -------------------------------------------------------------------- */
     985           75072 :     if( pabSuccess )
     986                 :     {
     987         9616386 :         for( i = 0; i < nCount; i++ )
     988                 :         {
     989         9861280 :             if( x[i] == HUGE_VAL || y[i] == HUGE_VAL )
     990          319966 :                 pabSuccess[i] = FALSE;
     991                 :             else
     992         9221348 :                 pabSuccess[i] = TRUE;
     993                 :         }
     994                 :     }
     995                 : 
     996           75072 :     return TRUE;
     997                 : }
     998                 : 
     999                 : /************************************************************************/
    1000                 : /*                           OCTTransformEx()                           */
    1001                 : /************************************************************************/
    1002                 : 
    1003               0 : int CPL_STDCALL OCTTransformEx( OGRCoordinateTransformationH hTransform,
    1004                 :                                 int nCount, double *x, double *y, double *z,
    1005                 :                                 int *pabSuccess )
    1006                 : 
    1007                 : {
    1008                 :     return ((OGRCoordinateTransformation*) hTransform)->
    1009               0 :         TransformEx( nCount, x, y, z, pabSuccess );
    1010                 : }
    1011                 : 

Generated by: LCOV version 1.7