Skip to content

Commit

Permalink
Add QgsSnappingUtils::snapToCurrentLayer() + utility methods in QgsTo…
Browse files Browse the repository at this point in the history
…lerance

Also added missing SIP wrappers for new classes QgsPointLocator and QgsSnappingUtils
  • Loading branch information
wonder-sk committed Jan 20, 2015
1 parent 488e7f1 commit 4b8ea28
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 57 deletions.
112 changes: 112 additions & 0 deletions python/core/qgspointlocator.sip
@@ -0,0 +1,112 @@

class QgsPointLocator : QObject
{
%TypeHeaderCode
#include <qgspointlocator.h>
%End

public:
explicit QgsPointLocator( QgsVectorLayer* layer, const QgsCoordinateReferenceSystem* destCRS = 0 );

~QgsPointLocator();

enum Type { Invalid, Vertex, Edge, Area, All };

/** Prepare the indexes for given or-ed combination of query types (Vertex, Edge, Area).
* If not initialized explicitly, index of particular type will be inited when first such query is issued.
*/
void init( int types = All, bool force = false );

//! check whether index for given query type exists
bool hasIndex( Type t ) const;

struct Match
{
//! consruct invalid match
Match();

Match( QgsPointLocator::Type t, QgsVectorLayer* vl, QgsFeatureId fid, double dist, const QgsPoint& pt, int vertexIndex = 0 );

QgsPointLocator::Type type() const;

bool isValid() const;
bool hasVertex() const;
bool hasEdge() const;
bool hasArea() const;

//! for vertex / edge match
//! units depending on what class returns it (geom.cache: layer units, map canvas snapper: dest crs units)
double distance() const;

//! for vertex / edge match
//! coords depending on what class returns it (geom.cache: layer coords, map canvas snapper: dest coords)
QgsPoint point() const;

//! for vertex / edge match (first vertex of the edge)
int vertexIndex();

//! reference vector layer
QgsVectorLayer* layer();

QgsFeatureId featureId();

void replaceIfBetter( const QgsPointLocator::Match& m, double maxDistance );

//! Only for a valid edge match - obtain endpoints of the edge
void edgePoints( QgsPoint& pt1 /Out/, QgsPoint& pt2 /Out/ ) const;
};

typedef QList<QgsPointLocator::Match> MatchList;

//! Interface that allows rejection of some matches in intersection queries
//! (e.g. a match can only belong to a particular feature / match must not be a particular point).
//! Implement the interface and pass its instance to QgsPointLocator or QgsSnappingUtils methods.
struct MatchFilter
{
virtual bool acceptMatch( const QgsPointLocator::Match& match ) = 0;
};

// 1-NN queries

//! find nearest vertex to the specified point
QgsPointLocator::Match nearestVertex( const QgsPoint& point );

//! find nearest edge to the specified point
QgsPointLocator::Match nearestEdge( const QgsPoint& point );

// k-NN queries

//! find nearest vertices to the specified point - sorted by distance
//! will return up to maxMatches matches
MatchList nearestVertices( const QgsPoint& point, int maxMatches );
//! find nearest edges to the specified point - sorted by distance
MatchList nearestEdges( const QgsPoint& point, int maxMatches );

// intersection queries

//! Find nearest vertices to the specified point - sorted by distance.
//! Will return matches up to distance given by tolerance.
//! Optional filter may discard unwanted matches.
MatchList verticesInTolerance( const QgsPoint& point, double tolerance, QgsPointLocator::MatchFilter* filter = 0 );
//! Find nearest edges to the specified point - sorted by distance.
//! Will return matches up to distance given by tolerance.
//! Optional filter may discard unwanted matches.
MatchList edgesInTolerance( const QgsPoint& point, double tolerance, QgsPointLocator::MatchFilter* filter = 0 );

//! Find vertices within given rectangle.
//! If distToPoint is given, the matches will be sorted by distance to that point.
//! Optional filter may discard unwanted matches.
MatchList verticesInRect( const QgsRectangle& rect, const QgsPoint* distToPoint = 0, QgsPointLocator::MatchFilter* filter = 0 );
//! Find edges within given rectangle.
//! If distToPoint is given, the matches will be sorted by distance to that point.
//! Optional filter may discard unwanted matches.
MatchList edgesInRect( const QgsRectangle& rect, const QgsPoint* distToPoint = 0, QgsPointLocator::MatchFilter* filter = 0 );

// point-in-polygon query

// TODO: function to return just the first match?
//! find out if the point is in any polygons
MatchList pointInPolygon( const QgsPoint& point );


};
79 changes: 79 additions & 0 deletions python/core/qgssnappingutils.sip
@@ -0,0 +1,79 @@

class QgsSnappingUtils : QObject
{
%TypeHeaderCode
#include <qgssnappingutils.h>
%End

public:
QgsSnappingUtils( QObject* parent /TransferThis/ = 0 );
~QgsSnappingUtils();

// main actions

/** get a point locator for the given layer. If such locator does not exist, it will be created */
QgsPointLocator* locatorForLayer( QgsVectorLayer* vl );

/** snap to map according to the current configuration (mode). Optional filter allows to discard unwanted matches. */
QgsPointLocator::Match snapToMap( const QPoint& point, QgsPointLocator::MatchFilter* filter = 0 );
QgsPointLocator::Match snapToMap( const QgsPoint& pointMap, QgsPointLocator::MatchFilter* filter = 0 );
// TODO: multi-variant

/** snap to current layer */
QgsPointLocator::Match snapToCurrentLayer( const QPoint& point, int type, QgsPointLocator::MatchFilter* filter = 0 );

// environment setup

/** assign current map settings to the utils - used for conversion between screen coords to map coords */
void setMapSettings( const QgsMapSettings& settings );
const QgsMapSettings& mapSettings() const;

/** set current layer so that if mode is SnapCurrentLayer we know which layer to use */
void setCurrentLayer( QgsVectorLayer* layer );
QgsVectorLayer* currentLayer() const;


// configuration

//! modes for "snap to background"
enum SnapToMapMode
{
SnapCurrentLayer, //!< snap just to current layer (tolerance+type from QSettings)
SnapPerLayerConfig, //!< snap according to the configuration set in setLayers()
};

/** Set how the snapping to map is done */
void setSnapToMapMode( SnapToMapMode mode );
/** Find out how the snapping to map is done */
SnapToMapMode snapToMapMode() const;

/** configure options used when the mode is snap to current layer */
void setDefaultSettings( int type, double tolerance, QgsTolerance::UnitType unit );
/** query options used when the mode is snap to current layer */
void defaultSettings( int& type /Out/, double& tolerance /Out/, QgsTolerance::UnitType& unit /Out/ );

struct LayerConfig
{
LayerConfig( QgsVectorLayer* l, int t, double tol, QgsTolerance::UnitType u );

QgsVectorLayer* layer;
int type;
double tolerance;
QgsTolerance::UnitType unit;
};

/** Set layers which will be used for snapping */
void setLayers( const QList<QgsSnappingUtils::LayerConfig>& layers );
/** Query layers used for snapping */
QList<QgsSnappingUtils::LayerConfig> layers() const;

/** Set whether to consider intersections of nearby segments for snapping */
void setSnapOnIntersections( bool enabled );
/** Query whether to consider intersections of nearby segments for snapping */
bool snapOnIntersections() const;

public slots:
/** Read snapping configuration from the project */
void readConfigFromProject();

};
34 changes: 26 additions & 8 deletions python/core/qgstolerance.sip
Expand Up @@ -15,53 +15,71 @@ class QgsTolerance
Pixels
};

/**
* Static function to get vertex tolerance value.
* The value is read from settings and transformed if necessary.
* @return value of vertex tolerance in map units (not layer units)
* @note added in 2.8
*/
static double vertexSearchRadius( const QgsMapSettings& mapSettings );

/**
* Static function to get vertex tolerance value for a layer.
* The value is read from settings and transformed if necessary.
* @return value of vertex tolerance in map units
* @return value of vertex tolerance in layer units
*/
static double vertexSearchRadius( QgsMapLayer* layer, const QgsMapSettings& mapSettings );

/**
* Static function to get vertex tolerance value for a layer.
* The value is read from settings and transformed if necessary.
* @return value of vertex tolerance in map units
* @return value of vertex tolerance in layer units
*/
//! @deprecated since 2.4 - use override with QgsMapSettings
static double vertexSearchRadius( QgsMapLayer* layer, QgsMapRenderer* renderer ) /Deprecated/;

/**
* Static function to get default tolerance value for a layer.
* The value is read from settings and transformed if necessary.
* @return value of default tolerance in map units
* @return value of vertex tolerance in layer units
*/
static double defaultTolerance( QgsMapLayer* layer, const QgsMapSettings& mapSettings );

/**
* Static function to get default tolerance value for a layer.
* The value is read from settings and transformed if necessary.
* @return value of default tolerance in map units
* @return value of vertex tolerance in layer units
*/
//! @deprecated since 2.4 - use override with QgsMapSettings
static double defaultTolerance( QgsMapLayer* layer, QgsMapRenderer* renderer ) /Deprecated/;

