Quantum GIS API Documentation  1.7.4
src/core/qgssnapper.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               qgssnapper.cpp
00003                               --------------
00004   begin                : June 7, 2007
00005   copyright            : (C) 2007 by Marco Hugentobler
00006   email                : marco dot hugentobler at karto dot baug dot ethz dot ch
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgssnapper.h"
00019 #include "qgsmaprenderer.h"
00020 #include "qgsmaptopixel.h"
00021 #include "qgsvectorlayer.h"
00022 #include <QMultiMap>
00023 #include <QPoint>
00024 #include <cmath>
00025 
00026 
00027 QgsSnapper::QgsSnapper( QgsMapRenderer* mapRenderer ): mMapRenderer( mapRenderer )
00028 {
00029 
00030 }
00031 
00032 QgsSnapper::QgsSnapper()
00033 {
00034 
00035 }
00036 
00037 QgsSnapper::~QgsSnapper()
00038 {
00039 
00040 }
00041 
00042 int QgsSnapper::snapPoint( const QPoint& startPoint, QList<QgsSnappingResult>& snappingResult, const QList<QgsPoint>& excludePoints )
00043 {
00044   snappingResult.clear();
00045 
00046   QMultiMap<double, QgsSnappingResult> snappingResultList;//all snapping results
00047   QMultiMap<double, QgsSnappingResult> currentResultList; //snapping results of examined layer
00048 
00049   //start point in (output) map coordinates
00050   QgsPoint mapCoordPoint = mMapRenderer->coordinateTransform()->toMapCoordinates( startPoint.x(), startPoint.y() );
00051   QgsPoint layerCoordPoint; //start point in layer coordinates
00052   QgsSnappingResult newResult;
00053 
00054   QList<QgsSnapper::SnapLayer>::iterator snapLayerIt;
00055   for ( snapLayerIt = mSnapLayers.begin(); snapLayerIt != mSnapLayers.end(); ++snapLayerIt )
00056   {
00057     //transform point from map coordinates to layer coordinates
00058     layerCoordPoint = mMapRenderer->mapToLayerCoordinates( snapLayerIt->mLayer, mapCoordPoint );
00059 
00060     double tolerance = QgsTolerance::toleranceInMapUnits( snapLayerIt->mTolerance, snapLayerIt->mLayer, mMapRenderer, snapLayerIt->mUnitType );
00061     if ( snapLayerIt->mLayer->snapWithContext( layerCoordPoint, tolerance,
00062          currentResultList, snapLayerIt->mSnapTo ) != 0 )
00063     {
00064       //error
00065     }
00066 
00067     //transform each result from layer crs to map crs (including distance)
00068     QMultiMap<double, QgsSnappingResult>::iterator currentResultIt;
00069     for ( currentResultIt = currentResultList.begin(); currentResultIt != currentResultList.end(); ++currentResultIt )
00070     {
00071       //for each snapping result: transform start point, snap point and other points into map coordinates to find out distance
00072       //store results in snapping result list
00073       newResult = currentResultIt.value();
00074       newResult.snappedVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().snappedVertex );
00075       newResult.beforeVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().beforeVertex );
00076       newResult.afterVertex = mMapRenderer->layerToMapCoordinates( snapLayerIt->mLayer, currentResultIt.value().afterVertex );
00077       snappingResultList.insert( sqrt( newResult.snappedVertex.sqrDist( mapCoordPoint ) ), newResult );
00078     }
00079   }
00080 
00081   //excluded specific points from result
00082   cleanResultList( snappingResultList, excludePoints );
00083 
00084   //evaluate results according to snap mode
00085   QMultiMap<double, QgsSnappingResult>::iterator evalIt =  snappingResultList.begin();
00086   if ( evalIt == snappingResultList.end() )
00087   {
00088     return 0;
00089   }
00090 
00091   if ( mSnapMode == QgsSnapper::SnapWithOneResult )
00092   {
00093     //return only closest result
00094     snappingResult.push_back( evalIt.value() );
00095   }
00096   else if ( mSnapMode == QgsSnapper::SnapWithResultsForSamePosition )
00097   {
00098     //take all snapping Results within a certain tolerance because rounding differences may occur
00099     double tolerance = 0.000001;
00100     double minDistance = evalIt.key();
00101 
00102     for ( evalIt = snappingResultList.begin(); evalIt != snappingResultList.end(); ++evalIt )
00103     {
00104       if ( evalIt.key() > ( minDistance + tolerance ) )
00105       {
00106         break;
00107       }
00108       snappingResult.push_back( evalIt.value() );
00109     }
00110 
00111   }
00112 
00113   else //take all results
00114   {
00115     for ( ; evalIt != snappingResultList.end(); ++evalIt )
00116     {
00117       snappingResult.push_back( evalIt.value() );
00118     }
00119   }
00120 
00121   return 0;
00122 }
00123 
00124 void QgsSnapper::setSnapLayers( const QList<QgsSnapper::SnapLayer>& snapLayers )
00125 {
00126   mSnapLayers = snapLayers;
00127 }
00128 
00129 
00130 void QgsSnapper::setSnapMode( QgsSnapper::SnappingMode snapMode )
00131 {
00132   mSnapMode = snapMode;
00133 }
00134 
00135 void QgsSnapper::cleanResultList( QMultiMap<double, QgsSnappingResult>& list, const QList<QgsPoint>& excludeList ) const
00136 {
00137   QgsPoint currentResultPoint;
00138   QgsSnappingResult currentSnappingResult;
00139   QList<double> keysToRemove;
00140 
00141   QMultiMap<double, QgsSnappingResult>::iterator result_it = list.begin();
00142   for ( ; result_it != list.end(); ++result_it )
00143   {
00144     currentSnappingResult = result_it.value();
00145     if ( currentSnappingResult.snappedVertexNr != -1 )
00146     {
00147       currentResultPoint = currentSnappingResult.snappedVertex;
00148       if ( excludeList.contains( currentResultPoint ) )
00149       {
00150         keysToRemove.push_back( result_it.key() );
00151       }
00152     }
00153   }
00154 
00155   QList<double>::const_iterator remove_it = keysToRemove.constBegin();
00156   for ( ; remove_it != keysToRemove.constEnd(); ++remove_it )
00157   {
00158     list.remove( *remove_it );
00159   }
00160 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines