QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 "qgsmaprenderer.h"
20 #include "qgsmaptopixel.h"
21 #include "qgsvectorlayer.h"
22 #include <QMultiMap>
23 #include <QPoint>
24 #include <cmath>
25 
26 
27 QgsSnapper::QgsSnapper( QgsMapRenderer* mapRenderer ): mMapRenderer( mapRenderer )
28 {
29 
30 }
31 
33 {
34 
35 }
36 
38 {
39 
40 }
41 
42 int QgsSnapper::snapPoint( const QPoint& startPoint, QList<QgsSnappingResult>& snappingResult, const QList<QgsPoint>& excludePoints )
43 {
44  snappingResult.clear();
45 
46  QMultiMap<double, QgsSnappingResult> snappingResultList;//all snapping results
47  QMultiMap<double, QgsSnappingResult> currentResultList; //snapping results of examined layer
48 
49  //start point in (output) map coordinates
50  QgsPoint mapCoordPoint = mMapRenderer->coordinateTransform()->toMapCoordinates( startPoint.x(), startPoint.y() );
51  QgsPoint layerCoordPoint; //start point in layer coordinates
52  QgsSnappingResult newResult;
53 
54  QList<QgsSnapper::SnapLayer>::iterator snapLayerIt;
55  for ( snapLayerIt = mSnapLayers.begin(); snapLayerIt != mSnapLayers.end(); ++snapLayerIt )
56  {
57  if ( !snapLayerIt->mLayer->hasGeometryType() )
58  continue;
59 
60  //transform point from map coordinates to layer coordinates
61  layerCoordPoint = mMapRenderer->mapToLayerCoordinates( snapLayerIt->mLayer, mapCoordPoint );
62 
63  double tolerance = QgsTolerance::toleranceInMapUnits( snapLayerIt->mTolerance, snapLayerIt->mLayer, mMapRenderer, snapLayerIt->mUnitType );
64  if ( snapLayerIt->mLayer->snapWithContext( layerCoordPoint, tolerance,
65  currentResultList, snapLayerIt->mSnapTo ) != 0 )
66  {
67  //error
68  }
69 
70  //transform each result from layer crs to map crs (including distance)
71  QMultiMap<double, QgsSnappingResult>::iterator currentResultIt;
72  for ( currentResultIt = currentResultList.begin(); currentResultIt != currentResultList.end(); ++currentResultIt )
73  {
74  //for each snapping result: transform start point, snap point and other points into map coordinates to find out distance
75  //store results in snapping result list
76  newResult = currentResultIt.value();
77  newResult.snappedVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().snappedVertex );
78  newResult.beforeVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().beforeVertex );
79  newResult.afterVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().afterVertex );
80  snappingResultList.insert( sqrt( newResult.snappedVertex.sqrDist( mapCoordPoint ) ), newResult );
81  }
82  }
83 
84  //excluded specific points from result
85  cleanResultList( snappingResultList, excludePoints );
86 
87  //evaluate results according to snap mode
88  QMultiMap<double, QgsSnappingResult>::iterator evalIt = snappingResultList.begin();
89  if ( evalIt == snappingResultList.end() )
90  {
91  return 0;
92  }
93 
95  {
96  //return only closest result
97  snappingResult.push_back( evalIt.value() );
98  }
100  {
101  //take all snapping Results within a certain tolerance because rounding differences may occur
102  double tolerance = 0.000001;
103  double minDistance = evalIt.key();
104 
105  for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
106  {
107  if ( evalIt.key() > ( minDistance + tolerance ) )
108  {
109  break;
110  }
111  snappingResult.push_back( evalIt.value() );
112  }
113 
114  }
115 
116  else //take all results
117  {
118  for ( ; evalIt != snappingResultList.end(); ++evalIt )
119  {
120  snappingResult.push_back( evalIt.value() );
121  }
122  }
123 
124  return 0;
125 }
126 
127 void QgsSnapper::setSnapLayers( const QList<QgsSnapper::SnapLayer>& snapLayers )
128 {
129  mSnapLayers = snapLayers;
130 }
131 
132 
134 {
135  mSnapMode = snapMode;
136 }
137 
138 void QgsSnapper::cleanResultList( QMultiMap<double, QgsSnappingResult>& list, const QList<QgsPoint>& excludeList ) const
139 {
140  QgsPoint currentResultPoint;
141  QgsSnappingResult currentSnappingResult;
142  QList<double> keysToRemove;
143 
144  QMultiMap<double, QgsSnappingResult>::iterator result_it = list.begin();
145  for ( ; result_it != list.end(); ++result_it )
146  {
147  currentSnappingResult = result_it.value();
148  if ( currentSnappingResult.snappedVertexNr != -1 )
149  {
150  currentResultPoint = currentSnappingResult.snappedVertex;
151  if ( excludeList.contains( currentResultPoint ) )
152  {
153  keysToRemove.push_back( result_it.key() );
154  }
155  }
156  }
157 
158  QList<double>::const_iterator remove_it = keysToRemove.constBegin();
159  for ( ; remove_it != keysToRemove.constEnd(); ++remove_it )
160  {
161  list.remove( *remove_it );
162  }
163 }