LCOV - code coverage report
Current view: directory - ogr - ogrct.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 320 243 75.9 %
Date: 2013-03-30 Functions: 21 17 81.0 %

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

Generated by: LCOV version 1.7