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