mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-26 00:02:08 -05:00
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@2944 c8812cc2-4d05-0410-92ff-de0c093fc19c
1154 lines
30 KiB
C++
1154 lines
30 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();
|
|
}
|
|
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)
|
|
{
|
|
|
|
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 char *uri)
|
|
{
|
|
return new QgsOgrProvider(QString::fromUtf8(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;*/
|
|
}
|