[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