Quantum GIS API Documentation
1.7.4
|
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 }