Original post at Makina Corpus
I did not find any ready-to-use snippets on the Web on this matter, so if you are lucky enough, you'll find this one.
The objective is to read GIS geometries from a PostGIS database and manipulate them in C++. I use Qt here, but it is not really a prerequisite, it just helps a lot. Well, actually, it saves lives.
Database Connection
m_db = QSqlDatabase::addDatabase("QPSQL");
m_db.setHostName("host");
m_db.setDatabaseName("dbname");
m_db.setUserName("user");
m_db.setPassword("pass");
Do not close the database at the end of each query.
m_db.close();
m_db = QSqlDatabase(); // reinitialize for real
Shut it down like this in your class' destructor or you may have errors like QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work
Records Reading
QSqlQueryModel* model = new QSqlQueryModel();
model->setQuery("SELECT id, ST_AsBinary(the_geom) AS the_geom "
"FROM table");
int numRows = model->rowCount();
for (int i=0; i<numRows; ++i) {
// Read fields
qlonglong id = record(i).value("id").toLongLong();
QByteArray wkb = record(i).value("the_geom").toByteArray();
// Process !
processRecord(id, wkb);
}
QByteArray uses implicit sharing and can be passed as argument without being copied.
Geometries Parsing
In this part, we rely on GDAL (Geospatial Data Abstraction Library) OGRSpatialReference.
It provides an API to access geometries coordinates etc.
#include "ogrsf_frmts.h" // GDAL
...
...
void Class::processRecord(qlonglong id, QByteArray wkb)
{
OGRSpatialReference osr;
OGRGeometry *geom = NULL;
// Parse WKB
OGRErr err = OGRGeometryFactory::createFromWkb((unsigned char*)wkb.constData(), &osr, &geom);
if (err != OGRERR_NONE){
// process error, like emit signal
}
// Analyse geometry by type and process them as you wish
OGRwkbGeometryType type = wkbFlatten(geom->getGeometryType());
switch(type) {
case wkbLineString: {
OGRLineString *poRing = (OGRLineString*)geom;
// Access line string nodes for example :
int numNode = poRing->getNumPoints();
OGRPoint p;
for(int i = 0; i < numNode; i++) {
poRing->getPoint(i, &p);
qDebug() << p.getX() << p.getY();
}
break;
}
case wkbMultiLineString:
{
OGRGeometryCollection *poCol = (OGRGeometryCollection*) geom;
int numCol = poCol->getNumGeometries();
for(int i=0; i<numCol; i++) {
// Access line length for example :
qDebug() << poCol->getGeometryRef(i)->get_Length();
}
break;
}
default:
// process error, like emit signal
}
// Clean-up
OGRGeometryFactory::destroyGeometry(geom);
}
In this snippet, I only process linestrings, but all geometry types are available. Consider writing a recursive function for geometry collections and so forth...
Hope this helped !
#c++, #qt, #postgis, #gdal - Posted in the Dev category