QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgssnapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssnapper.cpp
3  --------------
4  begin : June 7, 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 "qgssnapper.h"
19 #include "qgsmapsettings.h"
20 #include "qgsmaprenderer.h"
21 #include "qgsmaptopixel.h"
22 #include "qgsvectorlayer.h"
23 #include <QMultiMap>
24 #include <QPoint>
25 #include <cmath>
26 
27 
29  : mMapSettings( mapRenderer->mapSettings() )
30 {
31 
32 }
33 
35  : mMapSettings( mapSettings )
36 {
37 }
38 
40 {
41 
42 }
43 
44 int QgsSnapper::snapPoint( const QPoint& startPoint, QList<QgsSnappingResult>& snappingResult, const QList<QgsPoint>& excludePoints )
45 {
46  snappingResult.clear();
47 
48  QMultiMap<double, QgsSnappingResult> snappingResultList;//all snapping results
49  QMultiMap<double, QgsSnappingResult> currentResultList; //snapping results of examined layer
50 
51  //start point in (output) map coordinates
52  QgsPoint mapCoordPoint = mMapSettings.mapToPixel().toMapCoordinates( startPoint.x(), startPoint.y() );
53  QgsPoint layerCoordPoint; //start point in layer coordinates
54  QgsSnappingResult newResult;
55 
56  QList<QgsSnapper::SnapLayer>::iterator snapLayerIt;
57  for ( snapLayerIt = mSnapLayers.begin(); snapLayerIt != mSnapLayers.end(); ++snapLayerIt )
58  {
59  if ( !snapLayerIt->mLayer->hasGeometryType() )
60  continue;
61 
62  currentResultList.clear();
63  //transform point from map coordinates to layer coordinates
64  layerCoordPoint = mMapSettings.mapToLayerCoordinates( snapLayerIt->mLayer, mapCoordPoint );
65 
66  double tolerance = QgsTolerance::toleranceInMapUnits( snapLayerIt->mTolerance, snapLayerIt->mLayer, mMapSettings, snapLayerIt->mUnitType );
67  if ( snapLayerIt->mLayer->snapWithContext( layerCoordPoint, tolerance,
68  currentResultList, snapLayerIt->mSnapTo ) != 0 )
69  {
70  //error
71  }
72 
73  //transform each result from layer crs to map crs (including distance)
74  QMultiMap<double, QgsSnappingResult>::iterator currentResultIt;
75  for ( currentResultIt = currentResultList.begin(); currentResultIt != currentResultList.end(); ++currentResultIt )
76  {
77  //for each snapping result: transform start point, snap point and other points into map coordinates to find out distance
78  //store results in snapping result list
79  newResult = currentResultIt.value();
80  newResult.snappedVertex = mMapSettings.layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().snappedVertex );
81  newResult.beforeVertex = mMapSettings.layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().beforeVertex );
82  newResult.afterVertex = mMapSettings.layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().afterVertex );
83  snappingResultList.insert( sqrt( newResult.snappedVertex.sqrDist( mapCoordPoint ) ), newResult );
84  }
85  }
86 
87  //excluded specific points from result
88  cleanResultList( snappingResultList, excludePoints );
89 
90  //evaluate results according to snap mode
91  QMultiMap<double, QgsSnappingResult>::iterator evalIt = snappingResultList.begin();
92  if ( evalIt == snappingResultList.end() )
93  {
94  return 0;
95  }
96 
97 
98  //Gives a priority to vertex snapping over segment snapping
99  QgsSnappingResult returnResult = evalIt.value();
100  for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
101  {
102  if ( evalIt.value().snappedVertexNr != -1 )
103  {
104  returnResult = evalIt.value();
105  snappingResultList.erase( evalIt );
106  break;
107  }
108  }
109 
110  //We return the preferred result
111  snappingResult.push_back( returnResult );
112 
113  if ( mSnapMode == QgsSnapper::SnapWithOneResult )
114  {
115  //return only a single result, nothing more to do
116  }
117  else if ( mSnapMode == QgsSnapper::SnapWithResultsForSamePosition )
118  {
119  //take all snapping results within a certain tolerance because rounding differences may occur
120  double tolerance = 0.000001;
121 
122  for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
123  {
124  if ( returnResult.snappedVertex.sqrDist( evalIt.value().snappedVertex ) < tolerance*tolerance )
125  {
126  snappingResult.push_back( evalIt.value() );
127  }
128  }
129 
130  }
131 
132  else //take all results
133  {
134  for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
135  {
136  snappingResult.push_back( evalIt.value() );
137  }
138  }
139 
140  return 0;
141 }
142 
143 void QgsSnapper::setSnapLayers( const QList<QgsSnapper::SnapLayer>& snapLayers )
144 {
145  mSnapLayers = snapLayers;
146 }
147 
148 
150 {
151  mSnapMode = snapMode;
152 }
153 
154 void QgsSnapper::cleanResultList( QMultiMap<double, QgsSnappingResult>& list, const QList<QgsPoint>& excludeList ) const
155 {
156  QgsPoint currentResultPoint;
157  QgsSnappingResult currentSnappingResult;
158  QList<double> keysToRemove;
159 
160  QMultiMap<double, QgsSnappingResult>::iterator result_it = list.begin();
161  for ( ; result_it != list.end(); ++result_it )
162  {
163  currentSnappingResult = result_it.value();
164  if ( currentSnappingResult.snappedVertexNr != -1 )
165  {
166  currentResultPoint = currentSnappingResult.snappedVertex;
167  if ( excludeList.contains( currentResultPoint ) )
168  {
169  keysToRemove.push_back( result_it.key() );
170  }
171  }
172  }
173 
174  QList<double>::const_iterator remove_it = keysToRemove.constBegin();
175  for ( ; remove_it != keysToRemove.constEnd(); ++remove_it )
176  {
177  list.remove( *remove_it );
178  }
179 }
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer's CRS to output CRS
static double toleranceInMapUnits(double tolerance, QgsMapLayer *layer, const QgsMapSettings &mapSettings, UnitType units=MapUnits)
Static function to translate tolerance value into current map unit value.
int snapPoint(const QPoint &startPoint, QList< QgsSnappingResult > &snappingResult, const QList< QgsPoint > &excludePoints=QList< QgsPoint >())
Does the snapping operation.
Definition: qgssnapper.cpp:44
const QgsMapToPixel & mapToPixel() const
A non GUI class for rendering a map layer set onto a QPainter.
QgsPoint mapToLayerCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from output CRS to layer's CRS
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
Definition: qgspoint.cpp:333
The QgsMapSettings class contains configuration for rendering of the map.
Represents the result of a snapping operation.
Definition: qgssnapper.h:36
Several snapping results which have the same position are returned.
Definition: qgssnapper.h:80
A class to represent a point.
Definition: qgspoint.h:63
QgsPoint beforeVertex
The layer coordinates of the vertex before snappedVertex.
Definition: qgssnapper.h:44
QgsPoint afterVertex
The layer coordinates of the vertex after snappedVertex.
Definition: qgssnapper.h:49
QgsPoint toMapCoordinates(int x, int y) const
int snappedVertexNr
The vertex index of snappedVertex or -1 if no such vertex number (e.g.
Definition: qgssnapper.h:42
Only one snapping result is returned.
Definition: qgssnapper.h:77
QgsPoint snappedVertex
The coordinates of the snapping result.
Definition: qgssnapper.h:39
Q_DECL_DEPRECATED QgsSnapper(QgsMapRenderer *mapRender)
@ deprecated since 2.4 - use constructor with QgsMapSettings
Definition: qgssnapper.cpp:28
void setSnapLayers(const QList< QgsSnapper::SnapLayer > &snapLayers)
Definition: qgssnapper.cpp:143
void setSnapMode(QgsSnapper::SnappingMode snapMode)
Definition: qgssnapper.cpp:149