QGIS API Documentation  3.21.0-Master (909859188c)
qgsmodelsnapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmodelsnapper.cpp
3  --------------------
4  begin : March 2020
5  copyright : (C) 2020 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 #include "qgsmodelsnapper.h"
18 #include "qgssettings.h"
19 #include <cmath>
20 
22 {
23  const QgsSettings s;
24  mTolerance = s.value( QStringLiteral( "/Processing/Modeler/snapTolerancePixels" ), 40 ).toInt();
25 }
26 
27 void QgsModelSnapper::setSnapTolerance( const int snapTolerance )
28 {
29  mTolerance = snapTolerance;
30 }
31 
32 void QgsModelSnapper::setSnapToGrid( bool enabled )
33 {
34  mSnapToGrid = enabled;
35 }
36 
37 QPointF QgsModelSnapper::snapPoint( QPointF point, double scaleFactor, bool &snapped, bool snapHorizontal, bool snapVertical ) const
38 {
39  snapped = false;
40 
41  bool snappedXToGrid = false;
42  bool snappedYToGrid = false;
43  const QPointF res = snapPointToGrid( point, scaleFactor, snappedXToGrid, snappedYToGrid );
44  if ( snappedXToGrid && snapVertical )
45  {
46  snapped = true;
47  point.setX( res.x() );
48  }
49  if ( snappedYToGrid && snapHorizontal )
50  {
51  snapped = true;
52  point.setY( res.y() );
53  }
54 
55  return point;
56 }
57 
58 QRectF QgsModelSnapper::snapRect( const QRectF &rect, double scaleFactor, bool &snapped, bool snapHorizontal, bool snapVertical ) const
59 {
60  snapped = false;
61  QRectF snappedRect = rect;
62 
63  bool snappedXToGrid = false;
64  bool snappedYToGrid = false;
65  QList< QPointF > points;
66  points << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight();
67  const QPointF res = snapPointsToGrid( points, scaleFactor, snappedXToGrid, snappedYToGrid );
68  if ( snappedXToGrid && snapVertical )
69  {
70  snapped = true;
71  snappedRect.translate( res.x(), 0 );
72  }
73  if ( snappedYToGrid && snapHorizontal )
74  {
75  snapped = true;
76  snappedRect.translate( 0, res.y() );
77  }
78 
79  return snappedRect;
80 }
81 
82 QRectF QgsModelSnapper::snapRectWithResize( const QRectF &rect, double scaleFactor, bool &snapped, bool snapHorizontal, bool snapVertical ) const
83 {
84  snapped = false;
85  QRectF snappedRect = rect;
86 
87  bool snappedXToGrid = false;
88  bool snappedYToGrid = false;
89  QPointF res = snapPointsToGrid( QList< QPointF >() << rect.topLeft(), scaleFactor, snappedXToGrid, snappedYToGrid );
90  if ( snappedXToGrid && snapVertical )
91  {
92  snapped = true;
93  snappedRect.setLeft( snappedRect.left() + res.x() );
94  }
95  if ( snappedYToGrid && snapHorizontal )
96  {
97  snapped = true;
98  snappedRect.setTop( snappedRect.top() + res.y() );
99  }
100  res = snapPointsToGrid( QList< QPointF >() << rect.bottomRight(), scaleFactor, snappedXToGrid, snappedYToGrid );
101  if ( snappedXToGrid && snapVertical )
102  {
103  snapped = true;
104  snappedRect.setRight( snappedRect.right() + res.x() );
105  }
106  if ( snappedYToGrid && snapHorizontal )
107  {
108  snapped = true;
109  snappedRect.setBottom( snappedRect.bottom() + res.y() );
110  }
111 
112  return snappedRect;
113 }
114 
115 QPointF QgsModelSnapper::snapPointToGrid( QPointF point, double scaleFactor, bool &snappedX, bool &snappedY ) const
116 {
117  const QPointF delta = snapPointsToGrid( QList< QPointF >() << point, scaleFactor, snappedX, snappedY );
118  return point + delta;
119 }
120 
121 QPointF QgsModelSnapper::snapPointsToGrid( const QList<QPointF> &points, double scaleFactor, bool &snappedX, bool &snappedY ) const
122 {
123  snappedX = false;
124  snappedY = false;
125  if ( !mSnapToGrid )
126  {
127  return QPointF( 0, 0 );
128  }
129 #if 0
130  const QgsLayoutGridSettings &grid = mLayout->gridSettings();
131  if ( grid.resolution().length() <= 0 )
132  return QPointF( 0, 0 );
133 #endif
134 
135  double deltaX = 0;
136  double deltaY = 0;
137  double smallestDiffX = std::numeric_limits<double>::max();
138  double smallestDiffY = std::numeric_limits<double>::max();
139  for ( const QPointF point : points )
140  {
141  //snap x coordinate
142  const double gridRes = 30; //mLayout->convertToLayoutUnits( grid.resolution() );
143  int xRatio = static_cast< int >( ( point.x() ) / gridRes + 0.5 ); //NOLINT
144  int yRatio = static_cast< int >( ( point.y() ) / gridRes + 0.5 ); //NOLINT
145 
146  const double xSnapped = xRatio * gridRes;
147  const double ySnapped = yRatio * gridRes;
148 
149  const double currentDiffX = std::fabs( xSnapped - point.x() );
150  if ( currentDiffX < smallestDiffX )
151  {
152  smallestDiffX = currentDiffX;
153  deltaX = xSnapped - point.x();
154  }
155 
156  const double currentDiffY = std::fabs( ySnapped - point.y() );
157  if ( currentDiffY < smallestDiffY )
158  {
159  smallestDiffY = currentDiffY;
160  deltaY = ySnapped - point.y();
161  }
162  }
163 
164  //convert snap tolerance from pixels to layout units
165  const double alignThreshold = mTolerance / scaleFactor;
166 
167  QPointF delta( 0, 0 );
168  if ( smallestDiffX <= alignThreshold )
169  {
170  //snap distance is inside of tolerance
171  snappedX = true;
172  delta.setX( deltaX );
173  }
174  if ( smallestDiffY <= alignThreshold )
175  {
176  //snap distance is inside of tolerance
177  snappedY = true;
178  delta.setY( deltaY );
179  }
180 
181  return delta;
182 }
Contains settings relating to the appearance, spacing and offset for layout grids.
QgsLayoutMeasurement resolution() const
Returns the page/snap grid resolution.
double length() const
Returns the length of the measurement.
int snapTolerance() const
Returns the snap tolerance (in pixels) to use when snapping.
void setSnapTolerance(int snapTolerance)
Sets the snap tolerance (in pixels) to use when snapping.
QPointF snapPointsToGrid(const QList< QPointF > &points, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a set of points to the grid.
QRectF snapRect(const QRectF &rect, double scaleFactor, bool &snapped, bool snapHorizontal=true, bool snapVertical=true) const
Snaps a layout coordinate rect.
QgsModelSnapper()
Constructor for QgsModelSnapper, attached to the specified layout.
QPointF snapPoint(QPointF point, double scaleFactor, bool &snapped, bool snapHorizontal=true, bool snapVertical=true) const
Snaps a layout coordinate point.
QRectF snapRectWithResize(const QRectF &rect, double scaleFactor, bool &snapped, bool snapHorizontal=true, bool snapVertical=true) const
Snaps a layout coordinate rect.
QPointF snapPointToGrid(QPointF point, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a layout coordinate point to the grid.
void setSnapToGrid(bool enabled)
Sets whether snapping to grid is enabled.