LCOV - code coverage report
Current view: top level - analysis/vector - qgsgeometrysnapper.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 15 21 71.4 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :  *  qgsgeometrysnapper.h                                                   *
       3                 :            :  *  -------------------                                                    *
       4                 :            :  *  copyright            : (C) 2014 by Sandro Mani / Sourcepole AG         *
       5                 :            :  *  email                : smani@sourcepole.ch                             *
       6                 :            :  ***************************************************************************/
       7                 :            : 
       8                 :            : /***************************************************************************
       9                 :            :  *                                                                         *
      10                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      11                 :            :  *   it under the terms of the GNU General Public License as published by  *
      12                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      13                 :            :  *   (at your option) any later version.                                   *
      14                 :            :  *                                                                         *
      15                 :            :  ***************************************************************************/
      16                 :            : 
      17                 :            : #ifndef QGS_GEOMETRY_SNAPPER_H
      18                 :            : #define QGS_GEOMETRY_SNAPPER_H
      19                 :            : 
      20                 :            : #include <QMutex>
      21                 :            : #include <QFuture>
      22                 :            : #include <QStringList>
      23                 :            : #include "qgsspatialindex.h"
      24                 :            : #include "qgsabstractgeometry.h"
      25                 :            : #include "qgspoint.h"
      26                 :            : #include "qgsgeometry.h"
      27                 :            : #include "qgis_analysis.h"
      28                 :            : 
      29                 :            : class QgsVectorLayer;
      30                 :            : 
      31                 :            : /**
      32                 :            :  * \class QgsGeometrySnapper
      33                 :            :  * \ingroup analysis
      34                 :            :  * \brief QgsGeometrySnapper allows a geometry to be snapped to the geometries within a
      35                 :            :  * different reference layer. Vertices in the geometries will be modified to
      36                 :            :  * match the reference layer features within a specified snap tolerance.
      37                 :            :  * \since QGIS 3.0
      38                 :            :  */
      39                 :         13 : class ANALYSIS_EXPORT QgsGeometrySnapper : public QObject
      40                 :            : {
      41                 :            :     Q_OBJECT
      42                 :            : 
      43                 :            :   public:
      44                 :            : 
      45                 :            :     //! Snapping modes
      46                 :            :     enum SnapMode
      47                 :            :     {
      48                 :            :       PreferNodes = 0, //!< Prefer to snap to nodes, even when a segment may be closer than a node. New nodes will be inserted to make geometries follow each other exactly when inside allowable tolerance.
      49                 :            :       PreferClosest, //!< Snap to closest point, regardless of it is a node or a segment. New nodes will be inserted to make geometries follow each other exactly when inside allowable tolerance.
      50                 :            :       PreferNodesNoExtraVertices, //!< Prefer to snap to nodes, even when a segment may be closer than a node. No new nodes will be inserted.
      51                 :            :       PreferClosestNoExtraVertices, //!< Snap to closest point, regardless of it is a node or a segment. No new nodes will be inserted.
      52                 :            :       EndPointPreferNodes, //!< Only snap start/end points of lines (point features will also be snapped, polygon features will not be modified), prefer to snap to nodes
      53                 :            :       EndPointPreferClosest, //!< Only snap start/end points of lines (point features will also be snapped, polygon features will not be modified), snap to closest point
      54                 :            :       EndPointToEndPoint, //!< Only snap the start/end points of lines to other start/end points of lines
      55                 :            :     };
      56                 :            : 
      57                 :            :     /**
      58                 :            :      * Constructor for QgsGeometrySnapper. A reference feature source which contains geometries to snap to must be
      59                 :            :      * set. It is assumed that all geometries snapped using this object will have the
      60                 :            :      * same CRS as the reference source (ie, no reprojection is performed).
      61                 :            :      */
      62                 :            :     QgsGeometrySnapper( QgsFeatureSource *referenceSource );
      63                 :            : 
      64                 :            :     /**
      65                 :            :      * Snaps a geometry to the reference layer and returns the result. The geometry must be in the same
      66                 :            :      * CRS as the reference layer, and must have the same type as the reference layer geometry. The snap tolerance
      67                 :            :      * is specified in the layer units for the reference layer.
      68                 :            :      */
      69                 :            :     QgsGeometry snapGeometry( const QgsGeometry &geometry, double snapTolerance, SnapMode mode = PreferNodes ) const;
      70                 :            : 
      71                 :            :     /**
      72                 :            :      * Snaps a set of features to the reference layer and returns the result. This operation is
      73                 :            :      * multithreaded for performance. The featureSnapped() signal will be emitted each time a feature
      74                 :            :      * is processed. The snap tolerance is specified in the layer units for the reference layer.
      75                 :            :      */
      76                 :            :     QgsFeatureList snapFeatures( const QgsFeatureList &features, double snapTolerance, SnapMode mode = PreferNodes );
      77                 :            : 
      78                 :            :     /**
      79                 :            :      * Snaps a single geometry against a list of reference geometries.
      80                 :            :      */
      81                 :            :     static QgsGeometry snapGeometry( const QgsGeometry &geometry, double snapTolerance, const QList<QgsGeometry> &referenceGeometries, SnapMode mode = PreferNodes );
      82                 :            : 
      83                 :            :   signals:
      84                 :            : 
      85                 :            :     //! Emitted each time a feature has been processed when calling snapFeatures()
      86                 :            :     void featureSnapped();
      87                 :            : 
      88                 :            :   private:
      89                 :            :     struct ProcessFeatureWrapper
      90                 :            :     {
      91                 :            :       QgsGeometrySnapper *instance = nullptr;
      92                 :            :       double snapTolerance;
      93                 :            :       SnapMode mode;
      94                 :          0 :       explicit ProcessFeatureWrapper( QgsGeometrySnapper *_instance, double snapTolerance, SnapMode mode )
      95                 :          0 :         : instance( _instance )
      96                 :          0 :         , snapTolerance( snapTolerance )
      97                 :          0 :         , mode( mode )
      98                 :          0 :       {}
      99                 :          0 :       void operator()( QgsFeature &feature ) { instance->processFeature( feature, snapTolerance, mode ); }
     100                 :            :     };
     101                 :            : 
     102                 :            :     enum PointFlag { SnappedToRefNode, SnappedToRefSegment, Unsnapped };
     103                 :            : 
     104                 :            :     QgsFeatureSource *mReferenceSource = nullptr;
     105                 :            :     QgsFeatureList mInputFeatures;
     106                 :            : 
     107                 :            :     QgsSpatialIndex mIndex;
     108                 :            :     mutable QMutex mIndexMutex;
     109                 :            :     mutable QMutex mReferenceLayerMutex;
     110                 :            : 
     111                 :            :     void processFeature( QgsFeature &feature, double snapTolerance, SnapMode mode );
     112                 :            : 
     113                 :            :     static int polyLineSize( const QgsAbstractGeometry *geom, int iPart, int iRing );
     114                 :            : 
     115                 :            : };
     116                 :            : 
     117                 :            : 
     118                 :            : /**
     119                 :            :  * \class QgsInternalGeometrySnapper
     120                 :            :  * \ingroup analysis
     121                 :            :  * \brief QgsInternalGeometrySnapper allows a set of geometries to be snapped to each other. It can be used to close gaps in layers.
     122                 :            :  *
     123                 :            :  * To use QgsInternalGeometrySnapper, first construct the snapper using the desired snap parameters. Then,
     124                 :            :  * features are fed to to the snapper one-by-one by calling snapFeature(). Each feature passed by calling
     125                 :            :  * snapFeature() will be snapped to any features which have already been processed by the snapper.
     126                 :            :  *
     127                 :            :  * After processing all desired features, the results can be fetched by calling snappedGeometries().
     128                 :            :  * The returned QgsGeometryMap can be passed to QgsVectorDataProvider::changeGeometryValues() to save
     129                 :            :  * the snapped geometries back to the source layer.
     130                 :            :  *
     131                 :            :  * \since QGIS 3.0
     132                 :            :  */
     133                 :         21 : class ANALYSIS_EXPORT QgsInternalGeometrySnapper
     134                 :            : {
     135                 :            : 
     136                 :            :   public:
     137                 :            : 
     138                 :            :     /**
     139                 :            :      * Constructor for QgsInternalGeometrySnapper. The \a snapTolerance and \a mode parameters dictate
     140                 :            :      * how geometries will be snapped by the snapper.
     141                 :            :      */
     142                 :            :     QgsInternalGeometrySnapper( double snapTolerance, QgsGeometrySnapper::SnapMode mode = QgsGeometrySnapper::PreferNodes );
     143                 :            : 
     144                 :            :     /**
     145                 :            :      * Snaps a single feature's geometry against all feature geometries already processed by
     146                 :            :      * calls to snapFeature() in this object, and returns the snapped geometry.
     147                 :            :      */
     148                 :            :     QgsGeometry snapFeature( const QgsFeature &feature );
     149                 :            : 
     150                 :            :     /**
     151                 :            :      * Returns a QgsGeometryMap of all feature geometries snapped by this object.
     152                 :            :      */
     153                 :          1 :     QgsGeometryMap snappedGeometries() const { return mProcessedGeometries; }
     154                 :            : 
     155                 :            :   private:
     156                 :            : 
     157                 :            :     bool mFirstFeature = true;
     158                 :            :     double mSnapTolerance = 0;
     159                 :            :     QgsGeometrySnapper::SnapMode mMode = QgsGeometrySnapper::PreferNodes;
     160                 :            :     QgsSpatialIndex mProcessedIndex;
     161                 :            :     QgsGeometryMap mProcessedGeometries;
     162                 :            : 
     163                 :            : };
     164                 :            : 
     165                 :            : #ifndef SIP_RUN
     166                 :            : 
     167                 :            : ///@cond PRIVATE
     168                 :            : class QgsSnapIndex
     169                 :            : {
     170                 :            :   public:
     171                 :            :     struct CoordIdx
     172                 :            :     {
     173                 :       1382 :       CoordIdx( const QgsAbstractGeometry *_geom, QgsVertexId _vidx )
     174                 :       1382 :         : geom( _geom )
     175                 :       1382 :         , vidx( _vidx )
     176                 :       1382 :       {}
     177                 :       4294 :       QgsPoint point() const { return geom->vertexAt( vidx ); }
     178                 :            : 
     179                 :            :       const QgsAbstractGeometry *geom = nullptr;
     180                 :            :       QgsVertexId vidx;
     181                 :            :     };
     182                 :            : 
     183                 :            :     enum SnapType { SnapPoint, SnapEndPoint, SnapSegment };
     184                 :            : 
     185                 :            :     class SnapItem
     186                 :            :     {
     187                 :            :       public:
     188                 :       1814 :         virtual ~SnapItem() = default;
     189                 :            :         SnapType type;
     190                 :            :         virtual QgsPoint getSnapPoint( const QgsPoint &p ) const = 0;
     191                 :            : 
     192                 :            :       protected:
     193                 :       1814 :         explicit SnapItem( SnapType _type ) : type( _type ) {}
     194                 :            :     };
     195                 :            : 
     196                 :       1382 :     class PointSnapItem : public QgsSnapIndex::SnapItem
     197                 :            :     {
     198                 :            :       public:
     199                 :            :         explicit PointSnapItem( const CoordIdx *_idx, bool isEndPoint );
     200                 :            :         QgsPoint getSnapPoint( const QgsPoint &/*p*/ ) const override;
     201                 :            :         const CoordIdx *idx = nullptr;
     202                 :            :     };
     203                 :            : 
     204                 :       2246 :     class SegmentSnapItem : public QgsSnapIndex::SnapItem
     205                 :            :     {
     206                 :            :       public:
     207                 :            :         SegmentSnapItem( const CoordIdx *_idxFrom, const CoordIdx *_idxTo );
     208                 :            :         QgsPoint getSnapPoint( const QgsPoint &p ) const override;
     209                 :            :         bool getIntersection( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &inter ) const;
     210                 :            :         bool getProjection( const QgsPoint &p, QgsPoint &pProj );
     211                 :            :         const CoordIdx *idxFrom = nullptr;
     212                 :            :         const CoordIdx *idxTo = nullptr;
     213                 :            :     };
     214                 :            : 
     215                 :            :     QgsSnapIndex( const QgsPoint &origin, double cellSize );
     216                 :            :     ~QgsSnapIndex();
     217                 :            : 
     218                 :            :     QgsSnapIndex( const QgsSnapIndex &rh ) = delete;
     219                 :            :     QgsSnapIndex &operator=( const QgsSnapIndex &rh ) = delete;
     220                 :            : 
     221                 :            :     void addGeometry( const QgsAbstractGeometry *geom );
     222                 :            :     QgsPoint getClosestSnapToPoint( const QgsPoint &p, const QgsPoint &q );
     223                 :            :     SnapItem *getSnapItem( const QgsPoint &pos, double tol, PointSnapItem **pSnapPoint = nullptr, SegmentSnapItem **pSnapSegment = nullptr, bool endPointOnly = false ) const;
     224                 :            : 
     225                 :            :   private:
     226                 :            :     typedef QList<SnapItem *> Cell;
     227                 :            :     typedef QPair<QgsPoint, QgsPoint> Segment;
     228                 :            : 
     229                 :        331 :     class GridRow
     230                 :            :     {
     231                 :            :       public:
     232                 :        331 :         GridRow() = default;
     233                 :            :         ~GridRow();
     234                 :            :         const Cell *getCell( int col ) const;
     235                 :            :         Cell &getCreateCell( int col );
     236                 :            :         QList<SnapItem *> getSnapItems( int colStart, int colEnd ) const;
     237                 :            : 
     238                 :            :       private:
     239                 :            :         QList<QgsSnapIndex::Cell> mCells;
     240                 :        331 :         int mColStartIdx = 0;
     241                 :            :     };
     242                 :            : 
     243                 :            :     QgsPoint mOrigin;
     244                 :            :     double mCellSize;
     245                 :            : 
     246                 :            :     QList<CoordIdx *> mCoordIdxs;
     247                 :            :     QList<GridRow> mGridRows;
     248                 :            :     int mRowsStartIdx;
     249                 :            : 
     250                 :            :     void addPoint( const CoordIdx *idx, bool isEndPoint );
     251                 :            :     void addSegment( const CoordIdx *idxFrom, const CoordIdx *idxTo );
     252                 :            :     const Cell *getCell( int col, int row ) const;
     253                 :            :     Cell &getCreateCell( int col, int row );
     254                 :            : 
     255                 :            : };
     256                 :            : 
     257                 :            : ///@endcond
     258                 :            : 
     259                 :            : #endif
     260                 :            : 
     261                 :            : #endif // QGS_GEOMETRY_SNAPPER_H

Generated by: LCOV version 1.14