mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
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:
commit
740e3abcb9
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
238
src/app/nodetool/qgsnodeeditor.cpp
Normal file
238
src/app/nodetool/qgsnodeeditor.cpp
Normal 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() ) );
|
||||
}
|
52
src/app/nodetool/qgsnodeeditor.h
Normal file
52
src/app/nodetool/qgsnodeeditor.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -853,8 +853,7 @@ bool QgsAdvancedDigitizingDockWidget::alignToSegment( QgsMapMouseEvent* e, CadCo
|
||||
|
||||
bool QgsAdvancedDigitizingDockWidget::canvasPressEventFilter( QgsMapMouseEvent* e )
|
||||
{
|
||||
Q_UNUSED( e );
|
||||
|
||||
applyConstraints( e );
|
||||
return mCadEnabled && mConstructionMode;
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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) */
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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() )
|
||||
|
@ -175,6 +175,7 @@ SET(QGIS_GUI_SRCS
|
||||
qgsfilterlineedit.cpp
|
||||
qgsformannotationitem.cpp
|
||||
qgsgenericprojectionselector.cpp
|
||||
qgsgeometryrubberband.cpp
|
||||
qgshighlight.cpp
|
||||
qgshistogramwidget.cpp
|
||||
qgsidentifymenu.cpp
|
||||
|
161
src/gui/qgsgeometryrubberband.cpp
Normal file
161
src/gui/qgsgeometryrubberband.cpp
Normal 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 );
|
||||
}
|
99
src/gui/qgsgeometryrubberband.h
Normal file
99
src/gui/qgsgeometryrubberband.h
Normal 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
|
@ -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 )
|
||||
{
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -33,6 +33,7 @@ ADD_LIBRARY (dxf2shpconverterplugin MODULE ${dxf2shpconverter_SRCS} ${dxf2shpcon
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
../../core
|
||||
../../core/geometry
|
||||
../../core/raster
|
||||
../../gui
|
||||
..
|
||||
|
Loading…
x
Reference in New Issue
Block a user