• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MerginMaps / input / 5983636709

26 Aug 2023 07:50AM UTC coverage: 62.064% (+1.1%) from 60.955%
5983636709

push

github

web-flow
Lcov to lnx (#2772)

move lcov to linux tests

7552 of 12168 relevant lines covered (62.06%)

102.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.46
/app/snaputils.cpp
1
/***************************************************************************
2
 *                                                                         *
3
 *   This program is free software; you can redistribute it and/or modify  *
4
 *   it under the terms of the GNU General Public License as published by  *
5
 *   the Free Software Foundation; either version 2 of the License, or     *
6
 *   (at your option) any later version.                                   *
7
 *                                                                         *
8
 ***************************************************************************/
9

10
#include "qgis.h"
11

12
#include "snaputils.h"
13
#include "inpututils.h"
14

15
SnapUtils::SnapUtils( QObject *parent )
1✔
16
  : QObject{parent}
1✔
17
{
18
}
1✔
19

20
QgsProject *SnapUtils::qgsProject() const
×
21
{
22
  return mQgsProject;
×
23
}
24

25
void SnapUtils::setQgsProject( QgsProject *newQgsProject )
2✔
26
{
27
  if ( !newQgsProject && !mQgsProject )
2✔
28
    return;
1✔
29

30
  if ( !newQgsProject || !mQgsProject || newQgsProject->homePath() != mQgsProject->homePath() )
1✔
31
  {
32
    mQgsProject = newQgsProject;
1✔
33
    emit qgsProjectChanged( mQgsProject );
1✔
34

35
    setupSnapping();
1✔
36
  }
37
}
38

39
InputMapSettings *SnapUtils::mapSettings() const
×
40
{
41
  return mMapSettings;
×
42
}
43

44
void SnapUtils::setMapSettings( InputMapSettings *newMapSettings )
2✔
45
{
46
  if ( mMapSettings == newMapSettings )
2✔
47
    return;
1✔
48

49
  if ( mMapSettings )
1✔
50
  {
51
    disconnect( mMapSettings, nullptr, this, nullptr );
×
52
  }
53

54
  mMapSettings = newMapSettings;
1✔
55

56
  if ( mMapSettings )
1✔
57
  {
58
    connect( mMapSettings, &InputMapSettings::extentChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
59
    connect( mMapSettings, &InputMapSettings::destinationCrsChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
60
    connect( mMapSettings, &InputMapSettings::mapUnitsPerPixelChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
61
    connect( mMapSettings, &InputMapSettings::visibleExtentChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
62
    connect( mMapSettings, &InputMapSettings::outputSizeChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
63
    connect( mMapSettings, &InputMapSettings::outputDpiChanged, this, &SnapUtils::onMapSettingsUpdated );
1✔
64

65
    mSnappingUtils.setMapSettings( mMapSettings->mapSettings() );
1✔
66
  }
67

68
  emit mapSettingsChanged( mMapSettings );
1✔
69

70
  initializeRecordPosition();
1✔
71
}
72

73
void SnapUtils::getsnap()
3✔
74
{
75
  if ( !mDestinationLayer || !mMapSettings )
3✔
76
  {
77
    setRecordPoint( QgsPoint() );
1✔
78
    setSnapped( false );
1✔
79
    return;
2✔
80
  }
81

82
  // by default show crosshair in center, no snap
83
  QgsPoint recordpoint = mMapSettings->screenToCoordinate( mCenterPosition );
2✔
84
  QgsPoint centerPoint = InputUtils::transformPoint(
85
                           mMapSettings->destinationCrs(),
4✔
86
                           mDestinationLayer->crs(),
4✔
87
                           mDestinationLayer->transformContext(),
2✔
88
                           recordpoint );
2✔
89

90
  // do not snap in the streaming mode
91
  if ( !mUseSnapping )
2✔
92
  {
93
    setRecordPoint( centerPoint );
1✔
94
    setSnapped( false );
1✔
95
    return;
1✔
96
  }
97

98
  QgsPointLocator::Match snap = mSnappingUtils.snapToMap( QgsPointXY( recordpoint.x(), recordpoint.y() ) );
1✔
99
  if ( snap.isValid() )
1✔
100
  {
101
    QgsPoint layerPoint;
1✔
102

103
    // if snapped to vertex or line start/end point we get point coordinates from the
104
    // geometry of the feature to which we have snapped. Otherwise get point found by
105
    // the QgsPointLocator
106
    if ( snap.layer() && ( snap.hasVertex() || snap.hasLineEndpoint() ) )
1✔
107
    {
108
      QgsFeature f;
1✔
109
      QgsFeatureRequest request;
1✔
110
      request.setFilterFid( snap.featureId() );
1✔
111
      const bool fetched = snap.layer()->getFeatures( request ).nextFeature( f );
1✔
112
      if ( fetched )
1✔
113
      {
114
        QgsVertexId vId;
1✔
115
        if ( !f.geometry().vertexIdFromVertexNr( snap.vertexIndex(), vId ) )
1✔
116
        {
117
          setRecordPoint( centerPoint );
×
118
          setSnapped( false );
×
119
          return;
×
120
        }
121
        const QgsGeometry geom( f.geometry() );
1✔
122
        layerPoint = InputUtils::transformPoint( snap.layer()->crs(), mDestinationLayer->crs(), mQgsProject->transformContext(), geom.constGet()->vertexAt( vId ) );
1✔
123
      }
1✔
124
    }
1✔
125
    else
126
    {
127
      layerPoint = InputUtils::transformPoint( mMapSettings->destinationCrs(), mDestinationLayer->crs(), mQgsProject->transformContext(), QgsPoint( snap.point() ) );
×
128
    }
129

130
    setRecordPoint( layerPoint );
1✔
131

132
    if ( snap.hasVertex() )
1✔
133
    {
134
      setSnapType( SnapUtils::Vertex );
1✔
135
    }
136
    else if ( snap.hasArea() || snap.hasCentroid() || snap.hasMiddleSegment() )
×
137
    {
138
      setSnapType( SnapUtils::Other );
×
139
    }
140
    else
141
    {
142
      setSnapType( SnapUtils::Segment );
×
143
    }
144

145
    setSnapped( true );
1✔
146
  }
1✔
147
  else
148
  {
149
    setRecordPoint( centerPoint );
×
150
    setSnapped( false );
×
151
  }
152
}
3✔
153

154
void SnapUtils::clear()
×
155
{
156
  setSnapped( false );
×
157
  setQgsProject( nullptr );
×
158
  setMapSettings( nullptr );
×
159
  setDestinationLayer( nullptr );
×
160

161
  mSnappingUtils.setConfig( QgsSnappingConfig() );
×
162
}
×
163

164
void SnapUtils::onMapSettingsUpdated()
×
165
{
166
  if ( mMapSettings )
×
167
  {
168
    mSnappingUtils.setMapSettings( mMapSettings->mapSettings() );
×
169

170
    getsnap();
×
171
  }
172
}
×
173

174
QPointF SnapUtils::centerPosition() const
×
175
{
176
  return mCenterPosition;
×
177
}
178

179
void SnapUtils::setCenterPosition( QPointF newCenterPosition )
1✔
180
{
181
  if ( mCenterPosition == newCenterPosition )
1✔
182
    return;
×
183
  mCenterPosition = newCenterPosition;
1✔
184
  emit centerPositionChanged( mCenterPosition );
1✔
185

186
  initializeRecordPosition();
1✔
187
}
188

189
QgsPoint SnapUtils::recordPoint() const
×
190
{
191
  return mRecordPoint;
×
192
}
193

194
void SnapUtils::setRecordPoint( QgsPoint newRecordPoint )
4✔
195
{
196
  mRecordPoint = newRecordPoint;
4✔
197
  emit recordPointChanged( mRecordPoint );
4✔
198
}
4✔
199

200
bool SnapUtils::snapped() const
3✔
201
{
202
  return mSnapped;
3✔
203
}
204

205
void SnapUtils::setSnapped( bool newSnapped )
3✔
206
{
207
  if ( mSnapped == newSnapped )
3✔
208
    return;
1✔
209
  mSnapped = newSnapped;
2✔
210
  emit snappedChanged( mSnapped );
2✔
211
}
212

213
const SnapUtils::SnapType &SnapUtils::snapType() const
×
214
{
215
  return mSnapType;
×
216
}
217

218
void SnapUtils::setSnapType( const SnapUtils::SnapType &newSnapType )
1✔
219
{
220
  if ( mSnapType == newSnapType )
1✔
221
    return;
1✔
222
  mSnapType = newSnapType;
×
223
  emit snapTypeChanged( mSnapType );
×
224
}
225

226
bool SnapUtils::useSnapping() const
×
227
{
228
  return mUseSnapping;
×
229
}
230

231
void SnapUtils::setUseSnapping( bool useSnapping )
2✔
232
{
233
  if ( mUseSnapping == useSnapping )
2✔
234
    return;
×
235

236
  mUseSnapping = useSnapping;
2✔
237
  emit useSnappingChanged( mUseSnapping );
2✔
238

239
  getsnap();
2✔
240
}
241

242
void SnapUtils::setupSnapping()
1✔
243
{
244
  if ( !mQgsProject )
1✔
245
  {
246
    return;
×
247
  }
248

249
  int mode = mQgsProject->readNumEntry( QStringLiteral( "Mergin" ), QStringLiteral( "Snapping" ), 0 );
3✔
250
  switch ( mode )
1✔
251
  {
252
    case 0:
×
253
    {
254
      mUseSnapping = false;
×
255
      break;
×
256
    }
257
    case 1:
1✔
258
    {
259
      QgsSnappingConfig config;
1✔
260
      config.setMode( Qgis::SnappingMode::AllLayers );
1✔
261
      config.setTypeFlag( Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment );
1✔
262
      config.setTolerance( 20.0 * InputUtils::calculateDpRatio() );
1✔
263
      config.setUnits( Qgis::MapToolUnit::Pixels );
1✔
264
      config.setEnabled( true );
1✔
265

266
      mSnappingUtils.setConfig( config );
1✔
267
      mSnappingUtils.setEnableSnappingForInvisibleFeature( false );
1✔
268
      break;
1✔
269
    }
1✔
270
    case 2:
×
271
    {
272
      QgsSnappingConfig config = mQgsProject->snappingConfig();
×
273
      if ( config.units() == Qgis::MapToolUnit::Pixels )
×
274
      {
275
        config.setTolerance( config.tolerance() * InputUtils::calculateDpRatio() );
×
276
      }
277
      mSnappingUtils.setConfig( config );
×
278
      break;
×
279
    }
×
280
  }
281
  mSnappingUtils.setIndexingStrategy( QgsSnappingUtils::IndexExtent );
1✔
282
}
283

284
void SnapUtils::initializeRecordPosition()
3✔
285
{
286
  if ( !mMapSettings || ! mDestinationLayer || mCenterPosition == QPointF( -1, -1 ) )
3✔
287
  {
288
    return;
2✔
289
  }
290

291
  // take center position and convert it to destination layer CRS
292
  QgsPoint recordpoint = mMapSettings->screenToCoordinate( mCenterPosition );
1✔
293
  QgsPoint centerPoint = InputUtils::transformPoint(
294
                           mMapSettings->destinationCrs(),
2✔
295
                           mDestinationLayer->crs(),
2✔
296
                           mDestinationLayer->transformContext(),
1✔
297
                           recordpoint );
1✔
298

299
  setRecordPoint( centerPoint );
1✔
300
}
1✔
301

302
QgsVectorLayer *SnapUtils::destinationLayer() const
×
303
{
304
  return mDestinationLayer;
×
305
}
306

307
void SnapUtils::setDestinationLayer( QgsVectorLayer *newDestinationLayer )
2✔
308
{
309
  if ( mDestinationLayer == newDestinationLayer )
2✔
310
    return;
1✔
311
  mDestinationLayer = newDestinationLayer;
1✔
312
  emit destinationLayerChanged( mDestinationLayer );
1✔
313

314
  initializeRecordPosition();
1✔
315
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc