Merge pull request #2217 from mhugent/node_tool_changes

Add node editor widget and change node tool to click-click mode
This commit is contained in:
mhugent 2015-07-24 17:34:12 +02:00
commit 740e3abcb9
23 changed files with 1035 additions and 983 deletions

View File

@ -92,6 +92,7 @@ SET(QGIS_APP_SRCS
nodetool/qgsmaptoolnodetool.cpp
nodetool/qgsselectedfeature.cpp
nodetool/qgsvertexentry.cpp
nodetool/qgsnodeeditor.cpp
qgsmeasuredialog.cpp
qgsmeasuretool.cpp
@ -242,6 +243,7 @@ SET (QGIS_APP_MOC_HDRS
nodetool/qgsmaptoolnodetool.h
nodetool/qgsselectedfeature.h
nodetool/qgsnodeeditor.h
qgsmeasuredialog.h
qgsmeasuretool.h

View File

@ -17,372 +17,68 @@
#include "nodetool/qgsselectedfeature.h"
#include "nodetool/qgsvertexentry.h"
#include "nodetool/qgsnodeeditor.h"
#include "qgisapp.h"
#include "qgslayertreeview.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsrubberband.h"
#include "qgssnappingutils.h"
#include "qgsgeometryrubberband.h"
#include "qgsvectorlayer.h"
#include <QMouseEvent>
#include <QRubberBand>
//! Match filter that does not accept only one particular point
struct QgsExcludePointFilter : public QgsPointLocator::MatchFilter
{
QgsExcludePointFilter( const QgsPoint& exclPoint ) : mExclPoint( exclPoint ) {}
bool acceptMatch( const QgsPointLocator::Match& match ) override { return match.point() != mExclPoint; }
QgsPoint mExclPoint;
};
//! Match filter that accepts only matches from a particular feature ID
struct QgsFeatureIdFilter : public QgsPointLocator::MatchFilter
{
QgsFeatureIdFilter( const QgsFeatureId& fid ) : mFid( fid ) {}
bool acceptMatch( const QgsPointLocator::Match& match ) override { return match.featureId() == mFid; }
QgsFeatureId mFid;
};
QgsMapToolNodeTool::QgsMapToolNodeTool( QgsMapCanvas* canvas )
: QgsMapToolEdit( canvas )
, mSelectedFeature( 0 )
, mSelectionRectangle( false )
, mMoving( true )
, mClicked( false )
, mCtrl( false )
, mSelectAnother( false )
, mAnother( 0 )
, mSelectionRubberBand( 0 )
, mRect( NULL )
, mNodeEditor( 0 )
, mRect( 0 )
, mIsPoint( false )
, mDeselectOnRelease( -1 )
{
mToolName = tr( "Node tool" );
mSnapper.setMapCanvas( canvas );
mCadAllowed = true;
mSnapOnPress = true;
}
QgsMapToolNodeTool::~QgsMapToolNodeTool()
{
cleanTool();
delete mRect;
delete mSelectionRubberBand;
}
void QgsMapToolNodeTool::createMovingRubberBands()
void QgsMapToolNodeTool::canvasMapPressEvent( QgsMapMouseEvent* e )
{
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
Q_ASSERT( mSelectedFeature );
QgsVectorLayer *vlayer = mSelectedFeature->vlayer();
Q_ASSERT( vlayer );
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
QgsGeometry* geometry = mSelectedFeature->geometry();
int beforeVertex, afterVertex;
int lastRubberBand = 0;
int vertex;
for ( int i = 0; i < vertexMap.size(); i++ )
removeRubberBands();
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
if ( !vlayer )
{
// create rubberband
if ( vertexMap[i]->isSelected() && !vertexMap[i]->isInRubberBand() )
{
geometry->adjacentVertices( i, beforeVertex, afterVertex );
vertex = i;
while ( beforeVertex != -1 )
{
// move forward NOTE: end if whole cycle is selected
if ( vertexMap[beforeVertex]->isSelected() && beforeVertex != i ) // and take care of cycles
{
vertex = beforeVertex;
geometry->adjacentVertices( vertex, beforeVertex, afterVertex );
}
else
{
// break if cycle is found
break;
}
}
// we have first vertex of moving part
// create rubberband and set default paramaters
QgsRubberBand* rb = new QgsRubberBand( mCanvas, QGis::Line );
rb->setWidth( 2 );
rb->setColor( Qt::blue );
int index = 0;
if ( beforeVertex != -1 ) // adding first point which is not moving
{
rb->addPoint( toMapCoordinates( vlayer, vertexMap[beforeVertex]->point() ), false );
vertexMap[beforeVertex]->setRubberBandValues( true, lastRubberBand, index );
index++;
}
while ( vertex != -1 && vertexMap[vertex]->isSelected() && !vertexMap[vertex]->isInRubberBand() )
{
// topology rubberband creation if needed
if ( topologicalEditing )
{
createTopologyRubberBands( vlayer, vertexMap, vertex );
}
// adding point which will be moved
rb->addPoint( toMapCoordinates( vlayer, vertexMap[vertex]->point() ), false );
// setting values about added vertex
vertexMap[vertex]->setRubberBandValues( true, lastRubberBand, index );
index++;
geometry->adjacentVertices( vertex, beforeVertex, vertex );
}
if ( vertex != -1 && !vertexMap[vertex]->isSelected() ) // add last point not moving if exists
{
rb->addPoint( toMapCoordinates( vlayer, vertexMap[vertex]->point() ), true );
vertexMap[vertex]->setRubberBandValues( true, lastRubberBand, index );
index++;
}
rb->show();
mRubberBands.append( rb );
lastRubberBand++;
}
}
}
void QgsMapToolNodeTool::createTopologyRubberBands( QgsVectorLayer* vlayer, const QList<QgsVertexEntry*> &vertexMap, int vertex )
{
QMultiMap<double, QgsSnappingResult> currentResultList;
QgsGeometry *geometry = mSelectedFeature->geometry();
// snap from current vertex
currentResultList.clear();
vlayer->snapWithContext( vertexMap[vertex]->point(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex );
QMultiMap<double, QgsSnappingResult>::iterator resultIt = currentResultList.begin();
for ( ; resultIt != currentResultList.end(); ++resultIt )
{
// move all other
if ( mSelectedFeature->featureId() != resultIt.value().snappedAtGeometry )
{
if ( mTopologyMovingVertexes.contains( resultIt.value().snappedAtGeometry ) )
{
if ( mTopologyMovingVertexes[resultIt.value().snappedAtGeometry]->contains( resultIt.value().snappedVertexNr ) )
{
// skip vertex already exists in some rubberband
continue;
}
}
QgsRubberBand* trb = new QgsRubberBand( mCanvas, QGis::Line );
mTopologyRubberBand.append( trb );
int rbId = mTopologyRubberBand.size() - 1;
trb->setWidth( 1 );
trb->setColor( Qt::red );
int tVertex = resultIt.value().snappedVertexNr;
int tVertexBackup = -1, tVertexAfter = -1;
int tVertexFirst = tVertex; // vertex number to check for cycling
QgsFeature topolFeature;
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( resultIt.value().snappedAtGeometry ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( topolFeature );
const QgsGeometry* topolGeometry = topolFeature.constGeometry();
while ( tVertex != -1 ) // looking for first vertex to rubberband
{
tVertexBackup = tVertex;
topolGeometry->adjacentVertices( tVertex, tVertex, tVertexAfter );
if ( tVertex == -1 || tVertex == tVertexFirst )
break; // check if this is not first vertex of the feature or cycling error
// if closest vertex is not from selected feature or is not selected end
double dist;
QgsPoint point = topolGeometry->vertexAt( tVertex );
int at, before, after;
geometry->closestVertex( point, at, before, after, dist );
if ( dist > ZERO_TOLERANCE || !vertexMap[at]->isSelected() ) // problem with double precision
{
break; // found first vertex
}
}
int movingPointIndex = 0;
Vertexes* movingPoints = new Vertexes();
Vertexes* addedPoints = 0;
if ( mTopologyMovingVertexes.contains( resultIt.value().snappedAtGeometry ) )
{
addedPoints = mTopologyMovingVertexes[ resultIt.value().snappedAtGeometry ];
}
else
{
addedPoints = new Vertexes();
}
if ( tVertex == -1 ) // adding first point if needed
{
tVertex = tVertexBackup;
}
else
{
trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) );
if ( tVertex == tVertexFirst ) // cycle first vertex need to be added also
{
movingPoints->insert( movingPointIndex );
}
movingPointIndex = 1;
topolGeometry->adjacentVertices( tVertex, tVertexAfter, tVertex );
}
while ( tVertex != -1 )
{
// if closest vertex is not from selected feature or is not selected end
double dist;
QgsPoint point = topolGeometry->vertexAt( tVertex );
int at, before, after;
geometry->closestVertex( point, at, before, after, dist );
// find first no matching vertex
if ( dist > ZERO_TOLERANCE || !vertexMap[at]->isSelected() ) // problem with double precision
{
trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) );
break; // found first vertex
}
else // add moving point to rubberband
{
if ( addedPoints->contains( tVertex ) )
break; // just preventing to circle
trb->addPoint( toMapCoordinates( vlayer, topolGeometry->vertexAt( tVertex ) ) );
movingPoints->insert( movingPointIndex );
movingPointIndex++;
addedPoints->insert( tVertex );
}
topolGeometry->adjacentVertices( tVertex, tVertexAfter, tVertex );
}
mTopologyMovingVertexes.insert( resultIt.value().snappedAtGeometry, addedPoints );
mTopologyRubberBandVertexes.insert( rbId, movingPoints );
}
}
}
void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
{
if ( !mSelectedFeature || !mClicked )
return;
QgsVectorLayer* vlayer = mSelectedFeature->vlayer();
Q_ASSERT( vlayer );
mSelectAnother = false;
if ( mMoving )
{
// create rubberband, if none exists
if ( mRubberBands.empty() )
{
if ( mIsPoint )
{
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( vertexMap[i]->isSelected() )
{
QgsRubberBand* rb = createRubberBandMarker( vertexMap[i]->point(), vlayer );
mRubberBands.append( rb );
}
}
}
createMovingRubberBands();
mPosMapCoordBackup = toMapCoordinates( e->pos() );
}
else
{
// move rubberband
QgsPoint posMapCoord, pressMapCoords;
QgsExcludePointFilter excludePointFilter( mClosestMapVertex );
QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( e->pos(), &excludePointFilter );
if ( match.isValid() )
{
posMapCoord = match.point();
pressMapCoords = mClosestMapVertex;
}
else
{
posMapCoord = toMapCoordinates( e->pos() );
pressMapCoords = toMapCoordinates( mPressCoordinates );
}
QgsVector offset = posMapCoord - pressMapCoords;
// handle points
if ( mIsPoint )
{
for ( int i = 0; i < mRubberBands.size(); i++ )
{
mRubberBands[i]->setTranslationOffset( offset.x(), offset.y() );
}
return;
}
// move points
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( !vertexMap[i]->isSelected() )
continue;
QgsPoint p = toMapCoordinates( vlayer, vertexMap[i]->point() ) + offset;
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), p );
if ( vertexMap[i]->rubberBandIndex() == 0 )
{
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, p );
}
}
// topological editing
offset = posMapCoord - mPosMapCoordBackup;
for ( int i = 0; i < mTopologyRubberBand.size(); i++ )
{
for ( int pointIndex = 0; pointIndex < mTopologyRubberBand[i]->numberOfVertices(); pointIndex++ )
{
if ( mTopologyRubberBandVertexes[i]->contains( pointIndex ) )
{
const QgsPoint* point = mTopologyRubberBand[i]->getPoint( 0, pointIndex );
if ( point == 0 )
{
break;
}
mTopologyRubberBand[i]->movePoint( pointIndex, *point + offset );
}
}
}
mPosMapCoordBackup = posMapCoord;
}
}
else
bool ctrlModifier = e->modifiers() & Qt::ControlModifier;
QList<QgsSnappingResult> snapResults;
QgsFeatureId bkFeatureId = 0;
if ( mSelectedFeature )
{
if ( !mSelectionRectangle )
{
mSelectionRectangle = true;
mSelectionRubberBand = new QRubberBand( QRubberBand::Rectangle, mCanvas );
mRect = new QRect();
mRect->setTopLeft( mPressCoordinates );
}
mRect->setBottomRight( e->pos() );
QRect normalizedRect = mRect->normalized();
mSelectionRubberBand->setGeometry( normalizedRect );
mSelectionRubberBand->show();
bkFeatureId = mSelectedFeature->featureId();
}
}
void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
{
QgsDebugCall;
bool hasVertexSelection = mSelectedFeature && mSelectedFeature->hasSelection();
mClicked = true;
mPressCoordinates = e->pos();
if ( !mSelectedFeature )
if ( !mSelectedFeature || !hasVertexSelection )
{
//try to select feature
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
if ( !vlayer )
{
return;
}
mSelectAnother = false;
QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex | QgsPointLocator::Edge );
if ( !m.isValid() )
mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertexAndSegment, -1 );
if ( snapResults.size() < 1 )
{
emit messageEmitted( tr( "could not snap to a segment on the current layer." ) );
return;
@ -391,89 +87,95 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
// remove previous warning
emit messageDiscarded();
mSelectedFeature = new QgsSelectedFeature( m.featureId(), vlayer, mCanvas );
connect( QgisApp::instance()->layerTreeView(), SIGNAL( currentLayerChanged( QgsMapLayer* ) ), this, SLOT( currentLayerChanged( QgsMapLayer* ) ) );
connect( mSelectedFeature, SIGNAL( destroyed() ), this, SLOT( selectedFeatureDestroyed() ) );
connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
mIsPoint = vlayer->geometryType() == QGis::Point;
if ( !mSelectedFeature || snapResults[0].snappedAtGeometry != mSelectedFeature->featureId() )
{
delete mSelectedFeature;
mSelectedFeature = new QgsSelectedFeature( snapResults[0].snappedAtGeometry, vlayer, mCanvas );
connect( QgisApp::instance()->layerTreeView(), SIGNAL( currentLayerChanged( QgsMapLayer* ) ), this, SLOT( currentLayerChanged( QgsMapLayer* ) ) );
connect( mSelectedFeature, SIGNAL( destroyed() ), this, SLOT( selectedFeatureDestroyed() ) );
connect( mSelectedFeature, SIGNAL( lastVertexChanged( const QgsPointV2& ) ), this, SLOT( changeLastVertex( const QgsPointV2& ) ) );
connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
mIsPoint = vlayer->geometryType() == QGis::Point;
mNodeEditor = new QgsNodeEditor( vlayer, mSelectedFeature, mCanvas );
QgisApp::instance()->addDockWidget( Qt::LeftDockWidgetArea, mNodeEditor );
}
}
//select or move vertices if selected feature has not been changed
QgsPoint layerPoint = toLayerCoordinates( vlayer, e->mapPoint() );
if ( mSelectedFeature->featureId() == bkFeatureId )
{
if ( mSelectedFeature->hasSelection() && !ctrlModifier ) //move vertices
{
QgsPoint targetCoords = layerPoint;
mSelectedFeature->moveSelectedVertexes( targetCoords - mClosestLayerVertex );
mCanvas->refresh();
mSelectedFeature->deselectAllVertexes();
}
else //add vertex selection
{
int atVertex, beforeVertex, afterVertex;
double dist;
QgsPoint closestLayerVertex = mSelectedFeature->geometry()->closestVertex( layerPoint, atVertex, beforeVertex, afterVertex, dist );
mSelectedFeature->selectVertex( atVertex );
}
}
}
void QgsMapToolNodeTool::canvasMapMoveEvent( QgsMapMouseEvent* e )
{
if ( !mSelectedFeature || !mSelectedFeature->hasSelection() )
{
return;
}
QgsVectorLayer* vlayer = mSelectedFeature->vlayer();
if ( !vlayer )
{
return;
}
if ( mMoveRubberBands.empty() )
{
QgsGeometryRubberBand* rb = new QgsGeometryRubberBand( mCanvas, mSelectedFeature->geometry()->type() );
rb->setOutlineColor( Qt::blue );
rb->setBrushStyle( Qt::NoBrush );
rb->setOutlineWidth( 2 );
QgsAbstractGeometryV2* rbGeom = mSelectedFeature->geometry()->geometry()->clone();
if ( mCanvas->mapSettings().layerTransform( vlayer ) )
rbGeom->transform( *mCanvas->mapSettings().layerTransform( vlayer ) );
rb->setGeometry( rbGeom );
mMoveRubberBands.insert( mSelectedFeature->featureId(), rb );
foreach ( const QgsVertexEntry* vertexEntry, mSelectedFeature->vertexMap() )
{
if ( vertexEntry->isSelected() )
mMoveVertices[mSelectedFeature->featureId()].append( qMakePair( vertexEntry->vertexId(), toMapCoordinates( vlayer, vertexEntry->point() ) ) );
}
if ( QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ) )
{
createTopologyRubberBands();
}
}
else
{
// remove previous warning
emit messageDiscarded();
// move rubberband
QList<QgsSnappingResult> snapResults;
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, QList<QgsPoint>() << mClosestLayerVertex );
Q_ASSERT( mSelectedFeature->vlayer() );
QgsPoint origPos = toMapCoordinates( vlayer, mClosestLayerVertex );
QgsPoint curPos = snapPointFromResults( snapResults, e->pos() );
double diffX = curPos.x() - origPos.x();
double diffY = curPos.y() - origPos.y();
// try to find a piece of currently selected geometry
QgsFeatureIdFilter filterFid( mSelectedFeature->featureId() );
QgsPointLocator::Match mSel = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex | QgsPointLocator::Edge, &filterFid );
if ( mSel.hasVertex() )
foreach ( const QgsFeatureId& fid, mMoveRubberBands.keys() )
{
// mouse pressed on a vertex:
// - if clicked on already selected vertex - deselect it
// - if clicked on vertex that is not selected - select it
// - if clicked with CTRL - invert selection state of the vertex
// - if pressed+dragging on already selected vertex - will move selected vertices
mMoving = true;
mClosestMapVertex = mSel.point();
int atVertex = mSel.vertexIndex();
if ( mSelectedFeature->isSelected( atVertex ) )
typedef QPair<QgsVertexId, QgsPointV2> MoveVertex;
foreach ( const MoveVertex& pair, mMoveVertices[fid] )
{
mDeselectOnRelease = atVertex;
}
else if ( mCtrl )
{
mSelectedFeature->invertVertexSelection( atVertex );
}
else
{
mSelectedFeature->deselectAllVertexes();
mSelectedFeature->selectVertex( atVertex );
}
}
else if ( mSel.hasEdge() )
{
// mouse pressed on an edge:
// - if clicked - select just vertices of that edge
// - if clicked with CTRL - invert selection state of vertices of the edge
// - if pressed+dragging - will move vertices of the edge
mMoving = true;
QgsPoint p1, p2;
mSel.edgePoints( p1, p2 );
mClosestMapVertex = p1.sqrDist( mSel.point() ) < p2.sqrDist( mSel.point() ) ? p1 : p2;
if ( !mCtrl )
{
mSelectedFeature->deselectAllVertexes();
mSelectedFeature->selectVertex( mSel.vertexIndex() + 1 );
mSelectedFeature->selectVertex( mSel.vertexIndex() );
}
else
{
mSelectedFeature->invertVertexSelection( mSel.vertexIndex() + 1 );
mSelectedFeature->invertVertexSelection( mSel.vertexIndex() );
}
}
else
{
// nothing from the feature is acceptable:
// - if clicked - try to select a different feature. if nothing is around, at least deselect all vertices
QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Vertex | QgsPointLocator::Edge );
if ( m.isValid() )
{
// if this will be just a click, on release we will select this new feature
mAnother = m.featureId();
mSelectAnother = true;
}
else if ( !mCtrl )
{
mSelectedFeature->deselectAllVertexes();
QgsPointV2 pos = pair.second;
pos.setX( pos.x() + diffX );
pos.setY( pos.y() + diffY );
mMoveRubberBands.value( fid )->moveVertex( pair.first, pos );
}
}
}
@ -498,160 +200,15 @@ void QgsMapToolNodeTool::editingToggled()
cleanTool();
}
void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
{
if ( !mSelectedFeature )
return;
removeRubberBands();
QgsVectorLayer *vlayer = mSelectedFeature->vlayer();
Q_ASSERT( vlayer );
mClicked = false;
mSelectionRectangle = false;
if ( mSelectionRubberBand )
{
mSelectionRubberBand->close();
delete mSelectionRubberBand;
mSelectionRubberBand = 0;
}
if ( mRect )
{
delete mRect;
mRect = 0;
}
if ( mPressCoordinates == e->pos() )
{
if ( mSelectAnother )
{
// select another feature
mSelectedFeature->setSelectedFeature( mAnother, vlayer, mCanvas );
mIsPoint = vlayer->geometryType() == QGis::Point;
mSelectAnother = false;
}
}
else if ( mMoving )
{
mMoving = false;
QgsPoint releaseMapCoords, pressMapCoords;
QgsExcludePointFilter excludePointFilter( mClosestMapVertex );
QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( e->pos(), &excludePointFilter );
if ( match.isValid() )
{
releaseMapCoords = match.point();
pressMapCoords = mClosestMapVertex;
}
else
{
releaseMapCoords = toMapCoordinates( e->pos() );
pressMapCoords = toMapCoordinates( mPressCoordinates );
}
QgsPoint releaseLayerCoords = toLayerCoordinates( vlayer, releaseMapCoords );
QgsPoint pressLayerCoords = toLayerCoordinates( vlayer, pressMapCoords );
if ( match.isValid() )
{
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
if ( topologicalEditing )
{
addTopologicalPoints( QList<QgsPoint>() << releaseMapCoords );
}
}
mSelectedFeature->moveSelectedVertexes( releaseLayerCoords - pressLayerCoords );
mCanvas->refresh();
}
else // selecting vertexes by rubberband
{
// coordinates has to be coordinates from layer not canvas
QgsRectangle r( toLayerCoordinates( vlayer, mPressCoordinates ),
toLayerCoordinates( vlayer, e->pos() ) );
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
if ( !mCtrl )
{
mSelectedFeature->deselectAllVertexes();
}
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( r.contains( vertexMap[i]->point() ) )
{
// inverting selection is enough because all were deselected if ctrl is not pressed
mSelectedFeature->invertVertexSelection( i, false );
}
}
}
mMoving = false;
if ( mDeselectOnRelease != -1 )
{
if ( mCtrl )
{
mSelectedFeature->invertVertexSelection( mDeselectOnRelease );
}
else
{
mSelectedFeature->deselectAllVertexes();
mSelectedFeature->selectVertex( mDeselectOnRelease );
}
mDeselectOnRelease = -1;
}
mExcludePoint.clear();
}
void QgsMapToolNodeTool::deactivate()
{
cleanTool();
delete mRect;
mRect = 0;
delete mSelectionRubberBand;
mSelectionRubberBand = 0;
mSelectAnother = false;
mCtrl = false;
mMoving = true;
mClicked = false;
QgsMapTool::deactivate();
}
void QgsMapToolNodeTool::removeRubberBands()
{
// cleanup rubberbands and list
foreach ( QgsRubberBand *rb, mRubberBands )
{
delete rb;
}
mRubberBands.clear();
foreach ( QgsRubberBand *rb, mTopologyRubberBand )
{
delete rb;
}
mTopologyRubberBand.clear();
mTopologyMovingVertexes.clear();
mTopologyRubberBandVertexes.clear();
// remove all data from selected feature (no change to rubberbands itself)
if ( mSelectedFeature )
mSelectedFeature->cleanRubberBandsData();
}
void QgsMapToolNodeTool::cleanTool( bool deleteSelectedFeature )
{
removeRubberBands();
if ( mSelectedFeature )
{
QgsVectorLayer *vlayer = mSelectedFeature->vlayer();
@ -664,6 +221,11 @@ void QgsMapToolNodeTool::cleanTool( bool deleteSelectedFeature )
if ( deleteSelectedFeature ) delete mSelectedFeature;
mSelectedFeature = 0;
}
if ( mNodeEditor )
{
delete mNodeEditor;
mNodeEditor = 0;
}
}
void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
@ -677,13 +239,16 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
QMultiMap<double, QgsSnappingResult> currentResultList;
mMoving = false;
QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToCurrentLayer( e->pos(), QgsPointLocator::Edge );
if ( !m.isValid() || m.featureId() != mSelectedFeature->featureId() )
QList<QgsSnappingResult> snapResults;
double tol = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapSettings() );
mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToSegment, tol );
if ( snapResults.size() < 1 ||
snapResults.first().snappedAtGeometry != mSelectedFeature->featureId() ||
snapResults.first().snappedVertexNr != -1 )
return;
// some segment selected
QgsPoint layerCoords = toLayerCoordinates( vlayer, m.point() );
QgsPoint layerCoords = toLayerCoordinates( vlayer, snapResults.first().snappedVertex );
if ( topologicalEditing )
{
// snap from adding position to this vertex when topological editing is enabled
@ -694,7 +259,7 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
vlayer->beginEditCommand( tr( "Inserted vertex" ) );
// add vertex
vlayer->insertVertex( layerCoords.x(), layerCoords.y(), mSelectedFeature->featureId(), m.vertexIndex() + 1 );
vlayer->insertVertex( layerCoords.x(), layerCoords.y(), mSelectedFeature->featureId(), snapResults.first().afterVertexNr );
if ( topologicalEditing )
{
@ -716,12 +281,6 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
{
if ( e->key() == Qt::Key_Control )
{
mCtrl = true;
return;
}
if ( mSelectedFeature && ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
{
int firstSelectedIndex = firstSelectedVertex();
@ -743,6 +302,7 @@ void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
mSelectedFeature->deselectAllVertexes();
safeSelectVertex( firstSelectedIndex - 1 );
e->ignore();
}
else if ( mSelectedFeature && ( e->key() == Qt::Key_Greater || e->key() == Qt::Key_Period ) )
{
@ -752,62 +312,125 @@ void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
mSelectedFeature->deselectAllVertexes();
safeSelectVertex( firstSelectedIndex + 1 );
e->ignore();
}
}
void QgsMapToolNodeTool::keyReleaseEvent( QKeyEvent* e )
{
if ( e->key() == Qt::Key_Control )
{
mCtrl = false;
return;
}
}
QgsRubberBand* QgsMapToolNodeTool::createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer )
{
// create rubberband marker for moving points
QgsRubberBand* marker = new QgsRubberBand( mCanvas, QGis::Point );
marker->setColor( Qt::red );
marker->setWidth( 2 );
marker->setIcon( QgsRubberBand::ICON_FULL_BOX );
marker->setIconSize( 8 );
QgsPoint pom = toMapCoordinates( vlayer, center );
marker->addPoint( pom );
return marker;
}
int QgsMapToolNodeTool::firstSelectedVertex()
int QgsMapToolNodeTool::firstSelectedVertex( )
{
if ( mSelectedFeature )
{
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
int vertexNr = 0;
foreach ( QgsVertexEntry *entry, vertexMap )
for ( int i = 0, n = vertexMap.size(); i < n; ++i )
{
if ( entry->isSelected() )
if ( vertexMap[i]->isSelected() )
{
return vertexNr;
return i;
}
vertexNr++;
}
}
return -1;
}
int QgsMapToolNodeTool::safeSelectVertex( int vertexNr )
void QgsMapToolNodeTool::safeSelectVertex( int vertexNr )
{
if ( mSelectedFeature )
{
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
if ( vertexNr >= vertexMap.size() ) vertexNr -= vertexMap.size();
if ( vertexNr < 0 ) vertexNr = vertexMap.size() - 1 + vertexNr;
mSelectedFeature->selectVertex( vertexNr );
return vertexNr;
int n = mSelectedFeature->vertexMap().size();
mSelectedFeature->selectVertex(( vertexNr + n ) % n );
}
}
QgsPoint QgsMapToolNodeTool::snapPointFromResults( const QList<QgsSnappingResult>& snapResults, const QPoint& screenCoords )
{
if ( snapResults.size() < 1 )
{
return toMapCoordinates( screenCoords );
}
else
{
return snapResults.constBegin()->snappedVertex;
}
}
int QgsMapToolNodeTool::insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults, QgsVectorLayer* editedLayer )
{
QgsPoint layerPoint;
if ( !editedLayer || !editedLayer->isEditable() )
{
return 1;
}
//transform snaping coordinates to layer crs first
QList<QgsSnappingResult> transformedSnapResults = snapResults;
QList<QgsSnappingResult>::iterator it = transformedSnapResults.begin();
for ( ; it != transformedSnapResults.constEnd(); ++it )
{
QgsPoint layerPoint = toLayerCoordinates( editedLayer, it->snappedVertex );
it->snappedVertex = layerPoint;
}
return editedLayer->insertSegmentVerticesForSnap( transformedSnapResults );
}
void QgsMapToolNodeTool::changeLastVertex( const QgsPointV2& pt )
{
mClosestLayerVertex.setX( pt.x() );
mClosestLayerVertex.setY( pt.y() );
}
void QgsMapToolNodeTool::removeRubberBands()
{
qDeleteAll( mMoveRubberBands );
mMoveRubberBands.clear();
mMoveVertices.clear();
}
void QgsMapToolNodeTool::createTopologyRubberBands()
{
QgsVectorLayer* vlayer = mSelectedFeature->vlayer();
foreach ( const QgsVertexEntry* vertexEntry, mSelectedFeature->vertexMap() )
{
if ( !vertexEntry->isSelected() )
{
continue;
}
// Snap vertex
QMultiMap<double, QgsSnappingResult> snapResults;
vlayer->snapWithContext( vertexEntry->pointV1(), ZERO_TOLERANCE, snapResults, QgsSnapper::SnapToVertex );
foreach ( const QgsSnappingResult& snapResult, snapResults.values() )
{
// Get geometry of snapped feature
QgsFeatureId snapFeatureId = snapResult.snappedAtGeometry;
QgsFeature feature;
if ( !vlayer->getFeatures( QgsFeatureRequest( snapFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( feature ) )
{
continue;
}
// Get VertexId of snapped vertex
QgsVertexId vid;
if ( !feature.constGeometry()->vertexIdFromVertexNr( snapResult.snappedVertexNr, vid ) )
{
continue;
}
// Add rubberband if not already added
if ( !mMoveRubberBands.contains( snapFeatureId ) )
{
QgsGeometryRubberBand* rb = new QgsGeometryRubberBand( mCanvas, feature.constGeometry()->type() );
rb->setOutlineColor( Qt::blue );
rb->setBrushStyle( Qt::NoBrush );
rb->setOutlineWidth( 2 );
QgsAbstractGeometryV2* rbGeom = feature.constGeometry()->geometry()->clone();
if ( mCanvas->mapSettings().layerTransform( vlayer ) )
rbGeom->transform( *mCanvas->mapSettings().layerTransform( vlayer ) );
rb->setGeometry( rbGeom );
mMoveRubberBands.insert( snapFeatureId, rb );
}
// Add to list of vertices to be moved
mMoveVertices[snapFeatureId].append( qMakePair( vid, toMapCoordinates( vlayer, feature.constGeometry()->geometry()->vertexAt( vid ) ) ) );
}
}
return -1;
}

View File

@ -16,22 +16,17 @@
#ifndef QGSMAPTOOLNODETOOL_H
#define QGSMAPTOOLNODETOOL_H
#include "qgsfeature.h"
#include "qgsmaptooledit.h"
#include "qgspoint.h"
#include "qgsmapcanvassnapper.h"
class QRubberBand;
class QgsRubberBand;
class QgsGeometryRubberBand;
class QgsVertexEntry;
class QgsSelectedFeature;
class QgsNodeEditor;
/**
* Set representing set of vertex numbers
*/
typedef QSet<int> Vertexes;
/**A maptool to move/deletes/adds vertices of line or polygon features*/
/** A maptool to move/deletes/adds vertices of line or polygon features*/
class QgsMapToolNodeTool: public QgsMapToolEdit
{
Q_OBJECT
@ -39,20 +34,18 @@ class QgsMapToolNodeTool: public QgsMapToolEdit
QgsMapToolNodeTool( QgsMapCanvas* canvas );
virtual ~QgsMapToolNodeTool();
void canvasMoveEvent( QMouseEvent * e ) override;
void canvasDoubleClickEvent( QMouseEvent * e );
void canvasDoubleClickEvent( QMouseEvent * e ) override;
//! mouse press event in map coordinates (eventually filtered) to be redefined in subclass
void canvasMapPressEvent( QgsMapMouseEvent* e ) override;
void canvasPressEvent( QMouseEvent * e ) override;
//! mouse move event in map coordinates (eventually filtered) to be redefined in subclass
void canvasMapMoveEvent( QgsMapMouseEvent* e ) override;
void canvasReleaseEvent( QMouseEvent * e ) override;
void keyPressEvent( QKeyEvent* e ) override;
void keyReleaseEvent( QKeyEvent* e ) override;
void keyPressEvent( QKeyEvent* e );
//! called when map tool is being deactivated
void deactivate() override;
void deactivate();
public slots:
void selectedFeatureDestroyed();
@ -67,25 +60,24 @@ class QgsMapToolNodeTool: public QgsMapToolEdit
*/
void editingToggled();
void changeLastVertex( const QgsPointV2& pt );
private:
/**
* Deletes the rubber band pointers and clears mRubberBands
*/
void removeRubberBands();
/**
* Creates rubber bands for ther features when topology editing is enabled
*/
void createTopologyRubberBands();
/**
* Disconnects signals and clears objects
*/
void cleanTool( bool deleteSelectedFeature = true );
/**
* Creating rubber band marker for movin of point
* @param center coordinates of point to be moved
* @param vlayer vector layer on which we are working
* @return rubber band marker
*/
QgsRubberBand* createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer );
/**
* Function to check if selected feature exists and is same with original one
* stored in internal structures
@ -94,19 +86,6 @@ class QgsMapToolNodeTool: public QgsMapToolEdit
*/
bool checkCorrectnessOfFeature( QgsVectorLayer* vlayer );
/**
* Creates rubberbands for moving points
*/
void createMovingRubberBands();
/**
* Creates rubber bands for ther features when topology editing is enabled
* @param vlayer vector layer for ehich rubber bands are created
* @param vertexMap map of vertexes
* @param vertex currently processed vertex
*/
void createTopologyRubberBands( QgsVectorLayer* vlayer, const QList<QgsVertexEntry*> &vertexMap, int vertex );
/**
* Returns the index of first selected vertex, -1 when all unselected
*/
@ -115,64 +94,52 @@ class QgsMapToolNodeTool: public QgsMapToolEdit
/**
* Select the specified vertex bounded to current index range, returns the valid selected index
*/
int safeSelectVertex( int vertexNr );
void safeSelectVertex( int vertexNr );
/** The position of the vertex to move (in map coordinates) to exclude later from snapping*/
QList<QgsPoint> mExcludePoint;
/** Extracts a single snapping point from a set of snapping results.
This is useful for snapping operations that just require a position to snap to and not all the
snapping results. If the list is empty, the screen coordinates are transformed into map coordinates and returned
@param snapResults results collected from the snapping operation.
@return the snapped point in map coordinates*/
QgsPoint snapPointFromResults( const QList<QgsSnappingResult>& snapResults, const QPoint& screenCoords );
/** rubber bands */
QList<QgsRubberBand*> mRubberBands;
/** Inserts vertices to the snapped segments of the editing layer.
This is useful for topological editing if snap to segment is enabled.
@param snapResults results collected from the snapping operation
@param editedLayer pointer to the editing layer
@return 0 in case of success*/
int insertSegmentVerticesForSnap( const QList<QgsSnappingResult>& snapResults, QgsVectorLayer* editedLayer );
/** list of topology rubber bands */
QList<QgsRubberBand*> mTopologyRubberBand;
/** Snapper object that reads the settings from project and option
and applies it to the map canvas*/
QgsMapCanvasSnapper mSnapper;
/** vertexes of rubberbands which are to be moved */
QMap<QgsFeatureId, Vertexes*> mTopologyMovingVertexes;
/** vertexes of features with int id which were already added tu rubber bands */
QMap<QgsFeatureId, Vertexes*> mTopologyRubberBandVertexes;
/** object containing selected feature and it's vertexes */
/** Object containing selected feature and it's vertexes */
QgsSelectedFeature *mSelectedFeature;
/** flag if selection rectangle is active */
bool mSelectionRectangle;
/** Dock widget which allows to edit vertices */
QgsNodeEditor* mNodeEditor;
/** 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 feature can occur */
bool mSelectAnother;
/** feature id of another feature where user clicked */
/** Feature id of another feature where user clicked */
QgsFeatureId mAnother;
/** stored position of last press down action to count how much vertexes should be moved */
/** Stored position of last press down action to count how much vertexes should be moved */
QPoint mPressCoordinates;
/** closest vertex to click in map coordinates */
QgsPoint mClosestMapVertex;
/** Closest vertex to click in map coordinates */
QgsPoint mClosestLayerVertex;
/** backup of map coordinates to be able to count change between moves */
QgsPoint mPosMapCoordBackup;
/** active rubberband for selecting vertexes */
QRubberBand *mSelectionRubberBand;
/** rectangle defining area for selecting vertexes */
/** Rectangle defining area for selecting vertexes */
QRect* mRect;
/** flag to tell if edition points */
/** Flag to tell if edition points */
bool mIsPoint;
/** vertex to deselect on release */
int mDeselectOnRelease;
/** Rubber bands during node move */
QMap<QgsFeatureId, QgsGeometryRubberBand*> mMoveRubberBands;
/** Vertices of features to move */
QMap<QgsFeatureId, QList< QPair<QgsVertexId, QgsPointV2> > > mMoveVertices;
};
#endif

View File

@ -0,0 +1,238 @@
/***************************************************************************
qgsnodeeditor.cpp
-----------------
begin : Tue Mar 24 2015
copyright : (C) 2015 Sandro Mani / Sourcepole AG
email : smani@sourcepole.ch
***************************************************************************/
/***************************************************************************
* *
* 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 "qgsnodeeditor.h"
#include "qgsmapcanvas.h"
#include "qgsselectedfeature.h"
#include "qgsvertexentry.h"
#include "qgsvectorlayer.h"
#include "qgsgeometryutils.h"
#include <QTableWidget>
#include <QHeaderView>
#include <QVBoxLayout>
#include <QStyledItemDelegate>
#include <QLineEdit>
#include <QVector2D>
static const int MinRadiusRole = Qt::UserRole + 1;
class CoordinateItemDelegate : public QStyledItemDelegate
{
public:
QString displayText( const QVariant & value, const QLocale & locale ) const
{
return locale.toString( value.toDouble(), 'f', 4 );
}
protected:
QWidget* createEditor( QWidget * parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & index ) const
{
QLineEdit* lineEdit = new QLineEdit( parent );
QDoubleValidator* validator = new QDoubleValidator();
if ( !index.data( MinRadiusRole ).isNull() )
validator->setBottom( index.data( MinRadiusRole ).toDouble() );
lineEdit->setValidator( validator );
return lineEdit;
}
void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
QLineEdit* lineEdit = qobject_cast<QLineEdit*>( editor );
if ( lineEdit->hasAcceptableInput() )
{
QStyledItemDelegate::setModelData( editor, model, index );
}
}
};
QgsNodeEditor::QgsNodeEditor(
QgsVectorLayer *layer,
QgsSelectedFeature *selectedFeature,
QgsMapCanvas *canvas )
{
setWindowTitle( tr( "Vertex editor" ) );
setFeatures( features() ^ QDockWidget::DockWidgetClosable );
mLayer = layer;
mSelectedFeature = selectedFeature;
mCanvas = canvas;
mTableWidget = new QTableWidget( 0, 6, this );
mTableWidget->setHorizontalHeaderLabels( QStringList() << "id" << "x" << "y" << "z" << "m" << "r" );
mTableWidget->setSelectionMode( QTableWidget::ExtendedSelection );
mTableWidget->setSelectionBehavior( QTableWidget::SelectRows );
mTableWidget->verticalHeader()->hide();
mTableWidget->horizontalHeader()->setResizeMode( 1, QHeaderView::Stretch );
mTableWidget->horizontalHeader()->setResizeMode( 2, QHeaderView::Stretch );
mTableWidget->horizontalHeader()->setResizeMode( 3, QHeaderView::Stretch );
mTableWidget->horizontalHeader()->setResizeMode( 4, QHeaderView::Stretch );
mTableWidget->horizontalHeader()->setResizeMode( 5, QHeaderView::Stretch );
mTableWidget->setItemDelegateForColumn( 1, new CoordinateItemDelegate() );
mTableWidget->setItemDelegateForColumn( 2, new CoordinateItemDelegate() );
mTableWidget->setItemDelegateForColumn( 3, new CoordinateItemDelegate() );
mTableWidget->setItemDelegateForColumn( 4, new CoordinateItemDelegate() );
mTableWidget->setItemDelegateForColumn( 5, new CoordinateItemDelegate() );
setWidget( mTableWidget );
connect( mSelectedFeature, SIGNAL( selectionChanged() ), this, SLOT( updateTableSelection() ) );
connect( mSelectedFeature, SIGNAL( vertexMapChanged() ), this, SLOT( rebuildTable() ) );
connect( mTableWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( updateNodeSelection() ) );
connect( mTableWidget, SIGNAL( cellChanged( int, int ) ), this, SLOT( tableValueChanged( int, int ) ) );
rebuildTable();
}
void QgsNodeEditor::rebuildTable()
{
QFont curvePointFont = mTableWidget->font();
curvePointFont.setItalic( true );
mTableWidget->blockSignals( true );
mTableWidget->setRowCount( 0 );
int row = 0;
bool hasR = false;
foreach ( const QgsVertexEntry* entry, mSelectedFeature->vertexMap() )
{
mTableWidget->insertRow( row );
QTableWidgetItem* idItem = new QTableWidgetItem();
idItem->setData( Qt::DisplayRole, row );
idItem->setFlags( idItem->flags() ^ Qt::ItemIsEditable );
mTableWidget->setItem( row, 0, idItem );
QTableWidgetItem* xItem = new QTableWidgetItem();
xItem->setData( Qt::EditRole, entry->point().x() );
mTableWidget->setItem( row, 1, xItem );
QTableWidgetItem* yItem = new QTableWidgetItem();
yItem->setData( Qt::EditRole, entry->point().y() );
mTableWidget->setItem( row, 2, yItem );
QTableWidgetItem* zItem = new QTableWidgetItem();
zItem->setData( Qt::EditRole, entry->point().z() );
mTableWidget->setItem( row, 3, zItem );
QTableWidgetItem* mItem = new QTableWidgetItem();
mItem->setData( Qt::EditRole, entry->point().m() );
mTableWidget->setItem( row, 4, mItem );
QTableWidgetItem* rItem = new QTableWidgetItem();
mTableWidget->setItem( row, 5, rItem );
bool curvePoint = ( entry->vertexId().type == QgsVertexId::CurveVertex );
if ( curvePoint )
{
idItem->setFont( curvePointFont );
xItem->setFont( curvePointFont );
yItem->setFont( curvePointFont );
zItem->setFont( curvePointFont );
mItem->setFont( curvePointFont );
rItem->setFont( curvePointFont );
const QgsPointV2& p1 = mSelectedFeature->vertexMap()[row - 1]->point();
const QgsPointV2& p2 = mSelectedFeature->vertexMap()[row]->point();
const QgsPointV2& p3 = mSelectedFeature->vertexMap()[row + 1]->point();
double r, cx, cy;
QgsGeometryUtils::circleCenterRadius( p1, p2, p3, r, cx, cy );
rItem->setData( Qt::EditRole, r );
double x13 = p3.x() - p1.x(), y13 = p3.y() - p1.y();
rItem->setData( MinRadiusRole, 0.5 * qSqrt( x13 * x13 + y13 * y13 ) );
hasR = true;
}
else
{
rItem->setFlags( rItem->flags() & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled ) );
}
++row;
}
mTableWidget->setColumnHidden( 3, !mSelectedFeature->vertexMap()[0]->point().is3D() );
mTableWidget->setColumnHidden( 4, !mSelectedFeature->vertexMap()[0]->point().isMeasure() );
mTableWidget->setColumnHidden( 5, !hasR );
mTableWidget->resizeColumnToContents( 0 );
mTableWidget->blockSignals( false );
}
void QgsNodeEditor::tableValueChanged( int row, int col )
{
int nodeIdx = mTableWidget->item( row, 0 )->data( Qt::DisplayRole ).toInt();
double x, y;
if ( col == 5 ) // radius modified
{
double r = mTableWidget->item( row, 5 )->data( Qt::EditRole ).toDouble();
double x1 = mTableWidget->item( row - 1, 1 )->data( Qt::EditRole ).toDouble();
double y1 = mTableWidget->item( row - 1, 2 )->data( Qt::EditRole ).toDouble();
double x2 = mTableWidget->item( row , 1 )->data( Qt::EditRole ).toDouble();
double y2 = mTableWidget->item( row , 2 )->data( Qt::EditRole ).toDouble();
double x3 = mTableWidget->item( row + 1, 1 )->data( Qt::EditRole ).toDouble();
double y3 = mTableWidget->item( row + 1, 2 )->data( Qt::EditRole ).toDouble();
QgsPointV2 result;
QgsGeometryUtils::segmentMidPoint( QgsPointV2( x1, y1 ), QgsPointV2( x3, y3 ), result, r, QgsPointV2( x2, y2 ) );
x = result.x();
y = result.y();
}
else
{
x = mTableWidget->item( row, 1 )->data( Qt::EditRole ).toDouble();
y = mTableWidget->item( row, 2 )->data( Qt::EditRole ).toDouble();
}
double z = mTableWidget->item( row, 3 )->data( Qt::EditRole ).toDouble();
double m = mTableWidget->item( row, 4 )->data( Qt::EditRole ).toDouble();
QgsPointV2 p( QgsWKBTypes::PointZM, x, y, z, m );
mLayer->beginEditCommand( QObject::tr( "Moved vertices" ) );
mLayer->moveVertex( p, mSelectedFeature->featureId(), nodeIdx );
mLayer->endEditCommand();
mCanvas->refresh();
}
void QgsNodeEditor::updateTableSelection()
{
mTableWidget->blockSignals( true );
mTableWidget->clearSelection();
const QList<QgsVertexEntry*>& vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0, n = vertexMap.size(); i < n; ++i )
{
if ( vertexMap[i]->isSelected() )
{
mTableWidget->selectRow( i );
}
}
mTableWidget->blockSignals( false );
}
void QgsNodeEditor::updateNodeSelection()
{
disconnect( mSelectedFeature, SIGNAL( selectionChanged() ), this, SLOT( updateTableSelection() ) );
mSelectedFeature->deselectAllVertexes();
foreach ( const QModelIndex& index, mTableWidget->selectionModel()->selectedRows() )
{
int nodeIdx = mTableWidget->item( index.row(), 0 )->data( Qt::DisplayRole ).toInt();
mSelectedFeature->selectVertex( nodeIdx );
}
connect( mSelectedFeature, SIGNAL( selectionChanged() ), this, SLOT( updateTableSelection() ) );
}

View File

@ -0,0 +1,52 @@
/***************************************************************************
qgsnodeeditor.h
---------------
begin : Tue Mar 24 2015
copyright : (C) 2015 Sandro Mani / Sourcepole AG
email : smani@sourcepole.ch
***************************************************************************/
/***************************************************************************
* *
* 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 QGSNODEEDITOR_H
#define QGSNODEEDITOR_H
#include <QDockWidget>
class QgsMapCanvas;
class QgsRubberBand;
class QgsSelectedFeature;
class QgsVectorLayer;
class QTableWidget;
/** A widget to select and edit the vertex coordinates of a geometry numerically*/
class QgsNodeEditor : public QDockWidget
{
Q_OBJECT
public:
QgsNodeEditor( QgsVectorLayer* layer,
QgsSelectedFeature* selectedFeature,
QgsMapCanvas* canvas );
public:
QgsVectorLayer* mLayer;
QgsSelectedFeature* mSelectedFeature;
QgsMapCanvas* mCanvas;
QTableWidget* mTableWidget;
private slots:
void rebuildTable();
void tableValueChanged( int row, int col );
void updateTableSelection();
void updateNodeSelection();
};
#endif // QGSNODEEDITOR_H

View File

@ -16,6 +16,7 @@
#include "nodetool/qgsselectedfeature.h"
#include "nodetool/qgsvertexentry.h"
#include "qgspointv2.h"
#include <qgslogger.h>
#include <qgsvertexmarker.h>
#include <qgsgeometryvalidator.h>
@ -32,7 +33,6 @@ QgsSelectedFeature::QgsSelectedFeature( QgsFeatureId featureId,
: mFeatureId( featureId )
, mGeometry( 0 )
, mChangingGeometry( false )
, mRubberBand( 0 )
, mValidator( 0 )
{
QgsDebugCall;
@ -77,8 +77,10 @@ void QgsSelectedFeature::updateGeometry( QgsGeometry *geom )
if ( !geom )
{
QgsFeature f;
mVlayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureId ) ).nextFeature( f );
mGeometry = new QgsGeometry( *f.constGeometry() );
if ( mVlayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureId ) ).nextFeature( f ) )
{
mGeometry = new QgsGeometry( *f.constGeometry() );
}
}
else
{
@ -86,23 +88,12 @@ void QgsSelectedFeature::updateGeometry( QgsGeometry *geom )
}
}
void QgsSelectedFeature::cleanRubberBandsData()
{
for ( int i = 0; i < mVertexMap.size(); i++ )
{
mVertexMap[i]->setRubberBandValues( false, 0, 0 );
}
}
void QgsSelectedFeature::setSelectedFeature( QgsFeatureId featureId, QgsVectorLayer* vlayer, QgsMapCanvas* canvas )
{
mFeatureId = featureId;
mVlayer = vlayer;
mCanvas = canvas;
delete mRubberBand;
mRubberBand = 0;
delete mGeometry;
mGeometry = 0;
@ -262,18 +253,11 @@ void QgsSelectedFeature::deleteSelectedVertexes()
{
if ( mVertexMap[i]->isSelected() )
{
if ( mVertexMap[i]->equals() != -1 )
{
// to avoid try to delete some vertex twice
mVertexMap[ mVertexMap[i]->equals()]->setSelected( false );
nSelected--;
}
if ( topologicalEditing )
{
// snap from current vertex
currentResultList.clear();
mVlayer->snapWithContext( mVertexMap[i]->point(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex );
mVlayer->snapWithContext( mVertexMap[i]->pointV1(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex );
}
// only last update should trigger the geometry update
@ -345,7 +329,7 @@ void QgsSelectedFeature::moveSelectedVertexes( const QgsVector &v )
{
// snap from current vertex
currentResultList.clear();
mVlayer->snapWithContext( entry->point(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex );
mVlayer->snapWithContext( entry->pointV1(), ZERO_TOLERANCE, currentResultList, QgsSnapper::SnapToVertex );
}
// only last update should trigger the geometry update
@ -353,8 +337,10 @@ void QgsSelectedFeature::moveSelectedVertexes( const QgsVector &v )
if ( --nUpdates == 0 )
endGeometryChange();
QgsPoint p = entry->point() + v;
mVlayer->moveVertex( p.x(), p.y(), mFeatureId, i );
QgsPointV2 p = entry->point();
p.setX( p.x() + v.x() );
p.setY( p.y() + v.y() );
mVlayer->moveVertex( p, mFeatureId, i );
if ( topologicalEditing )
{
@ -364,8 +350,7 @@ void QgsSelectedFeature::moveSelectedVertexes( const QgsVector &v )
{
// move all other
if ( mFeatureId != resultIt.value().snappedAtGeometry )
mVlayer->moveVertex( p.x(), p.y(),
resultIt.value().snappedAtGeometry, resultIt.value().snappedVertexNr );
mVlayer->moveVertex( p, resultIt.value().snappedAtGeometry, resultIt.value().snappedVertexNr );
}
}
}
@ -386,6 +371,8 @@ void QgsSelectedFeature::replaceVertexMap()
// validate the geometry
validateGeometry();
emit vertexMapChanged();
}
void QgsSelectedFeature::deleteVertexMap()
@ -409,100 +396,8 @@ QgsGeometry *QgsSelectedFeature::geometry()
return mGeometry;
}
void QgsSelectedFeature::createVertexMapPolygon()
{
int y = 0;
QgsPolygon polygon = mGeometry->asPolygon();
if ( !polygon.empty() )
{
// polygon
for ( int i2 = 0; i2 < polygon.size(); i2++ )
{
const QgsPolyline& poly = polygon[i2];
for ( int i = 0; i < poly.size(); i++ )
{
mVertexMap.insert( y + i, new QgsVertexEntry( mCanvas, mVlayer, poly[i], tr( "ring %1, vertex %2" ).arg( i2 ).arg( i ) ) );
}
mVertexMap[y + poly.size() - 1 ]->setEqual( y );
mVertexMap[y]->setEqual( y + poly.size() - 1 );
y += poly.size();
}
}
else // multipolygon
{
QgsMultiPolygon multiPolygon = mGeometry->asMultiPolygon();
for ( int i2 = 0; i2 < multiPolygon.size(); i2++ )
{
// iterating through polygons
const QgsPolygon& poly2 = multiPolygon[i2];
for ( int i3 = 0; i3 < poly2.size(); i3++ )
{
// iterating through polygon rings
const QgsPolyline& poly = poly2[i3];
for ( int i = 0; i < poly.size(); i++ )
{
mVertexMap.insert( y + i, new QgsVertexEntry( mCanvas, mVlayer, poly[i], tr( "polygon %1, ring %2, vertex %3" ).arg( i2 ).arg( i3 ).arg( i ) ) );
}
mVertexMap[y + poly.size() - 1]->setEqual( y );
mVertexMap[y]->setEqual( y + poly.size() - 1 );
y += poly.size();
}
}
}
}
void QgsSelectedFeature::createVertexMapLine()
{
Q_ASSERT( mGeometry );
if ( mGeometry->isMultipart() )
{
int y = 0;
QgsMultiPolyline mLine = mGeometry->asMultiPolyline();
for ( int i2 = 0; i2 < mLine.size(); i2++ )
{
// iterating through polylines
QgsPolyline poly = mLine[i2];
for ( int i = 0; i < poly.size(); i++ )
{
mVertexMap.insert( y + i, new QgsVertexEntry( mCanvas, mVlayer, poly[i], tr( "polyline %1, vertex %2" ).arg( i2 ).arg( i ) ) );
}
y += poly.size();
}
}
else
{
QgsPolyline poly = mGeometry->asPolyline();
for ( int i = 0; i < poly.size(); i++ )
{
mVertexMap.insert( i, new QgsVertexEntry( mCanvas, mVlayer, poly[i], tr( "vertex %1" ).arg( i ) ) );
}
}
}
void QgsSelectedFeature::createVertexMapPoint()
{
Q_ASSERT( mGeometry );
if ( mGeometry->isMultipart() )
{
// multipoint
QgsMultiPoint poly = mGeometry->asMultiPoint();
for ( int i = 0; i < poly.size(); i++ )
{
mVertexMap.insert( i, new QgsVertexEntry( mCanvas, mVlayer, poly[i], tr( "point %1" ).arg( i ) ) );
}
}
else
{
// single point
mVertexMap.insert( 1, new QgsVertexEntry( mCanvas, mVlayer, mGeometry->asPoint(), tr( "single point" ) ) );
}
}
void QgsSelectedFeature::createVertexMap()
{
QgsDebugCall;
if ( !mGeometry )
{
@ -510,26 +405,22 @@ void QgsSelectedFeature::createVertexMap()
updateGeometry( 0 );
}
Q_ASSERT( mGeometry );
// createvertexmap for correct geometry type
switch ( mGeometry->type() )
if ( !mGeometry )
{
case QGis::Polygon:
createVertexMapPolygon();
break;
return;
}
case QGis::Line:
createVertexMapLine();
break;
const QgsAbstractGeometryV2* geom = mGeometry->geometry();
if ( !geom )
{
return;
}
case QGis::Point:
createVertexMapPoint();
break;
case QGis::UnknownGeometry:
case QGis::NoGeometry:
break;
QgsVertexId vertexId;
QgsPointV2 pt;
while ( geom->nextVertex( vertexId, pt ) )
{
mVertexMap.append( new QgsVertexEntry( mCanvas, mVlayer, pt, vertexId, tr( "ring %1, vertex %2" ).arg( vertexId.ring ).arg( vertexId.vertex ) ) );
}
}
@ -540,15 +431,9 @@ void QgsSelectedFeature::selectVertex( int vertexNr )
QgsVertexEntry *entry = mVertexMap[vertexNr];
entry->setSelected();
entry->update();
if ( entry->equals() != -1 )
{
// select both vertexes if this is first/last vertex
entry = mVertexMap[ entry->equals()];
entry->setSelected();
entry->update();
}
emit selectionChanged();
emit lastVertexChanged( entry->point() );
}
void QgsSelectedFeature::deselectVertex( int vertexNr )
@ -558,14 +443,22 @@ void QgsSelectedFeature::deselectVertex( int vertexNr )
QgsVertexEntry *entry = mVertexMap[vertexNr];
entry->setSelected( false );
entry->update();
emit selectionChanged();
if ( entry->equals() != -1 )
//todo: take another selected vertex as 'lastVertexChanged'
QList<QgsVertexEntry*>::const_iterator vIt = mVertexMap.constBegin();
for ( ; vIt != mVertexMap.constEnd(); ++vIt )
{
// deselect both vertexes if this is first/last vertex
entry = mVertexMap[ entry->equals()];
entry->setSelected( false );
entry->update();
if (( *vIt )->isSelected() )
{
emit lastVertexChanged(( *vIt )->point() );
return;
}
}
if ( vIt == mVertexMap.constEnd() )
{
emit lastVertexChanged( QgsPointV2() ); //no selection anymore
}
}
@ -574,11 +467,12 @@ void QgsSelectedFeature::deselectAllVertexes()
for ( int i = 0; i < mVertexMap.size(); i++ )
{
mVertexMap[i]->setSelected( false );
mVertexMap[i]->update();
}
emit selectionChanged();
emit lastVertexChanged( QgsPointV2() );
}
void QgsSelectedFeature::invertVertexSelection( int vertexNr, bool invert )
void QgsSelectedFeature::invertVertexSelection( int vertexNr )
{
if ( vertexNr < 0 || vertexNr >= mVertexMap.size() )
return;
@ -588,24 +482,18 @@ void QgsSelectedFeature::invertVertexSelection( int vertexNr, bool invert )
bool selected = !entry->isSelected();
entry->setSelected( selected );
entry->update();
if ( entry->equals() != -1 && invert )
emit selectionChanged();
if ( selected )
{
entry = mVertexMap[ entry->equals()];
entry->setSelected( selected );
entry->update();
emit lastVertexChanged( entry->point() );
}
}
void QgsSelectedFeature::updateVertexMarkersPosition()
{
// function for on-line updating vertex markers without refresh of canvas
for ( int i = 0; i < mVertexMap.size(); i++ )
foreach ( QgsVertexEntry* vertexEntry, mVertexMap )
{
QgsVertexEntry *entry = mVertexMap[i];
entry->setCenter( entry->point() );
entry->update();
vertexEntry->placeMarker();
}
}
@ -623,3 +511,17 @@ QgsVectorLayer* QgsSelectedFeature::vlayer()
{
return mVlayer;
}
bool QgsSelectedFeature::hasSelection() const
{
bool hasSelection = false;
QList<QgsVertexEntry*>::const_iterator vertexIt = mVertexMap.constBegin();
for ( ; vertexIt != mVertexMap.constEnd(); ++vertexIt )
{
if (( *vertexIt )->isSelected() )
{
return true;
}
}
return hasSelection;
}

View File

@ -89,7 +89,7 @@ class QgsSelectedFeature: public QObject
* @param vertexNr number of vertex which is to be inverted
* @param invert flag if vertex selection should be inverted or not
*/
void invertVertexSelection( int vertexNr, bool invert = true );
void invertVertexSelection( int vertexNr );
/**
* Tells if vertex is selected
@ -115,11 +115,6 @@ class QgsSelectedFeature: public QObject
*/
void replaceVertexMap();
/**
* Clears data about vertexes if they are in rubber band for moving etc.
*/
void cleanRubberBandsData();
/**
* Get the layer of the selected feature
* @return used vector layer
@ -134,6 +129,13 @@ class QgsSelectedFeature: public QObject
void beginGeometryChange();
void endGeometryChange();
bool hasSelection() const;
signals:
void selectionChanged();
void lastVertexChanged( const QgsPointV2& pt );
void vertexMapChanged();
public slots:
/*
* geometry validation found a problem
@ -186,21 +188,6 @@ class QgsSelectedFeature: public QObject
*/
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 geometry to actual one loaded from layer
* (or already available geometry)
@ -217,7 +204,6 @@ class QgsSelectedFeature: public QObject
bool mFeatureSelected;
bool mChangingGeometry;
QgsVectorLayer* mVlayer;
QgsRubberBand* mRubberBand;
QList<QgsVertexEntry*> mVertexMap;
QgsMapCanvas* mCanvas;

View File

@ -16,12 +16,10 @@
#include "nodetool/qgsvertexentry.h"
#include "qgsmaprenderer.h"
QgsVertexEntry::QgsVertexEntry( QgsMapCanvas *canvas, QgsMapLayer *layer, QgsPoint p, QString tooltip, QgsVertexMarker::IconType type, int penWidth )
QgsVertexEntry::QgsVertexEntry( QgsMapCanvas *canvas, QgsMapLayer *layer, const QgsPointV2 &p, const QgsVertexId &vertexId, QString tooltip, QgsVertexMarker::IconType type, int penWidth )
: mSelected( false )
, mEquals( -1 )
, mInRubberBand( false )
, mRubberBandNr( 0 )
, mRubberBandIndex( 0 )
, mPoint( p )
, mVertexId( vertexId )
, mPenWidth( penWidth )
, mToolTip( tooltip )
, mType( type )
@ -29,37 +27,39 @@ QgsVertexEntry::QgsVertexEntry( QgsMapCanvas *canvas, QgsMapLayer *layer, QgsPoi
, mCanvas( canvas )
, mLayer( layer )
{
setCenter( p );
placeMarker();
}
QgsVertexEntry::~QgsVertexEntry()
{
if ( mMarker )
{
delete mMarker;
mMarker = 0;
}
delete mMarker;
}
void QgsVertexEntry::setCenter( QgsPoint p )
void QgsVertexEntry::placeMarker()
{
mPoint = p;
p = mCanvas->mapSettings().layerToMapCoordinates( mLayer, p );
QgsPoint pm = mCanvas->mapSettings().layerToMapCoordinates( mLayer, pointV1() );
if ( mCanvas->extent().contains( p ) )
if ( mCanvas->extent().contains( pm ) )
{
if ( !mMarker )
{
mMarker = new QgsVertexMarker( mCanvas );
mMarker->setIconType( mType );
mMarker->setColor( mSelected ? Qt::blue : Qt::red );
QColor c = mSelected ? QColor( Qt::blue ) : QColor( Qt::red );
if ( mVertexId.type == QgsVertexId::CurveVertex )
{
mMarker->setIconType( QgsVertexMarker::ICON_CIRCLE );
}
else
{
mMarker->setIconType( mType );
}
mMarker->setColor( c );
mMarker->setPenWidth( mPenWidth );
if ( !mToolTip.isEmpty() )
mMarker->setToolTip( mToolTip );
mMarker->setToolTip( mToolTip );
}
mMarker->setCenter( p );
mMarker->setCenter( pm );
mMarker->update();
}
else if ( mMarker )
{
@ -73,19 +73,8 @@ void QgsVertexEntry::setSelected( bool selected )
mSelected = selected;
if ( mMarker )
{
mMarker->setColor( mSelected ? Qt::blue : Qt::red );
QColor c = mSelected ? QColor( Qt::blue ) : QColor( Qt::red );
mMarker->setColor( c );
mMarker->update();
}
}
void QgsVertexEntry::setRubberBandValues( bool inRubberBand, int rubberBandNr, int indexInRubberBand )
{
mRubberBandIndex = indexInRubberBand;
mInRubberBand = inRubberBand;
mRubberBandNr = rubberBandNr;
}
void QgsVertexEntry::update()
{
if ( mMarker )
mMarker->update();
}

View File

@ -16,7 +16,7 @@
#ifndef QGSVERTEXENTRY_H
#define QGSVERTEXENTRY_H
#include <qgspoint.h>
#include <qgspointv2.h>
#include <qgsvertexmarker.h>
#include <qgsmapcanvas.h>
#include <qgsmaplayer.h>
@ -24,11 +24,8 @@
class QgsVertexEntry
{
bool mSelected;
QgsPoint mPoint;
int mEquals;
bool mInRubberBand;
int mRubberBandNr;
int mRubberBandIndex;
QgsPointV2 mPoint;
QgsVertexId mVertexId;
int mPenWidth;
QString mToolTip;
QgsVertexMarker::IconType mType;
@ -39,28 +36,21 @@ class QgsVertexEntry
public:
QgsVertexEntry( QgsMapCanvas *canvas,
QgsMapLayer *layer,
QgsPoint p,
const QgsPointV2& p,
const QgsVertexId& vertexId,
QString tooltip = QString::null,
QgsVertexMarker::IconType type = QgsVertexMarker::ICON_BOX,
int penWidth = 2 );
~QgsVertexEntry();
QgsPoint point() const { return mPoint; }
int equals() const { return mEquals; }
const QgsPointV2& point() const { return mPoint; }
QgsPoint pointV1() const { return QgsPoint( mPoint.x(), mPoint.y() ); }
const QgsVertexId& vertexId() const { return mVertexId; }
bool isSelected() const { return mSelected; }
bool isInRubberBand() const { return mInRubberBand; }
void setCenter( QgsPoint p );
void placeMarker();
void setEqual( int index ) { mEquals = index; }
void setSelected( bool selected = true );
void setInRubberBand( bool inRubberBand = true ) { mInRubberBand = inRubberBand; }
int rubberBandNr() const { return mRubberBandNr; }
int rubberBandIndex() { return mRubberBandIndex; }
void setRubberBandValues( bool inRubberBand, int rubberBandNr, int indexInRubberBand );
void update();
};
#endif

View File

@ -853,8 +853,7 @@ bool QgsAdvancedDigitizingDockWidget::alignToSegment( QgsMapMouseEvent* e, CadCo
bool QgsAdvancedDigitizingDockWidget::canvasPressEventFilter( QgsMapMouseEvent* e )
{
Q_UNUSED( e );
applyConstraints( e );
return mCadEnabled && mConstructionMode;
}

View File

@ -990,6 +990,14 @@ bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, i
return utils.moveVertex( x, y, atFeatureId, atVertex );
}
bool QgsVectorLayer::moveVertex( const QgsPointV2& p, QgsFeatureId atFeatureId, int atVertex )
{
if ( !mEditBuffer || !mDataProvider )
return false;
QgsVectorLayerEditUtils utils( this );
return utils.moveVertex( p, atFeatureId, atVertex );
}
bool QgsVectorLayer::deleteVertex( QgsFeatureId atFeatureId, int atVertex )
{
@ -2189,7 +2197,7 @@ bool QgsVectorLayer::deleteAttributes( QList<int> attrs )
qSort( attrs.begin(), attrs.end(), qGreater<int>() );
Q_FOREACH ( int attr, attrs )
Q_FOREACH( int attr, attrs )
{
if ( deleteAttribute( attr ) )
{
@ -2963,7 +2971,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
if ( mEditBuffer )
{
QSet<QString> vals;
Q_FOREACH ( const QVariant& v, uniqueValues )
Q_FOREACH( const QVariant& v, uniqueValues )
{
vals << v.toString();
}
@ -3771,7 +3779,7 @@ void QgsVectorLayer::invalidateSymbolCountedFlag()
void QgsVectorLayer::onRelationsLoaded()
{
Q_FOREACH ( QgsAttributeEditorElement* elem, mAttributeEditorElements )
Q_FOREACH( QgsAttributeEditorElement* elem, mAttributeEditorElements )
{
if ( elem->type() == QgsAttributeEditorElement::AeTypeContainer )
{
@ -3780,7 +3788,7 @@ void QgsVectorLayer::onRelationsLoaded()
continue;
QList<QgsAttributeEditorElement*> relations = cont->findElements( QgsAttributeEditorElement::AeTypeRelation );
Q_FOREACH ( QgsAttributeEditorElement* relElem, relations )
Q_FOREACH( QgsAttributeEditorElement* relElem, relations )
{
QgsAttributeEditorRelation* rel = dynamic_cast< QgsAttributeEditorRelation* >( relElem );
if ( !rel )
@ -3849,7 +3857,7 @@ QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const
QDomElement elem = doc.createElement( "attributeEditorContainer" );
elem.setAttribute( "name", mName );
Q_FOREACH ( QgsAttributeEditorElement* child, mChildren )
Q_FOREACH( QgsAttributeEditorElement* child, mChildren )
{
elem.appendChild( child->toDomElement( doc ) );
}
@ -3870,7 +3878,7 @@ QList<QgsAttributeEditorElement*> QgsAttributeEditorContainer::findElements( Qgs
{
QList<QgsAttributeEditorElement*> results;
Q_FOREACH ( QgsAttributeEditorElement* elem, mChildren )
Q_FOREACH( QgsAttributeEditorElement* elem, mChildren )
{
if ( elem->type() == type )
{

View File

@ -30,6 +30,7 @@
#include "qgsfeatureiterator.h"
#include "qgseditorwidgetconfig.h"
#include "qgsfield.h"
#include "qgspointv2.h"
#include "qgssnapper.h"
#include "qgsrelation.h"
#include "qgsvectorsimplifymethod.h"
@ -966,18 +967,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeometry */
bool hasGeometryType() const;
/**Returns the WKBType or WKBUnknown in case of error*/
/** Returns the WKBType or WKBUnknown in case of error*/
QGis::WkbType wkbType() const;
/** Return the provider type for this layer */
QString providerType() const;
/** reads vector layer specific state from project file Dom node.
/** Reads vector layer specific state from project file Dom node.
* @note Called by QgsMapLayer::readXML().
*/
virtual bool readXml( const QDomNode& layer_node ) override;
/** write vector layer specific state to project file Dom node.
/** Write vector layer specific state to project file Dom node.
* @note Called by QgsMapLayer::writeXML().
*/
virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc ) override;
@ -1036,7 +1037,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
virtual bool applyNamedStyle( QString namedStyle, QString &errorMsg );
/** convert a saved attribute editor element into a AttributeEditor structure as it's used internally.
/** Convert a saved attribute editor element into a AttributeEditor structure as it's used internally.
* @param elem the DOM element
* @param parent the QObject which will own this object
*/
@ -1143,6 +1144,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex );
/** Moves the vertex at the given position number,
* ring and item (first number is index 0), and feature
* to the given coordinates
*/
bool moveVertex( const QgsPointV2& p, QgsFeatureId atFeatureId, int atVertex );
/** Deletes a vertex from a feature
*/
bool deleteVertex( QgsFeatureId atFeatureId, int atVertex );
@ -1152,7 +1159,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool deleteSelectedFeatures( int *deletedCount = 0 );
/**Adds a ring to polygon/multipolygon features
/** Adds a ring to polygon/multipolygon features
@return
0 in case of success,
1 problem with feature type,
@ -1163,7 +1170,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
6 layer not editable */
int addRing( const QList<QgsPoint>& ring );
/**Adds a new part polygon to a multipart feature
/** Adds a new part polygon to a multipart feature
@return
0 in case of success,
1 if selected feature is not multipart,
@ -1175,14 +1182,14 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
7 layer not editable */
int addPart( const QList<QgsPoint>& ring );
/**Translates feature by dx, dy
/** Translates feature by dx, dy
@param featureId id of the feature to translate
@param dx translation of x-coordinate
@param dy translation of y-coordinate
@return 0 in case of success*/
int translateFeature( QgsFeatureId featureId, double dx, double dy );
/**Splits parts cut by the given line
/** Splits parts cut by the given line
* @param splitLine line that splits the layer features
* @param topologicalEditing true if topological editing is enabled
* @return
@ -1191,7 +1198,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
int splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );
/**Splits features cut by the given line
/** Splits features cut by the given line
* @param splitLine line that splits the layer features
* @param topologicalEditing true if topological editing is enabled
* @return
@ -1200,7 +1207,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
int splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );
/**Changes the specified geometry such that it has no intersections with other
/** Changes the specified geometry such that it has no intersections with other
* polygon (or multipolygon) geometries in this vector layer
* @param geom geometry to modify
* @param ignoreFeatures list of feature ids where intersections should be ignored
@ -1226,7 +1233,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
int addTopologicalPoints( const QgsPoint& p );
/**Inserts vertices to the snapped segments.
/** Inserts vertices to the snapped segments.
* This is useful for topological editing if snap to segment is enabled.
* @param snapResults results collected from the snapping operation
* @return 0 in case of success
@ -1252,7 +1259,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Returns true if the provider has been modified since the last commit */
virtual bool isModified() const;
/**Snaps a point to the closest vertex if there is one within the snapping tolerance
/** Snaps a point to the closest vertex if there is one within the snapping tolerance
* @param point The point which is set to the position of a vertex if there is one within the snapping tolerance.
* If there is no point within this tolerance, point is left unchanged.
* @param tolerance The snapping tolerance
@ -1260,7 +1267,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool snapPoint( QgsPoint& point, double tolerance );
/**Snaps to segment or vertex within given tolerance
/** Snaps to segment or vertex within given tolerance
* @param startPoint point to snap (in layer coordinates)
* @param snappingTolerance distance tolerance for snapping
* @param snappingResults snapping results. Key is the distance between startPoint and snapping target
@ -1272,7 +1279,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
QMultiMap < double, QgsSnappingResult > &snappingResults,
QgsSnapper::SnappingType snap_to );
/**Synchronises with changes in the datasource */
/** Synchronises with changes in the datasource */
virtual void reload() override;
/** Return new instance of QgsMapLayerRenderer that will be used for rendering of given context
@ -1293,16 +1300,16 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Return the extent of the layer as a QRect */
QgsRectangle extent() override;
/** returns field list in the to-be-committed state */
/** Returns field list in the to-be-committed state */
const QgsFields &pendingFields() const;
/** returns list of attributes */
/** Returns list of attributes */
QgsAttributeList pendingAllAttributesList();
/** returns list of attribute making up the primary key */
/** Returns list of attribute making up the primary key */
QgsAttributeList pendingPkAttributesList();
/** returns feature count after commit */
/** Returns feature count after commit */
int pendingFeatureCount();
/** Make layer read-only (editing disabled) or not
@ -1313,7 +1320,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Make layer editable */
bool startEditing();
/** change feature's geometry */
/** Change feature's geometry */
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom );
/**
@ -1336,7 +1343,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
/** add an attribute field (but does not commit it)
/** Add an attribute field (but does not commit it)
returns true if the field was added */
bool addAttribute( const QgsField &field );
@ -1414,7 +1421,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
const QSet<QString>& excludeAttributesWFS() const { return mExcludeAttributesWFS; }
void setExcludeAttributesWFS( const QSet<QString>& att ) { mExcludeAttributesWFS = att; }
/** delete an attribute field (but does not commit it) */
/** Delete an attribute field (but does not commit it) */
bool deleteAttribute( int attr );
/**
@ -1429,7 +1436,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Insert a copy of the given features into the layer (but does not commit it) */
bool addFeatures( QgsFeatureList features, bool makeSelected = true );
/** delete a feature from the layer (but does not commit it) */
/** Delete a feature from the layer (but does not commit it) */
bool deleteFeature( QgsFeatureId fid );
/**
@ -1469,10 +1476,10 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
Q_DECL_DEPRECATED void setEditType( int idx, EditType edit );
/** get the active layout for the attribute editor for this layer */
/** Get the active layout for the attribute editor for this layer */
EditorLayout editorLayout();
/** set the active layout for the attribute editor for this layer */
/** Set the active layout for the attribute editor for this layer */
void setEditorLayout( EditorLayout editorLayout );
/**
@ -1529,10 +1536,10 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
Q_DECL_DEPRECATED void setCheckedState( int idx, QString checked, QString notChecked );
/** get edit form */
/** Get edit form */
QString editForm();
/** set edit form */
/** Set edit form */
void setEditForm( QString ui );
/** Type of feature form pop-up suppression after feature creation (overrides app setting)
@ -1543,16 +1550,16 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
* @note added in 2.1 */
void setFeatureFormSuppress( QgsVectorLayer::FeatureFormSuppress s ) { mFeatureFormSuppress = s; }
/** get annotation form */
/** Get annotation form */
QString annotationForm() const { return mAnnotationForm; }
/** set annotation form for layer */
/** Set annotation form for layer */
void setAnnotationForm( const QString& ui );
/** get python function for edit form initialization */
/** Get python function for edit form initialization */
QString editFormInit();
/** set python function for edit form initialization */
/** Set python function for edit form initialization */
void setEditFormInit( QString function );
/**
@ -1593,16 +1600,16 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
Q_DECL_DEPRECATED QSize widgetSize( int idx );
/**is edit widget editable **/
/** Is edit widget editable **/
bool fieldEditable( int idx );
/**label widget on top **/
/** Label widget on top **/
bool labelOnTop( int idx );
/**set edit widget editable **/
/** Set edit widget editable **/
void setFieldEditable( int idx, bool editable );
/**label widget on top **/
/** Label widget on top **/
void setLabelOnTop( int idx, bool onTop );
//! Buffer with uncommitted editing operations. Only valid after editing has been turned on.
@ -1640,16 +1647,16 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Caches joined attributes if required (and not already done) */
void createJoinCaches();
/**Returns unique values for column
/** Returns unique values for column
@param index column index for attribute
@param uniqueValues out: result list
@param limit maximum number of values to return (-1 if unlimited) */
void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 );
/**Returns minimum value for an attribute column or invalid variant in case of error */
/** Returns minimum value for an attribute column or invalid variant in case of error */
QVariant minimumValue( int index );
/**Returns maximum value for an attribute column or invalid variant in case of error */
/** Returns maximum value for an attribute column or invalid variant in case of error */
QVariant maximumValue( int index );
/** Fetches all values from a specified field name or expression.
@ -1917,14 +1924,14 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
private: // Private methods
/** vector layers are not copyable */
/** Vector layers are not copyable */
QgsVectorLayer( const QgsVectorLayer & rhs );
/** vector layers are not copyable */
/** Vector layers are not copyable */
QgsVectorLayer & operator=( QgsVectorLayer const & rhs );
/** bind layer to a specific data provider
/** Bind layer to a specific data provider
@param provider should be "postgres", "ogr", or ??
@todo XXX should this return bool? Throw exceptions?
*/
@ -1933,7 +1940,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Goes through all features and finds a free id (e.g. to give it temporarily to a not-commited feature) */
QgsFeatureId findFreeId();
/**Snaps to a geometry and adds the result to the multimap if it is within the snapping result
/** Snaps to a geometry and adds the result to the multimap if it is within the snapping result
@param startPoint start point of the snap
@param featureId id of feature
@param geom geometry to snap
@ -1959,10 +1966,10 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Pointer to data provider derived from the abastract base class QgsDataProvider */
QgsVectorDataProvider *mDataProvider;
/** index of the primary label field */
/** Index of the primary label field */
QString mDisplayField;
/** the preview expression used to generate a human readable preview string for features */
/** The preview expression used to generate a human readable preview string for features */
QString mDisplayExpression;
/** Data provider key */
@ -1980,21 +1987,21 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
QgsFeatureIds mSelectedFeatureIds;
/** field map to commit */
/** Field map to commit */
QgsFields mUpdatedFields;
/**Map that stores the aliases for attributes. Key is the attribute name and value the alias for that attribute*/
/** Map that stores the aliases for attributes. Key is the attribute name and value the alias for that attribute*/
QMap< QString, QString > mAttributeAliasMap;
/**Stores a list of attribute editor elements (Each holding a tree structure for a tab in the attribute editor)*/
/** Stores a list of attribute editor elements (Each holding a tree structure for a tab in the attribute editor)*/
QList< QgsAttributeEditorElement* > mAttributeEditorElements;
/**Attributes which are not published in WMS*/
/** Attributes which are not published in WMS*/
QSet<QString> mExcludeAttributesWMS;
/**Attributes which are not published in WFS*/
/** Attributes which are not published in WFS*/
QSet<QString> mExcludeAttributesWFS;
/**Map that stores the tab for attributes in the edit form. Key is the tab order and value the tab name*/
/** Map that stores the tab for attributes in the edit form. Key is the tab order and value the tab name*/
QList< TabData > mTabs;
/** Geometry type as defined in enum WkbType (qgis.h) */

View File

@ -51,6 +51,12 @@ bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atF
bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
{
QgsPointV2 p( x, y );
return moveVertex( p, atFeatureId, atVertex );
}
bool QgsVectorLayerEditUtils::moveVertex( const QgsPointV2& p, QgsFeatureId atFeatureId, int atVertex )
{
if ( !L->hasGeometryType() )
return false;
@ -66,7 +72,7 @@ bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFea
geometry = *f.constGeometry();
}
geometry.moveVertex( x, y, atVertex );
geometry.moveVertex( p, atVertex );
L->editBuffer()->changeGeometry( atFeatureId, &geometry );
return true;

View File

@ -42,6 +42,12 @@ class CORE_EXPORT QgsVectorLayerEditUtils
*/
bool moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex );
/** Moves the vertex at the given position number,
* ring and item (first number is index 0), and feature
* to the given coordinates
*/
bool moveVertex( const QgsPointV2& p, QgsFeatureId atFeatureId, int atVertex );
/** Deletes a vertex from a feature
*/
bool deleteVertex( QgsFeatureId atFeatureId, int atVertex );

View File

@ -276,15 +276,15 @@ void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
bool sel = mContext.showSelection() && mSelectedFeatureIds.contains( fet.id() );
bool drawMarker = ( mDrawVertexMarkers && mContext.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || sel ) );
// render feature
bool rendered = mRendererV2->renderFeature( fet, mContext, -1, sel, drawMarker );
if ( mCache )
{
// Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
mCache->cacheGeometry( fet.id(), *fet.constGeometry() );
}
// render feature
bool rendered = mRendererV2->renderFeature( fet, mContext, -1, sel, drawMarker );
// labeling - register feature
Q_UNUSED( rendered );
if ( rendered && mContext.labelingEngine() )

View File

@ -175,6 +175,7 @@ SET(QGIS_GUI_SRCS
qgsfilterlineedit.cpp
qgsformannotationitem.cpp
qgsgenericprojectionselector.cpp
qgsgeometryrubberband.cpp
qgshighlight.cpp
qgshistogramwidget.cpp
qgsidentifymenu.cpp

View File

@ -0,0 +1,161 @@
/***************************************************************************
qgsgeometryrubberband.cpp
-------------------------
begin : December 2014
copyright : (C) 2014 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/
/***************************************************************************
* *
* 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 "qgsgeometryrubberband.h"
#include "qgsabstractgeometryv2.h"
#include "qgsmapcanvas.h"
#include "qgspointv2.h"
#include <QPainter>
QgsGeometryRubberBand::QgsGeometryRubberBand( QgsMapCanvas* mapCanvas, QGis::GeometryType geomType ): QgsMapCanvasItem( mapCanvas ),
mGeometry( 0 ), mIconSize( 5 ), mIconType( ICON_CIRCLE ), mGeometryType( geomType )
{
mPen = QPen( QColor( 255, 0, 0 ) );
mBrush = QBrush( QColor( 255, 0, 0 ) );
}
QgsGeometryRubberBand::~QgsGeometryRubberBand()
{
delete mGeometry;
}
void QgsGeometryRubberBand::paint( QPainter* painter )
{
if ( !mGeometry || !painter )
{
return;
}
painter->save();
painter->translate( -pos() );
if ( mGeometryType == QGis::Polygon )
{
painter->setBrush( mBrush );
}
else
{
painter->setBrush( Qt::NoBrush );
}
painter->setPen( mPen );
QgsAbstractGeometryV2* paintGeom = mGeometry->clone();
paintGeom->transform( mMapCanvas->getCoordinateTransform()->transform() );
paintGeom->draw( *painter );
//draw vertices
QgsVertexId vertexId;
QgsPointV2 vertex;
while ( paintGeom->nextVertex( vertexId, vertex ) )
{
drawVertex( painter, vertex.x(), vertex.y() );
}
delete paintGeom;
painter->restore();
}
void QgsGeometryRubberBand::drawVertex( QPainter* p, double x, double y )
{
qreal s = ( mIconSize - 1 ) / 2;
switch ( mIconType )
{
case ICON_NONE:
break;
case ICON_CROSS:
p->drawLine( QLineF( x - s, y, x + s, y ) );
p->drawLine( QLineF( x, y - s, x, y + s ) );
break;
case ICON_X:
p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
break;
case ICON_BOX:
p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
break;
case ICON_FULL_BOX:
p->drawRect( x - s, y - s, mIconSize, mIconSize );
break;
case ICON_CIRCLE:
p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
break;
}
}
void QgsGeometryRubberBand::setGeometry( QgsAbstractGeometryV2* geom )
{
delete mGeometry;
mGeometry = geom;
if ( mGeometry )
{
setRect( rubberBandRectangle() );
}
}
void QgsGeometryRubberBand::moveVertex( const QgsVertexId& id, const QgsPointV2& newPos )
{
if ( mGeometry )
{
mGeometry->moveVertex( id, newPos );
setRect( rubberBandRectangle() );
}
}
void QgsGeometryRubberBand::setFillColor( const QColor& c )
{
mBrush.setColor( c );
}
void QgsGeometryRubberBand::setOutlineColor( const QColor& c )
{
mPen.setColor( c );
}
void QgsGeometryRubberBand::setOutlineWidth( int width )
{
mPen.setWidth( width );
}
void QgsGeometryRubberBand::setLineStyle( Qt::PenStyle penStyle )
{
mPen.setStyle( penStyle );
}
void QgsGeometryRubberBand::setBrushStyle( Qt::BrushStyle brushStyle )
{
mBrush.setStyle( brushStyle );
}
QgsRectangle QgsGeometryRubberBand::rubberBandRectangle() const
{
qreal scale = mMapCanvas->mapUnitsPerPixel();
qreal s = ( mIconSize - 1 ) / 2.0 * scale;
qreal p = mPen.width() * scale;
return mGeometry->boundingBox().buffer( s + p );
}

View File

@ -0,0 +1,99 @@
/***************************************************************************
qgsgeometryrubberband.h
-----------------------
begin : December 2014
copyright : (C) 2014 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/
/***************************************************************************
* *
* 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 QGSGEOMETRYRUBBERBAND_H
#define QGSGEOMETRYRUBBERBAND_H
#include "qgsmapcanvasitem.h"
#include <QBrush>
#include <QPen>
class QgsAbstractGeometryV2;
class QgsPointV2;
struct QgsVertexId;
/** A rubberband class for QgsAbstractGeometryV2 (considering curved geometries)*/
class GUI_EXPORT QgsGeometryRubberBand: public QgsMapCanvasItem
{
public:
enum IconType
{
/**
* No icon is used
*/
ICON_NONE,
/**
* A cross is used to highlight points (+)
*/
ICON_CROSS,
/**
* A cross is used to highlight points (x)
*/
ICON_X,
/**
* A box is used to highlight points ()
*/
ICON_BOX,
/**
* A circle is used to highlight points ()
*/
ICON_CIRCLE,
/**
* A full box is used to highlight points ()
*/
ICON_FULL_BOX
};
QgsGeometryRubberBand( QgsMapCanvas* mapCanvas, QGis::GeometryType geomType = QGis::Line );
~QgsGeometryRubberBand();
/** Sets geometry (takes ownership). Geometry is expected to be in map coordinates */
void setGeometry( QgsAbstractGeometryV2* geom );
/** Returns a pointer to the geometry*/
const QgsAbstractGeometryV2* geometry() { return mGeometry; }
/** Moves vertex to new position (in map coordinates)*/
void moveVertex( const QgsVertexId& id, const QgsPointV2& newPos );
/** Sets fill color for vertex markers*/
void setFillColor( const QColor& c );
/** Sets outline color for vertex markes*/
void setOutlineColor( const QColor& c );
/** Sets outline width*/
void setOutlineWidth( int width );
/** Sets pen style*/
void setLineStyle( Qt::PenStyle penStyle );
/** Sets brush style*/
void setBrushStyle( Qt::BrushStyle brushStyle );
/** Sets vertex marker icon type*/
void setIconType( IconType iconType ) { mIconType = iconType; }
protected:
virtual void paint( QPainter* painter );
private:
QgsAbstractGeometryV2* mGeometry;
QBrush mBrush;
QPen mPen;
int mIconSize;
IconType mIconType;
QGis::GeometryType mGeometryType;
void drawVertex( QPainter* p, double x, double y );
QgsRectangle rubberBandRectangle() const;
};
#endif // QGSGEOMETRYRUBBERBAND_H

View File

@ -44,6 +44,12 @@ QgsPoint QgsMapTool::toMapCoordinates( const QPoint& point )
return mCanvas->getCoordinateTransform()->toMapCoordinates( point );
}
QgsPointV2 QgsMapTool::toMapCoordinates( QgsMapLayer* layer, const QgsPointV2& point )
{
QgsPoint result = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( point.x(), point.y() ) );
return QgsPointV2( result.x(), result.y() );
}
QgsPoint QgsMapTool::toLayerCoordinates( QgsMapLayer* layer, const QPoint& point )
{

View File

@ -18,6 +18,7 @@
#include "qgsconfig.h"
#include "qgsmessagebar.h"
#include "qgspointv2.h"
#include <QCursor>
#include <QString>
@ -178,6 +179,9 @@ class GUI_EXPORT QgsMapTool : public QObject
//!transformation from layer's coordinates to map coordinates (which is different in case reprojection is used)
QgsPoint toMapCoordinates( QgsMapLayer* layer, const QgsPoint& point );
//!transformation from layer's coordinates to map coordinates (which is different in case reprojection is used)
QgsPointV2 toMapCoordinates( QgsMapLayer* layer, const QgsPointV2 &point );
//! trnasformation of the rect from map coordinates to layer's coordinates
QgsRectangle toLayerCoordinates( QgsMapLayer* layer, const QgsRectangle& rect );

View File

@ -83,6 +83,10 @@ void QgsVertexMarker::paint( QPainter* p )
p->drawLine( QLineF( s, s, -s, s ) );
p->drawLine( QLineF( -s, s, -s, -s ) );
break;
case ICON_CIRCLE:
p->drawEllipse( QPointF( 0, 0 ), s, s );
break;
}
}

View File

@ -34,7 +34,8 @@ class GUI_EXPORT QgsVertexMarker : public QgsMapCanvasItem
ICON_NONE,
ICON_CROSS,
ICON_X,
ICON_BOX
ICON_BOX,
ICON_CIRCLE
};
QgsVertexMarker( QgsMapCanvas* mapCanvas );

View File

@ -33,6 +33,7 @@ ADD_LIBRARY (dxf2shpconverterplugin MODULE ${dxf2shpconverter_SRCS} ${dxf2shpcon
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
../../core
../../core/geometry
../../core/raster
../../gui
..