Index: python/core/qgscoordinatereferencesystem.sip =================================================================== --- python/core/qgscoordinatereferencesystem.sip (revision 15613) +++ python/core/qgscoordinatereferencesystem.sip (working copy) @@ -253,8 +253,10 @@ * @return QGis::UnitType that gives the units for the coordinate system */ QGis::UnitType mapUnits() const; - - + /*! Update proj.4 parameters in our database from proj.4 + * @returns number of updated CRS on success and + * negative number of failed updates in case of errors. + * @note added in 1.7 + */ + static int syncDb(); }; - - Index: debian/qgis-providers.install =================================================================== --- debian/qgis-providers.install (revision 15613) +++ debian/qgis-providers.install (working copy) @@ -8,3 +8,4 @@ usr/lib/qgis/plugins/libspatialiteprovider.so usr/lib/qgis/plugins/libosmprovider.so usr/lib/qgis/plugins/libgdalprovider.so +usr/lib/qgis/crssync Index: debian/qgis-providers.postinst =================================================================== --- debian/qgis-providers.postinst (revision 0) +++ debian/qgis-providers.postinst (revision 0) @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e + +case "$1" in + configure) + /usr/lib/qgis/crssync + ;; +esac Property changes on: debian/qgis-providers.postinst ___________________________________________________________________ Added: svn:executable + * Index: src/crssync/main.cpp =================================================================== --- src/crssync/main.cpp (revision 0) +++ src/crssync/main.cpp (revision 0) @@ -0,0 +1,77 @@ +/*************************************************************************** + crssync.cpp + sync srs.db with proj + ------------------- + begin : 2011 + copyright : (C) 2011 by Juergen E. Fischer, norBIT GmbH + email : jef at norbit dot de +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "qgsapplication.h" +#include "qgscoordinatereferencesystem.h" +#include "qgsconfig.h" + +#include + +#include +#include + +#include + +void CPL_STDCALL showError( CPLErr errClass, int errNo, const char *msg ) +{ + QRegExp re( "EPSG PCS/GCS code \\d+ not found in EPSG support files. Is this a valid\nEPSG coordinate system?" ); + if ( errNo != 6 && !re.exactMatch( msg ) ) + { + std::cerr << msg; + } +} + +int main( int argc, char ** argv ) +{ + QgsApplication a( argc, argv, false ); + +#if defined(Q_WS_MACX) + // If we're on Mac, we have the resource library way above us... + a.setPkgDataPath( QgsApplication::prefixPath() + "/../../../../" + QString( QGIS_DATA_SUBDIR ) ); +#elif defined(Q_WS_WIN) + a.setPkgDataPath( QgsApplication::prefixPath() + "/" QGIS_DATA_SUBDIR ); +#else + a.setPkgDataPath( QgsApplication::prefixPath() + "/../" QGIS_DATA_SUBDIR ); +#endif + + std::cout << "Synchronizing CRS database with PROJ definitions." << std::endl; + + CPLPushErrorHandler( showError ); + + int res = QgsCoordinateReferenceSystem::syncDb(); + + CPLPopErrorHandler(); + + if ( res == 0 ) + { + std::cout << "No CRS updates were necessary." << std::endl; + } + else if ( res > 0 ) + { + std::cout << res << " CRSs updated." << std::endl; + } + else if ( res == std::numeric_limits::min() ) + { + std::cout << "CRSs synchronization not possible." << std::endl; + } + else if ( res < 0 ) + { + std::cout << -res << " CRSs could not be updated." << std::endl; + } + + return 0; +} Index: src/core/qgscoordinatereferencesystem.cpp =================================================================== --- src/core/qgscoordinatereferencesystem.cpp (revision 15613) +++ src/core/qgscoordinatereferencesystem.cpp (working copy) @@ -32,6 +32,7 @@ #include "qgis.h" //const vals declared here #include +#include //gdal and ogr includes (needed for == operator) #include @@ -1353,3 +1354,178 @@ value.replace( "'", "''" ); return value.prepend( "'" ).append( "'" ); } + +int QgsCoordinateReferenceSystem::syncDb() +{ + int updated = 0, errors = 0; + sqlite3 *database; + if ( sqlite3_open( QgsApplication::srsDbFilePath().toUtf8().constData(), &database ) != SQLITE_OK ) + { + qCritical( "Can't open database: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) ); + return -1; + } + + const char *tail; + sqlite3_stmt *select; + QString sql = "select auth_name,auth_id,parameters from tbl_srs WHERE auth_name IS NOT NULL AND auth_id IS NOT NULL"; + if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) != SQLITE_OK ) + { + qCritical( "Could not prepare: %s [%s]\n", sql.toAscii().constData(), sqlite3_errmsg( database ) ); + sqlite3_close( database ); + return -1; + } + + OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL ); + + while ( sqlite3_step( select ) == SQLITE_ROW ) + { + const char *auth_name = ( const char * ) sqlite3_column_text( select, 0 ); + const char *auth_id = ( const char * ) sqlite3_column_text( select, 1 ); + const char *params = ( const char * ) sqlite3_column_text( select, 2 ); + + QString proj4; + + QString input = QString( "%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id ); + QgsDebugMsgLevel( QString( "fetching crs %1" ).arg( input ), 3 ); + +#if !defined(PJ_VERSION) || PJ_VERSION!=470 + // 4.7.0 has a bug that crashes after 16 consecutive pj_init_plus with different strings + if ( proj4.isEmpty() ) + { + input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id ); + projPJ pj = pj_init_plus( input.toAscii() ); + if ( !pj ) + { + input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id ); + pj = pj_init_plus( input.toAscii() ); + } + + if ( pj ) + { + char *def = pj_get_def( pj, 0 ); + if ( def ) + { + proj4 = def; + pj_dalloc( def ); + + input.prepend( ' ' ).append( ' ' ); + if ( proj4.startsWith( input ) ) + { + proj4 = proj4.mid( input.size() ); + } + } + else + { + QgsDebugMsg( QString( "could not retrieve proj string for %1 from PROJ" ).arg( input ) ); + } + } + else + { + QgsDebugMsgLevel( QString( "could not retrieve crs for %1 from PROJ" ).arg( input ), 3 ); + } + + pj_free( pj ); + } +#else + // otherwise check OGR + if ( !proj4.isEmpty() ) + { + OGRErr ogrErr = OSRSetFromUserInput( crs, input.toAscii() ); + if ( ogrErr != OGRERR_NONE ) + { + input = QString( "%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id ); + ogrErr = OSRSetFromUserInput( crs, input.toAscii() ); + } + + if ( ogrErr == OGRERR_NONE ) + { + char *output = 0; + + if ( OSRExportToProj4( crs, &output ) == OGRERR_NONE ) + { + QString proj4ogr = output; + +#if 0 + QString proj4proj = proj4; + + proj4proj.replace( QRegExp( "\\.0+([, ])" ), "\\1" ); + proj4proj.replace( QRegExp( "(\\.\\d*[1-9])0+([, ])" ), "\\1\\2" ); + proj4proj.replace( ".0000000001 ", " " ); + proj4proj.replace( ".10000000000001 ", ".1 " ); + proj4proj.replace( ".50000000000001 ", ".5 " ); + proj4proj.replace( ".399999999999999 ", ".4 " ); + proj4proj.replace( ".16500000000001 ", ".165 " ); + proj4proj.replace( " +towgs84=0,0,0,0,0,0,0 ", " +datum=WGS84 " ); + + if ( proj4proj.contains( " +datum=WGS84 " ) && proj4proj.endsWith( " +towgs84=0,0,0" ) ) + { + proj4proj.replace( " +towgs84=0,0,0", "" ); + } + + proj4ogr.replace( " +towgs84=0,0,0,0,0,0,0 ", " +datum=WGS84 " ); + proj4ogr.replace( " +a=6378249.145 +b=6356514.96582849 ", " +ellps=clrk80 " ); + proj4ogr.replace( " +gamma=0 ", " " ); + proj4ogr.replace( " +alpha=0 ", " " ); + + if ( proj4ogr != proj4proj ) + { + 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() ); + } +#endif + + proj4 = proj4ogr.trimmed(); + } + else + { + QgsDebugMsg( QString( "could not retrieve proj.4 string for %1 from OGR" ).arg( input ) ); + } + + if ( output ) + CPLFree( output ); + } + } +#endif + + if ( proj4.isEmpty() ) + { + continue; + } + + if ( proj4 != params ) + { + char *errMsg = NULL; + + sql = QString( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" ) + .arg( quotedValue( proj4 ) ) + .arg( quotedValue( auth_name ) ) + .arg( quotedValue( auth_id ) ); + + if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) != SQLITE_OK ) + { + qCritical( "Could not execute: %s [%s/%s]\n", + sql.toLocal8Bit().constData(), + sqlite3_errmsg( database ), + errMsg ? errMsg : "(unknown error)" ); + errors++; + } + else + { + updated++; + QgsDebugMsgLevel( "Updated: " + sql, 3 ); + } + + if ( errMsg ) + sqlite3_free( errMsg ); + } + } + + OSRDestroySpatialReference( crs ); + + sqlite3_finalize( select ); + sqlite3_close( database ); + + if ( errors > 0 ) + return -errors; + else + return updated; +} Index: src/crssync/CMakeLists.txt =================================================================== --- src/crssync/CMakeLists.txt (revision 0) +++ src/crssync/CMakeLists.txt (revision 0) @@ -0,0 +1,15 @@ +ADD_EXECUTABLE(crssync main.cpp) +INCLUDE_DIRECTORIES( + ../core + ${GDAL_INCLUDE_DIR} + ${PROJ_INCLUDE_DIR} +) + +TARGET_LINK_LIBRARIES(crssync + qgis_core + ${PROJ_LIBRARY} + ${GDAL_LIBRARY} +) + +INSTALL(CODE "MESSAGE(\"Installing crssync ...\")") +INSTALL(TARGETS crssync RUNTIME DESTINATION ${QGIS_LIBEXEC_DIR}) Index: src/core/qgscoordinatereferencesystem.h =================================================================== --- src/core/qgscoordinatereferencesystem.h (revision 15613) +++ src/core/qgscoordinatereferencesystem.h (working copy) @@ -322,6 +322,13 @@ /*! Get user hint for validation */ QString validationHint(); + /*! Update proj.4 parameters in our database from proj.4 + * @returns number of updated CRS on success and + * negative number of failed updates in case of errors. + * @note added in 1.7 + */ + static int syncDb(); + // Mutators ----------------------------------- // We don't want to expose these to the public api since they wont create // a fully valid crs. Programmers should use the createFrom* methods rather @@ -418,7 +425,7 @@ long getRecordCount(); //! Helper for sql-safe value quoting - QString quotedValue( QString value ); + static QString quotedValue( QString value ); void *mCRS; Index: src/CMakeLists.txt =================================================================== --- src/CMakeLists.txt (revision 15613) +++ src/CMakeLists.txt (working copy) @@ -1,4 +1,4 @@ -SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer) +SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer crssync) IF (WITH_BINDINGS) SUBDIRS(python) Index: ms-windows/osgeo4w/postinstall.bat =================================================================== --- ms-windows/osgeo4w/postinstall.bat (revision 15613) +++ ms-windows/osgeo4w/postinstall.bat (working copy) @@ -8,3 +8,5 @@ set OSGEO4W_ROOT=%OSGEO4W_ROOT:\=\\% textreplace -std -t "%O4W_ROOT%\apps\@package@\bin\qgis.reg" "%WINDIR%\regedit" /s "%O4W_ROOT%\apps\@package@\bin\qgis.reg" + +start "CRS synchronization" /wait %OSGEO4W_ROOT%\apps\@package@\crssync