crs-syncdb.diff

patch to introduce crssync for synchronization on install - Jürgen Fischer, 2011-03-27 09:00 AM

Download (12.6 KB)

View differences:

python/core/qgscoordinatereferencesystem.sip (working copy)
253 253
         * @return QGis::UnitType that gives the units for the coordinate system
254 254
         */
255 255
        QGis::UnitType mapUnits() const;
256

  
257

  
256
        /*! Update proj.4 parameters in our database from proj.4
257
         * @returns number of updated CRS on success and
258
         *   negative number of failed updates in case of errors.
259
         * @note added in 1.7
260
         */
261
        static int syncDb();
258 262
};
259

  
260

  
debian/qgis-providers.install (working copy)
8 8
usr/lib/qgis/plugins/libspatialiteprovider.so
9 9
usr/lib/qgis/plugins/libosmprovider.so 
10 10
usr/lib/qgis/plugins/libgdalprovider.so 
11
usr/lib/qgis/crssync
debian/qgis-providers.postinst (revision 0)
1
#!/bin/sh
2

  
3
set -e
4

  
5
case "$1" in
6
	configure)
7
		/usr/lib/qgis/crssync
8
		;;
9
esac	
src/crssync/main.cpp (revision 0)
1
/***************************************************************************
2
                             crssync.cpp
3
                             sync srs.db with proj
4
                             -------------------
5
    begin                : 2011
6
    copyright            : (C) 2011 by Juergen E. Fischer, norBIT GmbH
7
    email                : jef at norbit dot de
8
***************************************************************************/
9

  
10
/***************************************************************************
11
 *                                                                         *
12
 *   This program is free software; you can redistribute it and/or modify  *
13
 *   it under the terms of the GNU General Public License as published by  *
14
 *   the Free Software Foundation; either version 2 of the License, or     *
15
 *   (at your option) any later version.                                   *
16
 *                                                                         *
17
 ***************************************************************************/
18
#include "qgsapplication.h"
19
#include "qgscoordinatereferencesystem.h"
20
#include "qgsconfig.h"
21

  
22
#include <QRegExp>
23

  
24
#include <iostream>
25
#include <limits>
26

  
27
#include <cpl_error.h>
28

  
29
void CPL_STDCALL showError( CPLErr errClass, int errNo, const char *msg )
30
{
31
  QRegExp re( "EPSG PCS/GCS code \\d+ not found in EPSG support files.  Is this a valid\nEPSG coordinate system?" );
32
  if ( errNo != 6 && !re.exactMatch( msg ) )
33
  {
34
    std::cerr << msg;
35
  }
36
}
37

  
38
int main( int argc, char ** argv )
39
{
40
  QgsApplication a( argc, argv, false );
41

  
42
#if defined(Q_WS_MACX)
43
  // If we're on Mac, we have the resource library way above us...
44
  a.setPkgDataPath( QgsApplication::prefixPath() + "/../../../../" + QString( QGIS_DATA_SUBDIR ) );
45
#elif defined(Q_WS_WIN)
46
  a.setPkgDataPath( QgsApplication::prefixPath() + "/" QGIS_DATA_SUBDIR );
47
#else
48
  a.setPkgDataPath( QgsApplication::prefixPath() + "/../" QGIS_DATA_SUBDIR );
49
#endif
50

  
51
  std::cout << "Synchronizing CRS database with PROJ definitions." << std::endl;
52

  
53
  CPLPushErrorHandler( showError );
54

  
55
  int res = QgsCoordinateReferenceSystem::syncDb();
56

  
57
  CPLPopErrorHandler();
58

  
59
  if ( res == 0 )
60
  {
61
    std::cout << "No CRS updates were necessary." << std::endl;
62
  }
63
  else if ( res > 0 )
64
  {
65
    std::cout << res << " CRSs updated." << std::endl;
66
  }
67
  else if ( res == std::numeric_limits<int>::min() )
68
  {
69
    std::cout << "CRSs synchronization not possible." << std::endl;
70
  }
71
  else if ( res < 0 )
72
  {
73
    std::cout << -res << " CRSs could not be updated." << std::endl;
74
  }
75

  
76
  return 0;
77
}
src/core/qgscoordinatereferencesystem.cpp (working copy)
32 32
#include "qgis.h" //const vals declared here
33 33

  
34 34
#include <sqlite3.h>
35
#include <proj_api.h>
35 36

  
36 37
//gdal and ogr includes (needed for == operator)
37 38
#include <ogr_srs_api.h>
......
1353 1354
  value.replace( "'", "''" );
1354 1355
  return value.prepend( "'" ).append( "'" );
1355 1356
}
1357

  
1358
int QgsCoordinateReferenceSystem::syncDb()
1359
{
1360
  int updated = 0, errors = 0;
1361
  sqlite3 *database;
1362
  if ( sqlite3_open( QgsApplication::srsDbFilePath().toUtf8().constData(), &database ) != SQLITE_OK )
1363
  {
1364
    qCritical( "Can't open database: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1365
    return -1;
1366
  }
1367

  
1368
  const char *tail;
1369
  sqlite3_stmt *select;
1370
  QString sql = "select auth_name,auth_id,parameters from tbl_srs WHERE auth_name IS NOT NULL AND auth_id IS NOT NULL";
1371
  if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) != SQLITE_OK )
1372
  {
1373
    qCritical( "Could not prepare: %s [%s]\n", sql.toAscii().constData(), sqlite3_errmsg( database ) );
1374
    sqlite3_close( database );
1375
    return -1;
1376
  }
1377

  
1378
  OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL );
1379

  
1380
  while ( sqlite3_step( select ) == SQLITE_ROW )
1381
  {
1382
    const char *auth_name = ( const char * ) sqlite3_column_text( select, 0 );
1383
    const char *auth_id   = ( const char * ) sqlite3_column_text( select, 1 );
1384
    const char *params    = ( const char * ) sqlite3_column_text( select, 2 );
1385

  
1386
    QString proj4;
1387

  
1388
    QString input = QString( "%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id );
1389
    QgsDebugMsgLevel( QString( "fetching crs %1" ).arg( input ), 3 );
1390

  
1391
#if !defined(PJ_VERSION) || PJ_VERSION!=470
1392
    // 4.7.0 has a bug that crashes after 16 consecutive pj_init_plus with different strings
1393
    if ( proj4.isEmpty() )
1394
    {
1395
      input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id );
1396
      projPJ pj = pj_init_plus( input.toAscii() );
1397
      if ( !pj )
1398
      {
1399
        input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id );
1400
        pj = pj_init_plus( input.toAscii() );
1401
      }
1402

  
1403
      if ( pj )
1404
      {
1405
        char *def = pj_get_def( pj, 0 );
1406
        if ( def )
1407
        {
1408
          proj4 = def;
1409
          pj_dalloc( def );
1410

  
1411
          input.prepend( ' ' ).append( ' ' );
1412
          if ( proj4.startsWith( input ) )
1413
          {
1414
            proj4 = proj4.mid( input.size() );
1415
          }
1416
        }
1417
        else
1418
        {
1419
          QgsDebugMsg( QString( "could not retrieve proj string for %1 from PROJ" ).arg( input ) );
1420
        }
1421
      }
1422
      else
1423
      {
1424
        QgsDebugMsgLevel( QString( "could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
1425
      }
1426

  
1427
      pj_free( pj );
1428
    }
1429
#else
1430
    // otherwise check OGR
1431
    if ( !proj4.isEmpty() )
1432
    {
1433
      OGRErr ogrErr = OSRSetFromUserInput( crs, input.toAscii() );
1434
      if ( ogrErr != OGRERR_NONE )
1435
      {
1436
        input = QString( "%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id );
1437
        ogrErr = OSRSetFromUserInput( crs, input.toAscii() );
1438
      }
1439

  
1440
      if ( ogrErr == OGRERR_NONE )
1441
      {
1442
        char *output = 0;
1443

  
1444
        if ( OSRExportToProj4( crs, &output ) == OGRERR_NONE )
1445
        {
1446
          QString proj4ogr = output;
1447

  
1448
#if 0
1449
          QString proj4proj = proj4;
1450

  
1451
          proj4proj.replace( QRegExp( "\\.0+([, ])" ), "\\1" );
1452
          proj4proj.replace( QRegExp( "(\\.\\d*[1-9])0+([, ])" ), "\\1\\2" );
1453
          proj4proj.replace( ".0000000001 ", " " );
1454
          proj4proj.replace( ".10000000000001 ", ".1 " );
1455
          proj4proj.replace( ".50000000000001 ", ".5 " );
1456
          proj4proj.replace( ".399999999999999 ", ".4 " );
1457
          proj4proj.replace( ".16500000000001 ", ".165 " );
1458
          proj4proj.replace( " +towgs84=0,0,0,0,0,0,0 ", " +datum=WGS84 " );
1459

  
1460
          if ( proj4proj.contains( " +datum=WGS84 " ) && proj4proj.endsWith( " +towgs84=0,0,0" ) )
1461
          {
1462
            proj4proj.replace( " +towgs84=0,0,0", "" );
1463
          }
1464

  
1465
          proj4ogr.replace( " +towgs84=0,0,0,0,0,0,0 ", " +datum=WGS84 " );
1466
          proj4ogr.replace( " +a=6378249.145 +b=6356514.96582849 ", " +ellps=clrk80 " );
1467
          proj4ogr.replace( " +gamma=0 ", " " );
1468
          proj4ogr.replace( " +alpha=0 ", " " );
1469

  
1470
          if ( proj4ogr != proj4proj )
1471
          {
1472
            qWarning( "%s", QString( "Mismatch for %1:%2 in OGR and PROJ found:\n  PROJ:'%3'\n  OGR :'%4'" ).arg( auth_name ).arg( auth_id ).arg( proj4proj ).arg( proj4ogr ).toAscii().constData() );
1473
          }
1474
#endif
1475

  
1476
          proj4 = proj4ogr.trimmed();
1477
        }
1478
        else
1479
        {
1480
          QgsDebugMsg( QString( "could not retrieve proj.4 string for %1 from OGR" ).arg( input ) );
1481
        }
1482

  
1483
        if ( output )
1484
          CPLFree( output );
1485
      }
1486
    }
1487
#endif
1488

  
1489
    if ( proj4.isEmpty() )
1490
    {
1491
      continue;
1492
    }
1493

  
1494
    if ( proj4 != params )
1495
    {
1496
      char *errMsg = NULL;
1497

  
1498
      sql = QString( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
1499
            .arg( quotedValue( proj4 ) )
1500
            .arg( quotedValue( auth_name ) )
1501
            .arg( quotedValue( auth_id ) );
1502

  
1503
      if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) != SQLITE_OK )
1504
      {
1505
        qCritical( "Could not execute: %s [%s/%s]\n",
1506
                   sql.toLocal8Bit().constData(),
1507
                   sqlite3_errmsg( database ),
1508
                   errMsg ? errMsg : "(unknown error)" );
1509
        errors++;
1510
      }
1511
      else
1512
      {
1513
        updated++;
1514
        QgsDebugMsgLevel( "Updated: " + sql, 3 );
1515
      }
1516

  
1517
      if ( errMsg )
1518
        sqlite3_free( errMsg );
1519
    }
1520
  }
1521

  
1522
  OSRDestroySpatialReference( crs );
1523

  
1524
  sqlite3_finalize( select );
1525
  sqlite3_close( database );
1526

  
1527
  if ( errors > 0 )
1528
    return -errors;
1529
  else
1530
    return updated;
1531
}
src/crssync/CMakeLists.txt (revision 0)
1
ADD_EXECUTABLE(crssync main.cpp)
2
INCLUDE_DIRECTORIES(
3
  ../core
4
  ${GDAL_INCLUDE_DIR}
5
  ${PROJ_INCLUDE_DIR}
6
)
7

  
8
TARGET_LINK_LIBRARIES(crssync
9
  qgis_core
10
  ${PROJ_LIBRARY}
11
  ${GDAL_LIBRARY}
12
)
13

  
14
INSTALL(CODE "MESSAGE(\"Installing crssync ...\")")
15
INSTALL(TARGETS crssync RUNTIME DESTINATION ${QGIS_LIBEXEC_DIR})
src/core/qgscoordinatereferencesystem.h (working copy)
322 322
    /*! Get user hint for validation
323 323
     */
