diff --git a/python/core/qgsvectorfilewriter.sip b/python/core/qgsvectorfilewriter.sip
index 00f250a5d1c..6f095d6c308 100644
--- a/python/core/qgsvectorfilewriter.sip
+++ b/python/core/qgsvectorfilewriter.sip
@@ -121,7 +121,10 @@ class QgsVectorFileWriter
@param newFilename QString pointer which will contain the new file name created (in case it is different to fileName).
@param symbologyExport symbology to export
@param symbologyScale scale of symbology
- @param filterExtent if not a null pointer, only features intersecting the extent will be saved
+ @param filterExtent if not a null pointer, only features intersecting the extent will be saved (added in QGIS 2.4)
+ allows for conversion of geometryless tables to null geometries, etc (added in QGIS 2.14)
+ @param forceMulti set to true to force creation of multi* geometries (added in QGIS 2.14)
+ @param includeZ set to true to include z dimension in output. This option is only valid if overrideGeometryType is set. (added in QGIS 2.14)
*/
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
const QString& fileName,
@@ -136,10 +139,33 @@ class QgsVectorFileWriter
QString *newFilename = 0,
SymbologyExport symbologyExport = NoSymbology,
double symbologyScale = 1.0,
- const QgsRectangle* filterExtent = 0 // added in 2.4
+ const QgsRectangle* filterExtent = 0,
+ QgsWKBTypes::Type overrideGeometryType = QgsWKBTypes::Unknown,
+ bool forceMulti = false,
+ bool includeZ = false
);
- //! @note added in v2.2
+ /** Writes a layer out to a vector file.
+ * @param layer layer to write
+ * @param fileName file name to write to
+ * @param fileEncoding encoding to use
+ * @param ct
+ * @param driverName OGR driver to use
+ * @param onlySelected write only selected features of layer
+ * @param errorMessage pointer to buffer fo error message
+ * @param datasourceOptions list of OGR data source creation options
+ * @param layerOptions list of OGR layer creation options
+ * @param skipAttributeCreation only write geometries
+ * @param newFilename QString pointer which will contain the new file name created (in case it is different to fileName).
+ * @param symbologyExport symbology to export
+ * @param symbologyScale scale of symbology
+ * @param filterExtent if not a null pointer, only features intersecting the extent will be saved (added in QGIS 2.4)
+ * @param overrideGeometryType set to a valid geometry type to override the default geometry type for the layer. This parameter
+ * allows for conversion of geometryless tables to null geometries, etc (added in QGIS 2.14)
+ * @param forceMulti set to true to force creation of multi* geometries (added in QGIS 2.14)
+ * @param includeZ set to true to include z dimension in output. This option is only valid if overrideGeometryType is set. (added in QGIS 2.14)
+ * @note added in v2.2
+ */
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
const QString& fileName,
const QString& fileEncoding,
@@ -153,7 +179,10 @@ class QgsVectorFileWriter
QString *newFilename = 0,
SymbologyExport symbologyExport = NoSymbology,
double symbologyScale = 1.0,
- const QgsRectangle* filterExtent = 0 // added in 2.4
+ const QgsRectangle* filterExtent = 0,
+ QgsWKBTypes::Type overrideGeometryType = QgsWKBTypes::Unknown,
+ bool forceMulti = false,
+ bool includeZ = false
);
/** Create shapefile and initialize it */
diff --git a/src/app/ogr/qgsvectorlayersaveasdialog.cpp b/src/app/ogr/qgsvectorlayersaveasdialog.cpp
index 83bd665488c..32a8221d9ea 100644
--- a/src/app/ogr/qgsvectorlayersaveasdialog.cpp
+++ b/src/app/ogr/qgsvectorlayersaveasdialog.cpp
@@ -67,6 +67,15 @@ void QgsVectorLayerSaveAsDialog::setup()
mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( format ) );
mFormatComboBox->blockSignals( false );
+ //add geometry types to combobox
+ mGeometryTypeComboBox->addItem( tr( "Automatic" ), -1 );
+ mGeometryTypeComboBox->addItem( QgsWKBTypes::displayString( QgsWKBTypes::Point ), QgsWKBTypes::Point );
+ mGeometryTypeComboBox->addItem( QgsWKBTypes::displayString( QgsWKBTypes::LineString ), QgsWKBTypes::LineString );
+ mGeometryTypeComboBox->addItem( QgsWKBTypes::displayString( QgsWKBTypes::Polygon ), QgsWKBTypes::Polygon );
+ mGeometryTypeComboBox->addItem( QgsWKBTypes::displayString( QgsWKBTypes::GeometryCollection ), QgsWKBTypes::GeometryCollection );
+ mGeometryTypeComboBox->addItem( tr( "No geometry" ), QgsWKBTypes::NoGeometry );
+ mGeometryTypeComboBox->setCurrentIndex( mGeometryTypeComboBox->findData( -1 ) );
+
mEncodingComboBox->addItems( QgsVectorDataProvider::availableEncodings() );
QString enc = settings.value( "/UI/encoding", "System" ).toString();
@@ -458,6 +467,44 @@ bool QgsVectorLayerSaveAsDialog::onlySelected() const
return mSelectedOnly->isChecked();
}
+QgsWKBTypes::Type QgsVectorLayerSaveAsDialog::geometryType() const
+{
+ int currentIndexData = mGeometryTypeComboBox->itemData( mGeometryTypeComboBox->currentIndex() ).toInt();
+ if ( currentIndexData == -1 )
+ {
+ //automatic
+ return QgsWKBTypes::Unknown;
+ }
+
+ return ( QgsWKBTypes::Type )currentIndexData;
+}
+
+bool QgsVectorLayerSaveAsDialog::automaticGeometryType() const
+{
+ int currentIndexData = mGeometryTypeComboBox->itemData( mGeometryTypeComboBox->currentIndex() ).toInt();
+ return currentIndexData == -1;
+}
+
+bool QgsVectorLayerSaveAsDialog::forceMulti() const
+{
+ return mForceMultiCheckBox->isChecked();
+}
+
+void QgsVectorLayerSaveAsDialog::setForceMulti( bool checked )
+{
+ mForceMultiCheckBox->setChecked( checked );
+}
+
+bool QgsVectorLayerSaveAsDialog::includeZ() const
+{
+ return mIncludeZCheckBox->isChecked();
+}
+
+void QgsVectorLayerSaveAsDialog::setIncludeZ( bool checked )
+{
+ mIncludeZCheckBox->setChecked( checked );
+}
+
void QgsVectorLayerSaveAsDialog::on_mSymbologyExportComboBox_currentIndexChanged( const QString& text )
{
bool scaleEnabled = true;
@@ -468,3 +515,11 @@ void QgsVectorLayerSaveAsDialog::on_mSymbologyExportComboBox_currentIndexChanged
mScaleSpinBox->setEnabled( scaleEnabled );
mScaleLabel->setEnabled( scaleEnabled );
}
+
+void QgsVectorLayerSaveAsDialog::on_mGeometryTypeComboBox_currentIndexChanged( int index )
+{
+ int currentIndexData = mGeometryTypeComboBox->itemData( index ).toInt();
+
+ mForceMultiCheckBox->setEnabled( currentIndexData != -1 );
+ mIncludeZCheckBox->setEnabled( currentIndexData != -1 );
+}
diff --git a/src/app/ogr/qgsvectorlayersaveasdialog.h b/src/app/ogr/qgsvectorlayersaveasdialog.h
index bd8565dc076..a4c78c457a3 100644
--- a/src/app/ogr/qgsvectorlayersaveasdialog.h
+++ b/src/app/ogr/qgsvectorlayersaveasdialog.h
@@ -65,6 +65,36 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
bool onlySelected() const;
+ /** Returns the selected flat geometry type for the export.
+ * @see automaticGeometryType()
+ * @see forceMulti()
+ * @see includeZ()
+ */
+ QgsWKBTypes::Type geometryType() const;
+
+ /** Returns true if geometry type is set to automatic.
+ * @see geometryType()
+ */
+ bool automaticGeometryType() const;
+
+ /** Returns true if force multi geometry type is checked.
+ * @see includeZ()
+ */
+ bool forceMulti() const;
+
+ /** Sets whether the force multi geometry checkbox should be checked.
+ */
+ void setForceMulti( bool checked );
+
+ /** Returns true if include z dimension is checked.
+ * @see forceMulti()
+ */
+ bool includeZ() const;
+
+ /** Sets whether the include z dimension checkbox should be checked.
+ */
+ void setIncludeZ( bool checked );
+
private slots:
void on_mFormatComboBox_currentIndexChanged( int idx );
void on_leFilename_textChanged( const QString& text );
@@ -72,6 +102,7 @@ class QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVectorLayerSav
void on_mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem& crs );
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
void on_mSymbologyExportComboBox_currentIndexChanged( const QString& text );
+ void on_mGeometryTypeComboBox_currentIndexChanged( int index );
void accept() override;
private:
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 3517315666e..eee03affe37 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -5476,6 +5476,7 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
QgsVectorLayerSaveAsDialog *dialog = new QgsVectorLayerSaveAsDialog( vlayer->crs().srsid(), vlayer->extent(), vlayer->selectedFeatureCount() != 0, options, this );
dialog->setCanvasExtent( mMapCanvas->mapSettings().visibleExtent(), mMapCanvas->mapSettings().destinationCrs() );
+ dialog->setIncludeZ( QgsWKBTypes::hasZ( QGis::fromOldWkbType( vlayer->wkbType() ) ) );
if ( dialog->exec() == QDialog::Accepted )
{
@@ -5483,6 +5484,8 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
QString vectorFilename = dialog->filename();
QString format = dialog->format();
QStringList datasourceOptions = dialog->datasourceOptions();
+ bool autoGeometryType = dialog->automaticGeometryType();
+ QgsWKBTypes::Type forcedGeometryType = dialog->geometryType();
QgsCoordinateTransform* ct = 0;
destCRS = QgsCoordinateReferenceSystem( dialog->crs(), QgsCoordinateReferenceSystem::InternalCrsId );
@@ -5529,7 +5532,11 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
&newFilename,
( QgsVectorFileWriter::SymbologyExport )( dialog->symbologyExport() ),
dialog->scaleDenominator(),
- dialog->hasFilterExtent() ? &filterExtent : 0 );
+ dialog->hasFilterExtent() ? &filterExtent : 0,
+ autoGeometryType ? QgsWKBTypes::Unknown : forcedGeometryType,
+ dialog->forceMulti(),
+ dialog->includeZ()
+ );
delete ct;
diff --git a/src/core/qgsvectorfilewriter.cpp b/src/core/qgsvectorfilewriter.cpp
index a8b482be9b1..3f4a7bbd7d4 100644
--- a/src/core/qgsvectorfilewriter.cpp
+++ b/src/core/qgsvectorfilewriter.cpp
@@ -1725,7 +1725,8 @@ OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
QgsGeometry *geom = feature.geometry();
// turn single geoemetry to multi geometry if needed
- if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) )
+ if ( geom && geom->wkbType() != mWkbType &&
+ QgsWKBTypes::flatType( geom->geometry()->wkbType() ) == QgsWKBTypes::flatType( QgsWKBTypes::singleType( QGis::fromOldWkbType( mWkbType ) ) ) )
{
geom->convertToMultiType();
}
@@ -1738,6 +1739,10 @@ OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
// we must force the use of 25D.
if ( mWkbType >= QGis::WKBPoint25D && mWkbType <= QGis::WKBMultiPolygon25D )
{
+ //ND: I suspect there's a bug here, in that this is NOT converting the geometry's WKB type,
+ //so the exported WKB has a different type to what the OGRGeometry is expecting.
+ //possibly this is handled already in OGR, but it should be fixed regardless by actually converting
+ //geom to the correct WKB type
QgsWKBTypes::Type wkbType = QGis::fromOldWkbType( geom->wkbType() );
if ( wkbType >= QgsWKBTypes::PointZ && wkbType <= QgsWKBTypes::MultiPolygonZ )
{
@@ -1799,6 +1804,10 @@ OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
// set geometry (ownership is not passed to OGR)
OGR_F_SetGeometry( poFeature, mGeom );
}
+ else
+ {
+ OGR_F_SetGeometry( poFeature, createEmptyGeometry( mWkbType ) );
+ }
}
return poFeature;
}
@@ -1848,7 +1857,10 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
QString *newFilename,
SymbologyExport symbologyExport,
double symbologyScale,
- const QgsRectangle* filterExtent )
+ const QgsRectangle* filterExtent,
+ QgsWKBTypes::Type overrideGeometryType,
+ bool forceMulti,
+ bool includeZ )
{
QgsCoordinateTransform* ct = 0;
if ( destCRS && layer )
@@ -1857,7 +1869,7 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
}
QgsVectorFileWriter::WriterError error = writeAsVectorFormat( layer, fileName, fileEncoding, ct, driverName, onlySelected,
- errorMessage, datasourceOptions, layerOptions, skipAttributeCreation, newFilename, symbologyExport, symbologyScale, filterExtent );
+ errorMessage, datasourceOptions, layerOptions, skipAttributeCreation, newFilename, symbologyExport, symbologyScale, filterExtent, overrideGeometryType, forceMulti, includeZ );
delete ct;
return error;
}
@@ -1875,7 +1887,10 @@ QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( QgsVe
QString *newFilename,
SymbologyExport symbologyExport,
double symbologyScale,
- const QgsRectangle* filterExtent )
+ const QgsRectangle* filterExtent,
+ QgsWKBTypes::Type overrideGeometryType,
+ bool forceMulti,
+ bool includeZ )
{
if ( !layer )
{
@@ -1896,7 +1911,18 @@ QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( QgsVe
outputCRS = &layer->crs();
}
- QGis::WkbType wkbType = layer->wkbType();
+ QgsWKBTypes::Type destWkbType = QGis::fromOldWkbType( layer->wkbType() );
+ if ( overrideGeometryType != QgsWKBTypes::Unknown )
+ {
+ destWkbType = QgsWKBTypes::flatType( overrideGeometryType );
+ if ( QgsWKBTypes::hasZ( overrideGeometryType ) || includeZ )
+ destWkbType = QgsWKBTypes::addZ( destWkbType );
+ }
+ if ( forceMulti )
+ {
+ destWkbType = QgsWKBTypes::multiType( destWkbType );
+ }
+
QgsFields fields = skipAttributeCreation ? QgsFields() : layer->fields();
if ( layer->providerType() == "ogr" && layer->dataProvider() )
@@ -1912,19 +1938,21 @@ QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( QgsVe
}
// Shapefiles might contain multi types although wkbType() only reports singles
- if ( layer->storageType() == "ESRI Shapefile" )
+ if ( layer->storageType() == "ESRI Shapefile" && !QgsWKBTypes::isMultiType( destWkbType ) )
{
- const QgsFeatureIds &ids = layer->selectedFeaturesIds();
- QgsFeatureIterator fit = layer->getFeatures();
+ QgsFeatureRequest req;
+ if ( onlySelected )
+ {
+ req.setFilterFids( layer->selectedFeaturesIds() );
+ }
+ QgsFeatureIterator fit = layer->getFeatures( req );
QgsFeature fet;
+
while ( fit.nextFeature( fet ) )
{
- if ( onlySelected && !ids.contains( fet.id() ) )
- continue;
-
- if ( fet.constGeometry() && fet.constGeometry()->wkbType() == QGis::multiType( wkbType ) )
+ if ( fet.constGeometry() && !fet.constGeometry()->isEmpty() && QgsWKBTypes::isMultiType( fet.constGeometry()->geometry()->wkbType() ) )
{
- wkbType = QGis::multiType( wkbType );
+ destWkbType = QgsWKBTypes::multiType( destWkbType );
break;
}
}
@@ -1947,7 +1975,7 @@ QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( QgsVe
}
QgsVectorFileWriter* writer =
- new QgsVectorFileWriter( fileName, fileEncoding, fields, wkbType, outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
+ new QgsVectorFileWriter( fileName, fileEncoding, fields, QGis::fromNewWkbType( destWkbType ), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
writer->setSymbologyScaleDenominator( symbologyScale );
if ( newFilename )
diff --git a/src/core/qgsvectorfilewriter.h b/src/core/qgsvectorfilewriter.h
index 4ccdb9b8a54..5879333105d 100644
--- a/src/core/qgsvectorfilewriter.h
+++ b/src/core/qgsvectorfilewriter.h
@@ -174,7 +174,11 @@ class CORE_EXPORT QgsVectorFileWriter
@param newFilename QString pointer which will contain the new file name created (in case it is different to fileName).
@param symbologyExport symbology to export
@param symbologyScale scale of symbology
- @param filterExtent if not a null pointer, only features intersecting the extent will be saved
+ @param filterExtent if not a null pointer, only features intersecting the extent will be saved (added in QGIS 2.4)
+ @param overrideGeometryType set to a valid geometry type to override the default geometry type for the layer. This parameter
+ allows for conversion of geometryless tables to null geometries, etc (added in QGIS 2.14)
+ @param forceMulti set to true to force creation of multi* geometries (added in QGIS 2.14)
+ @param includeZ set to true to include z dimension in output. This option is only valid if overrideGeometryType is set. (added in QGIS 2.14)
*/
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
const QString& fileName,
@@ -189,10 +193,33 @@ class CORE_EXPORT QgsVectorFileWriter
QString *newFilename = 0,
SymbologyExport symbologyExport = NoSymbology,
double symbologyScale = 1.0,
- const QgsRectangle* filterExtent = 0 // added in 2.4
+ const QgsRectangle* filterExtent = 0,
+ QgsWKBTypes::Type overrideGeometryType = QgsWKBTypes::Unknown,
+ bool forceMulti = false,
+ bool includeZ = false
);
- //! @note added in v2.2
+ /** Writes a layer out to a vector file.
+ * @param layer layer to write
+ * @param fileName file name to write to
+ * @param fileEncoding encoding to use
+ * @param ct
+ * @param driverName OGR driver to use
+ * @param onlySelected write only selected features of layer
+ * @param errorMessage pointer to buffer fo error message
+ * @param datasourceOptions list of OGR data source creation options
+ * @param layerOptions list of OGR layer creation options
+ * @param skipAttributeCreation only write geometries
+ * @param newFilename QString pointer which will contain the new file name created (in case it is different to fileName).
+ * @param symbologyExport symbology to export
+ * @param symbologyScale scale of symbology
+ * @param filterExtent if not a null pointer, only features intersecting the extent will be saved (added in QGIS 2.4)
+ * @param overrideGeometryType set to a valid geometry type to override the default geometry type for the layer. This parameter
+ * allows for conversion of geometryless tables to null geometries, etc (added in QGIS 2.14)
+ * @param forceMulti set to true to force creation of multi* geometries (added in QGIS 2.14)
+ * @param includeZ set to true to include z dimension in output. This option is only valid if overrideGeometryType is set. (added in QGIS 2.14)
+ * @note added in v2.2
+ */
static WriterError writeAsVectorFormat( QgsVectorLayer* layer,
const QString& fileName,
const QString& fileEncoding,
@@ -206,7 +233,10 @@ class CORE_EXPORT QgsVectorFileWriter
QString *newFilename = 0,
SymbologyExport symbologyExport = NoSymbology,
double symbologyScale = 1.0,
- const QgsRectangle* filterExtent = 0 // added in 2.4
+ const QgsRectangle* filterExtent = 0,
+ QgsWKBTypes::Type overrideGeometryType = QgsWKBTypes::Unknown,
+ bool forceMulti = false,
+ bool includeZ = false
);
/** Create shapefile and initialize it */
diff --git a/src/ui/qgsvectorlayersaveasdialogbase.ui b/src/ui/qgsvectorlayersaveasdialogbase.ui
index a81b6c6567c..270850d3643 100644
--- a/src/ui/qgsvectorlayersaveasdialogbase.ui
+++ b/src/ui/qgsvectorlayersaveasdialogbase.ui
@@ -91,7 +91,7 @@
0
0
555
- 523
+ 650
@@ -177,6 +177,43 @@
+ -
+
+
+ Geometry
+
+
+
-
+
+
-
+
+
+ Geometry type
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Force multi-type
+
+
+
+ -
+
+
+ Include z-dimension
+
+
+
+
+
+
-
@@ -320,15 +357,15 @@
- QgsCollapsibleGroupBox
- QGroupBox
-
+ QgsProjectionSelectionWidget
+ QWidget
+ qgsprojectionselectionwidget.h
1
- QgsProjectionSelectionWidget
- QWidget
- qgsprojectionselectionwidget.h
+ QgsCollapsibleGroupBox
+ QGroupBox
+
1
@@ -350,6 +387,9 @@
mAddToCanvas
mSymbologyExportComboBox
mScaleSpinBox
+ mGeometryTypeComboBox
+ mForceMultiCheckBox
+ mIncludeZCheckBox
mOgrDatasourceOptions
mOgrLayerOptions
buttonBox