~ubuntu-branches/ubuntu/wily/qgis/wily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/***************************************************************************
                              qgssnapper.cpp
                              --------------
  begin                : June 7, 2007
  copyright            : (C) 2007 by Marco Hugentobler
  email                : marco dot hugentobler at karto dot baug dot ethz dot ch
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "qgssnapper.h"
#include "qgsmaprenderer.h"
#include "qgsmaptopixel.h"
#include "qgsvectorlayer.h"
#include <QMultiMap>
#include <QPoint>
#include <cmath>


QgsSnapper::QgsSnapper( QgsMapRenderer* mapRenderer ): mMapRenderer( mapRenderer )
{

}

QgsSnapper::QgsSnapper()
{

}

QgsSnapper::~QgsSnapper()
{

}

int QgsSnapper::snapPoint( const QPoint& startPoint, QList<QgsSnappingResult>& snappingResult, const QList<QgsPoint>& excludePoints )
{
  snappingResult.clear();

  QMultiMap<double, QgsSnappingResult> snappingResultList;//all snapping results
  QMultiMap<double, QgsSnappingResult> currentResultList; //snapping results of examined layer

  //start point in (output) map coordinates
  QgsPoint mapCoordPoint = mMapRenderer->coordinateTransform()->toMapCoordinates( startPoint.x(), startPoint.y() );
  QgsPoint layerCoordPoint; //start point in layer coordinates
  QgsSnappingResult newResult;

  QList<QgsSnapper::SnapLayer>::iterator snapLayerIt;
  for ( snapLayerIt = mSnapLayers.begin(); snapLayerIt != mSnapLayers.end(); ++snapLayerIt )
  {
    //transform point from map coordinates to layer coordinates
    layerCoordPoint = mMapRenderer->mapToLayerCoordinates( snapLayerIt->mLayer, mapCoordPoint );

    double tolerance = QgsTolerance::toleranceInMapUnits( snapLayerIt->mTolerance, snapLayerIt->mLayer, mMapRenderer, snapLayerIt->mUnitType );
    if ( snapLayerIt->mLayer->snapWithContext( layerCoordPoint, tolerance,
         currentResultList, snapLayerIt->mSnapTo ) != 0 )
    {
      //error
    }

    //transform each result from layer crs to map crs (including distance)
    QMultiMap<double, QgsSnappingResult>::iterator currentResultIt;
    for ( currentResultIt = currentResultList.begin(); currentResultIt != currentResultList.end(); ++currentResultIt )
    {
      //for each snapping result: transform start point, snap point and other points into map coordinates to find out distance
      //store results in snapping result list
      newResult = currentResultIt.value();
      newResult.snappedVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().snappedVertex );
      newResult.beforeVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().beforeVertex );
      newResult.afterVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().afterVertex );
      snappingResultList.insert( sqrt( newResult.snappedVertex.sqrDist( mapCoordPoint ) ), newResult );
    }
  }

  //excluded specific points from result
  cleanResultList( snappingResultList, excludePoints );

  //evaluate results according to snap mode
  QMultiMap<double, QgsSnappingResult>::iterator evalIt =  snappingResultList.begin();
  if ( evalIt == snappingResultList.end() )
  {
    return 0;
  }

  if ( mSnapMode == QgsSnapper::SnapWithOneResult )
  {
    //return only closest result
    snappingResult.push_back( evalIt.value() );
  }
  else if ( mSnapMode == QgsSnapper::SnapWithResultsForSamePosition )
  {
    //take all snapping Results within a certain tolerance because rounding differences may occur
    double tolerance = 0.000001;
    double minDistance = evalIt.key();

    for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
    {
      if ( evalIt.key() > ( minDistance + tolerance ) )
      {
        break;
      }
      snappingResult.push_back( evalIt.value() );
    }

  }

  else //take all results
  {
    for ( ; evalIt != snappingResultList.end(); ++evalIt )
    {
      snappingResult.push_back( evalIt.value() );
    }
  }

  return 0;
}

void QgsSnapper::setSnapLayers( const QList<QgsSnapper::SnapLayer>& snapLayers )
{
  mSnapLayers = snapLayers;
}


void QgsSnapper::setSnapMode( QgsSnapper::SnappingMode snapMode )
{
  mSnapMode = snapMode;
}

void QgsSnapper::cleanResultList( QMultiMap<double, QgsSnappingResult>& list, const QList<QgsPoint>& excludeList ) const
{
  QgsPoint currentResultPoint;
  QgsSnappingResult currentSnappingResult;
  QList<double> keysToRemove;

  QMultiMap<double, QgsSnappingResult>::iterator result_it = list.begin();
  for ( ; result_it != list.end(); ++result_it )
  {
    currentSnappingResult = result_it.value();
    if ( currentSnappingResult.snappedVertexNr != -1 )
    {
      currentResultPoint = currentSnappingResult.snappedVertex;
      if ( excludeList.contains( currentResultPoint ) )
      {
        keysToRemove.push_back( result_it.key() );
      }
    }
  }

  QList<double>::const_iterator remove_it = keysToRemove.constBegin();
  for ( ; remove_it != keysToRemove.constEnd(); ++remove_it )
  {
    list.remove( *remove_it );
  }
}