/**
* Static function to translate tolerance value into current map unit value
* Static function to translate tolerance value into map units
* @param tolerance tolerance value to be translated
* @param layer reference layer
* @param mapSettings settings of the map
* @param units type of units to be translated
* @return value of tolerance in map units
* @note added in 2.8
*/
static double toleranceInMapUnits( double tolerance, const QgsMapSettings& mapSettings, QgsTolerance::UnitType units );

/**
* Static function to translate tolerance value into layer units
* @param tolerance tolerance value to be translated
* @param layer reference layer
* @param mapSettings settings of the map
* @param units type of units to be translated
* @return value of tolerance in layer units
*/
static double toleranceInMapUnits( double tolerance, QgsMapLayer* layer, const QgsMapSettings& mapSettings, UnitType units = MapUnits );

/**
* Static function to translate tolerance value into current map unit value
* Static function to translate tolerance value into layer units
* @param tolerance tolerance value to be translated
* @param layer reference layer
* @param renderer renderer
* @param units type of units to be translated
* @return value of tolerance in map units
* @return value of tolerance in layer units
*/
//! @deprecated since 2.4 - use the override with QgsMapSettings
static double toleranceInMapUnits( double tolerance, QgsMapLayer* layer, QgsMapRenderer* renderer, UnitType units = MapUnits ) /Deprecated/;
Expand Down
52 changes: 24 additions & 28 deletions src/app/qgsmaptooldeletepart.cpp
Expand Up @@ -19,6 +19,7 @@
#include "qgsvertexmarker.h"
#include "qgsvectorlayer.h"
#include "qgsgeometry.h"
#include "qgssnappingutils.h"
#include "qgstolerance.h"

#include <QMouseEvent>
Expand Down Expand Up @@ -122,38 +123,33 @@ QgsGeometry* QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId& f
case QGis::Point:
case QGis::Line:
{
if ( mSnapper.snapToCurrentLayer( point, mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) == 0 )
QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Vertex | QgsPointLocator::Edge );
if ( !match.isValid() )
return geomPart;

int snapVertex = match.vertexIndex();
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f );
QgsGeometry* g = f.geometry();
if ( !g->isMultipart() )
return geomPart;
if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D )
{
if ( mRecentSnappingResults.length() > 0 )
fid = match.featureId();
partNum = snapVertex;
return QgsGeometry::fromPoint( match.point() );
}
if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D )
{
QgsMultiPolyline mline = g->asMultiPolyline();
for ( int part = 0; part < mline.count(); part++ )
{
QgsSnappingResult sr = mRecentSnappingResults.first();
int snapVertex = sr.snappedVertexNr;
if ( snapVertex == -1 )
snapVertex = sr.beforeVertexNr;
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( sr.snappedAtGeometry ) ).nextFeature( f );
QgsGeometry* g = f.geometry();
if ( !g->isMultipart() )
return geomPart;
if ( g->wkbType() == QGis::WKBMultiPoint || g->wkbType() == QGis::WKBMultiPoint25D )
{
fid = sr.snappedAtGeometry;
partNum = snapVertex;
return QgsGeometry::fromPoint( sr.snappedVertex );
}
if ( g->wkbType() == QGis::WKBMultiLineString || g->wkbType() == QGis::WKBMultiLineString25D )
if ( snapVertex < mline[part].count() )
{
QgsMultiPolyline mline = g->asMultiPolyline();
for ( int part = 0; part < mline.count(); part++ )
{
if ( snapVertex < mline[part].count() )
{
fid = sr.snappedAtGeometry;
partNum = part;
return QgsGeometry::fromPolyline( mline[part] );
}
snapVertex -= mline[part].count();
}
fid = match.featureId();
partNum = part;
return QgsGeometry::fromPolyline( mline[part] );
}
snapVertex -= mline[part].count();
}
}
break;
Expand Down
1 change: 0 additions & 1 deletion src/app/qgsmaptooldeletepart.h
Expand Up @@ -41,7 +41,6 @@ class APP_EXPORT QgsMapToolDeletePart: public QgsMapToolEdit

private:
QgsVectorLayer* vlayer;
QList<QgsSnappingResult> mRecentSnappingResults;

QgsGeometry* partUnderPoint( QPoint p, QgsFeatureId &fid, int &partNum );

Expand Down

0 comments on commit 4b8ea28

Please sign in to comment.