int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z, int *pabSuccess ) { int err, i; /* -------------------------------------------------------------------- */ /* Potentially transform to radians. */ /* -------------------------------------------------------------------- */ if( bSourceLatLong ) { if( bSourceWrap ) { for( i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { if( x[i] < dfSourceWrapLong - 180.0 ) x[i] += 360.0; else if( x[i] > dfSourceWrapLong + 180 ) x[i] -= 360.0; } } } for( i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL ) { x[i] *= dfSourceToRadians; y[i] *= dfSourceToRadians; } } } /* -------------------------------------------------------------------- */ /* Do the transformation using PROJ.4. */ /* -------------------------------------------------------------------- */ if( !bIdentityTransform && pjctx == NULL ) { /* The mutex has already been created */ CPLAssert(hPROJMutex != NULL); CPLAcquireMutex(hPROJMutex, 1000.0); } if( bIdentityTransform ) err = 0; else if (bCheckWithInvertProj) { /* For some projections, we cannot detect if we are trying to reproject */ /* coordinates outside the validity area of the projection. So let's do */ /* the reverse reprojection and compare with the source coordinates */ if (nCount > nMaxCount) { nMaxCount = nCount; padfOriX = (double*) CPLRealloc(padfOriX, sizeof(double)*nCount); padfOriY = (double*) CPLRealloc(padfOriY, sizeof(double)*nCount); padfOriZ = (double*) CPLRealloc(padfOriZ, sizeof(double)*nCount); padfTargetX = (double*) CPLRealloc(padfTargetX, sizeof(double)*nCount); padfTargetY = (double*) CPLRealloc(padfTargetY, sizeof(double)*nCount); padfTargetZ = (double*) CPLRealloc(padfTargetZ, sizeof(double)*nCount); } memcpy(padfOriX, x, sizeof(double)*nCount); memcpy(padfOriY, y, sizeof(double)*nCount); if (z) { memcpy(padfOriZ, z, sizeof(double)*nCount); } err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z ); if (err == 0) { memcpy(padfTargetX, x, sizeof(double)*nCount); memcpy(padfTargetY, y, sizeof(double)*nCount); if (z) { memcpy(padfTargetZ, z, sizeof(double)*nCount); } err = pfn_pj_transform( psPJTarget, psPJSource , nCount, 1, padfTargetX, padfTargetY, (z) ? padfTargetZ : NULL); if (err == 0) { for( i = 0; i < nCount; i++ ) { if ( x[i] != HUGE_VAL && y[i] != HUGE_VAL && (fabs(padfTargetX[i] - padfOriX[i]) > dfThreshold || fabs(padfTargetY[i] - padfOriY[i]) > dfThreshold) ) { x[i] = HUGE_VAL; y[i] = HUGE_VAL; } } } } } else { err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z ); } /* -------------------------------------------------------------------- */ /* Try to report an error through CPL. Get proj.4 error string */ /* if possible. Try to avoid reporting thousands of error */ /* ... supress further error reporting on this OGRProj4CT if we */ /* have already reported 20 errors. */ /* -------------------------------------------------------------------- */ if( err != 0 ) { if( pabSuccess ) memset( pabSuccess, 0, sizeof(int) * nCount ); if( ++nErrorCount < 20 ) { if (pjctx != NULL) /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLAcquireMutex(hPROJMutex, 1000.0); const char *pszError = NULL; if( pfn_pj_strerrno != NULL ) pszError = pfn_pj_strerrno( err ); if( pszError == NULL ) CPLError( CE_Failure, CPLE_AppDefined, "Reprojection failed, err = %d", err ); else CPLError( CE_Failure, CPLE_AppDefined, "%s", pszError ); if (pjctx != NULL) /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLReleaseMutex(hPROJMutex); } else if( nErrorCount == 20 ) { CPLError( CE_Failure, CPLE_AppDefined, "Reprojection failed, err = %d, further errors will be supressed on the transform object.", err ); } if (pjctx == NULL) CPLReleaseMutex(hPROJMutex); return FALSE; } if( !bIdentityTransform && pjctx == NULL ) CPLReleaseMutex(hPROJMutex); /* -------------------------------------------------------------------- */ /* Potentially transform back to degrees. */ /* -------------------------------------------------------------------- */ if( bTargetLatLong ) { for( i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { x[i] *= dfTargetFromRadians; y[i] *= dfTargetFromRadians; } } if( bTargetWrap ) { for( i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { if( x[i] < dfTargetWrapLong - 180.0 ) x[i] += 360.0; else if( x[i] > dfTargetWrapLong + 180 ) x[i] -= 360.0; } } } } /* -------------------------------------------------------------------- */ /* Establish error information if pabSuccess provided. */ /* -------------------------------------------------------------------- */ if( pabSuccess ) { for( i = 0; i < nCount; i++ ) { if( x[i] == HUGE_VAL || y[i] == HUGE_VAL ) pabSuccess[i] = FALSE; else pabSuccess[i] = TRUE; } } return TRUE; }
/** Transform an array of points * * @param nCount Number of points * @param x Array of nCount x values. * @param y Array of nCount y values. * @param z Array of nCount z values. * @param pabSuccess Output array of nCount value that will be set to TRUE/FALSE * @return TRUE or FALSE */ int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z, int *pabSuccess ) { int err; /* -------------------------------------------------------------------- */ /* Potentially transform to radians. */ /* -------------------------------------------------------------------- */ if( bSourceLatLong ) { if( bSourceWrap ) { for( int i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { if( x[i] < dfSourceWrapLong - 180.0 ) x[i] += 360.0; else if( x[i] > dfSourceWrapLong + 180 ) x[i] -= 360.0; } } } for( int i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL ) { x[i] *= dfSourceToRadians; y[i] *= dfSourceToRadians; } } } /* -------------------------------------------------------------------- */ /* Optimized transform from WebMercator to WGS84 */ /* -------------------------------------------------------------------- */ bool bTransformDone = false; if( bWebMercatorToWGS84 ) { #define REVERSE_SPHERE_RADIUS (1. / 6378137.) double y0 = y[0]; for( int i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL ) { x[i] = x[i] * REVERSE_SPHERE_RADIUS; if( x[i] > M_PI ) { if( x[i] < M_PI+1e-14 ) x[i] = M_PI; else if( bCheckWithInvertProj ) { x[i] = y[i] = HUGE_VAL; y0 = HUGE_VAL; continue; } else { do { x[i] -= 2 * M_PI; } while ( x[i] > M_PI ); } } else if( x[i] < -M_PI ) { if( x[i] > -M_PI-1e-14 ) x[i] = -M_PI; else if( bCheckWithInvertProj ) { x[i] = y[i] = HUGE_VAL; y0 = HUGE_VAL; continue; } else { do { x[i] += 2 * M_PI; } while( x[i] < -M_PI ); } } // Optimization for the case where we are provided a whole line of same northing if( i > 0 && y[i] == y0 ) y[i] = y[0]; else y[i] = M_PI / 2 - 2. * atan(exp(-y[i] * REVERSE_SPHERE_RADIUS)); } } bTransformDone = true; } else if( bIdentityTransform ) { bTransformDone = true; } /* -------------------------------------------------------------------- */ /* Do the transformation (or not...) using PROJ.4. */ /* -------------------------------------------------------------------- */ if( !bTransformDone && pjctx == NULL ) { /* The mutex has already been created */ CPLAssert(hPROJMutex != NULL); CPLAcquireMutex(hPROJMutex, 1000.0); } if( bTransformDone ) err = 0; else if( bCheckWithInvertProj ) { // For some projections, we cannot detect if we are trying to reproject // coordinates outside the validity area of the projection. So let's do // the reverse reprojection and compare with the source coordinates. if (nCount > nMaxCount) { nMaxCount = nCount; padfOriX = (double*) CPLRealloc(padfOriX, sizeof(double)*nCount); padfOriY = (double*) CPLRealloc(padfOriY, sizeof(double)*nCount); padfOriZ = (double*) CPLRealloc(padfOriZ, sizeof(double)*nCount); padfTargetX = (double*) CPLRealloc(padfTargetX, sizeof(double)*nCount); padfTargetY = (double*) CPLRealloc(padfTargetY, sizeof(double)*nCount); padfTargetZ = (double*) CPLRealloc(padfTargetZ, sizeof(double)*nCount); } memcpy(padfOriX, x, sizeof(double)*nCount); memcpy(padfOriY, y, sizeof(double)*nCount); if (z) { memcpy(padfOriZ, z, sizeof(double)*nCount); } err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z ); if (err == 0) { memcpy(padfTargetX, x, sizeof(double)*nCount); memcpy(padfTargetY, y, sizeof(double)*nCount); if (z) { memcpy(padfTargetZ, z, sizeof(double)*nCount); } err = pfn_pj_transform( psPJTarget, psPJSource , nCount, 1, padfTargetX, padfTargetY, (z) ? padfTargetZ : NULL); if (err == 0) { for( int i = 0; i < nCount; i++ ) { if ( x[i] != HUGE_VAL && y[i] != HUGE_VAL && (fabs(padfTargetX[i] - padfOriX[i]) > dfThreshold || fabs(padfTargetY[i] - padfOriY[i]) > dfThreshold) ) { x[i] = HUGE_VAL; y[i] = HUGE_VAL; } } } } } else { err = pfn_pj_transform( psPJSource, psPJTarget, nCount, 1, x, y, z ); } /* -------------------------------------------------------------------- */ /* Try to report an error through CPL. Get proj.4 error string */ /* if possible. Try to avoid reporting thousands of error */ /* ... suppress further error reporting on this OGRProj4CT if we */ /* have already reported 20 errors. */ /* -------------------------------------------------------------------- */ if( err != 0 ) { if( pabSuccess ) memset( pabSuccess, 0, sizeof(int) * nCount ); if( ++nErrorCount < 20 ) { if (pjctx != NULL) /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLAcquireMutex(hPROJMutex, 1000.0); const char *pszError = NULL; if( pfn_pj_strerrno != NULL ) pszError = pfn_pj_strerrno( err ); if( pszError == NULL ) CPLError( CE_Failure, CPLE_AppDefined, "Reprojection failed, err = %d", err ); else CPLError( CE_Failure, CPLE_AppDefined, "%s", pszError ); if (pjctx != NULL) /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLReleaseMutex(hPROJMutex); } else if( nErrorCount == 20 ) { CPLError( CE_Failure, CPLE_AppDefined, "Reprojection failed, err = %d, further errors will be suppressed on the transform object.", err ); } if (pjctx == NULL) CPLReleaseMutex(hPROJMutex); return FALSE; } if( !bTransformDone && pjctx == NULL ) CPLReleaseMutex(hPROJMutex); /* -------------------------------------------------------------------- */ /* Potentially transform back to degrees. */ /* -------------------------------------------------------------------- */ if( bTargetLatLong ) { for( int i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { x[i] *= dfTargetFromRadians; y[i] *= dfTargetFromRadians; } } if( bTargetWrap ) { for( int i = 0; i < nCount; i++ ) { if( x[i] != HUGE_VAL && y[i] != HUGE_VAL ) { if( x[i] < dfTargetWrapLong - 180.0 ) x[i] += 360.0; else if( x[i] > dfTargetWrapLong + 180 ) x[i] -= 360.0; } } } } /* -------------------------------------------------------------------- */ /* Establish error information if pabSuccess provided. */ /* -------------------------------------------------------------------- */ if( pabSuccess ) { for( int i = 0; i < nCount; i++ ) { if( x[i] == HUGE_VAL || y[i] == HUGE_VAL ) pabSuccess[i] = FALSE; else pabSuccess[i] = TRUE; } } return TRUE; }
int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn, OGRSpatialReference * poTargetIn ) { if( poSourceIn == NULL || poTargetIn == NULL ) return FALSE; poSRSSource = poSourceIn->Clone(); poSRSTarget = poTargetIn->Clone(); bSourceLatLong = poSRSSource->IsGeographic(); bTargetLatLong = poSRSTarget->IsGeographic(); /* -------------------------------------------------------------------- */ /* Setup source and target translations to radians for lat/long */ /* systems. */ /* -------------------------------------------------------------------- */ dfSourceToRadians = DEG_TO_RAD; bSourceWrap = FALSE; dfSourceWrapLong = 0.0; if( bSourceLatLong ) { OGR_SRSNode *poUNITS = poSRSSource->GetAttrNode( "GEOGCS|UNIT" ); if( poUNITS && poUNITS->GetChildCount() >= 2 ) { dfSourceToRadians = atof(poUNITS->GetChild(1)->GetValue()); if( dfSourceToRadians == 0.0 ) dfSourceToRadians = DEG_TO_RAD; } } dfTargetFromRadians = RAD_TO_DEG; bTargetWrap = FALSE; dfTargetWrapLong = 0.0; if( bTargetLatLong ) { OGR_SRSNode *poUNITS = poSRSTarget->GetAttrNode( "GEOGCS|UNIT" ); if( poUNITS && poUNITS->GetChildCount() >= 2 ) { double dfTargetToRadians = atof(poUNITS->GetChild(1)->GetValue()); if( dfTargetToRadians != 0.0 ) dfTargetFromRadians = 1 / dfTargetToRadians; } } /* -------------------------------------------------------------------- */ /* Preliminary logic to setup wrapping. */ /* -------------------------------------------------------------------- */ const char *pszCENTER_LONG; if( CPLGetConfigOption( "CENTER_LONG", NULL ) != NULL ) { bSourceWrap = bTargetWrap = TRUE; dfSourceWrapLong = dfTargetWrapLong = atof(CPLGetConfigOption( "CENTER_LONG", "" )); CPLDebug( "OGRCT", "Wrap at %g.", dfSourceWrapLong ); } pszCENTER_LONG = poSRSSource->GetExtension( "GEOGCS", "CENTER_LONG" ); if( pszCENTER_LONG != NULL ) { dfSourceWrapLong = atof(pszCENTER_LONG); bSourceWrap = TRUE; CPLDebug( "OGRCT", "Wrap source at %g.", dfSourceWrapLong ); } pszCENTER_LONG = poSRSTarget->GetExtension( "GEOGCS", "CENTER_LONG" ); if( pszCENTER_LONG != NULL ) { dfTargetWrapLong = atof(pszCENTER_LONG); bTargetWrap = TRUE; CPLDebug( "OGRCT", "Wrap target at %g.", dfTargetWrapLong ); } bCheckWithInvertProj = CSLTestBoolean(CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", "NO" )); /* The threshold is rather experimental... Works well with the cases of ticket #2305 */ if (bSourceLatLong) dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", ".1" )); else /* 1 works well for most projections, except for +proj=aeqd that requires */ /* a tolerance of 10000 */ dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", "10000" )); /* -------------------------------------------------------------------- */ /* Establish PROJ.4 handle for source if projection. */ /* -------------------------------------------------------------------- */ // OGRThreadSafety: The following variable is not a thread safety issue // since the only issue is incrementing while accessing which at worse // means debug output could be one "increment" late. static int nDebugReportCount = 0; char *pszSrcProj4Defn = NULL; if( poSRSSource->exportToProj4( &pszSrcProj4Defn ) != OGRERR_NONE ) { CPLFree( pszSrcProj4Defn ); return FALSE; } if( strlen(pszSrcProj4Defn) == 0 ) { CPLFree( pszSrcProj4Defn ); CPLError( CE_Failure, CPLE_AppDefined, "No PROJ.4 translation for source SRS, coordinate\n" "transformation initialization has failed." ); return FALSE; } if (pjctx) psPJSource = pfn_pj_init_plus_ctx( pjctx, pszSrcProj4Defn ); else psPJSource = pfn_pj_init_plus( pszSrcProj4Defn ); if( psPJSource == NULL ) { if( pjctx != NULL) { int pj_errno = pfn_pj_ctx_get_errno(pjctx); /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLMutexHolderD(&hPROJMutex); CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n%s", pszSrcProj4Defn, pfn_pj_strerrno(pj_errno) ); } else if( pfn_pj_get_errno_ref != NULL && pfn_pj_strerrno != NULL ) { int *p_pj_errno = pfn_pj_get_errno_ref(); CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n%s", pszSrcProj4Defn, pfn_pj_strerrno(*p_pj_errno) ); } else { CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n", pszSrcProj4Defn ); } } if( nDebugReportCount < 10 ) CPLDebug( "OGRCT", "Source: %s", pszSrcProj4Defn ); if( psPJSource == NULL ) { CPLFree( pszSrcProj4Defn ); return FALSE; } /* -------------------------------------------------------------------- */ /* Establish PROJ.4 handle for target if projection. */ /* -------------------------------------------------------------------- */ char *pszDstProj4Defn = NULL; if( poSRSTarget->exportToProj4( &pszDstProj4Defn ) != OGRERR_NONE ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return FALSE; } if( strlen(pszDstProj4Defn) == 0 ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); CPLError( CE_Failure, CPLE_AppDefined, "No PROJ.4 translation for destination SRS, coordinate\n" "transformation initialization has failed." ); return FALSE; } if (pjctx) psPJTarget = pfn_pj_init_plus_ctx( pjctx, pszDstProj4Defn ); else psPJTarget = pfn_pj_init_plus( pszDstProj4Defn ); if( psPJTarget == NULL ) CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.", pszDstProj4Defn ); if( nDebugReportCount < 10 ) { CPLDebug( "OGRCT", "Target: %s", pszDstProj4Defn ); nDebugReportCount++; } if( psPJTarget == NULL ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return FALSE; } /* Determine if we really have a transformation to do */ bIdentityTransform = (strcmp(pszSrcProj4Defn, pszDstProj4Defn) == 0); /* In case of identity transform, under the following conditions, */ /* we can also avoid transforming from deegrees <--> radians. */ if( bIdentityTransform && bSourceLatLong && !bSourceWrap && bTargetLatLong && !bTargetWrap && abs(dfSourceToRadians * dfTargetFromRadians - 1.0) < 1e-10 ) { /*bSourceLatLong = FALSE; bTargetLatLong = FALSE;*/ } CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return TRUE; }
int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn, OGRSpatialReference * poTargetIn ) { if( poSourceIn == NULL || poTargetIn == NULL ) return FALSE; poSRSSource = poSourceIn->Clone(); poSRSTarget = poTargetIn->Clone(); bSourceLatLong = CPL_TO_BOOL(poSRSSource->IsGeographic()); bTargetLatLong = CPL_TO_BOOL(poSRSTarget->IsGeographic()); /* -------------------------------------------------------------------- */ /* Setup source and target translations to radians for lat/long */ /* systems. */ /* -------------------------------------------------------------------- */ dfSourceToRadians = DEG_TO_RAD; bSourceWrap = false; dfSourceWrapLong = 0.0; if( bSourceLatLong ) { OGR_SRSNode *poUNITS = poSRSSource->GetAttrNode( "GEOGCS|UNIT" ); if( poUNITS && poUNITS->GetChildCount() >= 2 ) { dfSourceToRadians = CPLAtof(poUNITS->GetChild(1)->GetValue()); if( dfSourceToRadians == 0.0 ) dfSourceToRadians = DEG_TO_RAD; } } dfTargetFromRadians = RAD_TO_DEG; bTargetWrap = false; dfTargetWrapLong = 0.0; if( bTargetLatLong ) { OGR_SRSNode *poUNITS = poSRSTarget->GetAttrNode( "GEOGCS|UNIT" ); if( poUNITS && poUNITS->GetChildCount() >= 2 ) { double dfTargetToRadians = CPLAtof(poUNITS->GetChild(1)->GetValue()); if( dfTargetToRadians != 0.0 ) dfTargetFromRadians = 1 / dfTargetToRadians; } } /* -------------------------------------------------------------------- */ /* Preliminary logic to setup wrapping. */ /* -------------------------------------------------------------------- */ if( CPLGetConfigOption( "CENTER_LONG", NULL ) != NULL ) { bSourceWrap = true; bTargetWrap = true; dfSourceWrapLong = dfTargetWrapLong = CPLAtof(CPLGetConfigOption( "CENTER_LONG", "" )); CPLDebug( "OGRCT", "Wrap at %g.", dfSourceWrapLong ); } const char *pszCENTER_LONG = poSRSSource->GetExtension( "GEOGCS", "CENTER_LONG" ); if( pszCENTER_LONG != NULL ) { dfSourceWrapLong = CPLAtof(pszCENTER_LONG); bSourceWrap = true; CPLDebug( "OGRCT", "Wrap source at %g.", dfSourceWrapLong ); } pszCENTER_LONG = poSRSTarget->GetExtension( "GEOGCS", "CENTER_LONG" ); if( pszCENTER_LONG != NULL ) { dfTargetWrapLong = CPLAtof(pszCENTER_LONG); bTargetWrap = true; CPLDebug( "OGRCT", "Wrap target at %g.", dfTargetWrapLong ); } bCheckWithInvertProj = CPLTestBool(CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", "NO" )); // The threshold is experimental. Works well with the cases of ticket #2305. if( bSourceLatLong ) dfThreshold = CPLAtof(CPLGetConfigOption( "THRESHOLD", ".1" )); else // 1 works well for most projections, except for +proj=aeqd that // requires a tolerance of 10000. dfThreshold = CPLAtof(CPLGetConfigOption( "THRESHOLD", "10000" )); // OGRThreadSafety: The following variable is not a thread safety issue // since the only issue is incrementing while accessing which at worse // means debug output could be one "increment" late. static int nDebugReportCount = 0; char *pszSrcProj4Defn = NULL; if( poSRSSource->exportToProj4( &pszSrcProj4Defn ) != OGRERR_NONE ) { CPLFree( pszSrcProj4Defn ); return FALSE; } if( strlen(pszSrcProj4Defn) == 0 ) { CPLFree( pszSrcProj4Defn ); CPLError( CE_Failure, CPLE_AppDefined, "No PROJ.4 translation for source SRS, coordinate\n" "transformation initialization has failed." ); return FALSE; } char *pszDstProj4Defn = NULL; if( poSRSTarget->exportToProj4( &pszDstProj4Defn ) != OGRERR_NONE ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return FALSE; } if( strlen(pszDstProj4Defn) == 0 ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); CPLError( CE_Failure, CPLE_AppDefined, "No PROJ.4 translation for destination SRS, coordinate\n" "transformation initialization has failed." ); return FALSE; } /* -------------------------------------------------------------------- */ /* Optimization to avoid useless nadgrids evaluation. */ /* For example when converting between WGS84 and WebMercator */ /* -------------------------------------------------------------------- */ if( pszSrcProj4Defn[strlen(pszSrcProj4Defn)-1] == ' ' ) pszSrcProj4Defn[strlen(pszSrcProj4Defn)-1] = 0; if( pszDstProj4Defn[strlen(pszDstProj4Defn)-1] == ' ' ) pszDstProj4Defn[strlen(pszDstProj4Defn)-1] = 0; char* pszNeedle = strstr(pszSrcProj4Defn, " "); if( pszNeedle ) memmove(pszNeedle, pszNeedle + 1, strlen(pszNeedle + 1)+1); pszNeedle = strstr(pszDstProj4Defn, " "); if( pszNeedle ) memmove(pszNeedle, pszNeedle + 1, strlen(pszNeedle + 1)+1); if( (strstr(pszSrcProj4Defn, "+datum=WGS84") != NULL || strstr(pszSrcProj4Defn, "+ellps=WGS84 +towgs84=0,0,0,0,0,0,0 ") != NULL) && strstr(pszDstProj4Defn, "+nadgrids=@null ") != NULL && strstr(pszDstProj4Defn, "+towgs84") == NULL ) { char* pszDst = strstr(pszSrcProj4Defn, "+towgs84=0,0,0,0,0,0,0 "); if( pszDst != NULL ) { char *pszSrc = pszDst + strlen("+towgs84=0,0,0,0,0,0,0 "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); } else { memcpy(strstr(pszSrcProj4Defn, "+datum=WGS84"), "+ellps", 6); } pszDst = strstr(pszDstProj4Defn, "+nadgrids=@null "); char *pszSrc = pszDst + strlen("+nadgrids=@null "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); pszDst = strstr(pszDstProj4Defn, "+wktext "); if( pszDst ) { pszSrc = pszDst + strlen("+wktext "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); } //bWGS84ToWebMercator = // strcmp(pszSrcProj4Defn, "+proj=longlat +ellps=WGS84 +no_defs") == 0 && // strcmp(pszDstProj4Defn, "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +no_defs") == 0; } else if( (strstr(pszDstProj4Defn, "+datum=WGS84") != NULL || strstr(pszDstProj4Defn, "+ellps=WGS84 +towgs84=0,0,0,0,0,0,0 ") != NULL) && strstr(pszSrcProj4Defn, "+nadgrids=@null ") != NULL && strstr(pszSrcProj4Defn, "+towgs84") == NULL ) { char* pszDst = strstr(pszDstProj4Defn, "+towgs84=0,0,0,0,0,0,0 "); if( pszDst != NULL) { char* pszSrc = pszDst + strlen("+towgs84=0,0,0,0,0,0,0 "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); } else memcpy(strstr(pszDstProj4Defn, "+datum=WGS84"), "+ellps", 6); pszDst = strstr(pszSrcProj4Defn, "+nadgrids=@null "); char* pszSrc = pszDst + strlen("+nadgrids=@null "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); pszDst = strstr(pszSrcProj4Defn, "+wktext "); if( pszDst ) { pszSrc = pszDst + strlen("+wktext "); memmove(pszDst, pszSrc, strlen(pszSrc)+1); } bWebMercatorToWGS84 = strcmp(pszDstProj4Defn, "+proj=longlat +ellps=WGS84 +no_defs") == 0 && strcmp(pszSrcProj4Defn, "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 " "+x_0=0.0 +y_0=0 +k=1.0 +units=m +no_defs") == 0; } /* -------------------------------------------------------------------- */ /* Establish PROJ.4 handle for source if projection. */ /* -------------------------------------------------------------------- */ if( !bWebMercatorToWGS84 ) { if (pjctx) psPJSource = pfn_pj_init_plus_ctx( pjctx, pszSrcProj4Defn ); else psPJSource = pfn_pj_init_plus( pszSrcProj4Defn ); if( psPJSource == NULL ) { if( pjctx != NULL) { int l_pj_errno = pfn_pj_ctx_get_errno(pjctx); /* pfn_pj_strerrno not yet thread-safe in PROJ 4.8.0 */ CPLMutexHolderD(&hPROJMutex); CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n%s", pszSrcProj4Defn, pfn_pj_strerrno(l_pj_errno) ); } else if( pfn_pj_get_errno_ref != NULL && pfn_pj_strerrno != NULL ) { int *p_pj_errno = pfn_pj_get_errno_ref(); CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n%s", pszSrcProj4Defn, pfn_pj_strerrno(*p_pj_errno) ); } else { CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.\n", pszSrcProj4Defn ); } } } if( nDebugReportCount < 10 ) CPLDebug( "OGRCT", "Source: %s", pszSrcProj4Defn ); if( !bWebMercatorToWGS84 && psPJSource == NULL ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return FALSE; } /* -------------------------------------------------------------------- */ /* Establish PROJ.4 handle for target if projection. */ /* -------------------------------------------------------------------- */ if( !bWebMercatorToWGS84 ) { if (pjctx) psPJTarget = pfn_pj_init_plus_ctx( pjctx, pszDstProj4Defn ); else psPJTarget = pfn_pj_init_plus( pszDstProj4Defn ); if( psPJTarget == NULL ) CPLError( CE_Failure, CPLE_NotSupported, "Failed to initialize PROJ.4 with `%s'.", pszDstProj4Defn ); } if( nDebugReportCount < 10 ) { CPLDebug( "OGRCT", "Target: %s", pszDstProj4Defn ); nDebugReportCount++; } if( !bWebMercatorToWGS84 && psPJTarget == NULL ) { CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return FALSE; } /* Determine if we really have a transformation to do */ bIdentityTransform = strcmp(pszSrcProj4Defn, pszDstProj4Defn) == 0; #if 0 /* In case of identity transform, under the following conditions, */ /* we can also avoid transforming from degrees <--> radians. */ if( bIdentityTransform && bSourceLatLong && !bSourceWrap && bTargetLatLong && !bTargetWrap && fabs(dfSourceToRadians * dfTargetFromRadians - 1.0) < 1e-10 ) { // bSourceLatLong = false; // bTargetLatLong = false; } #endif CPLFree( pszSrcProj4Defn ); CPLFree( pszDstProj4Defn ); return TRUE; }