QGIS/providers/ogr/qgsogrprovider.cpp
gsherman 86c976272f ** Merged Projections_Branch into HEAD
Problems:
      Polygon outlines are not drawn. This was checked twice and no cause
      was found.

      Projections do not work in all circumstances

      Note that both the proj4 library and sqlite3 are now required. The
      build system has not been modified to test for these yet.

      Qt 3.3.x is required to build this source tree.

      Make sure to increment the EXTRA_VERSION in configure.in when
      committing changes.

      Make sure to update the Changelog with each commit


git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@3112 c8812cc2-4d05-0410-92ff-de0c093fc19c
2005-04-10 07:04:07 +00:00

1231 lines
32 KiB
C++

/***************************************************************************
qgsogrprovider.cpp Data provider for OGR supported formats
Formerly known as qgsshapefileprovider.cpp
begin : Oct 29, 2003
copyright : (C) 2003 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
/* $Id$ */
#include "qgsogrprovider.h"
#ifndef WIN32
#include <netinet/in.h>
#endif
#include <iostream>
#include <cfloat>
#include <cassert>
#include <ogrsf_frmts.h>
#include <ogr_geometry.h>
#include <ogr_spatialref.h>
#include <cpl_error.h>
#include "ogr_api.h"//only for a test
#include <qmessagebox.h>
#include <qmap.h>
//TODO Following ifndef can be removed once WIN32 GEOS support
// is fixed
#ifndef NOWIN32GEOSXXX
//XXX GEOS support on windows is broken until we can get VC++ to
// tolerate geos.h without throwing a bunch of type errors. It
// appears that the windows version of GEOS may be compiled with
// MINGW rather than VC++.
#endif
#include "../../src/qgsdataprovider.h"
#include "../../src/qgsfeature.h"
#include "../../src/qgsfield.h"
#include "../../src/qgsrect.h"
#include "../../src/qgis.h"
#ifdef WIN32
#define QGISEXTERN extern "C" __declspec( dllexport )
#else
#define QGISEXTERN extern "C"
#endif
QgsOgrProvider::QgsOgrProvider(QString uri): QgsVectorDataProvider(), dataSourceUri(uri), minmaxcachedirty(true)
{
OGRRegisterAll();
// set the selection rectangle pointer to 0
mSelectionRectangle = 0;
// make connection to the data source
#ifdef QGISDEBUG
std::cerr << "Data source uri is " << uri << std::endl;
#endif
// try to open for update
ogrDataSource = OGRSFDriverRegistrar::Open((const char *) uri.local8Bit(),TRUE);
if(ogrDataSource == NULL)
{
// try to open read-only
ogrDataSource = OGRSFDriverRegistrar::Open((const char *) uri.local8Bit(),FALSE);
//TODO Need to set a flag or something to indicate that the layer
//TODO is in read-only mode, otherwise edit ops will fail
}
if (ogrDataSource != NULL) {
#ifdef QGISDEBUG
std::cerr << "Data source is valid" << std::endl;
#endif
valid = true;
ogrLayer = ogrDataSource->GetLayer(0);
// get the extent_ (envelope) of the layer
#ifdef QGISDEBUG
std::cerr << "Starting get extent\n";
#endif
extent_ = new OGREnvelope();
ogrLayer->GetExtent(extent_);
#ifdef QGISDEBUG
std::cerr << "Finished get extent\n";
#endif
// getting the total number of features in the layer
numberFeatures = ogrLayer->GetFeatureCount();
// check the validity of the layer
#ifdef QGISDEBUG
std::cerr << "checking validity\n";
#endif
OGRFeatureDefn* fdef = ogrLayer->GetLayerDefn();
if(fdef)
{
geomType = fdef->GetGeomType();
for(int i=0;i<fdef->GetFieldCount();++i)
{
OGRFieldDefn *fldDef = fdef->GetFieldDefn(i);
attributeFields.push_back(QgsField(
fldDef->GetNameRef(),
fldDef->GetFieldTypeName(fldDef->GetType()),
fldDef->GetWidth(),
fldDef->GetPrecision()));
}
}
#ifdef QGISDEBUG
std::cerr << "Done checking validity\n";
#endif
} else {
std::cerr << "Data source is invalid" << std::endl;
const char *er = CPLGetLastErrorMsg();
#ifdef QGISDEBUG
std::cerr << er << std::endl;
#endif
valid = false;
}
//resize the cache matrix
minmaxcache=new double*[fieldCount()];
for(int i=0;i<fieldCount();i++)
{
minmaxcache[i]=new double[2];
}
// create the geos objects
geometryFactory = new geos::GeometryFactory();
assert(geometryFactory!=0);
// create the reader
// std::cerr << "Creating the wktReader\n";
wktReader = new geos::WKTReader(geometryFactory);
mNumericalTypes.push_back("OFTInteger");
mNumericalTypes.push_back("OFTReal");
mNonNumericalTypes.push_back("OFTString");
}
QgsOgrProvider::~QgsOgrProvider()
{
for(int i=0;i<fieldCount();i++)
{
delete[] minmaxcache[i];
}
delete[] minmaxcache;
delete geometryFactory;
delete wktReader;
}
QString QgsOgrProvider::getProjectionWKT()
{
OGRSpatialReference * mySpatialRefSys = ogrLayer->GetSpatialRef();
if (mySpatialRefSys == NULL)
{
return NULL;
}
else
{
// if appropriate, morph the projection from ESRI form
QString fileName = ogrDataSource->GetName();
#ifdef QGISDEBUG
std::cerr << "Data source file name is : " << fileName << std::endl;
#endif
if(fileName.contains(".shp"))
{
#ifdef QGISDEBUG
std::cerr << "Morphing " << fileName << " WKT from ESRI" << std::endl;
#endif
// morph it
mySpatialRefSys->morphFromESRI();
}
// get the proj4 text
char * ppszProj4;
mySpatialRefSys->exportToProj4 ( &ppszProj4 );
std::cout << "vvvvvvvvvvvvvvvvv PROJ4 TEXT vvvvvvvvvvvvvvv" << std::endl;
std::cout << ppszProj4 << std::endl;
std::cout << "^^^^^^^^^^^^^^^^^ PROJ4 TEXT ^^^^^^^^^^^^^^^" << std::endl;
char *pszWKT = NULL;
mySpatialRefSys->exportToWkt( &pszWKT );
QString myWKTString = QString(pszWKT);
OGRFree(pszWKT);
return myWKTString;
}
}
/**
* Get the first feature resutling from a select operation
* @return QgsFeature
*/
QgsFeature * QgsOgrProvider::getFirstFeature(bool fetchAttributes)
{
QgsFeature *f = 0;
if(valid)
{
#ifdef QGISDEBUG
std::cerr << "getting first feature\n";
#endif
ogrLayer->ResetReading();
OGRFeature * feat = ogrLayer->GetNextFeature();
Q_CHECK_PTR( feat );
if(feat)
{
#ifdef QGISDEBUG
std::cerr << "First feature is not null\n";
#endif
}
else
{
#ifdef QGISDEBUG
std::cerr << "First feature is null\n";
#endif
return 0x0; // so return a null feature indicating that we got a null feature
}
// get the feature type name, if any
OGRFeatureDefn * featureDefinition = feat->GetDefnRef();
QString featureTypeName =
featureDefinition ? QString(featureDefinition->GetName()) : QString("");
f = new QgsFeature(feat->GetFID(), featureTypeName );
Q_CHECK_PTR( f );
if ( ! f ) // return null if we can't get a new QgsFeature
{
delete feat;
return 0x0;
}
size_t geometry_size = feat->GetGeometryRef()->WkbSize();
f->setGeometry(getGeometryPointer(feat), geometry_size);
if(fetchAttributes)
{
getFeatureAttributes(feat, f);
}
delete feat;
}
return f;
} // QgsOgrProvider::getFirstFeature()
bool QgsOgrProvider::getNextFeature(QgsFeature &f, bool fetchAttributes)
{
bool returnValue;
if(valid){
//std::cerr << "getting next feature\n";
// skip features without geometry
OGRFeature *fet;
while ((fet = ogrLayer->GetNextFeature()) != NULL) {
if (fet->GetGeometryRef())
break;
}
if(fet){
OGRGeometry *geom = fet->GetGeometryRef();
// get the wkb representation
unsigned char *feature = new unsigned char[geom->WkbSize()];
geom->exportToWkb((OGRwkbByteOrder) endian(), feature);
f.setFeatureId(fet->GetFID());
f.setGeometry(feature, geom->WkbSize());
OGRFeatureDefn * featureDefinition = fet->GetDefnRef();
QString featureTypeName =
featureDefinition ? QString(featureDefinition->GetName()) : QString("");
f.typeName( featureTypeName );
if(fetchAttributes){
getFeatureAttributes(fet, &f);
}
/* char *wkt = new char[2 * geom->WkbSize()];
geom->exportToWkt(&wkt);
f->setWellKnownText(wkt);
delete[] wkt; */
delete fet;
returnValue = true;
}else{
#ifdef QGISDEBUG
std::cerr << "Feature is null\n";
f.setValid(false);
returnValue = false;
#endif
// probably should reset reading here
ogrLayer->ResetReading();
}
}else{
#ifdef QGISDEBUG
std::cerr << "Read attempt on an invalid shapefile data source\n";
#endif
}
return returnValue;
}
/**
* Get the next feature resutling from a select operation
* Return 0 if there are no features in the selection set
* @return QgsFeature
*/
QgsFeature *QgsOgrProvider::getNextFeature(bool fetchAttributes)
{
if(!valid)
{
std::cerr << "Read attempt on an invalid shapefile data source\n";
return 0;
}
OGRFeature* fet;
OGRGeometry* geom;
QgsFeature *f = 0;
while((fet = ogrLayer->GetNextFeature()) != NULL)
{
if (fet->GetGeometryRef())
{
geom = fet->GetGeometryRef();
// get the wkb representation
unsigned char *feature = new unsigned char[geom->WkbSize()];
geom->exportToWkb((OGRwkbByteOrder) endian(), feature);
OGRFeatureDefn * featureDefinition = fet->GetDefnRef();
QString featureTypeName = featureDefinition ? QString(featureDefinition->GetName()) : QString("");
f = new QgsFeature(fet->GetFID(), featureTypeName);
f->setGeometry(feature, geom->WkbSize());
if(fetchAttributes)
{
getFeatureAttributes(fet, f);
}
delete fet;
if(mUseIntersect)
{
geos::Geometry* geosGeom=f->geosGeometry();
char *sWkt = new char[2 * mSelectionRectangle->WkbSize()];
mSelectionRectangle->exportToWkt(&sWkt);
geos::Geometry *geosRect = wktReader->read(sWkt);
if(geosGeom->intersects(geosRect))
{
#ifdef QGISDEBUG
qWarning("intersection found");
#endif
delete[] sWkt;
delete geosGeom;
break;
}
else
{
#ifdef QGISDEBUG
qWarning("no intersection found");
#endif
delete[] sWkt;
delete geosGeom;
delete f;
f=0;
}
}
else
{
break;
}
}
}
return f;
}
/**
* Get the next feature resutling from a select operation
* Return 0 if there are no features in the selection set
* @return QgsFeature
*/
/*QgsFeature *QgsOgrProvider::getNextFeature(bool fetchAttributes)
{
QgsFeature *f = 0;
if(valid){
OGRFeature *fet;
OGRGeometry *geom;
while ((fet = ogrLayer->GetNextFeature()) != NULL) {
if (fet->GetGeometryRef())
{
if(mUseIntersect)
{
geom = fet->GetGeometryRef();
char *wkt = new char[2 * geom->WkbSize()];
geom->exportToWkt(&wkt);
geos::Geometry *geosGeom = wktReader->read(wkt);
assert(geosGeom != 0);
std::cerr << "Geometry type of geos object is : " << geosGeom->getGeometryType() << std::endl;
// get the selection rectangle and create a geos geometry from it
char *sWkt = new char[2 * mSelectionRectangle->WkbSize()];
mSelectionRectangle->exportToWkt(&sWkt);
std::cerr << "Passing " << sWkt << " to goes\n";
geos::Geometry *geosRect = wktReader->read(sWkt);
assert(geosRect != 0);
std::cerr << "About to apply intersects function\n";
// test the geometry
if(geosGeom->intersects(geosRect))
{
std::cerr << "Intersection found\n";
break;
}
//XXX For some reason deleting these on win32 causes segfault
//XXX Someday I'll figure out why...
//delete[] wkt;
//delete[] sWkt;
}
else
{
break;
}
}
}
if(fet){
geom = fet->GetGeometryRef();
// get the wkb representation
unsigned char *feature = new unsigned char[geom->WkbSize()];
geom->exportToWkb((OGRwkbByteOrder) endian(), feature);
OGRFeatureDefn * featureDefinition = fet->GetDefnRef();
QString featureTypeName =
featureDefinition ? QString(featureDefinition->GetName()) : QString("");
f = new QgsFeature(fet->GetFID(), featureTypeName);
f->setGeometry(feature, geom->WkbSize());
if(fetchAttributes){
getFeatureAttributes(fet, f);
}
delete fet;
}else{
#ifdef QGISDEBUG
std::cerr << "Feature is null\n";
#endif
// probably should reset reading here
ogrLayer->ResetReading();
}
}else{
#ifdef QGISDEBUG
std::cerr << "Read attempt on an invalid shapefile data source\n";
#endif
}
return f;
}*/
QgsFeature *QgsOgrProvider::getNextFeature(std::list<int> const& attlist)
{
QgsFeature *f = 0;
if(valid)
{
// skip features without geometry
OGRFeature *fet;
while ((fet = ogrLayer->GetNextFeature()) != NULL) {
if (fet->GetGeometryRef())
{
if(mUseIntersect)
{
// test this geometry to see if it should be
// returned
#ifdef QGISDEBUG2
std::cerr << "Testing geometry using intersect" << std::endl;
#endif
}
else
{
#ifdef QGISDEBUG2
std::cerr << "Testing geometry using mbr" << std::endl;
#endif
break;
}
}
}
if(fet)
{
OGRGeometry *geom = fet->GetGeometryRef();
// get the wkb representation
unsigned char *feature = new unsigned char[geom->WkbSize()];
geom->exportToWkb((OGRwkbByteOrder) endian(), feature);
OGRFeatureDefn * featureDefinition = fet->GetDefnRef();
QString featureTypeName =
featureDefinition ? QString(featureDefinition->GetName()) : QString("");
f = new QgsFeature(fet->GetFID(), featureTypeName);
f->setGeometry(feature, geom->WkbSize());
for(std::list<int>::const_iterator it=attlist.begin();it!=attlist.end();++it)
{
getFeatureAttribute(fet,f,*it);
}
delete fet;
//delete [] feature;
}
else
{
#ifdef QGISDEBUG
std::cerr << "Feature is null\n";
#endif
// probably should reset reading here
ogrLayer->ResetReading();
}
}
else
{
#ifdef QGISDEBUG
std::cerr << "Read attempt on an invalid shapefile data source\n";
#endif
}
return f;
}
/**
* Select features based on a bounding rectangle. Features can be retrieved
* with calls to getFirstFeature and getNextFeature.
* @param mbr QgsRect containing the extent to use in selecting features
* @param useIntersect If true, an intersect test will be used in selecting
* features. In OGR, this is a two pass affair. The mUseIntersect value is
* stored. If true, a secondary filter (using GEOS) is applied to each
* feature in the getNextFeature function.
*/
void QgsOgrProvider::select(QgsRect *rect, bool useIntersect)
{
mUseIntersect = useIntersect;
// spatial query to select features
std::cerr << "Selection rectangle is " << *rect << std::endl;
OGRGeometry *filter = 0;
filter = new OGRPolygon();
QString wktExtent = QString("POLYGON ((%1))").arg(rect->asPolygon());
const char *wktText = (const char *)wktExtent;
if(useIntersect)
{
// store the selection rectangle for use in filtering features during
// an identify and display attributes
// delete mSelectionRectangle;
mSelectionRectangle = new OGRPolygon();
mSelectionRectangle->importFromWkt((char **)&wktText);
}
// reset the extent for the ogr filter
wktExtent = QString("POLYGON ((%1))").arg(rect->asPolygon());
wktText = (const char *)wktExtent;
OGRErr result = ((OGRPolygon *) filter)->importFromWkt((char **)&wktText);
//TODO - detect an error in setting the filter and figure out what to
//TODO about it. If setting the filter fails, all records will be returned
if (result == OGRERR_NONE)
{
std::cerr << "Setting spatial filter using " << wktExtent << std::endl;
ogrLayer->SetSpatialFilter(filter);
std::cerr << "Feature count: " << ogrLayer->GetFeatureCount() << std::endl;
}else{
#ifdef QGISDEBUG
std::cerr << "Setting spatial filter failed!" << std::endl;
assert(result==OGRERR_NONE);
#endif
}
} // QgsOgrProvider::select
/**
* Set the data source specification. This may be a path or database
* connection string
* @uri data source specification
*/
void QgsOgrProvider::setDataSourceUri(QString uri)
{
dataSourceUri = uri;
}
/**
* Get the data source specification. This may be a path or database
* connection string
* @return data source specification
*/
QString QgsOgrProvider::getDataSourceUri()
{
return dataSourceUri;
}
/**
* Identify features within the search radius specified by rect
* @param rect Bounding rectangle of search radius
* @return std::vector containing QgsFeature objects that intersect rect
*/
std::vector<QgsFeature>& QgsOgrProvider::identify(QgsRect * rect)
{
// select the features
select(rect);
#ifdef WIN32
//TODO fix this later for win32
std::vector<QgsFeature> feat;
return feat;
#endif
}
unsigned char * QgsOgrProvider::getGeometryPointer(OGRFeature *fet){
OGRGeometry *geom = fet->GetGeometryRef();
unsigned char *gPtr=0;
// get the wkb representation
gPtr = new unsigned char[geom->WkbSize()];
geom->exportToWkb((OGRwkbByteOrder) endian(), gPtr);
return gPtr;
}
// TODO - make this function return the real extent_
QgsRect *QgsOgrProvider::extent()
{
return new QgsRect(extent_->MinX, extent_->MinY, extent_->MaxX, extent_->MaxY);
}
/**
* Return the feature type
*/
int QgsOgrProvider::geometryType() const
{
return geomType;
}
/**
* Return the feature type
*/
long QgsOgrProvider::featureCount() const
{
return numberFeatures;
}
/**
* Return the number of fields
*/
int QgsOgrProvider::fieldCount() const
{
return attributeFields.size();
}
void QgsOgrProvider::getFeatureAttribute(OGRFeature * ogrFet, QgsFeature * f, int attindex)
{
OGRFieldDefn *fldDef = ogrFet->GetFieldDefnRef(attindex);
if ( ! fldDef )
{
qDebug( "%s:%d ogrFet->GetFieldDefnRef(attindex) returns NULL",
__FILE__, __LINE__ );
return;
}
QString fld = fldDef->GetNameRef();
QCString cstr(ogrFet->GetFieldAsString(attindex));
f->addAttribute(fld, mEncoding->toUnicode(cstr));
}
/**
* Fetch attributes for a selected feature
*/
void QgsOgrProvider::getFeatureAttributes(OGRFeature *ogrFet, QgsFeature *f){
for (int i = 0; i < ogrFet->GetFieldCount(); i++) {
getFeatureAttribute(ogrFet,f,i);
// add the feature attributes to the tree
/*OGRFieldDefn *fldDef = ogrFet->GetFieldDefnRef(i);
QString fld = fldDef->GetNameRef();
// OGRFieldType fldType = fldDef->GetType();
QString val;
val = ogrFet->GetFieldAsString(i);
f->addAttribute(fld, val);*/
}
}
std::vector<QgsField> const & QgsOgrProvider::fields() const
{
return attributeFields;
}
void QgsOgrProvider::reset()
{
ogrLayer->SetSpatialFilter(0);
ogrLayer->ResetReading();
// Reset the use intersect flag on a provider reset, otherwise only the last
// selected feature(s) will be displayed when the attribute table
// is opened.
//XXX In a future release, this "feature" can be used to implement
// the display of only selected records in the attribute table.
mUseIntersect = false;
}
QString QgsOgrProvider::minValue(int position)
{
if(position>=fieldCount())
{
std::cerr << "Warning: access requested to invalid position in QgsOgrProvider::minValue(..)" << std::endl;
}
if(minmaxcachedirty)
{
fillMinMaxCash();
}
return QString::number(minmaxcache[position][0],'f',2);
}
QString QgsOgrProvider::maxValue(int position)
{
if(position>=fieldCount())
{
std::cerr << "Warning: access requested to invalid position in QgsOgrProvider::maxValue(..)" << std::endl;
}
if(minmaxcachedirty)
{
fillMinMaxCash();
}
return QString::number(minmaxcache[position][1],'f',2);
}
void QgsOgrProvider::fillMinMaxCash()
{
for(int i=0;i<fieldCount();i++)
{
minmaxcache[i][0]=DBL_MAX;
minmaxcache[i][1]=-DBL_MAX;
}
QgsFeature* f=getFirstFeature(true);
do
{
for(int i=0;i<fieldCount();i++)
{
double value=(f->attributeMap())[i].fieldValue().toDouble();
if(value<minmaxcache[i][0])
{
minmaxcache[i][0]=value;
}
if(value>minmaxcache[i][1])
{
minmaxcache[i][1]=value;
}
}
delete f;
}while(f=getNextFeature(true));
minmaxcachedirty=false;
}
//TODO - add sanity check for shape file layers, to include cheking to
// see if the .shp, .dbf, .shx files are all present and the layer
// actually has features
bool QgsOgrProvider::isValid()
{
return valid;
}
bool QgsOgrProvider::addFeature(QgsFeature* f)
{
#ifdef QGISDEBUG
qWarning("in add Feature");
#endif
bool returnValue = true;
OGRFeatureDefn* fdef=ogrLayer->GetLayerDefn();
OGRFeature* feature=new OGRFeature(fdef);
QGis::WKBTYPE ftype;
memcpy(&ftype, (f->getGeometry()+1), sizeof(int));
switch(ftype)
{
case QGis::WKBPoint:
{
OGRPoint* p=new OGRPoint();
p->importFromWkb(f->getGeometry(),1+sizeof(int)+2*sizeof(double));
feature->SetGeometry(p);
break;
}
case QGis::WKBLineString:
{
OGRLineString* l=new OGRLineString();
int length;
memcpy(&length,f->getGeometry()+1+sizeof(int),sizeof(int));
l->importFromWkb(f->getGeometry(),1+2*sizeof(int)+2*length*sizeof(double));
feature->SetGeometry(l);
break;
}
case QGis::WKBPolygon:
{
OGRPolygon* pol=new OGRPolygon();
int numrings;
int totalnumpoints=0;
int numpoints;//number of points in one ring
unsigned char* ptr=f->getGeometry()+1+sizeof(int);
memcpy(&numrings,ptr,sizeof(int));
ptr+=sizeof(int);
for(int i=0;i<numrings;++i)
{
memcpy(&numpoints,ptr,sizeof(int));
ptr+=sizeof(int);
totalnumpoints+=numpoints;
ptr+=(2*sizeof(double));
}
pol->importFromWkb(f->getGeometry(),1+2*sizeof(int)+numrings*sizeof(int)+totalnumpoints*2*sizeof(double));
feature->SetGeometry(pol);
break;
}
case QGis::WKBMultiPoint:
{
OGRMultiPoint* multip= new OGRMultiPoint();
int count;
//determine how many points
memcpy(&count,f->getGeometry()+1+sizeof(int),sizeof(int));
multip->importFromWkb(f->getGeometry(),1+2*sizeof(int)+count*2*sizeof(double));
feature->SetGeometry(multip);
break;
}
case QGis::WKBMultiLineString:
{
OGRMultiLineString* multil=new OGRMultiLineString();
int numlines;
memcpy(&numlines,f->getGeometry()+1+sizeof(int),sizeof(int));
int totalpoints=0;
int numpoints;//number of point in one line
unsigned char* ptr=f->getGeometry()+9;
for(int i=0;i<numlines;++i)
{
memcpy(&numpoints,ptr,sizeof(int));
ptr+=4;
for(int j=0;j<numpoints;++j)
{
ptr+=16;
totalpoints+=2;
}
}
int size=1+2*sizeof(int)+numlines*sizeof(int)+totalpoints*2*sizeof(double);
multil->importFromWkb(f->getGeometry(),size);
feature->SetGeometry(multil);
break;
}
case QGis::WKBMultiPolygon:
{
OGRMultiPolygon* multipol=new OGRMultiPolygon();
int numpolys;
memcpy(&numpolys,f->getGeometry()+1+sizeof(int),sizeof(int));
int numrings;//number of rings in one polygon
int totalrings=0;
int totalpoints=0;
int numpoints;//number of points in one ring
unsigned char* ptr=f->getGeometry()+9;
for(int i=0;i<numpolys;++i)
{
memcpy(&numrings,ptr,sizeof(int));
ptr+=4;
for(int j=0;j<numrings;++j)
{
totalrings++;
memcpy(&numpoints,ptr,sizeof(int));
for(int k=0;k<numpoints;++k)
{
ptr+=16;
totalpoints+=2;
}
}
}
int size=1+2*sizeof(int)+numpolys*sizeof(int)+totalrings*sizeof(int)+totalpoints*2*sizeof(double);
multipol->importFromWkb(f->getGeometry(),size);
feature->SetGeometry(multipol);
break;
}
}
//add possible attribute information
#ifdef QGISDEBUG
qWarning("before attribute commit section");
#endif
for(int i=0;i<f->attributeMap().size();++i)
{
QString s=(f->attributeMap())[i].fieldValue();
#ifdef QGISDEBUG
qWarning("adding attribute: "+s);
#endif
if(!s.isEmpty())
{
if(fdef->GetFieldDefn(i)->GetType()==OFTInteger)
{
feature->SetField(i,s.toInt());
#ifdef QGISDEBUG
qWarning("OFTInteger, attribute value: "+s.toInt());
#endif
}
else if(fdef->GetFieldDefn(i)->GetType()==OFTReal)
{
feature->SetField(i,s.toDouble());
#ifdef QGISDEBUG
qWarning("OFTReal, attribute value: "+QString::number(s.toDouble(),'f',3));
#endif
}
else if(fdef->GetFieldDefn(i)->GetType()==OFTString)
{
feature->SetField(i,s.ascii());
#ifdef QGISDEBUG
qWarning("OFTString, attribute value: "+QString(s.ascii()));
#endif
}
else
{
#ifdef QGISDEBUG
qWarning("no type found");
#endif
}
}
}
if(ogrLayer->CreateFeature(feature)!=OGRERR_NONE)
{
//writing failed
QMessageBox::warning (0, "Warning", "Writing of the feature failed",
QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton );
returnValue = false;
}
++numberFeatures;
delete feature;
ogrLayer->SyncToDisk();
return returnValue;
}
bool QgsOgrProvider::addFeatures(std::list<QgsFeature*> const flist)
{
bool returnvalue=true;
for(std::list<QgsFeature*>::const_iterator it=flist.begin();it!=flist.end();++it)
{
if(!addFeature(*it))
{
returnvalue=false;
}
}
return returnvalue;
}
bool QgsOgrProvider::addAttributes(std::map<QString,QString> const & name)
{
bool returnvalue=true;
for(std::map<QString,QString>::const_iterator iter=name.begin();iter!=name.end();++iter)
{
if(iter->second=="OFTInteger")
{
OGRFieldDefn fielddefn(iter->first,OFTInteger);
if(ogrLayer->CreateField(&fielddefn)!=OGRERR_NONE)
{
#ifdef QGISDEBUG
qWarning("QgsOgrProvider.cpp: writing of the field failed");
#endif
returnvalue=false;
}
}
else if(iter->second=="OFTReal")
{
OGRFieldDefn fielddefn(iter->first,OFTReal);
if(ogrLayer->CreateField(&fielddefn)!=OGRERR_NONE)
{
#ifdef QGISDEBUG
qWarning("QgsOgrProvider.cpp: writing of the field failed");
#endif
returnvalue=false;
}
}
else if(iter->second=="OFTString")
{
OGRFieldDefn fielddefn(iter->first,OFTString);
if(ogrLayer->CreateField(&fielddefn)!=OGRERR_NONE)
{
#ifdef QGISDEBUG
qWarning("QgsOgrProvider.cpp: writing of the field failed");
#endif
returnvalue=false;
}
}
else
{
#ifdef QGISDEBUG
qWarning("QgsOgrProvider.cpp: type not found");
#endif
returnvalue=false;
}
}
return returnvalue;
}
bool QgsOgrProvider::changeAttributeValues(std::map<int,std::map<QString,QString> > const & attr_map)
{
#ifdef QGISDEBUG
std::cerr << "QgsOgrProvider::changeAttributeValues()" << std::endl;
#endif
std::map<int,std::map<QString,QString> > am = attr_map; // stupid, but I don't know other way to convince gcc to compile
for( std::map<int,std::map<QString,QString> >::iterator it=am.begin();it!=am.end();++it)
{
long fid = (long) (*it).first;
OGRFeature *of = ogrLayer->GetFeature ( fid );
if ( !of ) {
QMessageBox::warning (0, "Warning", "Cannot read feature, cannot change attributes" );
return false;
}
std::map<QString,QString> attr = (*it).second;
for( std::map<QString,QString>::iterator it2 = attr.begin(); it2!=attr.end(); ++it2 )
{
QString name = (*it2).first;
QString value = (*it2).second;
int fc = of->GetFieldCount();
for ( int f = 0; f < fc; f++ ) {
OGRFieldDefn *fd = of->GetFieldDefnRef ( f );
if ( name.compare( fd->GetNameRef() ) == 0 ) {
OGRFieldType type = fd->GetType();
#ifdef QGISDEBUG
std::cerr << "set field " << f << " : " << name << " to " << value << std::endl;
#endif
switch ( type ) {
case OFTInteger:
of->SetField ( f, value.toInt() );
break;
case OFTReal:
of->SetField ( f, value.toDouble() );
break;
case OFTString:
of->SetField ( f, value.ascii() );
break;
default:
QMessageBox::warning (0, "Warning", "Unknown field type, cannot change attribute" );
break;
}
continue;
}
}
ogrLayer->SetFeature ( of );
}
}
ogrLayer->SyncToDisk();
return true;
}
int QgsOgrProvider::capabilities() const
{
return (QgsVectorDataProvider::AddFeatures
| QgsVectorDataProvider::ChangeAttributeValues);
}
/**
* Class factory to return a pointer to a newly created
* QgsOgrProvider object
*/
QGISEXTERN QgsOgrProvider * classFactory(const QString *uri)
{
return new QgsOgrProvider(*uri);
}
/** Required key function (used to map the plugin to a data store type)
*/
QGISEXTERN QString providerKey()
{
return QString("ogr");
}
/**
* Required description function
*/
QGISEXTERN QString description()
{
return QString("OGR data provider (shapefile and other formats)");
}
/**
* Required isProvider function. Used to determine if this shared library
* is a data provider plugin
*/
QGISEXTERN bool isProvider()
{
return true;
}
QGISEXTERN bool createEmptyDataSource(const QString& uri,const QString& format, QGis::WKBTYPE vectortype)
{
//hard coded for the moment
OGRwkbGeometryType geomtype=(OGRwkbGeometryType)((int)vectortype);
QString mOutputFormat = "ESRI Shapefile";
QString mOutputFileName = uri;
#ifdef WIN32
QString outname=mOutputFileName.mid(mOutputFileName.findRev("\\")+1,mOutputFileName.length());
#else
QString outname=mOutputFileName.mid(mOutputFileName.findRev("/")+1,mOutputFileName.length());
#endif
OGRSFDriverRegistrar* driverregist = OGRSFDriverRegistrar::GetRegistrar();
if(driverregist==0)
{
return false;
}
OGRSFDriver* driver = driverregist->GetDriverByName(mOutputFormat);
if(driver==0)
{
return false;
}
OGRDataSource* datasource = driver->CreateDataSource(mOutputFileName,NULL);
if(datasource==0)
{
return false;
}
OGRSpatialReference reference;
OGRLayer* layer = datasource->CreateLayer(outname.latin1(),&reference,geomtype,NULL);
if(layer==0)
{
return false;
}
//create a dummy field
OGRFieldDefn fielddef("dummy",OFTReal);
fielddef.SetWidth(1);
fielddef.SetPrecision(1);
if(layer->CreateField(&fielddef,FALSE)!=OGRERR_NONE)
{
return false;
}
int count=layer->GetLayerDefn()->GetFieldCount();
#ifdef QGISDEBUG
qWarning("Field count is: "+QString::number(count));
#endif
//just for a test: create a dummy featureO
/*OGRFeatureDefn* fdef=layer->GetLayerDefn();
OGRFeature* feature=new OGRFeature(fdef);
OGRPoint* p=new OGRPoint();
p->setX(700000);
p->setY(300000);
feature->SetGeometry(p);
if(layer->CreateFeature(feature)!=OGRERR_NONE)
{
qWarning("errrrrrrrrrror!");
}*/
if(layer->SyncToDisk()!=OGRERR_NONE)
{
return false;
}
return true;
/*OGRLayerH mLayerHandle;
OGRRegisterAll();
OGRSFDriverH myDriverHandle = OGRGetDriverByName( mOutputFormat );
if( myDriverHandle == NULL )
{
std::cout << "Unable to find format driver named " << mOutputFormat << std::endl;
return false;
}
OGRDataSourceH mDataSourceHandle = OGR_Dr_CreateDataSource( myDriverHandle, mOutputFileName, NULL );
if( mDataSourceHandle == NULL )
{
std::cout << "Datasource handle is null! " << std::endl;
return false;
}
//define the spatial ref system
OGRSpatialReferenceH mySpatialReferenceSystemHandle = NULL;
QString myWKT = NULL; //WKT = Well Known Text
//sample below shows how to extract srs from a raster
// const char *myWKT = GDALGetProjectionRef( hBand );
if( myWKT != NULL && strlen(myWKT) != 0 )
{
mySpatialReferenceSystemHandle = OSRNewSpatialReference( myWKT );
}
//change 'contour' to something more useful!
#ifdef QGISDEBUG
qWarning("mOutputFileName: "+mOutputFileName);
#endif //QGISDEBUG
#ifdef QGISDEBUG
qWarning("outname: "+outname);
#endif //QGISDEBUG
mLayerHandle = OGR_DS_CreateLayer( mDataSourceHandle, outname,
mySpatialReferenceSystemHandle, geomtype, NULL );
if( mLayerHandle == NULL )
{
std::cout << "Error layer handle is null!" << std::endl;
return false;
}
else
{
std::cout << "File handle created!" << std::endl;
}
OGRFieldDefnH myFieldDefinitionHandle;
myFieldDefinitionHandle = OGR_Fld_Create( "dummy",OFTReal);
OGR_Fld_SetWidth( myFieldDefinitionHandle,1);
OGR_Fld_SetPrecision( myFieldDefinitionHandle,1);
OGR_L_CreateField( mLayerHandle, myFieldDefinitionHandle, FALSE );
OGR_Fld_Destroy( myFieldDefinitionHandle );
return true;*/
}