|
QGIS API Documentation
master-28efcda
|
00001 /*************************************************************************** 00002 qgsmapcanvassnapper.cpp 00003 ----------------------- 00004 begin : June 21, 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 "qgsmapcanvassnapper.h" 00019 #include "qgsmapcanvas.h" 00020 #include "qgsmaplayerregistry.h" 00021 #include "qgsmaptopixel.h" 00022 #include "qgsproject.h" 00023 #include "qgsvectorlayer.h" 00024 #include "qgstolerance.h" 00025 #include <QSettings> 00026 #include "qgslogger.h" 00027 #include "qgsgeometry.h" 00028 00029 QgsMapCanvasSnapper::QgsMapCanvasSnapper( QgsMapCanvas* canvas ) 00030 : mMapCanvas( canvas ) 00031 , mSnapper( 0 ) 00032 { 00033 if ( !canvas ) 00034 return; 00035 00036 QgsMapRenderer *canvasRender = canvas->mapRenderer(); 00037 if ( !canvasRender ) 00038 return; 00039 00040 mSnapper = new QgsSnapper( canvasRender ); 00041 } 00042 00043 QgsMapCanvasSnapper::QgsMapCanvasSnapper(): mMapCanvas( 0 ), mSnapper( 0 ) 00044 { 00045 } 00046 00047 QgsMapCanvasSnapper::~QgsMapCanvasSnapper() 00048 { 00049 delete mSnapper; 00050 } 00051 00052 void QgsMapCanvasSnapper::setMapCanvas( QgsMapCanvas* canvas ) 00053 { 00054 mMapCanvas = canvas; 00055 delete mSnapper; 00056 if ( mMapCanvas ) 00057 { 00058 mSnapper = new QgsSnapper( canvas->mapRenderer() ); 00059 } 00060 else 00061 { 00062 mSnapper = 0; 00063 } 00064 } 00065 00066 int QgsMapCanvasSnapper::snapToCurrentLayer( const QPoint& p, QList<QgsSnappingResult>& results, 00067 QgsSnapper::SnappingType snap_to, 00068 double snappingTol, 00069 const QList<QgsPoint>& excludePoints ) 00070 { 00071 results.clear(); 00072 00073 if ( !mSnapper || !mMapCanvas ) 00074 return 1; 00075 00076 //topological editing on? 00077 int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); 00078 if ( topologicalEditing == 0 ) 00079 { 00080 mSnapper->setSnapMode( QgsSnapper::SnapWithOneResult ); 00081 } 00082 else 00083 { 00084 mSnapper->setSnapMode( QgsSnapper::SnapWithResultsForSamePosition ); 00085 } 00086 00087 //current vector layer 00088 QgsMapLayer* currentLayer = mMapCanvas->currentLayer(); 00089 if ( !currentLayer ) 00090 return 2; 00091 00092 QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer ); 00093 if ( !vlayer ) 00094 return 3; 00095 00096 QgsSnapper::SnapLayer snapLayer; 00097 snapLayer.mLayer = vlayer; 00098 snapLayer.mSnapTo = snap_to; 00099 snapLayer.mUnitType = QgsTolerance::MapUnits; 00100 00101 if ( snappingTol < 0 ) 00102 { 00103 //use search tolerance for vertex editing 00104 snapLayer.mTolerance = QgsTolerance::vertexSearchRadius( vlayer, mMapCanvas->mapRenderer() ); 00105 } 00106 else 00107 { 00108 snapLayer.mTolerance = snappingTol; 00109 } 00110 00111 QList<QgsSnapper::SnapLayer> snapLayers; 00112 snapLayers.append( snapLayer ); 00113 mSnapper->setSnapLayers( snapLayers ); 00114 00115 if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 ) 00116 return 4; 00117 00118 return 0; 00119 } 00120 00121 int QgsMapCanvasSnapper::snapToBackgroundLayers( const QPoint& p, QList<QgsSnappingResult>& results, const QList<QgsPoint>& excludePoints ) 00122 { 00123 results.clear(); 00124 00125 if ( !mSnapper ) 00126 return 5; 00127 00128 //topological editing on? 00129 int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); 00130 00131 //snapping on intersection on? 00132 int intersectionSnapping = QgsProject::instance()->readNumEntry( "Digitizing", "/IntersectionSnapping", 0 ); 00133 00134 if ( topologicalEditing == 0 ) 00135 { 00136 if ( intersectionSnapping == 0 ) 00137 mSnapper->setSnapMode( QgsSnapper::SnapWithOneResult ); 00138 else 00139 mSnapper->setSnapMode( QgsSnapper::SnapWithResultsWithinTolerances ); 00140 } 00141 else if ( intersectionSnapping == 0 ) 00142 { 00143 mSnapper->setSnapMode( QgsSnapper::SnapWithResultsForSamePosition ); 00144 } 00145 else 00146 { 00147 mSnapper->setSnapMode( QgsSnapper::SnapWithResultsWithinTolerances ); 00148 } 00149 00150 //read snapping settings from project 00151 bool snappingDefinedInProject, ok; 00152 QStringList layerIdList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingList", QStringList(), &snappingDefinedInProject ); 00153 QStringList enabledList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingEnabledList", QStringList(), &ok ); 00154 QStringList toleranceList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceList", QStringList(), &ok ); 00155 QStringList toleranceUnitList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnappingToleranceUnitList", QStringList(), &ok ); 00156 QStringList snapToList = QgsProject::instance()->readListEntry( "Digitizing", "/LayerSnapToList", QStringList(), &ok ); 00157 00158 if ( !( layerIdList.size() == enabledList.size() && 00159 layerIdList.size() == toleranceList.size() && 00160 layerIdList.size() == toleranceUnitList.size() && 00161 layerIdList.size() == snapToList.size() ) ) 00162 { 00163 // lists must have the same size, otherwise something is wrong 00164 return 1; 00165 } 00166 00167 QList<QgsSnapper::SnapLayer> snapLayers; 00168 QgsSnapper::SnapLayer snapLayer; 00169 00170 // Use snapping information from the project 00171 if ( snappingDefinedInProject ) 00172 { 00173 // set layers, tolerances, snap to segment/vertex to QgsSnapper 00174 QStringList::const_iterator layerIt( layerIdList.constBegin() ); 00175 QStringList::const_iterator tolIt( toleranceList.constBegin() ); 00176 QStringList::const_iterator tolUnitIt( toleranceUnitList.constBegin() ); 00177 QStringList::const_iterator snapIt( snapToList.constBegin() ); 00178 QStringList::const_iterator enabledIt( enabledList.constBegin() ); 00179 for ( ; layerIt != layerIdList.constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt ) 00180 { 00181 if ( *enabledIt != "enabled" ) 00182 { 00183 // skip layer if snapping is not enabled 00184 continue; 00185 } 00186 00187 //layer 00188 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( *layerIt ) ); 00189 if ( !vlayer ) 00190 continue; 00191 00192 snapLayer.mLayer = vlayer; 00193 00194 //tolerance 00195 snapLayer.mTolerance = tolIt->toDouble(); 00196 snapLayer.mUnitType = ( QgsTolerance::UnitType ) tolUnitIt->toInt(); 00197 00198 // segment or vertex 00199 if ( *snapIt == "to_vertex" ) 00200 { 00201 snapLayer.mSnapTo = QgsSnapper::SnapToVertex; 00202 } 00203 else if ( *snapIt == "to_segment" ) 00204 { 00205 snapLayer.mSnapTo = QgsSnapper::SnapToSegment; 00206 } 00207 else 00208 { 00209 // to vertex and segment 00210 snapLayer.mSnapTo = QgsSnapper::SnapToVertexAndSegment; 00211 } 00212 00213 snapLayers.append( snapLayer ); 00214 } 00215 } 00216 else 00217 { 00218 // nothing in project. Use default snapping tolerance to vertex of current layer 00219 QgsMapLayer* currentLayer = mMapCanvas->currentLayer(); 00220 if ( !currentLayer ) 00221 return 2; 00222 00223 QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer ); 00224 if ( !currentVectorLayer ) 00225 return 3; 00226 00227 snapLayer.mLayer = currentVectorLayer; 00228 00229 //default snap mode 00230 QSettings settings; 00231 QString defaultSnapString = settings.value( "/qgis/digitizing/default_snap_mode", "off" ).toString(); 00232 if ( defaultSnapString == "to segment" ) 00233 { 00234 snapLayer.mSnapTo = QgsSnapper::SnapToSegment; 00235 } 00236 else if ( defaultSnapString == "to vertex and segment" ) 00237 { 00238 snapLayer.mSnapTo = QgsSnapper::SnapToVertexAndSegment; 00239 } 00240 else if ( defaultSnapString == "to vertex" ) 00241 { 00242 snapLayer.mSnapTo = QgsSnapper::SnapToVertex; 00243 } 00244 else 00245 { 00246 return 0; 00247 } 00248 00249 //default snapping tolerance (returned in map units) 00250 snapLayer.mTolerance = QgsTolerance::defaultTolerance( currentVectorLayer, mMapCanvas->mapRenderer() ); 00251 snapLayer.mUnitType = QgsTolerance::MapUnits; 00252 00253 snapLayers.append( snapLayer ); 00254 } 00255 00256 mSnapper->setSnapLayers( snapLayers ); 00257 00258 if ( mSnapper->snapPoint( p, results, excludePoints ) != 0 ) 00259 return 4; 00260 00261 if ( intersectionSnapping != 1 ) 00262 return 0; 00263 00264 QList<QgsSnappingResult> segments; 00265 QList<QgsSnappingResult> points; 00266 for ( QList<QgsSnappingResult>::const_iterator it = results.constBegin(); 00267 it != results.constEnd(); 00268 ++it ) 00269 { 00270 if ( it->snappedVertexNr == -1 ) 00271 { 00272 QgsDebugMsg( "segment" ); 00273 segments.push_back( *it ); 00274 } 00275 else 00276 { 00277 QgsDebugMsg( "no segment" ); 00278 points.push_back( *it ); 00279 } 00280 } 00281 00282 if ( segments.length() < 2 ) 00283 return 0; 00284 00285 QList<QgsSnappingResult> myResults; 00286 00287 for ( QList<QgsSnappingResult>::const_iterator oSegIt = segments.constBegin(); 00288 oSegIt != segments.constEnd(); 00289 ++oSegIt ) 00290 { 00291 QgsDebugMsg( QString::number( oSegIt->beforeVertexNr ) ); 00292 00293 QVector<QgsPoint> vertexPoints; 00294 vertexPoints.append( oSegIt->beforeVertex ); 00295 vertexPoints.append( oSegIt->afterVertex ); 00296 00297 QgsGeometry* lineA = QgsGeometry::fromPolyline( vertexPoints ); 00298 00299 for ( QList<QgsSnappingResult>::iterator iSegIt = segments.begin(); 00300 iSegIt != segments.end(); 00301 ++iSegIt ) 00302 { 00303 QVector<QgsPoint> vertexPoints; 00304 vertexPoints.append( iSegIt->beforeVertex ); 00305 vertexPoints.append( iSegIt->afterVertex ); 00306 QgsGeometry* lineB = QgsGeometry::fromPolyline( vertexPoints ); 00307 00308 QgsGeometry* intersectionPoint = lineA->intersection( lineB ); 00309 if ( intersectionPoint->type() == QGis::Point ) 00310 { 00311 iSegIt->snappedVertex = intersectionPoint->asPoint(); 00312 myResults.append( *iSegIt ); 00313 } 00314 } 00315 } 00316 00317 if ( myResults.length() > 0 ) 00318 { 00319 results.clear(); 00320 results = myResults; 00321 } 00322 00323 return 0; 00324 }