QGIS API Documentation  master-28efcda
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 )
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines