[QGIS Commit] r10890 - in trunk/qgis: . images/themes/default
src/app
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sat Jun 6 10:46:49 EDT 2009
Author: wonder
Date: 2009-06-06 10:46:49 -0400 (Sat, 06 Jun 2009)
New Revision: 10890
Added:
trunk/qgis/images/themes/default/mActionNodeTool.png
trunk/qgis/src/app/qgsmaptoolnodetool.cpp
trunk/qgis/src/app/qgsmaptoolnodetool.h
Modified:
trunk/qgis/CONTRIBUTORS
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/qgisapp.cpp
trunk/qgis/src/app/qgisapp.h
Log:
[FEATURE] Added a new "node" tool (in advanced digitizing toolbar).
Integrates add, move and delete vertex tools for faster editing.
Contributed by Richard Kostecky, qgis-mapper team.
Modified: trunk/qgis/CONTRIBUTORS
===================================================================
--- trunk/qgis/CONTRIBUTORS 2009-06-05 23:20:00 UTC (rev 10889)
+++ trunk/qgis/CONTRIBUTORS 2009-06-06 14:46:49 UTC (rev 10890)
@@ -23,6 +23,7 @@
Maurizio Napolitano
Paul Ramsey
Peter Ersts
+Richard Kostecky
Stefanie Tellex
Tom Russo
Tyler Mitchell
Added: trunk/qgis/images/themes/default/mActionNodeTool.png
===================================================================
(Binary files differ)
Property changes on: trunk/qgis/images/themes/default/mActionNodeTool.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2009-06-05 23:20:00 UTC (rev 10889)
+++ trunk/qgis/src/app/CMakeLists.txt 2009-06-06 14:46:49 UTC (rev 10890)
@@ -35,6 +35,7 @@
qgsmaptoolidentify.cpp
qgsmaptoolmovefeature.cpp
qgsmaptoolmovevertex.cpp
+ qgsmaptoolnodetool.cpp
qgsmaptoolselect.cpp
qgsmaptoolsimplify.cpp
qgsmaptoolsplitfeatures.cpp
Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp 2009-06-05 23:20:00 UTC (rev 10889)
+++ trunk/qgis/src/app/qgisapp.cpp 2009-06-06 14:46:49 UTC (rev 10890)
@@ -166,6 +166,7 @@
#include "qgsmaptoolidentify.h"
#include "qgsmaptoolmovefeature.h"
#include "qgsmaptoolmovevertex.h"
+#include "qgsmaptoolnodetool.h"
#include "qgsmaptoolpan.h"
#include "qgsmaptoolselect.h"
#include "qgsmaptoolsplitfeatures.h"
@@ -475,6 +476,7 @@
delete mMapTools.mDeleteRing;
delete mMapTools.mDeletePart;
delete mMapTools.mAddIsland;
+ delete mMapTools.mNodeTool;
delete mPythonConsole;
delete mPythonUtils;
@@ -710,6 +712,11 @@
connect( mActionMergeFeatures, SIGNAL(triggered()), this, SLOT(mergeSelectedFeatures()));
mActionMergeFeatures->setEnabled(false);
+ mActionNodeTool = new QAction( getThemeIcon( "mActionNodeTool.png" ), tr( "Node Tool" ), this );
+ shortcuts->registerAction( mActionNodeTool );
+ mActionNodeTool->setStatusTip( tr( "Node Tool" ) );
+ connect( mActionNodeTool, SIGNAL( triggered() ), this, SLOT( nodeTool() ) );
+ mActionNodeTool->setEnabled( false );
// View Menu Items
@@ -1061,6 +1068,9 @@
mActionDeletePart->setCheckable( true );
mMapToolGroup->addAction( mActionDeletePart );
mMapToolGroup->addAction( mActionMergeFeatures);
+ mActionNodeTool->setCheckable( true );
+ mMapToolGroup->addAction( mActionNodeTool );
+
}
void QgisApp::createMenus()
@@ -1150,7 +1160,8 @@
mEditMenu->addAction( mActionDeleteRing );
mEditMenu->addAction( mActionDeletePart );
mEditMenu->addAction( mActionMergeFeatures );
-
+ mEditMenu->addAction( mActionNodeTool );
+
if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
mActionEditSeparator3 = mEditMenu->addSeparator();
@@ -1355,6 +1366,7 @@
mAdvancedDigitizeToolBar->addAction( mActionDeleteRing );
mAdvancedDigitizeToolBar->addAction( mActionDeletePart );
mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures );
+ mAdvancedDigitizeToolBar->addAction( mActionNodeTool );
mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );
@@ -1707,6 +1719,8 @@
mMapTools.mDeleteRing->setAction( mActionDeleteRing );
mMapTools.mDeletePart = new QgsMapToolDeletePart( mMapCanvas );
mMapTools.mDeletePart->setAction( mActionDeletePart );
+ mMapTools.mNodeTool = new QgsMapToolNodeTool( mMapCanvas );
+ mMapTools.mNodeTool->setAction( mActionNodeTool );
//ensure that non edit tool is initialised or we will get crashes in some situations
mNonEditMapTool = mMapTools.mPan;
}
@@ -4228,6 +4242,11 @@
}
}
+void QgisApp::nodeTool()
+{
+ mMapCanvas->setMapTool( mMapTools.mNodeTool );
+}
+
void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
@@ -5472,10 +5491,12 @@
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
mActionMoveFeature->setEnabled( true );
+ mActionNodeTool->setEnabled( true );
}
else
{
mActionMoveFeature->setEnabled( false );
+ mActionNodeTool->setEnabled( false );
}
if ( vlayer->geometryType() == QGis::Point )
Modified: trunk/qgis/src/app/qgisapp.h
===================================================================
--- trunk/qgis/src/app/qgisapp.h 2009-06-05 23:20:00 UTC (rev 10889)
+++ trunk/qgis/src/app/qgisapp.h 2009-06-06 14:46:49 UTC (rev 10890)
@@ -227,6 +227,7 @@
QAction *actionSimplifyFeature() { return mActionSimplifyFeature; }
QAction *actionDeleteRing() { return mActionDeleteRing; }
QAction *actionDeletePart() { return mActionDeletePart; }
+ QAction *actionNodeTool() { return mActionNodeTool; }
QAction *actionEditSeparator2() { return mActionEditSeparator2; }
QAction *actionPan() { return mActionPan; }
@@ -513,6 +514,8 @@
void deletePart();
//! merges the selected features together
void mergeSelectedFeatures();
+ //! provides operations with nodes
+ void nodeTool();
//! activates the selection tool
void select();
@@ -727,6 +730,7 @@
QAction *mActionDeleteRing;
QAction *mActionDeletePart;
QAction *mActionMergeFeatures;
+ QAction *mActionNodeTool;
QAction *mActionEditSeparator3;
QAction *mActionPan;
@@ -847,6 +851,7 @@
QgsMapTool* mSimplifyFeature;
QgsMapTool* mDeleteRing;
QgsMapTool* mDeletePart;
+ QgsMapTool* mNodeTool;
} mMapTools;
QgsMapTool *mNonEditMapTool;
Added: trunk/qgis/src/app/qgsmaptoolnodetool.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolnodetool.cpp (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolnodetool.cpp 2009-06-06 14:46:49 UTC (rev 10890)
@@ -0,0 +1,899 @@
+/***************************************************************************
+ qgsmaptoolnodetool.cpp - add/move/delete vertex integrated in one tool
+ ---------------------
+ begin : April 2009
+ copyright : (C) 2009 by Richard Kostecky
+ email : csf dot kostej at mail dot 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. *
+ * *
+ ***************************************************************************/
+
+#include "qgsmaptoolnodetool.h"
+#include "qgsmapcanvas.h"
+#include "qgsproject.h"
+#include "qgsrubberband.h"
+#include "qgsvectorlayer.h"
+#include "qgstolerance.h"
+#include <math.h>
+#include <QMouseEvent>
+
+QgsMapToolNodeTool::QgsMapToolNodeTool( QgsMapCanvas* canvas ): QgsMapToolVertexEdit( canvas )
+{
+ mSelectionFeature = NULL;
+ mQRubberBand = NULL;
+ mSelectAnother = false;
+ mCtrl = false;
+ mMoving = true;
+ mClicked = false;
+}
+
+QgsMapToolNodeTool::~QgsMapToolNodeTool()
+{
+ removeRubberBands();
+}
+
+void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
+{
+ QgsMapLayer* currentLayer = mCanvas->currentLayer();
+ QgsVectorLayer* vlayer = 0;
+ if ( currentLayer )
+ {
+ vlayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
+ }
+
+ if (mSelectionFeature == NULL)
+ {
+ return; // check that we are able to move something
+ }
+ if (mClicked)
+ {
+ mSelectAnother = false;
+ if (mMoving)
+ { //should be changed to something without bugs
+ //create rubberband
+ if (mQgsRubberBands.empty())
+ {
+ QList<VertexEntry> vertexMap = mSelectionFeature->vertexMap();
+ QgsGeometry* geometry = mSelectionFeature->feature()->geometry();
+ int beforeVertex, afterVertex;
+ int lastRubberBand = 0;
+ int vertex;
+ for ( int i = 0; i < vertexMap.size(); i++ )
+ {
+ //debug this to create rubber band
+ if (vertexMap[i].selected && !(vertexMap[i].inRubberBand) )
+ {
+ geometry->adjacentVertices(i, beforeVertex, afterVertex);
+ vertex = i;
+ while (beforeVertex != -1)
+ { //move forward NOTE: end if whole cycle is selected
+ if (vertexMap[beforeVertex].selected && beforeVertex != i) //and take care of cycles
+ {
+ vertex = beforeVertex;
+ geometry->adjacentVertices(vertex, beforeVertex, afterVertex);
+ }
+ else
+ { //break
+ break;
+ }
+ }
+ //we have first vertex of moving part
+ QgsRubberBand* rb = new QgsRubberBand( mCanvas, false );
+ rb->setWidth(2);
+ rb->setColor(Qt::blue);
+ int index = 0;
+ if (beforeVertex != -1) //adding first point which is not moving
+ {
+ rb->addPoint(vertexMap[beforeVertex].point, false );
+ mSelectionFeature->setRubberBandValues(beforeVertex, true, lastRubberBand, index );
+ vertexMap[beforeVertex].inRubberBand = true;
+ index ++;
+ }
+ while (vertex != -1 && vertexMap[vertex].selected && !vertexMap[vertex].inRubberBand)
+ {
+ rb->addPoint(vertexMap[vertex].point, false);
+ mSelectionFeature->setRubberBandValues(vertex, true, lastRubberBand, index );
+ vertexMap[vertex].inRubberBand = true;
+ index ++;
+ geometry->adjacentVertices(vertex, beforeVertex, vertex);
+ }
+ if (vertex != -1 && !vertexMap[vertex].selected) //add last point if exists
+ {
+ rb->addPoint(vertexMap[vertex].point, true);
+ mSelectionFeature->setRubberBandValues(vertex, true, lastRubberBand, index );
+ vertexMap[vertex].inRubberBand = true;
+ index ++;
+ }
+ mQgsRubberBands.append(rb);
+ lastRubberBand ++;
+ }
+
+ }
+ }
+ else
+ {
+ //move points
+ QList<QgsSnappingResult> snapResults;
+ QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
+ mSnapper.snapToBackgroundLayers(e->pos(), snapResults);
+ QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
+ if (snapResults.size() > 0)
+ {
+ firstCoords = mClosestVertex;
+ }
+ QList<VertexEntry> vertexMap = mSelectionFeature->vertexMap();
+ for ( int i = 0; i < vertexMap.size(); i++ )
+ {
+
+ if (vertexMap[i].selected)
+ {
+ double x = vertexMap[i].point.x() + posMapCoord.x() - firstCoords.x();
+ double y = vertexMap[i].point.y() + posMapCoord.y() - firstCoords.y();
+ mQgsRubberBands[vertexMap[i].rubberBandNr]->movePoint( vertexMap[i].index + 1, QgsPoint(x, y));
+ if (vertexMap[i].index == 0)
+ {
+ mQgsRubberBands[vertexMap[i].rubberBandNr]->movePoint( 0, QgsPoint(x, y));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!mSelectionRectangle)
+ {
+ mSelectionRectangle = true;
+ mQRubberBand = new QRubberBand( QRubberBand::Rectangle, mCanvas );
+ mRect = new QRect();
+ mRect->setTopLeft(QPoint(mLastCoordinates->x(), mLastCoordinates->y()));
+ }
+ mRect->setBottomRight(e->pos());
+ QRect normalizedRect = mRect->normalized();
+ mQRubberBand->setGeometry(normalizedRect);
+ mQRubberBand->show();
+ }
+ }
+
+
+}
+
+void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
+{
+ QgsMapLayer* currentLayer = mCanvas->currentLayer();
+ QgsVectorLayer* vlayer = 0;
+ if ( currentLayer )
+ {
+ vlayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
+ }
+ mClicked = true;
+ mLastCoordinates = new QgsPoint(e->pos().x(), e->pos().y());
+ QList<QgsSnappingResult> snapResults;
+ if (mSelectionFeature == NULL)
+ {
+ mSelectAnother = false;
+ mSnapper.snapToCurrentLayer(e->pos(), snapResults, QgsSnapper::SnapToVertexAndSegment, -1);
+
+ if (snapResults.size() < 1)
+ {
+ return;
+ }
+ mSelectionFeature = new SelectionFeature();
+ mSelectionFeature->setSelectedFeature(snapResults[0].snappedAtGeometry, vlayer, NULL, mCanvas );
+ }
+ else
+ { //some feature already selected
+ QgsPoint mapCoordPoint = mCanvas->getCoordinateTransform()->toMapPoint(e->pos().x(), e->pos().y());
+ double tol = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapRenderer());
+ //get geometry and find if snapping is near it
+ QgsFeature f;
+ vlayer->featureAtId(mSelectionFeature->featureId(), f, true, false);
+ QgsGeometry* g = f.geometry();
+ int atVertex, beforeVertex, afterVertex;
+ double dist;
+ g->closestVertex(mapCoordPoint, atVertex, beforeVertex, afterVertex, dist);
+ dist = sqrt(dist);
+
+ mSnapper.snapToCurrentLayer(e->pos(), snapResults, QgsSnapper::SnapToVertex, tol);
+ //if (snapResults.size() < 1)
+ if (dist > tol)
+ {
+ //no vertexes found (selecting or inverting selection) if move
+ //or select another feature if clicked there
+ mSnapper.snapToCurrentLayer(e->pos(), snapResults, QgsSnapper::SnapToSegment, tol);
+ if (snapResults.size() > 0)
+ {
+ //need to check all if there is a point in my selected feature
+ mAnother = snapResults.first().snappedAtGeometry;
+ mSelectAnother = true;
+ QList<QgsSnappingResult>::iterator it = snapResults.begin();
+ QgsSnappingResult snapResult;
+ for ( ; it != snapResults.end() ; ++it )
+ {
+ if (it->snappedAtGeometry == mSelectionFeature->featureId())
+ {
+ snapResult = *it;
+ mAnother = 0;
+ mSelectAnother = false;
+ break;
+ }
+ }
+ if (!mSelectAnother)
+ {
+ mMoving = true;
+ QgsPoint point = mCanvas->getCoordinateTransform()->toMapPoint(e->pos().x(), e->pos().y());
+ mClosestVertex = getClosestVertex( point );
+ if ( !mSelectionFeature->isSelected( snapResult.beforeVertexNr ) || !mSelectionFeature->isSelected( snapResult.afterVertexNr ))
+ {
+ mSelectionFeature->deselectAllVertexes();
+ mSelectionFeature->selectVertex(snapResult.afterVertexNr);
+ mSelectionFeature->selectVertex(snapResult.beforeVertexNr);
+ }
+ }
+ }
+ else
+ {
+ if (!mCtrl)
+ {
+ mSelectionFeature->deselectAllVertexes();
+ }
+ }
+ }
+ else
+ {
+ //some vertex selected
+ QgsSnappingResult snapResult = snapResults[0];
+ mMoving = true;
+ QgsPoint point = mCanvas->getCoordinateTransform()->toMapPoint(e->pos().x(), e->pos().y());
+ mClosestVertex = getClosestVertex( point );
+ if (mMoving)
+ {
+ if (mCtrl)
+ {
+ //mSelectionFeature->invertVertexSelection( snapResult.snappedVertexNr);
+ mSelectionFeature->invertVertexSelection( atVertex );
+ }
+ else
+ {
+ if (!(mSelectionFeature->isSelected( atVertex )))
+ {
+ mSelectionFeature->deselectAllVertexes();
+ mSelectionFeature->selectVertex( atVertex );
+ }
+ }
+ }
+ else
+ {
+ //select another feature
+ mAnother = snapResults.first().snappedAtGeometry;
+ mSelectAnother = true;
+ }
+ }
+ }
+
+}
+
+void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
+{
+ if ( mSelectionFeature == NULL)
+ {
+ // no feature is selected
+ return;
+ }
+ removeRubberBands();
+ QgsMapLayer* currentLayer = mCanvas->currentLayer();
+ QgsVectorLayer* vlayer = 0;
+ if ( currentLayer )
+ {
+ vlayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
+ }
+
+ mClicked = false;
+ mSelectionRectangle = false;
+ QgsPoint coords = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
+ QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
+ if (mQRubberBand != NULL)
+ {
+ mQRubberBand->close();
+ delete mQRubberBand;
+ mQRubberBand = NULL;
+ }
+ if (mLastCoordinates->x() == e->pos().x() && mLastCoordinates->y() == e->pos().y())
+ {
+ if (mSelectAnother)
+ {
+ //select another feature (this should deselect current one ;-) )
+ mSelectionFeature->setSelectedFeature( mAnother, vlayer, NULL, mCanvas);
+ mSelectAnother = false;
+ }
+ }
+ else
+ {
+ //got correct coordinates
+ double topX;
+ double bottomX;
+ if (coords.x() > firstCoords.x())
+ {
+ topX = firstCoords.x();
+ bottomX = coords.x();
+ }
+ else
+ {
+ topX = coords.x();
+ bottomX = firstCoords.x();
+ }
+ double leftY;
+ double rightY;
+ if (coords.y() > firstCoords.y())
+ {
+ leftY = firstCoords.y();
+ rightY = coords.y();
+ }
+ else
+ {
+ leftY = coords.y();
+ rightY = firstCoords.y();
+ }
+ if (mMoving)
+ {
+ mMoving = false;
+ QList<QgsSnappingResult> snapResults;
+ QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
+ mSnapper.snapToBackgroundLayers(e->pos(), snapResults);
+ coords = snapPointFromResults( snapResults, e->pos() );
+ //coords = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
+ if (snapResults.size() > 0)
+ {
+ firstCoords = mClosestVertex;
+ }
+
+ double changeX = coords.x() - firstCoords.x();
+ double changeY = coords.y() - firstCoords.y();
+ mSelectionFeature->moveSelectedVertexes( changeX, changeY );
+ mCanvas->refresh();
+ //movingVertexes
+ }
+ else //selecting vertexes by rubber band
+ {
+ QList<VertexEntry> vertexMap = mSelectionFeature->vertexMap();
+ if ( !mCtrl )
+ {
+ mSelectionFeature->deselectAllVertexes();
+ }
+ for ( int i = 0; i < vertexMap.size(); i++)
+ {
+ if (vertexMap[i].point.x() < bottomX && vertexMap[i].point.y() > leftY && vertexMap[i].point.x() > topX && vertexMap[i].point.y() < rightY)
+ {
+ //inverting selection is enough because all were deselected if ctrl is not pressed
+ mSelectionFeature->invertVertexSelection(i, false);
+ }
+ }
+ }
+ }
+ mMoving = false;
+
+ removeRubberBands();
+
+ mRecentSnappingResults.clear();
+ mExcludePoint.clear();
+
+}
+
+void QgsMapToolNodeTool::deactivate()
+{
+ removeRubberBands();
+ delete mSelectionFeature;
+ mSelectionFeature = NULL;
+ mQRubberBand = NULL;
+ mSelectAnother = false;
+ mCtrl = false;
+ mMoving = true;
+ mClicked = false;
+ QgsMapTool::deactivate();
+}
+
+void QgsMapToolNodeTool::removeRubberBands()
+{
+ //cleanup rubber bands and list
+ QList<QgsRubberBand*>::iterator rb_it = mQgsRubberBands.begin();
+ for ( ;rb_it != mQgsRubberBands.end(); ++rb_it )
+ {
+ delete *rb_it;
+ }
+ mQgsRubberBands.clear();
+
+ //remove all data from selected feature (no change to rubber bands itself
+ if (mSelectionFeature != NULL )
+ mSelectionFeature->cleanRubberBandsData();
+}
+
+
+void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
+{
+ QgsMapLayer* currentLayer = mCanvas->currentLayer();
+ QgsVectorLayer* vlayer = 0;
+ if ( currentLayer )
+ {
+ vlayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
+ }
+
+ QList<QgsSnappingResult> snapResults;
+ mMoving = false;
+ double tol = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapRenderer());
+ mSnapper.snapToCurrentLayer(e->pos(), snapResults, QgsSnapper::SnapToSegment, tol);
+ if (snapResults.size() < 1)
+ {
+ //nowhere to pul vertex
+ }
+ else
+ {
+ //some segment selected
+ if (snapResults.first().snappedAtGeometry == mSelectionFeature->featureId())
+ {
+ if (snapResults.first().snappedVertexNr == -1)
+ {
+ QgsPoint coords = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
+ //add vertex
+ vlayer->insertVertex(coords.x(), coords.y(), mSelectionFeature->featureId(), snapResults.first().afterVertexNr );
+
+ mSelectionFeature->updateFromFeature();
+ }
+ }
+ }
+}
+
+
+
+
+QgsPoint QgsMapToolNodeTool::getClosestVertex(QgsPoint point)
+{
+ int at;
+ int before;
+ int after;
+ double dist;
+ return mSelectionFeature->feature()->geometry()->closestVertex( point, at, before, after, dist );
+}
+
+void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
+{
+ if (e->key() == Qt::Key_Control)
+ {
+ mCtrl = true;
+ }
+}
+
+void QgsMapToolNodeTool::keyReleaseEvent( QKeyEvent* e )
+{
+ if (e->key() == Qt::Key_Control)
+ {
+ mCtrl = false;
+ return;
+ }
+ if (e->key() == Qt::Key_Delete)
+ {
+ mSelectionFeature->deleteSelectedVertexes();
+ mCanvas->refresh();
+ }
+}
+
+
+//selection object
+
+
+SelectionFeature::SelectionFeature()
+{
+ mFeature = new QgsFeature();
+ mFeatureId = 0;
+}
+
+SelectionFeature::~SelectionFeature()
+{
+ deleteVertexMap();
+}
+
+void SelectionFeature::updateFeature()
+{
+ delete mFeature;
+ mFeature = new QgsFeature();
+ mVlayer->featureAtId(mFeatureId, *mFeature);
+}
+
+void SelectionFeature::cleanRubberBandsData()
+{
+ for ( int i = 0; i < mVertexMap.size(); i++)
+ {
+ mVertexMap[i].rubberBandNr = 0;
+ mVertexMap[i].index = 0;
+ mVertexMap[i].inRubberBand = false;
+ }
+}
+
+void SelectionFeature::setSelectedFeature( int featureId, QgsVectorLayer* vlayer, QgsRubberBand* rubberBand, QgsMapCanvas* canvas, QgsFeature* feature)
+{
+ if (mFeatureId != 0)
+ {
+ deleteVertexMap();
+ }
+ mFeatureId = featureId;
+ mVlayer = vlayer;
+ mCanvas = canvas;
+ mRubberBand = rubberBand;
+ if (feature == NULL)
+ {
+ vlayer->featureAtId(featureId, *mFeature);
+ }
+ else
+ {
+ mFeature = feature;
+ }
+ //createvertexmap
+ createVertexMap();
+}
+
+void SelectionFeature::deleteSelectedVertexes()
+{
+ for (int i = mVertexMap.size() -1; i > -1 ; i--)
+ {
+ if (mVertexMap[i].selected)
+ {
+ mVlayer->deleteVertex(mFeatureId, i);
+
+ if (mVertexMap[i].equals != -1 && !mVertexMap[mVertexMap[i].equals].selected)
+ {
+ //for polygon delete both
+ }
+ }
+ }
+ updateFromFeature();
+}
+
+
+void SelectionFeature::moveSelectedVertexes( double changeX, double changeY )
+{
+ for (int i = mVertexMap.size() -1; i > -1 ; i--)
+ {
+ if (mVertexMap[i].selected)
+ {
+ mVlayer->moveVertex( mVertexMap[i].point.x() + changeX, mVertexMap[i].point.y() + changeY, mFeatureId, i);
+ mVertexMap[i].point = QgsPoint(mVertexMap[i].point.x() + changeX, mVertexMap[i].point.y() + changeY);
+ setMarkerCenter(mVertexMap[i].vertexMarker, mVertexMap[i].point);
+ if (mVertexMap[i].equals != -1 && !mVertexMap[mVertexMap[i].equals].selected)
+ {
+ int index = mVertexMap[i].equals;
+ mVertexMap[index].point = QgsPoint(mVertexMap[index].point.x() + changeX, mVertexMap[index].point.y() + changeY);
+ setMarkerCenter(mVertexMap[index].vertexMarker, mVertexMap[index].point);
+ //for polygon delete both
+ }
+ }
+ }
+ updateFeature();
+}
+
+void SelectionFeature::setMarkerCenter(QgsRubberBand* marker, QgsPoint center)
+{
+ double movement = 4;
+ double s = QgsTolerance::toleranceInMapUnits(movement, mVlayer, mCanvas->mapRenderer(), QgsTolerance::Pixels);
+ QgsPoint pom = QgsPoint(center);
+ pom.setX(pom.x() - s);
+ pom.setY(pom.y() - s);
+ marker->movePoint(0, pom);
+ marker->movePoint(1, pom);
+ pom.setX(pom.x() + 2*s);
+ marker->movePoint(2,pom);
+ pom.setY(pom.y() + 2*s);
+ marker->movePoint(3,pom);
+ pom.setX(pom.x() - 2*s);
+ marker->movePoint(4,pom);
+ pom.setY(pom.y() - 2*s);
+ marker->movePoint(5,pom);
+
+}
+
+QgsRubberBand* SelectionFeature::createRubberBandMarker(QgsPoint center)
+{
+ QgsRubberBand* marker = new QgsRubberBand(mCanvas);
+ marker->setColor(Qt::red);
+ marker->setWidth(2);
+ double movement = 4;
+ double s = QgsTolerance::toleranceInMapUnits(movement, mVlayer, mCanvas->mapRenderer(), QgsTolerance::Pixels);
+ QgsPoint pom = center;
+ pom.setX(pom.x() - s);
+ pom.setY(pom.y() - s);
+ marker->addPoint(pom);
+ pom.setX(pom.x() + 2*s);
+ marker->addPoint(pom);
+ pom.setY(pom.y() + 2*s);
+ marker->addPoint(pom);
+ pom.setX(pom.x() - 2*s);
+ marker->addPoint(pom);
+ pom.setY(pom.y() - 2*s);
+ marker->addPoint(pom);
+ return marker;
+}
+
+
+void SelectionFeature::updateFromFeature()
+{
+ //delete old map
+ deleteVertexMap();
+
+ //create new map
+ createVertexMap();
+}
+
+void SelectionFeature::deleteVertexMap()
+{
+ while (!mVertexMap.empty())
+ {
+ VertexEntry entry = mVertexMap.takeLast();
+ delete entry.vertexMarker;
+ }
+}
+
+bool SelectionFeature::isSelected(int vertexNr)
+{
+ return mVertexMap[vertexNr].selected;
+}
+
+QgsFeature* SelectionFeature::feature()
+{
+ return mFeature;
+}
+
+void SelectionFeature::createVertexMapPolygon()
+{
+ int y = 0;
+ if (!mFeature->geometry()->asPolygon().empty())
+ { //polygon
+ for (int i2 = 0; i2 < mFeature->geometry()->asPolygon().size(); i2++ )
+ {
+ QgsPolyline poly = mFeature->geometry()->asPolygon()[i2];
+ int i;
+ for ( i = 0; i < poly.size(); i++ )
+ {
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly[i];
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = i;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly[i]);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(y + i, entry);
+ }
+ mVertexMap[y + i - 1 ].equals = y;
+ mVertexMap[y].equals = y + i - 1;
+ y = y + poly.size();
+ }
+ }
+ else //multipolygon
+ {
+ //print("Number of polygons: " + str(len(feature.geometry().asMultiPolygon())))
+ for (int i2 = 0 ; i2 < mFeature->geometry()->asMultiPolygon().size(); i2++ )
+ {
+ QgsPolygon poly2 = mFeature->geometry()->asMultiPolygon()[i2];
+ for (int i3 = 0; i3 < poly2.size(); i3++)
+ {
+ QgsPolyline poly = poly2[i3];
+ int i;
+ //print("Number of vertexes:" + str(len(poly)))
+ for (i = 0; i < poly.size(); i++)
+ {
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly[i];
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = y + i -1;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly[i]);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(y + i, entry);
+ }
+ mVertexMap[y + i - 1].equals = y;
+ mVertexMap[y].equals = y + i -1;
+ y = y + poly.size();
+ }
+ }
+ }
+}
+
+void SelectionFeature::createVertexMapLine()
+{
+ if (mFeature->geometry()->isMultipart())
+ {
+ int y = 0;
+ QgsMultiPolyline mLine = mFeature->geometry()->asMultiPolyline();
+ for (int i2 = 0; i2 < mLine.size(); i2++ )
+ {
+ QgsPolyline poly = mLine[i2];
+ int i;
+ for ( i = 0; i < poly.size(); i++ )
+ {
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly[i];
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = i;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly[i]);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(y + i, entry);
+ }
+ y = y + poly.size();
+ }
+ }
+ else
+ {
+ QgsPolyline poly = mFeature->geometry()->asPolyline();
+ int i;
+ for ( i = 0; i < poly.size(); i++ )
+ {
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly[i];
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = i;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly[i]);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(i, entry);
+ }
+ }
+}
+
+void SelectionFeature::createVertexMapPoint()
+{
+ if (mFeature->geometry()->isMultipart())
+ {//multipoint
+ QgsMultiPoint poly = mFeature->geometry()->asMultiPoint();
+ int i;
+ for ( i = 0; i < poly.size(); i++ )
+ {
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly[i];
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = 1;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly[i]);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(i, entry);
+ }
+ }
+ else
+ {//single point
+ QgsPoint poly = mFeature->geometry()->asPoint();
+ VertexEntry entry;
+ entry.selected = false;
+ entry.point = poly;
+ entry.equals = -1;
+ entry.rubberBandNr = 0;
+ entry.originalIndex = 1;
+ entry.inRubberBand = false;
+ QgsRubberBand* marker = createRubberBandMarker(poly);
+ entry.vertexMarker = marker;
+ mVertexMap.insert(1, entry);
+ }
+}
+
+void SelectionFeature::createVertexMap()
+{
+ mVlayer->featureAtId(mFeatureId, *mFeature);
+ //createvertexmap
+ if (mFeature->geometry()->type() == QGis::Polygon)
+ {
+ createVertexMapPolygon();
+ }
+ else if (mFeature->geometry()->type() == QGis::Line)
+ {
+ createVertexMapLine();
+ }
+ else if (mFeature->geometry()->type() == QGis::Point)
+ {
+ createVertexMapPoint();
+ }
+}
+
+void SelectionFeature::setRubberBandValues(int index, bool inRubberBand, int rubberBandNr, int indexInRubberBand )
+{
+ mVertexMap[index].index = indexInRubberBand;
+ mVertexMap[index].inRubberBand = inRubberBand;
+ mVertexMap[index].rubberBandNr = rubberBandNr;
+}
+
+void SelectionFeature::selectVertex( int vertexNr )
+{
+ mVertexMap[vertexNr].selected = true;
+ mVertexMap[vertexNr].vertexMarker->setColor(Qt::blue);
+ mVertexMap[vertexNr].vertexMarker->updatePosition();
+ if (mVertexMap[vertexNr].equals != -1)
+ {
+ mVertexMap[mVertexMap[vertexNr].equals].selected = true;
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->setColor(Qt::blue);
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->updatePosition();
+
+ }
+}
+
+
+void SelectionFeature::deselectVertex( int vertexNr )
+{
+ mVertexMap[vertexNr].selected = false;
+ mVertexMap[vertexNr].vertexMarker->setColor(Qt::red);
+ mVertexMap[vertexNr].vertexMarker->updatePosition();
+}
+
+
+void SelectionFeature::deselectAllVertexes()
+{
+ for (int i = 0; i < mVertexMap.size() ;i++)
+ {
+ mVertexMap[i].selected = false;
+ mVertexMap[i].vertexMarker->setColor(Qt::red);
+ mVertexMap[i].vertexMarker->updatePosition();
+ }
+}
+
+
+void SelectionFeature::invertVertexSelection( int vertexNr, bool invert )
+{
+ if (mVertexMap[vertexNr].selected == false)
+ {
+ mVertexMap[vertexNr].selected = true;
+ mVertexMap[vertexNr].vertexMarker->setColor(Qt::blue);
+ mVertexMap[vertexNr].vertexMarker->updatePosition();
+ if (mVertexMap[vertexNr].equals != -1 && invert)
+ {
+ mVertexMap[mVertexMap[vertexNr].equals].selected = true;
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->setColor(Qt::blue);
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->updatePosition();
+ }
+ }
+ else
+ {
+ mVertexMap[vertexNr].selected = false;
+ mVertexMap[vertexNr].vertexMarker->setColor(Qt::red);
+ mVertexMap[vertexNr].vertexMarker->updatePosition();
+ if (mVertexMap[vertexNr].equals != -1 && invert)
+ {
+ mVertexMap[mVertexMap[vertexNr].equals].selected = false;
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->setColor(Qt::red);
+ mVertexMap[mVertexMap[vertexNr].equals].vertexMarker->updatePosition();
+ }
+ }
+}
+
+
+void SelectionFeature::updateVertexMarkersPosition( QgsMapCanvas* canvas )
+{
+ for (int i=0; i< mVertexMap.size() ;i++)
+ {
+ setMarkerCenter( mVertexMap[i].vertexMarker, mVertexMap[i].point);
+ }
+}
+
+
+int SelectionFeature::featureId()
+{
+ return mFeatureId;
+}
+
+
+QList<VertexEntry> SelectionFeature::vertexMap()
+{
+ return mVertexMap;
+}
+
+
+
+
+
Added: trunk/qgis/src/app/qgsmaptoolnodetool.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolnodetool.h (rev 0)
+++ trunk/qgis/src/app/qgsmaptoolnodetool.h 2009-06-06 14:46:49 UTC (rev 10890)
@@ -0,0 +1,268 @@
+/***************************************************************************
+ qgsmaptoolnodetool.h - add/move/delete vertex integrated in one tool
+ ---------------------
+ begin : April 2009
+ copyright : (C) 2009 by Richard Kostecky
+ email : csf dot kostej at mail dot 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef QGSMAPTOOLNODETOOL_H
+#define QGSMAPTOOLNODETOOL_H
+
+#include "qgsmaptoolvertexedit.h"
+#include "qgsfeature.h"
+#include <QRect>
+#include <QRubberBand>
+
+class QgsRubberBand;
+
+/**
+ * Structure to store entry about vertex of the feature
+ */
+struct VertexEntry
+{
+ bool selected;
+ QgsPoint point;
+ int equals;
+ QgsRubberBand *vertexMarker;;
+ bool inRubberBand;
+ int rubberBandNr;
+ int index;
+ int originalIndex;
+};
+
+/**
+ * Class that supports feature which is selected/
+ */
+class SelectionFeature
+{
+
+ public:
+ SelectionFeature();
+ ~SelectionFeature();
+
+ /**
+ * Setting selected feature
+ * @param featureId id of feature which was selected
+ * @param vlayer vector layer in which feature is selected
+ * @param rubberBand rubber band which displays feature
+ * @param canvas mapCanvas on which we are working
+ * @param feature feature with which we work this parameter is not mandatory if it's not filled feature will be loaded
+ */
+ void setSelectedFeature( int featureId, QgsVectorLayer* vlayer, QgsRubberBand* rubberBand, QgsMapCanvas* canvas, QgsFeature* feature = NULL);
+
+ /**
+ * Function to select vertex with number
+ * @param vertexNr number of vertex which is to be selected
+ */
+ void selectVertex( int vertexNr );
+
+ /**
+ * Function to deselect vertex with number
+ * @param vertexNr number of vertex which is to be deselected
+ */
+ void deselectVertex( int vertexNr );
+
+ /**
+ * Deselects all vertexes of selected feature
+ */
+ void deselectAllVertexes();
+
+ /**
+ * Deletes all selected vertexes
+ */
+ void deleteSelectedVertexes();
+
+ /**
+ * Moves selected vertex
+ * @param changeX change in X coordinate
+ * @param changeY change in Y coordinate
+ */
+ void moveSelectedVertexes( double changeX, double changeY );
+
+ /**
+ * Inverts selection of vertex with number
+ * @param vertexNr number of vertex which is to be inverted
+ */
+ void invertVertexSelection( int vertexNr, bool invert = true );
+
+ /**
+ * Updates vertex markers position accoording to changed feature geometry
+ * @param canvas map canvas we are working with
+ */
+ void updateVertexMarkersPosition( QgsMapCanvas* canvas);
+
+ /**
+ * Tells if vertex is selected
+ * @param vertexNr number of vertex for which we are getting info
+ * @return true if vertex is selected, false otherwise
+ */
+ bool isSelected(int vertexNr);
+
+ /**
+ * Getting feature Id of feature selected
+ * @return feature id of selected feature
+ */
+ int featureId();
+
+ /**
+ * Getting vertex map of vertexes
+ * @return currently used vertex map
+ */
+ QList<VertexEntry> vertexMap();
+
+ /**
+ * Getting currently edited feature
+ * @return selected feature
+ */
+ QgsFeature* feature();
+
+ /**
+ * Updates whole selection object from the selected object
+ */
+ void updateFromFeature();
+
+ /**
+ * Sets values for rubber band
+ * @param index index of vertex for rubberbanf
+ * @param inRubberBand flag if vertex is already in rubber band
+ * @param rubberBandNr number of geometry (rubber band) in which this vertex should be)
+ * @param indexInRubberBand
+ */
+ void setRubberBandValues(int index, bool inRubberBand, int rubberBandNr, int indexInRubberBand );
+
+ /**
+ * Clears data about vertexes if they are in rubber band for moving etc.
+ */
+ void cleanRubberBandsData();
+
+ void setMarkerCenter(QgsRubberBand* marker, QgsPoint center);
+
+ QgsRubberBand* createRubberBandMarker(QgsPoint center);
+
+
+
+ private:
+
+ /**
+ * Deletes whole vertex map.
+ */
+ void deleteVertexMap();
+
+ /**
+ * Creates vertex map when
+ */
+ void createVertexMap();
+
+ /**
+ * Creates vertex map for polygon type feature
+ */
+ void createVertexMapPolygon();
+
+ /**
+ * Creates vertex map for line type feature
+ */
+ void createVertexMapLine();
+
+ /**
+ * Creates vertex map for ppint type feature
+ */
+ void createVertexMapPoint();
+
+ /**
+ * Updates stored feauture to actual one loaded from layer
+ */
+ void updateFeature();
+
+ QgsFeature* mFeature;
+ int mFeatureId;
+ QgsVectorLayer* mVlayer;
+ QgsRubberBand* mRubberBand;
+ QList<VertexEntry> mVertexMap;
+ QgsMapCanvas* mCanvas;
+};
+
+/**A maptool to move/deletes/adds vertices of line or polygon fetures*/
+class QgsMapToolNodeTool: public QgsMapToolVertexEdit
+{
+ public:
+ QgsMapToolNodeTool( QgsMapCanvas* canvas );
+ virtual ~QgsMapToolNodeTool();
+
+ void canvasMoveEvent( QMouseEvent * e );
+
+ void canvasDoubleClickEvent( QMouseEvent * e );
+
+ void canvasPressEvent( QMouseEvent * e );
+
+ void canvasReleaseEvent( QMouseEvent * e );
+
+ void keyPressEvent( QKeyEvent* e );
+
+ void keyReleaseEvent( QKeyEvent* e );
+
+ //! called when map tool is being deactivated
+ void deactivate();
+
+ /**
+ * Returns closest vertex to given point from selected feature
+ */
+ QgsPoint getClosestVertex(QgsPoint point);
+
+
+ private:
+
+ /** Deletes the rubber band pointers
+ and clears mRubberBands*/
+ void removeRubberBands();
+
+ /** The position of the vertex to move (in map coordinates) to exclude later from snapping*/
+ QList<QgsPoint> mExcludePoint;
+
+ /** rubber bands */
+ QList<QgsRubberBand*> mQgsRubberBands;
+
+ /** object containing selected feature and it's vertexes */
+ SelectionFeature* mSelectionFeature;
+
+ /** flag if selection rectangle is active */
+ bool mSelectionRectangle;
+
+ /** flag if moving of vertexes is occuring */
+ bool mMoving;
+
+ /** flag if click action is still in queue to be processed */
+ bool mClicked;
+
+ /** flag if crtl is pressed */
+ bool mCtrl;
+
+ /** flag if selection of another frature can occur */
+ bool mSelectAnother;
+
+ /** feature id of another feature where user clicked */
+ int mAnother;
+
+ /** stored position of last press down action to count how much vertexes should be moved */
+ QgsPoint* mLastCoordinates;
+
+ /** closest vertex to click */
+ QgsPoint mClosestVertex;
+
+ /** active rubberband for selecting vertexes */
+ QRubberBand* mQRubberBand;
+
+ /** rectangle defining area for selecting vertexes */
+ QRect* mRect;
+
+};
+
+
+#endif
More information about the QGIS-commit
mailing list