QGIS API Documentation  2.2.0-Valmiera
 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  QgsMapRenderer *canvasRender = canvas->mapRenderer();
37  if ( !canvasRender )
38  return;
39 
40  mSnapper = new QgsSnapper( canvasRender );
41 }
42 
43 QgsMapCanvasSnapper::QgsMapCanvasSnapper(): mMapCanvas( 0 ), mSnapper( 0 )
44 {
45 }
46 
48 {
49  delete mSnapper;
50 }
51 
53 {
54  mMapCanvas = canvas;
55  delete mSnapper;
56  if ( mMapCanvas )
57  {
58  mSnapper = new QgsSnapper( canvas->mapRenderer() );
59  }
60  else
61  {
62  mSnapper = 0;
63  }
64 }
65 
66 int QgsMapCanvasSnapper::snapToCurrentLayer( const QPoint& p, QList<QgsSnappingResult>& results,
68  double snappingTol,
69  const QList<QgsPoint>& excludePoints )
70 {
71  results.clear();
72 
73  if ( !mSnapper || !mMapCanvas )
74  return 1;
75 
76  //topological editing on?
77  int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
78  if ( topologicalEditing == 0 )
79  {
81  }
82  else
83  {
85  }
86 
87  //current vector layer
88  QgsMapLayer* currentLayer = mMapCanvas->currentLayer();
89  if ( !currentLayer )
90  return 2;
91 
92  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
93  if ( !vlayer )
94  return 3;
95 
96  QgsSnapper::SnapLayer snapLayer;
97  snapLayer.mLayer = vlayer;
98  snapLayer.mSnapTo = snap_to;
100 
101  if ( snappingTol < 0 )
102  {
103  //use search tolerance for vertex editing
105  }
106  else
107  {
108  snapLayer.mTolerance = snappingTol;
109  }
110 
111  QList<QgsSnapper::SnapLayer> snapLayers;
112  snapLayers.append( snapLayer );
113  mSnapper->setSnapLayers( snapLayers );
114 
115  if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 )
116  return 4;
117 
118  return 0;
119 }
120 
121 int QgsMapCanvasSnapper::snapToBackgroundLayers( const QPoint& p, QList<QgsSnappingResult>& results, const QList<QgsPoint>& excludePoints )
122 {
123  results.clear();
124 
125  if ( !mSnapper )
126  return 5;
127 
128  //topological editing on?
129  int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
130 
131  //snapping on intersection on?
132  int intersectionSnapping = QgsProject::instance()->readNumEntry( "Digitizing", "/IntersectionSnapping", 0 );
133 
134  if ( topologicalEditing == 0 )
135  {
136  if ( intersectionSnapping == 0 )
138  else
140  }
141  else if ( intersectionSnapping == 0 )
142  {
144  }
145  else
146  {
148  }
149 
150  //read snapping settings from project
151  bool snappingDefinedInProject, ok;
152  QStringList layerIdList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingList", QStringList(), &snappingDefinedInProject );
153  QStringList enabledList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingEnabledList", QStringList(), &ok );
154  QStringList toleranceList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceList", QStringList(), &ok );
155  QStringList toleranceUnitList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceUnitList", QStringList(), &ok );
156  QStringList snapToList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnapToList", QStringList(), &ok );
157 
158  if ( !( layerIdList.size() == enabledList.size() &&
159  layerIdList.size() == toleranceList.size() &&
160  layerIdList.size() == toleranceUnitList.size() &&
161  layerIdList.size() == snapToList.size() ) )
162  {
163  // lists must have the same size, otherwise something is wrong
164  return 1;
165  }
166 
167  QList<QgsSnapper::SnapLayer> snapLayers;
168  QgsSnapper::SnapLayer snapLayer;
169 
170  // Use snapping information from the project
171  if ( snappingDefinedInProject )
172  {
173  // set layers, tolerances, snap to segment/vertex to QgsSnapper
174  QStringList::const_iterator layerIt( layerIdList.constBegin() );
175  QStringList::const_iterator tolIt( toleranceList.constBegin() );
176  QStringList::const_iterator tolUnitIt( toleranceUnitList.constBegin() );
177  QStringList::const_iterator snapIt( snapToList.constBegin() );
178  QStringList::const_iterator enabledIt( enabledList.constBegin() );
179  for ( ; layerIt != layerIdList.constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
180  {
181  if ( *enabledIt != "enabled" )
182  {
183  // skip layer if snapping is not enabled
184  continue;
185  }
186 
187  //layer
188  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( *layerIt ) );
189  if ( !vlayer || !vlayer->hasGeometryType() )
190  continue;
191 
192  snapLayer.mLayer = vlayer;
193 
194  //tolerance
195  snapLayer.mTolerance = tolIt->toDouble();
196  snapLayer.mUnitType = ( QgsTolerance::UnitType ) tolUnitIt->toInt();
197 
198  // segment or vertex
199  if ( *snapIt == "to_vertex" )
200  {
201  snapLayer.mSnapTo = QgsSnapper::SnapToVertex;
202  }
203  else if ( *snapIt == "to_segment" )
204  {
206  }
207  else
208  {
209  // to vertex and segment
211  }
212 
213  snapLayers.append( snapLayer );
214  }
215  }
216  else
217  {
218  // nothing in project. Use default snapping tolerance to vertex of current layer
219  QgsMapLayer* currentLayer = mMapCanvas->currentLayer();
220  if ( !currentLayer )
221  return 2;
222 
223  QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
224  if ( !currentVectorLayer )
225  return 3;
226 
227  snapLayer.mLayer = currentVectorLayer;
228 
229  //default snap mode
230  QSettings settings;
231  QString defaultSnapString = settings.value( "/qgis/digitizing/default_snap_mode", "off" ).toString();
232  if ( defaultSnapString == "to segment" )
233  {
235  }
236  else if ( defaultSnapString == "to vertex and segment" )
237  {
239  }
240  else if ( defaultSnapString == "to vertex" )
241  {
242  snapLayer.mSnapTo = QgsSnapper::SnapToVertex;
243  }
244  else
245  {
246  return 0;
247  }
248 
249  //default snapping tolerance (returned in map units)
250  snapLayer.mTolerance = QgsTolerance::defaultTolerance( currentVectorLayer, mMapCanvas->mapRenderer() );
251  snapLayer.mUnitType = QgsTolerance::MapUnits;
252 
253  snapLayers.append( snapLayer );
254  }
255 
256  mSnapper->setSnapLayers( snapLayers );
257 
258  if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 )
259  return 4;
260 
261  if ( intersectionSnapping != 1 )
262  return 0;
263 
264  QList<QgsSnappingResult> segments;
265  QList<QgsSnappingResult> points;
266  for ( QList<QgsSnappingResult>::const_iterator it = results.constBegin();
267  it != results.constEnd();
268  ++it )
269  {
270  if ( it->snappedVertexNr == -1 )
271  {
272  QgsDebugMsg( "segment" );
273  segments.push_back( *it );
274  }
275  else
276  {
277  QgsDebugMsg( "no segment" );
278  points.push_back( *it );
279  }
280  }
281 
282  if ( segments.length() < 2 )
283  return 0;
284 
285  QList<QgsSnappingResult> myResults;
286 
287  for ( QList<QgsSnappingResult>::const_iterator oSegIt = segments.constBegin();
288  oSegIt != segments.constEnd();
289  ++oSegIt )
290  {
291  QgsDebugMsg( QString::number( oSegIt->beforeVertexNr ) );
292 
293  QVector<QgsPoint> vertexPoints;
294  vertexPoints.append( oSegIt->beforeVertex );
295  vertexPoints.append( oSegIt->afterVertex );
296 
297  QgsGeometry* lineA = QgsGeometry::fromPolyline( vertexPoints );
298 
299  for ( QList<QgsSnappingResult>::iterator iSegIt = segments.begin();
300  iSegIt != segments.end();
301  ++iSegIt )
302  {
303  QVector<QgsPoint> vertexPoints;
304  vertexPoints.append( iSegIt->beforeVertex );
305  vertexPoints.append( iSegIt->afterVertex );
306  QgsGeometry* lineB = QgsGeometry::fromPolyline( vertexPoints );
307 
308  QgsGeometry* intersectionPoint = lineA->intersection( lineB );
309  if ( intersectionPoint->type() == QGis::Point )
310  {
311  iSegIt->snappedVertex = intersectionPoint->asPoint();
312  myResults.append( *iSegIt );
313  }
314  }
315  }
316 
317  if ( myResults.length() > 0 )
318  {
319  results.clear();
320  results = myResults;
321  }
322 
323  return 0;
324 }