📄 qgsshapefile.cpp
字号:
/*************************************************************************** qgsshapefile.cpp - description ------------------- begin : Fri Dec 19 2003 copyright : (C) 2003 by Denis Antipov email : ***************************************************************************//*************************************************************************** * * * 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: qgsshapefile.cpp 8293 2008-03-28 17:36:20Z jef $ */#include <QApplication>#include <ogr_api.h>#include <string>#include <iostream>#include <fstream>#include <cstdio>#include <QFile>#include <QProgressDialog>#include <QString>#include <QLabel>#include <QTextCodec>#include <QFileInfo>#include "qgsdbfbase.h"#include "cpl_error.h"#include "qgsshapefile.h"#include "qgis.h"#include "qgslogger.h"#include "qgspgutil.h"// for htonl#ifdef WIN32#include <winsock.h>#else#include <netinet/in.h>#endif QgsShapeFile::QgsShapeFile(QString name, QString encoding){ filename = name; features = 0; OGRRegisterAll(); ogrDataSource = OGROpen(QFile::encodeName(filename).constData(),FALSE,NULL); if (ogrDataSource != NULL){ valid = true; ogrLayer = OGR_DS_GetLayer(ogrDataSource,0); features = OGR_L_GetFeatureCount(ogrLayer,TRUE); } else valid = false; setDefaultTable(); // init the geometry types geometries << "NULL" << "POINT" << "LINESTRING" << "POLYGON" << "MULTPOINT" << "MULTILINESTRING" << "MULTIPOLYGON" << "GEOMETRYCOLLECTION"; codec = QTextCodec::codecForName(encoding.toLocal8Bit().data()); if (!codec) codec = QTextCodec::codecForLocale();}QgsShapeFile::~QgsShapeFile(){ OGR_DS_Destroy( ogrDataSource ); delete filename; delete geom_type;}int QgsShapeFile::getFeatureCount(){ return features;}bool QgsShapeFile::scanGeometries(){ QProgressDialog *sg = new QProgressDialog(); sg->setMinimum(0); sg->setMaximum(0); QString label = "Scanning "; label += filename; sg->setLabel(new QLabel(label)); sg->show(); qApp->processEvents(); OGRFeatureH feat; OGRwkbGeometryType currentType = wkbUnknown; bool multi = false; while((feat = OGR_L_GetNextFeature(ogrLayer))) { qApp->processEvents(); // feat->DumpReadable(NULL); OGRGeometryH geom = OGR_F_GetGeometryRef(feat); if(geom) { QString gml = OGR_G_ExportToGML(geom); // std::cerr << gml << std::endl; if(gml.find("gml:Multi") > -1) { // std::cerr << "MULTI Part Feature detected" << std::endl; multi = true; } OGRFeatureDefnH fDef = OGR_F_GetDefnRef(feat); OGRwkbGeometryType gType = OGR_FD_GetGeomType(fDef); // std::cerr << fDef->GetGeomType() << std::endl; if(gType > currentType) { currentType = gType; } if(gType < currentType) { std::cerr << "Encountered inconsistent geometry type " << gType << std::endl; } } } // a hack to support 2.5D geometries (their wkb is equivalent to 2D variants // except that the highest bit is set also). For now we will ignore 3rd coordinate. hasMoreDimensions = false; if (currentType & wkb25DBit) { QgsDebugMsg("Got a shapefile with 2.5D geometry."); currentType = wkbFlatten(currentType); hasMoreDimensions = true; } OGR_L_ResetReading(ogrLayer); geom_type = geometries[currentType]; if(multi && (geom_type.find("MULTI") == -1)) { geom_type = "MULTI" + geom_type; } delete sg; // std::cerr << "Geometry type is " << currentType << " (" << geometries[currentType] << ")" << std::endl; return multi;}QString QgsShapeFile::getFeatureClass(){ // scan the whole layer to try to determine the geometry // type. qApp->processEvents(); isMulti = scanGeometries(); OGRFeatureH feat; // skip features without geometry while ((feat = OGR_L_GetNextFeature(ogrLayer)) != NULL) { if (OGR_F_GetGeometryRef(feat)) break; } if(feat){ OGRGeometryH geom = OGR_F_GetGeometryRef(feat); if(geom){ /* OGR doesn't appear to report geometry type properly * for a layer containing both polygon and multipolygon * entities * // get the feature type from the layer OGRFeatureDefn * gDef = ogrLayer->GetLayerDefn(); OGRwkbGeometryType gType = gDef->GetGeomType(); geom_type = QGis::qgisFeatureTypes[gType]; */ //geom_type = QString(geom->getGeometryName()); //geom_type = "GEOMETRY"; QgsDebugMsg("Preparing to escape " + geom_type); char * esc_str = new char[geom_type.length()*2+1]; PQescapeString(esc_str, (const char *)geom_type, geom_type.length()); geom_type = QString(esc_str); QgsDebugMsg("After escaping, geom_type is : " + geom_type); delete[] esc_str; QString file(filename); file.replace(file.length()-3, 3, "dbf"); // open the dbf file std::ifstream dbf((const char*)file, std::ios::in | std::ios::binary); // read header DbaseHeader dbh; dbf.read((char *)&dbh, sizeof(dbh)); // Check byte order if(htonl(1) == 1) { /* DbaseHeader is stored in little-endian format. * The num_recs, size_hdr and size_rec fields must be byte-swapped when read * on a big-endian processor. Currently only size_hdr is used. */ unsigned char *byte = reinterpret_cast<unsigned char *>(&dbh.size_hdr); unsigned char t = *byte; *byte = *(byte+1); *(byte+1) = t; } Fda fda; QString str_type = "varchar("; for(int field_count = 0, bytes_read = sizeof(dbh); bytes_read < dbh.size_hdr-1; field_count++, bytes_read +=sizeof(fda)){ dbf.read((char *)&fda, sizeof(fda)); switch(fda.field_type){ case 'N': if((int)fda.field_decimal>0) column_types.push_back("float"); else column_types.push_back("int"); break; case 'F': column_types.push_back("float"); break; case 'D': column_types.push_back("date"); break; case 'C': str_type= QString("varchar(%1)").arg(fda.field_length); column_types.push_back(str_type); break; case 'L': column_types.push_back("boolean"); break; default: column_types.push_back("varchar(256)"); break; } } dbf.close(); int numFields = OGR_F_GetFieldCount(feat); for(int n=0; n<numFields; n++) { QString s = codec->toUnicode(OGR_Fld_GetNameRef(OGR_F_GetFieldDefnRef(feat,n))); column_names.push_back(s); } }else valid = false; OGR_F_Destroy( feat ); }else valid = false; OGR_L_ResetReading(ogrLayer); return valid?geom_type:QString::null;}bool QgsShapeFile::is_valid(){ return valid;}QString QgsShapeFile::getName(){ return filename;}QString QgsShapeFile::getTable(){ return table_name;}void QgsShapeFile::setTable(QString new_table){ new_table.replace("\'","\\'"); new_table.replace("\\","\\\\"); table_name = new_table;}void QgsShapeFile::setDefaultTable(){ QFileInfo fi(filename); table_name = fi.baseName();}void QgsShapeFile::setColumnNames(QStringList columns){ column_names.clear(); for (QStringList::Iterator it = columns.begin(); it != columns.end(); ++it) { column_names.push_back(*it); }}bool QgsShapeFile::insertLayer(QString dbname, QString schema, QString primary_key, QString geom_col, QString srid, PGconn * conn, QProgressDialog& pro, bool &fin, QString& errorText){ connect(&pro, SIGNAL(canceled()), this, SLOT(cancelImport())); import_canceled = false; bool result = true; QString query = QString("CREATE TABLE %1.%2(%3 int4 PRIMARY KEY") .arg( QgsPgUtil::quotedIdentifier(schema) ) .arg( QgsPgUtil::quotedIdentifier(table_name) ) .arg( QgsPgUtil::quotedIdentifier(primary_key) ); for(uint n=0; n<column_names.size() && result; n++) { query += QString(",%1 %2") .arg( QgsPgUtil::quotedIdentifier(column_names[n]) ) .arg( column_types[n] ); } query += " )"; QgsDebugMsg("Query string is: " + query); PGresult *res = PQexec(conn, query.toUtf8() ); if(PQresultStatus(res)!=PGRES_COMMAND_OK){ // flag error and send query and error message to stdout on debug errorText += tr("The database gave an error while executing this SQL:") + "\n"; errorText += query + '\n'; errorText += tr("The error was:") + "\n"; errorText += PQresultErrorMessage(res) + '\n'; PQclear(res); return false; } else { PQclear(res); } query = QString("SELECT AddGeometryColumn(%1,%2,%3,%4,%5,2)") .arg( QgsPgUtil::quotedValue( schema ) ) .arg( QgsPgUtil::quotedValue( table_name ) ) .arg( QgsPgUtil::quotedValue( geom_col ) ) .arg( srid ) .arg( QgsPgUtil::quotedValue( geom_type ) ); res = PQexec(conn, query.toUtf8() ); if(PQresultStatus(res)!=PGRES_TUPLES_OK){ errorText += tr("The database gave an error while executing this SQL:") + "\n"; errorText += query + '\n'; errorText += tr("The error was:") + "\n"; errorText += PQresultErrorMessage(res) + '\n'; PQclear(res); return false; } else{ PQclear(res); } if(isMulti) { query = QString("select constraint_name from information_schema.table_constraints where table_schema=%1 and table_name=%2 and constraint_name in ('$2','enforce_geotype_the_geom')") .arg( QgsPgUtil::quotedValue(schema) ) .arg( QgsPgUtil::quotedValue(table_name) ); QStringList constraints; res = PQexec(conn, query.toUtf8() ); if( PQresultStatus( res ) == PGRES_TUPLES_OK ) { for(int i=0; i<PQntuples(res); i++) constraints.append( PQgetvalue(res, i, 0) ); } PQclear(res); if( constraints.size()>0 ) { // drop the check constraint // TODO This whole concept needs to be changed to either // convert the geometries to the same type or allow // multiple types in the check constraint. For now, we // just drop the constraint... query = QString("alter table %1 drop constraint %2") .arg( QgsPgUtil::quotedIdentifier(table_name) ) .arg( QgsPgUtil::quotedIdentifier(constraints[0]) ); res = PQexec(conn, query.toUtf8() ); if(PQresultStatus(res)!=PGRES_COMMAND_OK) { errorText += tr("The database gave an error while executing this SQL:") + "\n"; errorText += query + '\n'; errorText += tr("The error was:") + "\n"; errorText += PQresultErrorMessage(res) + '\n'; PQclear(res); return false; } PQclear(res); } } //adding the data into the table for(int m=0; m<features && result; m++) { if(import_canceled) { fin = true; break; } OGRFeatureH feat = OGR_L_GetNextFeature(ogrLayer); if(feat){ OGRGeometryH geom = OGR_F_GetGeometryRef(feat); if(geom){ query = QString("INSERT INTO %1.%2 VALUES(%3") .arg( QgsPgUtil::quotedIdentifier(schema) ) .arg( QgsPgUtil::quotedIdentifier(table_name) ) .arg( m ); int num = OGR_G_WkbSize(geom); char * geo_temp = new char[num*3]; // 'GeometryFromText' supports only 2D coordinates // TODO for proper 2.5D support we would need to use 'GeomFromEWKT' if (hasMoreDimensions) OGR_G_SetCoordinateDimension(geom,2); OGR_G_ExportToWkt(geom,&geo_temp); QString geometry(geo_temp); for(uint n=0; n<column_types.size(); n++) { QString val; // FIXME: OGR_F_GetFieldAsString returns junk when called with a 8.255 float field if( column_types[n] == "float" ) val = QString::number( OGR_F_GetFieldAsDouble(feat,n) ); else val = codec->toUnicode(OGR_F_GetFieldAsString(feat,n) ); if( val.isEmpty() ) val = "NULL"; else val = QgsPgUtil::quotedValue( val ); query += "," + val; } query += QString(",GeometryFromText(%1,%2))") .arg( QgsPgUtil::quotedValue( geometry ) ) .arg( srid ); if(result) res = PQexec(conn, query.utf8() ); if(PQresultStatus(res)!=PGRES_COMMAND_OK){ // flag error and send query and error message to stdout on debug result = false; errorText += tr("The database gave an error while executing this SQL:") + "\n"; // the query string can be quite long. Trim if necessary... if (query.count() > 100) errorText += query.left(150) + tr("... (rest of SQL trimmed)", "is appended to a truncated SQL statement") + "\n"; else errorText += query + '\n'; errorText += tr("The error was:") + "\n"; errorText += PQresultErrorMessage(res); errorText += '\n'; } else { PQclear(res); } pro.setValue(pro.value()+1); qApp->processEvents(); delete[] geo_temp; } OGR_F_Destroy( feat ); } } // create the GIST index if the the load was successful if(result) { // prompt user to see if they want to build the index and warn // them about the potential time-cost } OGR_L_ResetReading(ogrLayer); return result;}void QgsShapeFile::cancelImport(){ import_canceled = true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -