mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
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
1231 lines
32 KiB
C++
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;*/
|
|
}
|