QGIS API Documentation 3.99.0-Master (7d2ca374f2d)
Loading...
Searching...
No Matches
qgsbeziermarker.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbeziermarker.cpp - Visualization for Poly-Bézier curve digitizing
3 ---------------------
4 begin : December 2025
5 copyright : (C) 2025 by Loïc Bartoletti
6 Adapted from BezierEditing plugin work by Takayuki Mizutani
7 email : loic dot bartoletti at oslandia dot com
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
18
19#include "qgsbeziermarker.h"
20
21#include "qgsmapcanvas.h"
22#include "qgsrubberband.h"
25#include "qgsvertexmarker.h"
26
27QgsBezierMarker::QgsBezierMarker( QgsMapCanvas *canvas, QObject *parent )
28 : QObject( parent )
29 , mCanvas( canvas )
30 , mCurveRubberBand( new QgsRubberBand( canvas, Qgis::GeometryType::Line ) )
31{
32 mCurveRubberBand->setColor( QgsSettingsRegistryCore::settingsDigitizingLineColor->value() );
33 mCurveRubberBand->setWidth( QgsSettingsRegistryCore::settingsDigitizingLineWidth->value() );
34}
35
36QgsBezierMarker::~QgsBezierMarker()
37{
38 qDeleteAll( mAnchorMarkers );
39 qDeleteAll( mHandleMarkers );
40}
41
42QgsVertexMarker *QgsBezierMarker::createAnchorMarker()
43{
44 QgsVertexMarker *marker = new QgsVertexMarker( mCanvas );
46 marker->setIconSize( MarkerConfig::AnchorMarkerSize );
47 const QColor snapColor = QgsSettingsRegistryCore::settingsDigitizingSnapColor->value();
48 marker->setColor( snapColor );
49 QColor fillColor = snapColor;
50 fillColor.setAlpha( MarkerConfig::FillAlpha );
51 marker->setFillColor( fillColor );
52 marker->setPenWidth( MarkerConfig::MarkerPenWidth );
53 return marker;
54}
55
56QgsVertexMarker *QgsBezierMarker::createHandleMarker()
57{
58 QgsVertexMarker *marker = new QgsVertexMarker( mCanvas );
60 marker->setIconSize( MarkerConfig::HandleMarkerSize );
62 int h, s, v, a;
63 lineColor.getHsv( &h, &s, &v, &a );
64 QColor handleColor = QColor::fromHsv( ( h + 120 ) % 360, s, v, a );
65 marker->setColor( handleColor );
66 QColor fillColor = handleColor;
67 fillColor.setAlpha( MarkerConfig::FillAlpha );
68 marker->setFillColor( fillColor );
69 marker->setPenWidth( MarkerConfig::MarkerPenWidth );
70 return marker;
71}
72
73QObjectUniquePtr<QgsRubberBand> QgsBezierMarker::createHandleLine()
74{
77 lineColor.setAlpha( MarkerConfig::HandleLineAlpha );
78 rb->setColor( lineColor );
79 rb->setWidth( MarkerConfig::HandleLineWidth );
80 rb->setLineStyle( Qt::DashLine );
81 return rb;
82}
83
84void QgsBezierMarker::updateFromData( const QgsBezierData &data )
85{
86 updateAnchorMarkers( data );
87 updateHandleMarkers( data );
88 updateHandleLines( data );
89 updateCurve( data );
90}
91
92void QgsBezierMarker::updateCurve( const QgsBezierData &data )
93{
94 mCurveRubberBand->reset( Qgis::GeometryType::Line );
95
96 if ( data.anchorCount() < 1 )
97 return;
98
99 QgsPointSequence points = data.interpolateLine();
100
101 for ( const QgsPoint &pt : std::as_const( points ) )
102 {
103 mCurveRubberBand->addPoint( QgsPointXY( pt ) );
104 }
105
106 mCurveRubberBand->setVisible( mVisible );
107}
108
109void QgsBezierMarker::updateAnchorMarkers( const QgsBezierData &data )
110{
111 while ( static_cast<int>( mAnchorMarkers.size() ) < data.anchorCount() )
112 {
113 mAnchorMarkers.push_back( createAnchorMarker() );
114 }
115 while ( static_cast<int>( mAnchorMarkers.size() ) > data.anchorCount() )
116 {
117 delete mAnchorMarkers.back();
118 mAnchorMarkers.pop_back();
119 }
120
121 const QColor snapColor = QgsSettingsRegistryCore::settingsDigitizingSnapColor->value();
122 QColor snapFillColor = snapColor;
123 snapFillColor.setAlpha( 100 );
124
125 for ( int i = 0; i < data.anchorCount(); ++i )
126 {
127 const QgsPoint &anchor = data.anchor( i );
128 mAnchorMarkers[i]->setCenter( QgsPointXY( anchor ) );
129 mAnchorMarkers[i]->setVisible( mVisible );
130
131 if ( i == mHighlightedAnchor )
132 {
133 const QColor selColor = mCanvas->selectionColor();
134 mAnchorMarkers[i]->setColor( selColor );
135 QColor selFillColor = selColor;
136 selFillColor.setAlpha( MarkerConfig::SelectionAlpha );
137 mAnchorMarkers[i]->setFillColor( selFillColor );
138 }
139 else
140 {
141 mAnchorMarkers[i]->setColor( snapColor );
142 mAnchorMarkers[i]->setFillColor( snapFillColor );
143 }
144 }
145}
146
147void QgsBezierMarker::updateHandleMarkers( const QgsBezierData &data )
148{
149 while ( static_cast<int>( mHandleMarkers.size() ) < data.handleCount() )
150 {
151 mHandleMarkers.push_back( createHandleMarker() );
152 }
153 while ( static_cast<int>( mHandleMarkers.size() ) > data.handleCount() )
154 {
155 delete mHandleMarkers.back();
156 mHandleMarkers.pop_back();
157 }
158
160 int h, s, v, a;
161 lineColor.getHsv( &h, &s, &v, &a );
162 QColor handleColor = QColor::fromHsv( ( h + 120 ) % 360, s, v, a );
163 QColor handleFillColor = handleColor;
164 handleFillColor.setAlpha( 100 );
165
166 for ( int i = 0; i < data.handleCount(); ++i )
167 {
168 const QgsPoint &handle = data.handle( i );
169 const int anchorIndex = i / 2;
170 if ( anchorIndex >= data.anchorCount() )
171 {
172 mHandleMarkers[i]->setVisible( false );
173 continue;
174 }
175 const QgsPoint &anchor = data.anchor( anchorIndex );
176
177 const bool isRetracted = qgsDoubleNear( handle.x(), anchor.x() ) && qgsDoubleNear( handle.y(), anchor.y() );
178
179 mHandleMarkers[i]->setCenter( QgsPointXY( handle ) );
180 mHandleMarkers[i]->setVisible( mVisible && mHandlesVisible && !isRetracted );
181
182 if ( i == mHighlightedHandle )
183 {
184 const QColor selColor = mCanvas->selectionColor();
185 mHandleMarkers[i]->setColor( selColor );
186 QColor selFillColor = selColor;
187 selFillColor.setAlpha( MarkerConfig::SelectionAlpha );
188 mHandleMarkers[i]->setFillColor( selFillColor );
189 }
190 else
191 {
192 mHandleMarkers[i]->setColor( handleColor );
193 mHandleMarkers[i]->setFillColor( handleFillColor );
194 }
195 }
196}
197
198void QgsBezierMarker::updateHandleLines( const QgsBezierData &data )
199{
200 while ( static_cast<int>( mHandleLines.size() ) < data.handleCount() )
201 {
202 mHandleLines.push_back( createHandleLine() );
203 }
204 while ( static_cast<int>( mHandleLines.size() ) > data.handleCount() )
205 {
206 mHandleLines.pop_back();
207 }
208
209 for ( int i = 0; i < data.handleCount(); ++i )
210 {
211 mHandleLines[i]->reset( Qgis::GeometryType::Line );
212
213 // Reapply style properties after reset
215 lineColor.setAlpha( MarkerConfig::HandleLineAlpha );
216 mHandleLines[i]->setColor( lineColor );
217 mHandleLines[i]->setWidth( MarkerConfig::HandleLineWidth );
218 mHandleLines[i]->setLineStyle( Qt::DashLine );
219
220 const QgsPoint &handle = data.handle( i );
221 const int anchorIndex = i / 2;
222 if ( anchorIndex >= data.anchorCount() )
223 {
224 mHandleLines[i]->setVisible( false );
225 continue;
226 }
227 const QgsPoint &anchor = data.anchor( anchorIndex );
228
229 const bool isRetracted = qgsDoubleNear( handle.x(), anchor.x() ) && qgsDoubleNear( handle.y(), anchor.y() );
230
231 if ( !isRetracted )
232 {
233 mHandleLines[i]->addPoint( QgsPointXY( anchor ) );
234 mHandleLines[i]->addPoint( QgsPointXY( handle ) );
235 }
236 }
237}
238
239void QgsBezierMarker::setVisible( bool visible )
240{
241 mVisible = visible;
242
243 for ( const auto &marker : mAnchorMarkers )
244 marker->setVisible( visible );
245
246 for ( const auto &marker : mHandleMarkers )
247 marker->setVisible( visible && mHandlesVisible );
248
249 for ( const auto &rb : mHandleLines )
250 {
251 if ( rb->numberOfVertices() > 0 )
252 rb->setVisible( visible && mHandlesVisible );
253 else
254 rb->setVisible( false );
255 }
256
257 mCurveRubberBand->setVisible( visible );
258}
259
260void QgsBezierMarker::setHandlesVisible( bool visible )
261{
262 mHandlesVisible = visible;
263
264 for ( const auto &marker : mHandleMarkers )
265 marker->setVisible( mVisible && visible );
266
267 for ( const auto &rb : mHandleLines )
268 {
269 if ( rb->numberOfVertices() > 0 )
270 rb->setVisible( mVisible && visible );
271 else
272 rb->setVisible( false );
273 }
274}
275
276void QgsBezierMarker::clear()
277{
278 qDeleteAll( mAnchorMarkers );
279 mAnchorMarkers.clear();
280 qDeleteAll( mHandleMarkers );
281 mHandleMarkers.clear();
282 mHandleLines.clear();
283
284 if ( mCurveRubberBand )
285 mCurveRubberBand->reset( Qgis::GeometryType::Line );
286
287 mHighlightedAnchor = -1;
288 mHighlightedHandle = -1;
289}
290
291void QgsBezierMarker::setHighlightedAnchor( int idx )
292{
293 mHighlightedAnchor = idx;
294}
295
296void QgsBezierMarker::setHighlightedHandle( int idx )
297{
298 mHighlightedHandle = idx;
299}
300
302
303#include "moc_qgsbeziermarker.cpp"
Keeps a pointer to a QObject and deletes it whenever this object is deleted.
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:59
@ Line
Lines.
Definition qgis.h:378
Map canvas is a class for displaying all GIS data types on a canvas.
Represents a 2D point.
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double x
Definition qgspoint.h:56
double y
Definition qgspoint.h:57
Responsible for drawing transient features (e.g.
static const QgsSettingsEntryInteger * settingsDigitizingLineWidth
Settings entry digitizing line width.
static const QgsSettingsEntryColor * settingsDigitizingSnapColor
Settings entry digitizing snap color.
static const QgsSettingsEntryColor * settingsDigitizingLineColor
Settings entry digitizing line color.
A map canvas item for marking vertices of features using e.g.
void setFillColor(const QColor &color)
Sets the fill color for the marker.
void setPenWidth(int width)
void setIconSize(int iconSize)
void setIconType(int iconType)
void setColor(const QColor &color)
Sets the stroke color for the marker.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6950
QVector< QgsPoint > QgsPointSequence