Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
New functionality for merging features
git-svn-id: http://svn.osgeo.org/qgis/trunk@10879 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent committed Jun 3, 2009
1 parent aa18385 commit dbaf7bd
Show file tree
Hide file tree
Showing 9 changed files with 909 additions and 0 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/mActionMergeFeatures.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -41,6 +41,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolvertexedit.cpp
qgsmeasuredialog.cpp
qgsmeasuretool.cpp
qgsmergeattributesdialog.cpp
qgsnewhttpconnection.cpp
qgsnumericsortlistviewitem.cpp
qgsogrsublayersdialog.cpp
Expand Down Expand Up @@ -129,6 +130,7 @@ SET (QGIS_APP_MOC_HDRS

qgsmeasuretool.h
qgsmeasuredialog.h
qgsmergeattributesdialog.h
qgsnewhttpconnection.h
qgsoptions.h
qgsogrsublayersdialog.h
Expand Down
155 changes: 155 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -114,6 +114,7 @@
#include "qgsmapoverviewcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaptip.h"
#include "qgsmergeattributesdialog.h"
#include "qgsmessageviewer.h"
#include "qgsoptions.h"
#include "qgspastetransformations.h"
Expand Down Expand Up @@ -703,6 +704,12 @@ void QgisApp::createActions()
connect( mActionDeletePart, SIGNAL( triggered() ), this, SLOT( deletePart() ) );
mActionDeletePart->setEnabled( false );

mActionMergeFeatures = new QAction( getThemeIcon("mActionMergeFeatures.png"), tr("Merge selected features"), this);
shortcuts->registerAction(mActionMergeFeatures);
mActionMergeFeatures->setStatusTip( tr("Merge selected features"));
connect( mActionMergeFeatures, SIGNAL(triggered()), this, SLOT(mergeSelectedFeatures()));
mActionMergeFeatures->setEnabled(false);


// View Menu Items

Expand Down Expand Up @@ -1053,6 +1060,7 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionDeleteRing );
mActionDeletePart->setCheckable( true );
mMapToolGroup->addAction( mActionDeletePart );
mMapToolGroup->addAction( mActionMergeFeatures);
}

void QgisApp::createMenus()
Expand Down Expand Up @@ -1141,6 +1149,7 @@ void QgisApp::createMenus()
mEditMenu->addAction( mActionAddIsland );
mEditMenu->addAction( mActionDeleteRing );
mEditMenu->addAction( mActionDeletePart );
mEditMenu->addAction( mActionMergeFeatures );

if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
Expand Down Expand Up @@ -1345,6 +1354,7 @@ void QgisApp::createToolBars()
mAdvancedDigitizeToolBar->addAction( mActionAddIsland );
mAdvancedDigitizeToolBar->addAction( mActionDeleteRing );
mAdvancedDigitizeToolBar->addAction( mActionDeletePart );
mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures );
mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );


Expand Down Expand Up @@ -4085,6 +4095,139 @@ void QgisApp::deletePart()
mMapCanvas->setMapTool( mMapTools.mDeletePart );
}

QgsGeometry* QgisApp::unionGeometries(const QgsVectorLayer* vl, QgsFeatureList& featureList) const
{
if(!vl || featureList.size() < 2)
{
return 0;
}

QgsGeometry* unionGeom = featureList[0].geometry();
QgsGeometry* backupPtr = 0; //pointer to delete intermediate results
if(!unionGeom)
{
return 0;
}

for(int i = 1; i < featureList.size(); ++i)
{
QgsGeometry* currentGeom = featureList[i].geometry();
if(currentGeom)
{
backupPtr = unionGeom;
unionGeom = unionGeom->combine(currentGeom);
if(i > 1) //delete previous intermediate results
{
delete backupPtr;
backupPtr = 0;
}
}
}
return unionGeom;
}

void QgisApp::mergeSelectedFeatures()
{
//get active layer (hopefully vector)
QgsMapLayer* activeMapLayer = activeLayer();
if(!activeMapLayer)
{
QMessageBox::information(0, tr("No active layer"), tr("No active layer found. Please select a layer in the layer list"));
return;
}
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>(activeMapLayer);
if(!vl)
{
QMessageBox::information(0, tr("Active layer is not vector"), tr("The merge features tool only works on vector layers. Please select a vector layer from the layer list"));
return;
}
if(!vl->isEditable())
{
QMessageBox::information(0, tr("Layer not editable"), tr("Merging features can only be done for layers in editing mode. To use the merge tool, go to Layer->Toggle editing"));
return;
}

//get selected feature ids (as a QSet<int> )
const QgsFeatureIds& featureIdSet = vl->selectedFeaturesIds();
if(featureIdSet.size() < 2)
{
QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features"));
return;
}

//get initial selection (may be altered by attribute merge dialog later)
QgsFeatureList featureList = vl->selectedFeatures(); //get QList<QgsFeature>
QgsGeometry* unionGeom = unionGeometries(vl, featureList);
if(!unionGeom)
{
return;
}

//make a first geometry union and notify the user straight away if the union geometry type does not match the layer one
QGis::WkbType originalType = vl->wkbType();
QGis::WkbType newType = unionGeom->wkbType();
if(unionGeom->wkbType() != vl->wkbType())
{
QMessageBox::critical(0, "Union operation canceled", tr("The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled"));
delete unionGeom;
return;
}

//merge the attributes together
QgsMergeAttributesDialog d(featureList, vl, mapCanvas());
if(d.exec() == QDialog::Rejected)
{
return;
}

QgsFeatureList featureListAfter = vl->selectedFeatures();

if(featureListAfter.size() < 2)
{
QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features"));
delete unionGeom;
return;
}

//if the user changed the feature selection in the merge dialog, we need to repead the union and check the type
if(featureList.size() != featureListAfter.size())
{
delete unionGeom;
unionGeom = unionGeometries(vl, featureListAfter);
if(!unionGeom)
{
return;
}

originalType = vl->wkbType();
newType = unionGeom->wkbType();
if(unionGeom->wkbType() != vl->wkbType())
{
QMessageBox::critical(0, "Union operation canceled", tr("The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled"));
delete unionGeom;
return;
}
}

//create new feature
QgsFeature newFeature;
newFeature.setGeometry(unionGeom);
newFeature.setAttributeMap(d.mergedAttributesMap());

QgsFeatureList::const_iterator feature_it = featureListAfter.constBegin();
for(; feature_it != featureListAfter.constEnd(); ++feature_it)
{
vl->deleteFeature(feature_it->id());
}

vl->addFeature(newFeature, false);

if(mapCanvas())
{
mapCanvas()->refresh();
}
}

void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
Expand Down Expand Up @@ -5314,6 +5457,17 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionCutFeatures->setEnabled( false );
}

//merge tool needs editable layer and provider with the capability of adding and deleting features
if ( vlayer->isEditable() && (dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures) \
&& QgsVectorDataProvider::AddFeatures)
{
mActionMergeFeatures->setEnabled(layerHasSelection);
}
else
{
mActionMergeFeatures->setEnabled( false );
}

// moving enabled if geometry changes are supported
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
Expand Down Expand Up @@ -5366,6 +5520,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionSplitFeatures->setEnabled( true );
mActionSimplifyFeature->setEnabled( true );
mActionDeletePart->setEnabled( true );

}
else
{
Expand Down
8 changes: 8 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -41,6 +41,7 @@ class QValidator;
class QgisAppInterface;
class QgsClipboard;
class QgsComposer;
class QgsGeometry;
class QgsHelpViewer;
class QgsFeature;

Expand All @@ -63,6 +64,7 @@ class QgsVectorLayer;
#include <QPointer>

#include "qgsconfig.h"
#include "qgsfeature.h"
#include "qgspoint.h"

/*! \class QgisApp
Expand Down Expand Up @@ -509,6 +511,8 @@ class QgisApp : public QMainWindow
void deleteRing();
//! deletes part of polygon
void deletePart();
//! merges the selected features together
void mergeSelectedFeatures();

//! activates the selection tool
void select();
Expand Down Expand Up @@ -655,6 +659,9 @@ class QgisApp : public QMainWindow
void pasteTransformations();
//! check to see if file is dirty and if so, prompt the user th save it
bool saveDirty();
/** Helper function to union several geometries together (used in function mergeSelectedFeatures)
@return 0 in case of error*/
QgsGeometry* unionGeometries(const QgsVectorLayer* vl, QgsFeatureList& featureList) const;

/// QgisApp aren't copyable
QgisApp( QgisApp const & );
Expand Down Expand Up @@ -719,6 +726,7 @@ class QgisApp : public QMainWindow
QAction *mActionSimplifyFeature;
QAction *mActionDeleteRing;
QAction *mActionDeletePart;
QAction *mActionMergeFeatures;
QAction *mActionEditSeparator3;

QAction *mActionPan;
Expand Down

0 comments on commit dbaf7bd

Please sign in to comment.