QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgspointcloudrendererpropertieswidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudrendererpropertieswidget.cpp
3 ---------------------
4 begin : November 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
16
17#include "qgis.h"
18#include "qgsapplication.h"
19#include "qgsfontbutton.h"
20#include "qgslogger.h"
25#include "qgspointcloudlayer.h"
30#include "qgsproject.h"
31#include "qgsprojectutils.h"
32#include "qgsstyle.h"
34#include "qgstextformatwidget.h"
35#include "qgsvirtualpointcloudprovider.h"
36
37#include <QString>
38
39#include "moc_qgspointcloudrendererpropertieswidget.cpp"
40
41using namespace Qt::StringLiterals;
42
43static bool initPointCloudRenderer( const QString &name, QgsPointCloudRendererWidgetFunc f, const QString &iconName = QString() )
44{
46 if ( !rendererAbstractMetadata )
47 return false;
48 QgsPointCloudRendererMetadata *rendererMetadata = dynamic_cast<QgsPointCloudRendererMetadata *>( rendererAbstractMetadata );
49 if ( !rendererMetadata )
50 return false;
51
52 rendererMetadata->setWidgetFunction( f );
53
54 if ( !iconName.isEmpty() )
55 {
56 rendererMetadata->setIcon( QgsApplication::getThemeIcon( iconName ) );
57 }
58
59 QgsDebugMsgLevel( "Set for " + name, 2 );
60 return true;
61}
62
63void QgsPointCloudRendererPropertiesWidget::initRendererWidgetFunctions()
64{
65 static bool sInitialized = false;
66 if ( sInitialized )
67 return;
68
69 initPointCloudRenderer( u"extent"_s, QgsPointCloudExtentRendererWidget::create, u"styleicons/pointcloudextent.svg"_s );
70 initPointCloudRenderer( u"rgb"_s, QgsPointCloudRgbRendererWidget::create, u"styleicons/multibandcolor.svg"_s );
71 initPointCloudRenderer( u"ramp"_s, QgsPointCloudAttributeByRampRendererWidget::create, u"styleicons/singlebandpseudocolor.svg"_s );
72 initPointCloudRenderer( u"classified"_s, QgsPointCloudClassifiedRendererWidget::create, u"styleicons/paletted.svg"_s );
73
74 sInitialized = true;
75}
76
78 : QgsMapLayerConfigWidget( layer, nullptr, parent )
79 , mLayer( layer )
80 , mStyle( style )
81{
82 setupUi( this );
83
84 layout()->setContentsMargins( 0, 0, 0, 0 );
85
86 // initialize registry's widget functions
87 initRendererWidgetFunctions();
88
90 const QStringList renderers = reg->renderersList();
91 for ( const QString &name : renderers )
92 {
94 cboRenderers->addItem( m->icon(), m->visibleName(), name );
95 }
96
97 cboRenderers->setCurrentIndex( -1 ); // set no current renderer
98
99 mPointStyleComboBox->addItem( tr( "Square" ), QVariant::fromValue( Qgis::PointCloudSymbol::Square ) );
100 mPointStyleComboBox->addItem( tr( "Circle" ), QVariant::fromValue( Qgis::PointCloudSymbol::Circle ) );
101
102 connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::rendererChanged );
103
104 connect( mBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
105 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
106
108
109 connect( mPointSizeSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
110 connect( mPointSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
111
112 mDrawOrderComboBox->addItem( tr( "Default" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::Default ) );
113 mDrawOrderComboBox->addItem( tr( "Bottom to Top" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::BottomToTop ) );
114 mDrawOrderComboBox->addItem( tr( "Top to Bottom" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::TopToBottom ) );
115
117 mMaxErrorSpinBox->setClearValue( 0.3 );
118
119 mHorizontalTriangleThresholdSpinBox->setClearValue( 5.0 );
121
122 connect( mMaxErrorSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
123 connect( mMaxErrorUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
124
125 connect( mPointStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
126 connect( mDrawOrderComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
127
128 connect( mTriangulateGroupBox, &QGroupBox::toggled, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
129 connect( mHorizontalTriangleCheckBox, &QCheckBox::clicked, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
130 connect( mHorizontalTriangleThresholdSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
131 connect( mHorizontalTriangleUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
132
133 // show virtual point cloud options only when vpc layer is selected
134 if ( !mLayer->dataProvider()->subIndexes().isEmpty() )
135 {
136 mLabelOptions->setDialogTitle( tr( "Customize label text" ) );
137 mLabelOptions->setText( tr( "Label format" ) );
138 connect( mLabels, &QCheckBox::stateChanged, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
139 connect( mLabelOptions, &QgsFontButton::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
140 mZoomOutOptions->addItem( tr( "Show Extents Only" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderExtents ) );
141
142 if ( const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mLayer->dataProvider() ) )
143 {
144 if ( vpcProvider->overview() )
145 {
146 mZoomOutOptions->addItem( tr( "Show Overview Only" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderOverview ) );
147 mZoomOutOptions->addItem( tr( "Show Extents Over Overview" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderOverviewAndExtents ) );
148
149 for ( auto it = mOverviewSwitchingScaleMap.constBegin(); it != mOverviewSwitchingScaleMap.constEnd(); ++it )
150 {
151 mOverviewSwitchingScale->addItem( it.value(), it.key() );
152 }
153 setOverviewSwitchingScale( 1.0 );
154 }
155 }
156 else
157 {
158 mZoomOutOptions->setEnabled( false );
159 mOverviewSwitchingScale->setEnabled( false );
160 }
161
162 connect( mOverviewSwitchingScale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
163
164 connect( mZoomOutOptions, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
165 switch ( mZoomOutOptions->currentData().value<Qgis::PointCloudZoomOutRenderBehavior>() )
166 {
168 mLabels->setEnabled( false );
169 mLabelOptions->setEnabled( false );
170 break;
173 mLabels->setEnabled( true );
174 mLabelOptions->setEnabled( true );
175 }
176 emitWidgetChanged();
177 } );
178 }
179 else
180 {
181 mVpcGroupBox->setVisible( false );
182 }
183
184 syncToLayer( layer );
185}
186
188{
189 mMapCanvas = context.mapCanvas();
190 mMessageBar = context.messageBar();
191 if ( mActiveWidget )
192 {
193 mActiveWidget->setContext( context );
194 }
195}
196
198{
199 mLayer = qobject_cast<QgsPointCloudLayer *>( layer );
200
201 mBlockChangedSignal = true;
202 mOpacityWidget->setOpacity( mLayer->opacity() );
203 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mLayer ) );
204 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
205
206 if ( mLayer->renderer() )
207 {
208 // set current renderer from layer
209 const QString rendererName = mLayer->renderer()->type();
210
211 const int rendererIdx = cboRenderers->findData( rendererName );
212 if ( cboRenderers->currentIndex() != rendererIdx )
213 {
214 cboRenderers->setCurrentIndex( rendererIdx );
215 }
216 else
217 {
218 rendererChanged();
219 }
220
221 // no renderer found... this mustn't happen
222 Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
223
224 mPointSizeSpinBox->setValue( mLayer->renderer()->pointSize() );
225 mPointSizeUnitWidget->setUnit( mLayer->renderer()->pointSizeUnit() );
226 mPointSizeUnitWidget->setMapUnitScale( mLayer->renderer()->pointSizeMapUnitScale() );
227
228 mPointStyleComboBox->setCurrentIndex( mPointStyleComboBox->findData( QVariant::fromValue( mLayer->renderer()->pointSymbol() ) ) );
229 mDrawOrderComboBox->setCurrentIndex( mDrawOrderComboBox->findData( QVariant::fromValue( mLayer->renderer()->drawOrder2d() ) ) );
230
231 mMaxErrorSpinBox->setValue( mLayer->renderer()->maximumScreenError() );
232 mMaxErrorUnitWidget->setUnit( mLayer->renderer()->maximumScreenErrorUnit() );
233 setOverviewSwitchingScale( mLayer->renderer()->overviewSwitchingScale() );
234
235 mTriangulateGroupBox->setChecked( mLayer->renderer()->renderAsTriangles() );
236 mHorizontalTriangleCheckBox->setChecked( mLayer->renderer()->horizontalTriangleFilter() );
237 mHorizontalTriangleThresholdSpinBox->setValue( mLayer->renderer()->horizontalTriangleFilterThreshold() );
238 mHorizontalTriangleUnitWidget->setUnit( mLayer->renderer()->horizontalTriangleFilterUnit() );
239
240 if ( !mLayer->dataProvider()->subIndexes().isEmpty() )
241 {
242 mLabels->setChecked( mLayer->renderer()->showLabels() );
243 mLabelOptions->setTextFormat( mLayer->renderer()->labelTextFormat() );
244 mZoomOutOptions->setCurrentIndex( mZoomOutOptions->findData( QVariant::fromValue( mLayer->renderer()->zoomOutBehavior() ) ) );
245 switch ( mLayer->renderer()->zoomOutBehavior() )
246 {
248 mLabels->setEnabled( false );
249 mLabelOptions->setEnabled( false );
250 break;
251 default:
252 mLabels->setEnabled( true );
253 mLabelOptions->setEnabled( true );
254 }
255 }
256 }
257
258 mBlockChangedSignal = false;
259}
260
262{
263 if ( mActiveWidget )
264 mActiveWidget->setDockMode( dockMode );
266}
267
269{
270 mLayer->setOpacity( mOpacityWidget->opacity() );
271 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
272
273 if ( mActiveWidget )
274 mLayer->setRenderer( mActiveWidget->renderer() );
275 else if ( !cboRenderers->currentData().toString().isEmpty() )
276 {
277 QDomElement elem;
278 if ( QgsPointCloudRendererAbstractMetadata *metadata = QgsApplication::pointCloudRendererRegistry()->rendererMetadata( cboRenderers->currentData().toString() ) )
279 {
280 mLayer->setRenderer( metadata->createRenderer( elem, QgsReadWriteContext() ) );
281 }
282 }
283
284 mLayer->renderer()->setPointSize( mPointSizeSpinBox->value() );
285 mLayer->renderer()->setPointSizeUnit( mPointSizeUnitWidget->unit() );
286 mLayer->renderer()->setPointSizeMapUnitScale( mPointSizeUnitWidget->getMapUnitScale() );
287
288 mLayer->renderer()->setPointSymbol( mPointStyleComboBox->currentData().value<Qgis::PointCloudSymbol>() );
289
290 mLayer->renderer()->setMaximumScreenError( mMaxErrorSpinBox->value() );
291 mLayer->renderer()->setMaximumScreenErrorUnit( mMaxErrorUnitWidget->unit() );
292 mLayer->renderer()->setDrawOrder2d( mDrawOrderComboBox->currentData().value<Qgis::PointCloudDrawOrder>() );
293
294 mLayer->renderer()->setRenderAsTriangles( mTriangulateGroupBox->isChecked() );
295 mLayer->renderer()->setHorizontalTriangleFilter( mHorizontalTriangleCheckBox->isChecked() );
296 mLayer->renderer()->setHorizontalTriangleFilterThreshold( mHorizontalTriangleThresholdSpinBox->value() );
297 mLayer->renderer()->setHorizontalTriangleFilterUnit( mHorizontalTriangleUnitWidget->unit() );
298
299 mLayer->renderer()->setShowLabels( mLabels->isChecked() );
300 mLayer->renderer()->setLabelTextFormat( mLabelOptions->textFormat() );
301 mLayer->renderer()->setZoomOutBehavior( mZoomOutOptions->currentData().value<Qgis::PointCloudZoomOutRenderBehavior>() );
302
303 mLayer->renderer()->setOverviewSwitchingScale( overviewSwitchingScale() );
304}
305
306void QgsPointCloudRendererPropertiesWidget::rendererChanged()
307{
308 if ( cboRenderers->currentIndex() == -1 )
309 {
310 QgsDebugError( u"No current item -- this should never happen!"_s );
311 return;
312 }
313
314 const QString rendererName = cboRenderers->currentData().toString();
315
316 //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
317 std::unique_ptr<QgsPointCloudRenderer> oldRenderer;
318 std::unique_ptr<QgsPointCloudRenderer> newRenderer;
319 if ( mActiveWidget )
320 newRenderer.reset( mActiveWidget->renderer() );
321
322 if ( newRenderer )
323 {
324 oldRenderer = std::move( newRenderer );
325 }
326 else
327 {
328 oldRenderer.reset( mLayer->renderer()->clone() );
329 }
330
331 // get rid of old active widget (if any)
332 if ( mActiveWidget )
333 {
334 stackedWidget->removeWidget( mActiveWidget );
335
336 delete mActiveWidget;
337 mActiveWidget = nullptr;
338 }
339
340 QgsPointCloudRendererWidget *widget = nullptr;
341 QgsPointCloudRendererAbstractMetadata *rendererMetadata = QgsApplication::pointCloudRendererRegistry()->rendererMetadata( rendererName );
342 if ( rendererMetadata )
343 widget = rendererMetadata->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
344 oldRenderer.reset();
345
346 if ( widget )
347 {
348 // instantiate the widget and set as active
349 mActiveWidget = widget;
350 stackedWidget->addWidget( mActiveWidget );
351 stackedWidget->setCurrentWidget( mActiveWidget );
352
353 if ( mMapCanvas || mMessageBar )
354 {
355 QgsSymbolWidgetContext context;
356 context.setMapCanvas( mMapCanvas );
357 context.setMessageBar( mMessageBar );
358 mActiveWidget->setContext( context );
359 }
360
363 widget->setDockMode( dockMode() );
364 }
365 else
366 {
367 // set default "no edit widget available" page
368 stackedWidget->setCurrentWidget( pageNoWidget );
369 }
370 emitWidgetChanged();
371}
372
373void QgsPointCloudRendererPropertiesWidget::emitWidgetChanged()
374{
375 if ( !mBlockChangedSignal )
376 emit widgetChanged();
377}
378
379void QgsPointCloudRendererPropertiesWidget::setOverviewSwitchingScale( double scale )
380{
381 mOverviewSwitchingScale->setCurrentIndex( mOverviewSwitchingScale->findData( scale ) );
382}
383
384double QgsPointCloudRendererPropertiesWidget::overviewSwitchingScale() const
385{
386 return mOverviewSwitchingScaleMap.key( mOverviewSwitchingScale->currentText() );
387}
PointCloudSymbol
Rendering symbols for point cloud points.
Definition qgis.h:4340
@ Circle
Renders points as circles.
Definition qgis.h:4342
@ Square
Renders points as squares.
Definition qgis.h:4341
PointCloudDrawOrder
Pointcloud rendering order for 2d views.
Definition qgis.h:4352
@ BottomToTop
Draw points with larger Z values last.
Definition qgis.h:4354
@ Default
Draw points in the order they are stored.
Definition qgis.h:4353
@ TopToBottom
Draw points with larger Z values first.
Definition qgis.h:4355
PointCloudZoomOutRenderBehavior
Point cloud zoom out options.
Definition qgis.h:6386
@ RenderOverviewAndExtents
Render point cloud extents over overview point cloud.
Definition qgis.h:6389
@ RenderExtents
Render only point cloud extents when zoomed out.
Definition qgis.h:6387
@ RenderOverview
Render overview point cloud when zoomed out.
Definition qgis.h:6388
@ Millimeters
Millimeters.
Definition qgis.h:5291
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5295
@ MapUnits
Map units.
Definition qgis.h:5292
@ Pixels
Pixels.
Definition qgis.h:5293
@ Inches
Inches.
Definition qgis.h:5296
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5298
static QgsPointCloudRendererRegistry * pointCloudRendererRegistry()
Returns the application's point cloud renderer registry, used for managing point cloud layer 2D rende...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
void changed()
Emitted when the widget's text format settings are changed.
QgsMapLayerConfigWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
A panel widget that can be shown in the map style dock.
Base class for all map layer types.
Definition qgsmaplayer.h:83
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
void widgetChanged()
Emitted when the widget state changes.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
Represents a map layer supporting display of point clouds.
Stores metadata about one point cloud renderer class.
void setIcon(const QIcon &icon)
Sets an icon representing the renderer.
virtual QgsPointCloudRendererWidget * createRendererWidget(QgsPointCloudLayer *layer, QgsStyle *style, QgsPointCloudRenderer *oldRenderer)
Returns new instance of settings widget for the renderer.
Convenience metadata class that uses static functions to create point cloud renderer and its widget.
void setWidgetFunction(QgsPointCloudRendererWidgetFunc f)
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the widget is shown, e.g., the associated map canvas and expression context...
QgsPointCloudRendererPropertiesWidget(QgsPointCloudLayer *layer, QgsStyle *style, QWidget *parent=nullptr)
Constructor for QgsPointCloudRendererPropertiesWidget, associated with the specified layer and style ...
void syncToLayer(QgsMapLayer *layer) final
Reset to original (vector layer) values.
void setDockMode(bool dockMode) final
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
Registry of 2D renderers for point clouds.
QgsPointCloudRendererAbstractMetadata * rendererMetadata(const QString &rendererName)
Returns the metadata for a specified renderer.
QStringList renderersList() const
Returns a list of available renderers.
static bool layerIsContainedInGroupLayer(QgsProject *project, QgsMapLayer *layer)
Returns true if the specified layer is a child layer from any QgsGroupLayer in the given project.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A container for the context for various read/write operations on objects.
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:89
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QgsPointCloudRendererWidget *(* QgsPointCloudRendererWidgetFunc)(QgsPointCloudLayer *, QgsStyle *, QgsPointCloudRenderer *)