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