QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsmapcanvassnapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmapcanvassnapper.cpp
3  -----------------------
4  begin : June 21, 2007
5  copyright : (C) 2007 by Marco Hugentobler
6  email : marco dot hugentobler at karto dot baug dot ethz dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsmapcanvassnapper.h"
19 #include "qgsmapcanvas.h"
20 #include "qgsmaplayerregistry.h"
21 #include "qgsmaptopixel.h"
22 #include "qgsproject.h"
23 #include "qgsvectorlayer.h"
24 #include "qgstolerance.h"
25 #include <QSettings>
26 #include "qgslogger.h"
27 #include "qgsgeometry.h"
28 
30  : mMapCanvas( canvas )
31  , mSnapper( 0 )
32 {
33  if ( !canvas )
34  return;
35 
36  mSnapper = new QgsSnapper( canvas->mapSettings() );
37 }
38 
39 QgsMapCanvasSnapper::QgsMapCanvasSnapper(): mMapCanvas( 0 ), mSnapper( 0 )
40 {
41 }
42 
44 {
45  delete mSnapper;
46 }
47 
49 {
50  mMapCanvas = canvas;
51  delete mSnapper;
52  if ( mMapCanvas )
53  {
54  mSnapper = new QgsSnapper( canvas->mapSettings() );
55  }
56  else
57  {
58  mSnapper = 0;
59  }
60 }
61 
62 int QgsMapCanvasSnapper::snapToCurrentLayer( const QPoint& p, QList<QgsSnappingResult>& results,
64  double snappingTol,
65  const QList<QgsPoint>& excludePoints )
66 {
67  results.clear();
68 
69  if ( !mSnapper || !mMapCanvas )
70  return 1;
71 
72  //topological editing on?
73  int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
74  if ( topologicalEditing == 0 )
75  {
77  }
78  else
79  {
81  }
82 
83  //current vector layer
84  QgsMapLayer* currentLayer = mMapCanvas->currentLayer();
85  if ( !currentLayer )
86  return 2;
87 
88  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
89  if ( !vlayer )
90  return 3;
91 
92  QgsSnapper::SnapLayer snapLayer;
93  snapLayer.mLayer = vlayer;
94  snapLayer.mSnapTo = snap_to;
96 
97  if ( snappingTol < 0 )
98  {
99  //use search tolerance for vertex editing
101  }
102  else
103  {
104  snapLayer.mTolerance = snappingTol;
105  }
106 
107  QList<QgsSnapper::SnapLayer> snapLayers;
108  snapLayers.append( snapLayer );
109  mSnapper->setSnapLayers( snapLayers );
110 
111  if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 )
112  return 4;
113 
114  return 0;
115 }
116 
117 int QgsMapCanvasSnapper::snapToBackgroundLayers( const QPoint& p, QList<QgsSnappingResult>& results, const QList<QgsPoint>& excludePoints )
118 {
119  results.clear();
120 
121  if ( !mSnapper )
122  return 5;
123 
124  //topological editing on?
125  int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
126 
127  //snapping on intersection on?
128  int intersectionSnapping = QgsProject::instance()->readNumEntry( "Digitizing", "/IntersectionSnapping", 0 );
129 
130  if ( topologicalEditing == 0 )
131  {
132  if ( intersectionSnapping == 0 )
134  else
136  }
137  else if ( intersectionSnapping == 0 )
138  {
140  }
141  else
142  {
144  }
145 
146  //read snapping settings from project
147  bool snappingDefinedInProject, ok;
148  QStringList layerIdList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingList", QStringList(), &snappingDefinedInProject );
149  QStringList enabledList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingEnabledList", QStringList(), &ok );
150  QStringList toleranceList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceList", QStringList(), &ok );
151  QStringList toleranceUnitList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceUnitList", QStringList(), &ok );
152  QStringList snapToList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnapToList", QStringList(), &ok );
153 
154  if ( !( layerIdList.size() == enabledList.size() &&
155  layerIdList.size() == toleranceList.size() &&
156  layerIdList.size() == toleranceUnitList.size() &&
157  layerIdList.size() == snapToList.size() ) )
158  {
159  // lists must have the same size, otherwise something is wrong
160  return 1;
161  }
162 
163  QList<QgsSnapper::SnapLayer> snapLayers;
164  QgsSnapper::SnapLayer snapLayer;
165 
166  // Use snapping information from the project
167  if ( snappingDefinedInProject )
168  {
169  // set layers, tolerances, snap to segment/vertex to QgsSnapper
170  QStringList::const_iterator layerIt( layerIdList.constBegin() );
171  QStringList::const_iterator tolIt( toleranceList.constBegin() );
172  QStringList::const_iterator tolUnitIt( toleranceUnitList.constBegin() );
173  QStringList::const_iterator snapIt( snapToList.constBegin() );
174  QStringList::const_iterator enabledIt( enabledList.constBegin() );
175  for ( ; layerIt != layerIdList.constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
176  {
177  if ( *enabledIt != "enabled" )
178  {
179  // skip layer if snapping is not enabled
180  continue;
181  }
182 
183  //layer
184  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( *layerIt ) );
185  if ( !vlayer || !vlayer->hasGeometryType() )
186  continue;
187 
188  snapLayer.mLayer = vlayer;
189 
190  //tolerance
191  snapLayer.mTolerance = tolIt->toDouble();
192  snapLayer.mUnitType = ( QgsTolerance::UnitType ) tolUnitIt->toInt();
193 
194  // segment or vertex
195  if ( *snapIt == "to_vertex" )
196  {
197  snapLayer.mSnapTo = QgsSnapper::SnapToVertex;
198  }
199  else if ( *snapIt == "to_segment" )
200  {
202  }
203  else
204  {
205  // to vertex and segment
207  }
208 
209  snapLayers.append( snapLayer );
210  }
211  }
212  else
213  {
214  // nothing in project. Use default snapping tolerance to vertex of current layer
215  QgsMapLayer* currentLayer = mMapCanvas->currentLayer();
216  if ( !currentLayer )
217  return 2;
218 
219  QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
220  if ( !currentVectorLayer )
221  return 3;
222 
223  snapLayer.mLayer = currentVectorLayer;
224 
225  //default snap mode
226  QSettings settings;
227  QString defaultSnapString = settings.value( "/qgis/digitizing/default_snap_mode", "off" ).toString();
228  if ( defaultSnapString == "to segment" )
229  {
231  }
232  else if ( defaultSnapString == "to vertex and segment" )
233  {
235  }
236  else if ( defaultSnapString == "to vertex" )
237  {
238  snapLayer.mSnapTo = QgsSnapper::SnapToVertex;
239  }
240  else
241  {
242  return 0;
243  }
244 
245  //default snapping tolerance (returned in map units)
246  snapLayer.mTolerance = QgsTolerance::defaultTolerance( currentVectorLayer, mMapCanvas->mapSettings() );
247  snapLayer.mUnitType = QgsTolerance::MapUnits;
248 
249  snapLayers.append( snapLayer );
250  }
251 
252  mSnapper->setSnapLayers( snapLayers );
253 
254  if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 )
255  return 4;
256 
257  if ( intersectionSnapping != 1 )
258  return 0;
259 
260  QList<QgsSnappingResult> segments;
261  QList<QgsSnappingResult> points;
262  for ( QList<QgsSnappingResult>::const_iterator it = results.constBegin();
263  it != results.constEnd();
264  ++it )
265  {
266  if ( it->snappedVertexNr == -1 )
267  {
268  QgsDebugMsg( "segment" );
269  segments.push_back( *it );
270  }
271  else
272  {
273  QgsDebugMsg( "no segment" );
274  points.push_back( *it );
275  }
276  }
277 
278  if ( segments.length() < 2 )
279  return 0;
280 
281  QList<QgsSnappingResult> myResults;
282 
283  for ( QList<QgsSnappingResult>::const_iterator oSegIt = segments.constBegin();
284  oSegIt != segments.constEnd();
285  ++oSegIt )
286  {
287  QgsDebugMsg( QString::number( oSegIt->beforeVertexNr ) );
288 
289  QVector<QgsPoint> vertexPoints;
290  vertexPoints.append( oSegIt->beforeVertex );
291  vertexPoints.append( oSegIt->afterVertex );
292 
293  QgsGeometry* lineA = QgsGeometry::fromPolyline( vertexPoints );
294 
295  for ( QList<QgsSnappingResult>::iterator iSegIt = segments.begin();
296  iSegIt != segments.end();
297  ++iSegIt )
298  {
299  QVector<QgsPoint> vertexPoints;
300  vertexPoints.append( iSegIt->beforeVertex );
301  vertexPoints.append( iSegIt->afterVertex );
302  QgsGeometry* lineB = QgsGeometry::fromPolyline( vertexPoints );
303 
304  QgsGeometry* intersectionPoint = lineA->intersection( lineB );
305  if ( intersectionPoint->type() == QGis::Point )
306  {
307  //We have to check the intersection point is inside the tolerance distance for both layers
308  double toleranceA, toleranceB;
309  for ( int i = 0 ;i < snapLayers.size();++i )
310  {
311  if ( snapLayers[i].mLayer == oSegIt->layer )
312  {
313  toleranceA = QgsTolerance::toleranceInMapUnits( snapLayers[i].mTolerance, snapLayers[i].mLayer, mMapCanvas->mapSettings(), snapLayers[i].mUnitType );
314  }
315  if ( snapLayers[i].mLayer == iSegIt->layer )
316  {
317  toleranceB = QgsTolerance::toleranceInMapUnits( snapLayers[i].mTolerance, snapLayers[i].mLayer, mMapCanvas->mapSettings(), snapLayers[i].mUnitType );
318  }
319  }
321  QgsGeometry* cursorPoint = QgsGeometry::fromPoint( point );
322  double distance = intersectionPoint->distance( *cursorPoint );
323  if ( distance < toleranceA && distance < toleranceB )
324  {
325  iSegIt->snappedVertex = intersectionPoint->asPoint();
326  myResults.append( *iSegIt );
327  }
328  }
329  }
330  }
331 
332  if ( myResults.length() > 0 )
333  {
334  results.clear();
335  results = myResults;
336  }
337 
338  return 0;
339 }
int snapToCurrentLayer(const QPoint &p, QList< QgsSnappingResult > &results, QgsSnapper::SnappingType snap_to, double snappingTol=-1, const QList< QgsPoint > &excludePoints=QList< QgsPoint >())
Does a snap to the current layer.
Base class for all map layer types.
Definition: qgsmaplayer.h:47
static double toleranceInMapUnits(double tolerance, QgsMapLayer *layer, const QgsMapSettings &mapSettings, UnitType units=MapUnits)
Static function to translate tolerance value into current map unit value.
QgsSnapper * mSnapper
The object which does the snapping operations.
int snapPoint(const QPoint &startPoint, QList< QgsSnappingResult > &snappingResult, const QList< QgsPoint > &excludePoints=QList< QgsPoint >())
Does the snapping operation.
Definition: qgssnapper.cpp:44
double mTolerance
The snapping tolerances for the layers, always in source coordinate systems of the layer...
Definition: qgssnapper.h:90
All results within the given layer tolerances are returned.
Definition: qgssnapper.h:82
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
UnitType
Type of unit of tolerance value from settings.
Definition: qgstolerance.h:33
QGis::GeometryType type()
Returns type of the vector.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
QgsTolerance::UnitType mUnitType
What unit is used for tolerance.
Definition: qgssnapper.h:94
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=0) const
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:104
QgsSnapper::SnappingType mSnapTo
What snapping type to use (snap to segment or to vertex)
Definition: qgssnapper.h:92
SnappingType
Snap to vertex, to segment or both.
Definition: qgssnapper.h:66
QStringList readListEntry(const QString &scope, const QString &key, QStringList def=QStringList(), bool *ok=0) const
key value accessors
int snapToBackgroundLayers(const QPoint &p, QList< QgsSnappingResult > &results, const QList< QgsPoint > &excludePoints=QList< QgsPoint >())
Snaps to the background layers.
Map unit value.
Definition: qgstolerance.h:36
A class that allows advanced snapping operations on a set of vector layers.
Definition: qgssnapper.h:62
static double defaultTolerance(QgsMapLayer *layer, const QgsMapSettings &mapSettings)
Static function to get default tolerance value for a layer.
Several snapping results which have the same position are returned.
Definition: qgssnapper.h:80
QgsGeometry * intersection(QgsGeometry *geometry)
Returns a geometry representing the points shared by this geometry and other.
A class to represent a point geometry.
Definition: qgspoint.h:63
static QgsGeometry * fromPoint(const QgsPoint &point)
construct geometry from a point
QgsMapCanvas * mMapCanvas
Pointer to the map canvas.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QgsPoint toMapCoordinates(int x, int y) const
Only one snapping result is returned.
Definition: qgssnapper.h:77
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
QgsVectorLayer * mLayer
The layer to which snapping is applied.
Definition: qgssnapper.h:88
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
void setSnapLayers(const QList< QgsSnapper::SnapLayer > &snapLayers)
Definition: qgssnapper.cpp:143
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
Represents a vector layer which manages a vector based data sets.
static double vertexSearchRadius(QgsMapLayer *layer, const QgsMapSettings &mapSettings)
Static function to get vertex tolerance value for a layer.
void setMapCanvas(QgsMapCanvas *canvas)
void setSnapMode(QgsSnapper::SnappingMode snapMode)
Definition: qgssnapper.cpp:149
double distance(QgsGeometry &geom)