QGIS API Documentation  master-6227475
src/gui/qgsmapcanvassnapper.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines