Skip to content

Commit d66c307

Browse files
committedJul 22, 2012
improve CRS GDAL synchronization (fixes #6071, #4337 and #2777)
1 parent 8e10e8c commit d66c307

File tree

2 files changed

+246
-61
lines changed

2 files changed

+246
-61
lines changed
 

‎src/core/qgscoordinatereferencesystem.cpp

Lines changed: 241 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
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+
15121623
int 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
}

‎src/core/qgscoordinatereferencesystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
//qt includes
2525
#include <QString>
2626
#include <QMap>
27+
#include <QHash>
28+
2729
class QDomNode;
2830
class QDomDocument;
2931

@@ -477,6 +479,9 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
477479
QString mValidationHint;
478480
mutable QString mWkt;
479481

482+
static bool loadIDs( QHash<int, QString> &wkts );
483+
static bool loadWkts( QHash<int, QString> &wkts, const char *filename );
484+
480485
//!Whether this is a coordinate system has inverted axis
481486
mutable int mAxisInverted;
482487

0 commit comments

Comments
 (0)
Please sign in to comment.