Example #1
0
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 ();
}
Example #2
0
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
}