2626#include < QFileInfo>
2727#include < QRegExp>
2828#include < QTextStream>
29+ #include < QFile>
2930
3031#include " qgsapplication.h"
3132#include " qgscrscache.h"
@@ -1509,9 +1510,119 @@ QString QgsCoordinateReferenceSystem::quotedValue( QString value )
15091510 return value.prepend ( " '" ).append ( " '" );
15101511}
15111512
1513+ // adapted from gdal/ogr/ogr_srs_dict.cpp
1514+ bool QgsCoordinateReferenceSystem::loadWkts ( QHash<int , QString> &wkts, const char *filename )
1515+ {
1516+ qDebug ( " Loading %s" , filename );
1517+ const char *pszFilename = CPLFindFile ( " gdal" , filename );
1518+ if ( !pszFilename )
1519+ return false ;
1520+
1521+ QFile csv ( pszFilename );
1522+ if ( !csv.open ( QIODevice::ReadOnly ) )
1523+ return false ;
1524+
1525+ QTextStream lines ( &csv );
1526+
1527+ for ( ;; )
1528+ {
1529+ QString line = lines.readLine ();
1530+ if ( line.isNull () )
1531+ break ;
1532+
1533+ if ( line.startsWith ( ' #' ) )
1534+ {
1535+ continue ;
1536+ }
1537+ else if ( line.startsWith ( " include " ) )
1538+ {
1539+ if ( !loadWkts ( wkts, line.mid ( 8 ).toUtf8 () ) )
1540+ break ;
1541+ }
1542+ else
1543+ {
1544+ int pos = line.indexOf ( " ," );
1545+ if ( pos < 0 )
1546+ return false ;
1547+
1548+ bool ok;
1549+ int epsg = line.left ( pos ).toInt ( &ok );
1550+ if ( !ok )
1551+ return false ;
1552+
1553+ wkts.insert ( epsg, line.mid ( pos + 1 ) );
1554+ }
1555+ }
1556+
1557+ csv.close ();
1558+
1559+ return true ;
1560+ }
1561+
1562+ bool QgsCoordinateReferenceSystem::loadIDs ( QHash<int , QString> &wkts )
1563+ {
1564+ OGRSpatialReferenceH crs = OSRNewSpatialReference ( NULL );
1565+
1566+ foreach ( QString csv, QStringList () << " gcs.csv" << " pcs.csv" << " vertcs.csv" << " compdcs.csv" << " geoccs.csv" )
1567+ {
1568+ QString filename = CPLFindFile ( " gdal" , csv.toUtf8 () );
1569+
1570+ QFile f ( filename );
1571+ if ( !f.open ( QIODevice::ReadOnly ) )
1572+ continue ;
1573+
1574+ QTextStream lines ( &f );
1575+ int l = 0 , n = 0 ;
1576+
1577+ lines.readLine ();
1578+ for ( ;; )
1579+ {
1580+ l++;
1581+ QString line = lines.readLine ();
1582+ if ( line.isNull () )
1583+ break ;
1584+
1585+ int pos = line.indexOf ( " ," );
1586+ if ( pos < 0 )
1587+ continue ;
1588+
1589+ bool ok;
1590+ int epsg = line.left ( pos ).toInt ( &ok );
1591+ if ( !ok )
1592+ continue ;
1593+
1594+ if ( OSRImportFromEPSG ( crs, epsg ) != OGRERR_NONE )
1595+ {
1596+ qDebug ( " EPSG %d: not imported" , epsg );
1597+ continue ;
1598+ }
1599+
1600+ char *wkt = 0 ;
1601+ if ( OSRExportToWkt ( crs, &wkt ) != OGRERR_NONE )
1602+ {
1603+ qWarning ( " EPSG %d: not exported to WKT" , epsg );
1604+ continue ;
1605+ }
1606+
1607+ wkts.insert ( epsg, wkt );
1608+ n++;
1609+
1610+ OGRFree ( wkt );
1611+ }
1612+
1613+ f.close ();
1614+
1615+ qDebug ( " Loaded %d/%d from %s" , n, l, filename.toUtf8 ().constData () );
1616+ }
1617+
1618+ OSRDestroySpatialReference ( crs );
1619+
1620+ return true ;
1621+ }
1622+
15121623int QgsCoordinateReferenceSystem::syncDb ()
15131624{
1514- int updated = 0 , errors = 0 ;
1625+ int inserted = 0 , updated = 0 , deleted = 0 , errors = 0 ;
15151626
15161627 sqlite3 *database;
15171628 if ( sqlite3_open ( QgsApplication::srsDbFilePath ().toUtf8 ().constData (), &database ) != SQLITE_OK )
@@ -1524,54 +1635,154 @@ int QgsCoordinateReferenceSystem::syncDb()
15241635 {
15251636 qCritical ( " Could not begin transaction: %s [%s]\n " , QgsApplication::srsDbFilePath ().toLocal8Bit ().constData (), sqlite3_errmsg ( database ) );
15261637 return -1 ;
1638+
15271639 }
15281640
1641+ sqlite3_exec ( database, " UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'" , 0 , 0 , 0 );
1642+
1643+ OGRSpatialReferenceH crs = OSRNewSpatialReference ( NULL );
15291644 const char *tail;
15301645 sqlite3_stmt *select;
1531- QString sql = " select auth_name,auth_id,parameters from tbl_srs WHERE auth_name IS NOT NULL AND auth_id IS NOT NULL order by deprecated" ;
1532- if ( sqlite3_prepare ( database, sql.toAscii (), sql.size (), &select, &tail ) != SQLITE_OK )
1533- {
1534- qCritical ( " Could not prepare: %s [%s]\n " , sql.toAscii ().constData (), sqlite3_errmsg ( database ) );
1535- sqlite3_close ( database );
1536- return -1 ;
1537- }
1646+ char *errMsg = NULL ;
15381647
1539- OGRSpatialReferenceH crs = OSRNewSpatialReference ( NULL );
1648+ QString sql;
1649+ QHash<int , QString> wkts;
1650+ loadIDs ( wkts );
1651+ loadWkts ( wkts, " epsg.wkt" );
15401652
1541- while ( sqlite3_step ( select ) == SQLITE_ROW )
1653+ qDebug ( " %d WKTs loaded" , wkts.count () );
1654+
1655+ for ( QHash<int , QString>::const_iterator it = wkts.constBegin (); it != wkts.constEnd (); ++it )
15421656 {
1543- const char *auth_name = ( const char * ) sqlite3_column_text ( select, 0 );
1544- const char *auth_id = ( const char * ) sqlite3_column_text ( select, 1 );
1545- const char *params = ( const char * ) sqlite3_column_text ( select, 2 );
1657+ QByteArray ba ( it.value ().toUtf8 () );
1658+ char *psz = ba.data ();
1659+ OGRErr ogrErr = OSRImportFromWkt ( crs, &psz );
1660+ if ( ogrErr != OGRERR_NONE )
1661+ {
1662+ continue ;
1663+ }
15461664
1547- QString proj4;
1665+ if ( OSRExportToProj4 ( crs, &psz ) != OGRERR_NONE )
1666+ continue ;
1667+
1668+ QString proj4 ( psz );
1669+ proj4 = proj4.trimmed ();
15481670
1549- if ( QString ( auth_name ).compare ( " epsg" , Qt::CaseInsensitive ) == 0 )
1671+ CPLFree ( psz );
1672+
1673+ if ( proj4.isEmpty () )
15501674 {
1551- OGRErr ogrErr = OSRSetFromUserInput ( crs, QString ( " epsg:%1" ).arg ( auth_id ).toAscii () );
1675+ continue ;
1676+ }
1677+
1678+ sql = QString ( " SELECT parameters FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg ( it.key () );
1679+ if ( sqlite3_prepare ( database, sql.toAscii (), sql.size (), &select, &tail ) != SQLITE_OK )
1680+ {
1681+ qCritical ( " Could not prepare: %s [%s]\n " , sql.toAscii ().constData (), sqlite3_errmsg ( database ) );
1682+ continue ;
1683+ }
1684+
1685+ QString srsProj4;
1686+ if ( sqlite3_step ( select ) == SQLITE_ROW )
1687+ {
1688+ srsProj4 = ( const char * ) sqlite3_column_text ( select, 0 );
1689+ }
15521690
1553- if ( ogrErr == OGRERR_NONE )
1691+ sqlite3_finalize ( select );
1692+
1693+ if ( !srsProj4.isEmpty () )
1694+ {
1695+ if ( proj4 != srsProj4 )
15541696 {
1555- char *output = 0 ;
1697+ errMsg = NULL ;
1698+ sql = QString ( " UPDATE tbl_srs SET parameters=%1 WHERE auth_name='EPSG' AND auth_id=%2" ).arg ( quotedValue ( proj4 ) ).arg ( it.key () );
15561699
1557- if ( OSRExportToProj4 ( crs, &output ) == OGRERR_NONE )
1700+ if ( sqlite3_exec ( database, sql. toUtf8 (), 0 , 0 , &errMsg ) != SQLITE_OK )
15581701 {
1559- proj4 = output;
1560- proj4 = proj4.trimmed ();
1702+ qCritical ( " Could not execute: %s [%s/%s]\n " ,
1703+ sql.toLocal8Bit ().constData (),
1704+ sqlite3_errmsg ( database ),
1705+ errMsg ? errMsg : " (unknown error)" );
1706+ errors++;
15611707 }
15621708 else
15631709 {
1564- QgsDebugMsg ( QString ( " could not retrieve proj.4 string for epsg:%1 from OGR" ).arg ( auth_id ) );
1710+ updated++;
1711+ QgsDebugMsgLevel ( QString ( " SQL: %1\n OLD:%2\n NEW:%3" ).arg ( sql ).arg ( srsProj4 ).arg ( proj4 ), 3 );
15651712 }
1713+ }
1714+ }
1715+ else
1716+ {
1717+ QRegExp projRegExp ( " \\ +proj=(\\ S+)" );
1718+ if ( projRegExp.indexIn ( proj4 ) < 0 )
1719+ {
1720+ QgsDebugMsg ( QString ( " EPSG %1: no +proj argument found [%2]" ).arg ( it.key () ).arg ( proj4 ) );
1721+ continue ;
1722+ }
15661723
1567- if ( output )
1568- CPLFree ( output );
1724+ QRegExp ellipseRegExp ( " \\ +ellps=(\\ S+)" );
1725+ QString ellps;
1726+ if ( ellipseRegExp.indexIn ( proj4 ) >= 0 )
1727+ {
1728+ ellps = ellipseRegExp.cap ( 1 );
1729+ }
1730+
1731+ QString name ( OSRIsGeographic ( crs ) ? OSRGetAttrValue ( crs, " GEOCS" , 0 ) : OSRGetAttrValue ( crs, " PROJCS" , 0 ) );
1732+ if ( name.isEmpty () )
1733+ name = QObject::tr ( " Imported from GDAL" );
1734+
1735+ sql = QString ( " INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) VALUES (%1,%2,%3,%4,%5,'EPSG',%5,%6,0)" )
1736+ .arg ( quotedValue ( name ) )
1737+ .arg ( quotedValue ( projRegExp.cap ( 1 ) ) )
1738+ .arg ( quotedValue ( ellps ) )
1739+ .arg ( quotedValue ( proj4 ) )
1740+ .arg ( it.key () )
1741+ .arg ( OSRIsGeographic ( crs ) );
1742+
1743+ errMsg = NULL ;
1744+ if ( sqlite3_exec ( database, sql.toUtf8 (), 0 , 0 , &errMsg ) == SQLITE_OK )
1745+ {
1746+ inserted++;
1747+ }
1748+ else
1749+ {
1750+ qCritical ( " Could not execute: %s [%s/%s]\n " ,
1751+ sql.toLocal8Bit ().constData (),
1752+ sqlite3_errmsg ( database ),
1753+ errMsg ? errMsg : " (unknown error)" );
1754+ errors++;
1755+
1756+ if ( errMsg )
1757+ sqlite3_free ( errMsg );
15691758 }
15701759 }
1760+ }
1761+
1762+ sql = " DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" ;
1763+ QString delim;
1764+ foreach ( int i, wkts.keys () )
1765+ {
1766+ sql += delim + QString::number ( i );
1767+ delim = " ," ;
1768+ }
1769+ sql += " )" ;
1770+
1771+ if ( sqlite3_exec ( database, sql.toUtf8 (), 0 , 0 , 0 ) == SQLITE_OK )
1772+ {
1773+ deleted = sqlite3_changes ( database );
1774+ }
1775+
15711776#if !defined(PJ_VERSION) || PJ_VERSION!=470
1572- // 4.7.0 has a bug that crashes after 16 consecutive pj_init_plus with different strings
1573- else
1777+ QString sql = QString ( " select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' WHERE NOT deprecated" );
1778+ if ( sqlite3_prepare ( database, sql.toAscii (), sql.size (), &select, &tail ) == SQLITE_OK )
1779+ {
1780+ while ( sqlite3_step ( select ) == SQLITE_ROW )
15741781 {
1782+ const char *auth_name = ( const char * ) sqlite3_column_text ( select, 0 );
1783+ const char *auth_id = ( const char * ) sqlite3_column_text ( select, 1 );
1784+ const char *params = ( const char * ) sqlite3_column_text ( select, 2 );
1785+
15751786 QString input = QString ( " +init=%1:%2" ).arg ( QString ( auth_name ).toLower () ).arg ( auth_id );
15761787 projPJ pj = pj_init_plus ( input.toAscii () );
15771788 if ( !pj )
@@ -1607,44 +1818,11 @@ int QgsCoordinateReferenceSystem::syncDb()
16071818
16081819 pj_free ( pj );
16091820 }
1610- #endif
1611-
1612- if ( proj4.isEmpty () )
1613- {
1614- continue ;
1615- }
1616-
1617- if ( proj4 != params )
1618- {
1619- char *errMsg = NULL ;
1620- sql = QString ( " UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
1621- .arg ( quotedValue ( proj4 ) )
1622- .arg ( quotedValue ( auth_name ) )
1623- .arg ( quotedValue ( auth_id ) );
1624-
1625- if ( sqlite3_exec ( database, sql.toUtf8 (), 0 , 0 , &errMsg ) != SQLITE_OK )
1626- {
1627- qCritical ( " Could not execute: %s [%s/%s]\n " ,
1628- sql.toLocal8Bit ().constData (),
1629- sqlite3_errmsg ( database ),
1630- errMsg ? errMsg : " (unknown error)" );
1631- errors++;
1632- }
1633- else
1634- {
1635- updated++;
1636- QgsDebugMsgLevel ( QString ( " SQL: %1\n OLD:%2\n NEW:%3" ).arg ( sql ).arg ( params ).arg ( proj4 ), 3 );
1637- }
1638-
1639- if ( errMsg )
1640- sqlite3_free ( errMsg );
1641- }
16421821 }
1822+ #endif
16431823
16441824 OSRDestroySpatialReference ( crs );
16451825
1646- sqlite3_finalize ( select );
1647-
16481826 if ( sqlite3_exec ( database, " COMMIT" , 0 , 0 , 0 ) != SQLITE_OK )
16491827 {
16501828 qCritical ( " Could not commit transaction: %s [%s]\n " , QgsApplication::srsDbFilePath ().toLocal8Bit ().constData (), sqlite3_errmsg ( database ) );
@@ -1653,8 +1831,10 @@ int QgsCoordinateReferenceSystem::syncDb()
16531831
16541832 sqlite3_close ( database );
16551833
1834+ qWarning ( " CRS update (inserted:%d updated:%d deleted:%d errors:%d)" , inserted, updated, deleted, errors );
1835+
16561836 if ( errors > 0 )
16571837 return -errors;
16581838 else
1659- return updated;
1839+ return updated + inserted ;
16601840}
0 commit comments