static int roundtrip (const char *args) { /***************************************************************************** Check how far we go from the ACCEPTed point when doing successive back/forward transformation pairs. Without args, roundtrip defaults to 100 iterations: roundtrip With one arg, roundtrip will default to a tolerance of T.tolerance: roundtrip ntrips With two args: roundtrip ntrips tolerance Always returns 0. ******************************************************************************/ int ntrips; double d, r, ans; char *endp; PJ_COORD coo; if (nullptr==T.P) { if (T.ignore == proj_errno(T.P)) return another_skip(); return another_failure (); } ans = proj_strtod (args, &endp); if (endp==args) { /* Default to 100 iterations if not args. */ ntrips = 100; } else { if (ans < 1.0 || ans > 1000000.0) { errmsg (2, "Invalid number of roundtrips: %lf\n", ans); return another_failing_roundtrip (); } ntrips = (int)ans; } d = strtod_scaled (endp, 1); d = d==HUGE_VAL? T.tolerance: d; /* input ("accepted") values - probably in degrees */ coo = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; r = proj_roundtrip (T.P, T.dir, ntrips, &coo); if (r <= d) return another_succeeding_roundtrip (); if (T.verbosity > -1) { if (0==T.op_ko && T.verbosity < 2) banner (T.operation); fprintf (T.fout, "%s", T.op_ko? " -----\n": delim); fprintf (T.fout, " FAILURE in %s(%d):\n", opt_strip_path (T.curr_file), (int) F->lineno); fprintf (T.fout, " roundtrip deviation: %.6f mm, expected: %.6f mm\n", 1000*r, 1000*d); } return another_failing_roundtrip (); }
void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *y, double *z, TransformDirection direction ) const { if ( !d->mIsValid || d->mShortCircuit ) return; // Refuse to transform the points if the srs's are invalid if ( !d->mSourceCRS.isValid() ) { QgsMessageLog::logMessage( QObject::tr( "The source spatial reference system (CRS) is not valid. " "The coordinates can not be reprojected. The CRS is: %1" ) .arg( d->mSourceCRS.toProj4() ), QObject::tr( "CRS" ) ); return; } if ( !d->mDestCRS.isValid() ) { QgsMessageLog::logMessage( QObject::tr( "The destination spatial reference system (CRS) is not valid. " "The coordinates can not be reprojected. The CRS is: %1" ).arg( d->mDestCRS.toProj4() ), QObject::tr( "CRS" ) ); return; } #ifdef COORDINATE_TRANSFORM_VERBOSE double xorg = *x; double yorg = *y; QgsDebugMsg( QStringLiteral( "[[[[[[ Number of points to transform: %1 ]]]]]]" ).arg( numPoints ) ); #endif #ifdef QGISDEBUG if ( !mHasContext ) QgsDebugMsgLevel( QStringLiteral( "No QgsCoordinateTransformContext context set for transform" ), 4 ); #endif // use proj4 to do the transform // if the source/destination projection is lat/long, convert the points to radians // prior to transforming ProjData projData = d->threadLocalProjData(); #if PROJ_VERSION_MAJOR<6 bool sourceIsLatLong = false; bool destIsLatLong = false; projPJ sourceProj = projData.first; projPJ destProj = projData.second; sourceIsLatLong = pj_is_latlong( sourceProj ); destIsLatLong = pj_is_latlong( destProj ); if ( ( destIsLatLong && ( direction == ReverseTransform ) ) || ( sourceIsLatLong && ( direction == ForwardTransform ) ) ) { for ( int i = 0; i < numPoints; ++i ) { x[i] *= DEG_TO_RAD; y[i] *= DEG_TO_RAD; } } #endif int projResult = 0; #if PROJ_VERSION_MAJOR>=6 const bool sourceAxisOrderSwapped = direction == ForwardTransform ? d->mSourceAxisOrderSwapped : d->mDestAxisOrderSwapped; proj_trans_generic( projData, direction == ForwardTransform ? PJ_FWD : PJ_INV, !sourceAxisOrderSwapped ? x : y, sizeof( double ), numPoints, !sourceAxisOrderSwapped ? y : x, sizeof( double ), numPoints, z, sizeof( double ), numPoints, nullptr, sizeof( double ), 0 ); projResult = proj_errno( projData ); // ewww - this logic is gross. We should drop support for PROJ 6.0 as quickly as possible and dump this code (in favour of built in methods used for >=6.1 builds) if ( projResult == 0 && ( d->mSourceAxisOrderSwapped != d->mDestAxisOrderSwapped ) ) { size_t size = sizeof( double ) * numPoints; void *tmp = malloc( size ); memcpy( tmp, x, size ); memcpy( x, y, size ); memcpy( y, tmp, size ); free( tmp ); } #else if ( direction == ReverseTransform ) { projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z ); } else { Q_ASSERT( sourceProj ); Q_ASSERT( destProj ); projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z ); } #endif if ( projResult != 0 ) { //something bad happened.... QString points; for ( int i = 0; i < numPoints; ++i ) { if ( direction == ForwardTransform ) { points += QStringLiteral( "(%1, %2)\n" ).arg( x[i], 0, 'f' ).arg( y[i], 0, 'f' ); } else { #if PROJ_VERSION_MAJOR>=6 points += QStringLiteral( "(%1, %2)\n" ).arg( x[i], 0, 'f' ).arg( y[i], 0, 'f' ); #else points += QStringLiteral( "(%1, %2)\n" ).arg( x[i] * RAD_TO_DEG, 0, 'f' ).arg( y[i] * RAD_TO_DEG, 0, 'f' ); #endif } } QString dir = ( direction == ForwardTransform ) ? QObject::tr( "forward transform" ) : QObject::tr( "inverse transform" ); #if PROJ_VERSION_MAJOR>=6 QgsProjUtils::proj_pj_unique_ptr src( proj_get_source_crs( QgsProjContext::get(), projData ) ); QgsProjUtils::proj_pj_unique_ptr dest( proj_get_source_crs( QgsProjContext::get(), projData ) ); QString msg = QObject::tr( "%1 of\n" "%2" "PROJ: %3\n" "Error: %4" ) .arg( dir, points, proj_as_proj_string( QgsProjContext::get(), projData, PJ_PROJ_5, nullptr ), QString::fromUtf8( proj_errno_string( projResult ) ) ); #else char *srcdef = pj_get_def( sourceProj, 0 ); char *dstdef = pj_get_def( destProj, 0 ); QString msg = QObject::tr( "%1 of\n" "%2" "PROJ: %3 +to %4\n" "Error: %5" ) .arg( dir, points, srcdef, dstdef, QString::fromUtf8( pj_strerrno( projResult ) ) ); pj_dalloc( srcdef ); pj_dalloc( dstdef ); #endif QgsDebugMsg( "Projection failed emitting invalid transform signal: " + msg ); QgsDebugMsg( QStringLiteral( "throwing exception" ) ); throw QgsCsException( msg ); } #if PROJ_VERSION_MAJOR<6 // if the result is lat/long, convert the results from radians back // to degrees if ( ( destIsLatLong && ( direction == ForwardTransform ) ) || ( sourceIsLatLong && ( direction == ReverseTransform ) ) ) { for ( int i = 0; i < numPoints; ++i ) { x[i] *= RAD_TO_DEG; y[i] *= RAD_TO_DEG; } } #endif #ifdef COORDINATE_TRANSFORM_VERBOSE QgsDebugMsg( QStringLiteral( "[[[[[[ Projected %1, %2 to %3, %4 ]]]]]]" ) .arg( xorg, 0, 'g', 15 ).arg( yorg, 0, 'g', 15 ) .arg( *x, 0, 'g', 15 ).arg( *y, 0, 'g', 15 ) ); #endif }