324 324
    QString validationHint();
325
    /*! Update proj.4 parameters in our database from proj.4
326
     * @returns number of updated CRS on success and
327
     *   negative number of failed updates in case of errors.
328
     * @note added in 1.7
329
     */
330
    static int syncDb();
331

  
325 332
    // Mutators -----------------------------------
326 333
    // We don't want to expose these to the public api since they wont create
327 334
    // a fully valid crs. Programmers should use the createFrom* methods rather
......
418 425
    long getRecordCount();
419 426

  
420 427
    //! Helper for sql-safe value quoting
421
    QString quotedValue( QString value );
428
    static QString quotedValue( QString value );
422 429

  
423 430
    void *mCRS;
424 431

  
src/CMakeLists.txt (working copy)
1
SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer)
1
SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer crssync)
2 2

  
3 3
IF (WITH_BINDINGS)
4 4
  SUBDIRS(python)
ms-windows/osgeo4w/postinstall.bat (working copy)
8 8
set OSGEO4W_ROOT=%OSGEO4W_ROOT:\=\\%
9 9
textreplace -std -t "%O4W_ROOT%\apps\@package@\bin\qgis.reg"
10 10
"%WINDIR%\regedit" /s "%O4W_ROOT%\apps\@package@\bin\qgis.reg"
11

  
12
start "CRS synchronization" /wait %OSGEO4W_ROOT%\apps\@package@\crssync