Tutorial 7 - Creating spatial datasets with the QGIS API

Hi all.This is a repost since the original article got deleted some
how. A while ago I decided to make some improvements to some of my code
that creates a shapefile. I was using shapelib which
is nice and simple and self contained, but I found it a little awkward
to add attributes to features in a flexible way. Since my application
use the QGIS libs anyway, I thought I may as well give using
the QgsVectorFileWriter a
go...

I started by creating a unit test for QGIS that puts the QgsVectorFileWriter class
though its paces - doing so gave me a good reminder of how the API
works. You can find the source of the unit test in the QGIS sources here. The unit test is
too long to go through in its entirety here so instead I'll take a few
choice parts that together will hopefully illustrate the process of
creating vector data using the QGIS api. Internally the QGIS vector file
writer class is using OGR to do its magic.
At the moment it supports only writing to ESRI shapefile format but in
the future we will implement support for writing to other OGR writeble
formats. In the descriptiion below I only cover creating features with
point geometry, but examples of creating more complex geometries are
available in the above mentioned unit test.

Preparing to create a new vector layer

Lets first look at what headers are needed:

#include <qgsvectorlayer.h> //defines QgsFieldMap

#include <qgsvectorfilewriter.h> //logic for
writing shpfiles

#include <qgsfeature.h> //we will need to pass
a bunch of these for each rec

#include <qgsgeometry.h> //each feature needs
a geometry

#include <qgspoint.h> //we will use point
geometry

#include <qgsspatialrefsys.h> //needed for
creating a srs

#include <qgsapplication.h> //search path for
srs.db

#include <qgsfield.h> //defines a
field in an attribute table

#include <qgis.h> //defines GEOWKT

All of these includes come from the qgis core library. You can see
that although the underlying logic is based on OGR, we dont need to
include any OGR sources since everything we want to do is encapsulated
with the QGIS api.  First up, we need to tell QGIS what character
encoding will be used for vector file we create so first we define a
string to represent the desired encoding:

QString myEncoding = "UTF-8";

Next I create a container to store any error messages in:

QgsVectorFileWriter::WriterError myError;

 

We can write features in our preferred spatial reference system - to
do that we define a new QgsSpatialRefSys object - I'll be using Jamaican
National Grid for this example:

// We are testing projected coordinate

// system vector writing to lets use something fun...

// Jamaica National Grid

// QGIS SRSID: 1286

// PostGIS SRID: 24200

// +proj=lcc +lat_1=18 +lat_0=18 +lon_0=-77 +k_0=1 +x_0=250000

// +y_0=150000 +ellps=clrk66 +units=m +no_defs

//

QgsSpatialRefSys mySRS =
QgsSpatialRefSys(1286,QgsSpatialRefSys::QGIS_SRSID);

 

Next we define one or more fields to store attributes for the
features we create...

 

QgsFieldMap myFields;

QgsField
myField1("Field1",QVariant::String,"String",10,0,&
quot;Field 1 comment");

myFields.insert(0, myField1);

 

Now we create a vector file writer object :

QgsVectorFileWriter myWriter (myFileName,

    myEncoding,

    myFields,

    QGis::WKBPoint,

    &mySRS);

 

Now we create one or more features. A feature is a combination of a
geometry object (point in this case) and one or more attributes that
store information about this geometry. In this example I am just using
simple point geometry - see the unit test for mode examples using
polyline / polygon geometries.

QgsPoint myPoint1 = QgsPoint(10.0,10.0);

// NOTE: dont delete this pointer again -

// ownership is passed to the feature which will

// delete it in its dtor!

QgsGeometry * mypPointGeometry = QgsGeometry::fromPoint(myPoint1);

QgsFeature myFeature;

myFeature.setGeometry(mypPointGeometry);

myFeature.addAttribute(0,"HelloWorld");

 

Finally we write the feature using the filewriter and check for
errors:

myWriter.addFeature(myFeature);

myError = myWriter.hasError();

if (mError!=QgsVectorFileWriter::NoError)

{

  if(myError==QgsVectorFileWriter::ErrDriverNotFound)

  {

    std::cout << "Driver not found
error" << std::endl;

  }

  else if (mError==QgsVectorFileWriter::ErrCreateDataSource)

  {

    std::cout << "Create data source
error" << std::endl;

  }

  else if (mError==QgsVectorFileWriter::ErrCreateLayer)

  {

    std::cout << "Create layer
error" << std::endl;

  }

}

 

Well hopefully that will get you started creating your own spatial
dataset programmatically using the QGIS API. We will be adding support
for other output formats in the future, at the moment only ESRI
shapefiles are supported.

Reply