QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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
107 mPointSizeUnitWidget->setUnits(
109 );
110
111 connect( mPointSizeSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
112 connect( mPointSizeUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
113
114 mDrawOrderComboBox->addItem( tr( "Default" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::Default ) );
115 mDrawOrderComboBox->addItem( tr( "Bottom to Top" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::BottomToTop ) );
116 mDrawOrderComboBox->addItem( tr( "Top to Bottom" ), QVariant::fromValue( Qgis::PointCloudDrawOrder::TopToBottom ) );
117
118 mMaxErrorUnitWidget->setUnits(
120 );
121 mMaxErrorSpinBox->setClearValue( 0.3 );
122
123 mHorizontalTriangleThresholdSpinBox->setClearValue( 5.0 );
124 mHorizontalTriangleUnitWidget->setUnits(
126 );
127
128 connect( mMaxErrorSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
129 connect( mMaxErrorUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
130
131 connect( mPointStyleComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
132 connect( mDrawOrderComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
133
134 connect( mTriangulateGroupBox, &QGroupBox::toggled, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
135 connect( mHorizontalTriangleCheckBox, &QCheckBox::clicked, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
136 connect( mHorizontalTriangleThresholdSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
137 connect( mHorizontalTriangleUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
138
139 // show virtual point cloud options only when vpc layer is selected
140 if ( !mLayer->dataProvider()->subIndexes().isEmpty() )
141 {
142 mLabelOptions->setDialogTitle( tr( "Customize label text" ) );
143 mLabelOptions->setText( tr( "Label format" ) );
144 connect( mLabels, &QCheckBox::stateChanged, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
145 connect( mLabelOptions, &QgsFontButton::changed, this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
146 mZoomOutOptions->addItem( tr( "Show Extents Only" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderExtents ) );
147
148 if ( const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mLayer->dataProvider() ) )
149 {
150 if ( vpcProvider->overview() )
151 {
152 mZoomOutOptions->addItem( tr( "Show Overview Only" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderOverview ) );
153 mZoomOutOptions->addItem( tr( "Show Extents Over Overview" ), QVariant::fromValue( Qgis::PointCloudZoomOutRenderBehavior::RenderOverviewAndExtents ) );
154 }
155
156 for ( auto it = mOverviewSwitchingScaleMap.constBegin(); it != mOverviewSwitchingScaleMap.constEnd(); ++it )
157 {
158 mOverviewSwitchingScale->addItem( it.value(), it.key() );
159 }
160 setOverviewSwitchingScale( 1.0 );
161 }
162 else
163 {
164 mZoomOutOptions->setEnabled( false );
165 mOverviewSwitchingScale->setEnabled( false );
166 }
167
168 connect( mOverviewSwitchingScale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloudRendererPropertiesWidget::emitWidgetChanged );
169
170 connect( mZoomOutOptions, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
171 switch ( mZoomOutOptions->currentData().value<Qgis::PointCloudZoomOutRenderBehavior>() )
172 {
174 mLabels->setEnabled( false );
175 mLabelOptions->setEnabled( false );
176 break;
179 mLabels->setEnabled( true );
180 mLabelOptions->setEnabled( true );
181 }
182 emitWidgetChanged();
183 } );
184 }
185 else
186 {
187 mVpcGroupBox->setVisible( false );
188 }
189
190 syncToLayer( layer );
191}
192
194{
195 mMapCanvas = context.mapCanvas();
196 mMessageBar = context.messageBar();
197 if ( mActiveWidget )
198 {
199 mActiveWidget->setContext( context );
200 }
201}
202
204{
205 mLayer = qobject_cast<QgsPointCloudLayer *>( layer );
206
207 mBlockChangedSignal = true;
208 mOpacityWidget->setOpacity( mLayer->opacity() );
209 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mLayer ) );
210 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
211
212 if ( mLayer->renderer() )
213 {
214 // set current renderer from layer
215 const QString rendererName = mLayer->renderer()->type();
216
217 const int rendererIdx = cboRenderers->findData( rendererName );
218 if ( cboRenderers->currentIndex() != rendererIdx )
219 {
220 cboRenderers->setCurrentIndex( rendererIdx );
221 }
222 else
223 {
224 rendererChanged();
225 }
226
227 // no renderer found... this mustn't happen
228 Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
229
230 mPointSizeSpinBox->setValue( mLayer->renderer()->pointSize() );
231 mPointSizeUnitWidget->setUnit( mLayer->renderer()->pointSizeUnit() );
232 mPointSizeUnitWidget->setMapUnitScale( mLayer->renderer()->pointSizeMapUnitScale() );
233
234 mPointStyleComboBox->setCurrentIndex( mPointStyleComboBox->findData( QVariant::fromValue( mLayer->renderer()->pointSymbol() ) ) );
235 mDrawOrderComboBox->setCurrentIndex( mDrawOrderComboBox->findData( QVariant::fromValue( mLayer->renderer()->drawOrder2d() ) ) );
236
237 mMaxErrorSpinBox->setValue( mLayer->renderer()->maximumScreenError() );
238 mMaxErrorUnitWidget->setUnit( mLayer->renderer()->maximumScreenErrorUnit() );
239 setOverviewSwitchingScale( mLayer->renderer()->overviewSwitchingScale() );
240
241 mTriangulateGroupBox->setChecked( mLayer->renderer()->renderAsTriangles() );
242 mHorizontalTriangleCheckBox->setChecked( mLayer->renderer()->horizontalTriangleFilter() );
243 mHorizontalTriangleThresholdSpinBox->setValue( mLayer->renderer()->horizontalTriangleFilterThreshold() );
244 mHorizontalTriangleUnitWidget->setUnit( mLayer->renderer()->horizontalTriangleFilterUnit() );
245
246 if ( !mLayer->dataProvider()->subIndexes().isEmpty() )
247 {
248 mLabels->setChecked( mLayer->renderer()->showLabels() );
249 mLabelOptions->setTextFormat( mLayer->renderer()->labelTextFormat() );
250 mZoomOutOptions->setCurrentIndex( mZoomOutOptions->findData( QVariant::fromValue( mLayer->renderer()->zoomOutBehavior() ) ) );
251 switch ( mLayer->renderer()->zoomOutBehavior() )
252 {
254 mLabels->setEnabled( false );
255 mLabelOptions->setEnabled( false );
256 break;
257 default:
258 mLabels->setEnabled( true );
259 mLabelOptions->setEnabled( true );
260 }
261 }
262 }
263
264 mBlockChangedSignal = false;
265}
266
268{
269 if ( mActiveWidget )
270 mActiveWidget->setDockMode( dockMode );
272}
273
275{
276 mLayer->setOpacity( mOpacityWidget->opacity() );
277 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
278
279 if ( mActiveWidget )
280 mLayer->setRenderer( mActiveWidget->renderer() );
281 else if ( !cboRenderers->currentData().toString().isEmpty() )
282 {
283 QDomElement elem;
284 if ( QgsPointCloudRendererAbstractMetadata *metadata = QgsApplication::pointCloudRendererRegistry()->rendererMetadata( cboRenderers->currentData().toString() ) )
285 {
286 mLayer->setRenderer( metadata->createRenderer( elem, QgsReadWriteContext() ) );
287 }
288 }
289
290 mLayer->renderer()->setPointSize( mPointSizeSpinBox->value() );
291 mLayer->renderer()->setPointSizeUnit( mPointSizeUnitWidget->unit() );
292 mLayer->renderer()->setPointSizeMapUnitScale( mPointSizeUnitWidget->getMapUnitScale() );
293
294 mLayer->renderer()->setPointSymbol( mPointStyleComboBox->currentData().value<Qgis::PointCloudSymbol>() );
295
296 mLayer->renderer()->setMaximumScreenError( mMaxErrorSpinBox->value() );
297 mLayer->renderer()->setMaximumScreenErrorUnit( mMaxErrorUnitWidget->unit() );
298 mLayer->renderer()->setDrawOrder2d( mDrawOrderComboBox->currentData().value<Qgis::PointCloudDrawOrder>() );
299
300 mLayer->renderer()->setRenderAsTriangles( mTriangulateGroupBox->isChecked() );
301 mLayer->renderer()->setHorizontalTriangleFilter( mHorizontalTriangleCheckBox->isChecked() );
302 mLayer->renderer()->setHorizontalTriangleFilterThreshold( mHorizontalTriangleThresholdSpinBox->value() );
303 mLayer->renderer()->setHorizontalTriangleFilterUnit( mHorizontalTriangleUnitWidget->unit() );
304
305 mLayer->renderer()->setShowLabels( mLabels->isChecked() );
306 mLayer->renderer()->setLabelTextFormat( mLabelOptions->textFormat() );
307 mLayer->renderer()->setZoomOutBehavior( mZoomOutOptions->currentData().value<Qgis::PointCloudZoomOutRenderBehavior>() );
308
309 mLayer->renderer()->setOverviewSwitchingScale( overviewSwitchingScale() );
310}
311
312void QgsPointCloudRendererPropertiesWidget::rendererChanged()
313{
314 if ( cboRenderers->currentIndex() == -1 )
315 {
316 QgsDebugError( u"No current item -- this should never happen!"_s );
317 return;
318 }
319
320 const QString rendererName = cboRenderers->currentData().toString();
321
322 //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
323 std::unique_ptr<QgsPointCloudRenderer> oldRenderer;
324 std::unique_ptr<QgsPointCloudRenderer> newRenderer;
325 if ( mActiveWidget )
326 newRenderer.reset( mActiveWidget->renderer() );
327
328 if ( newRenderer )
329 {
330 oldRenderer = std::move( newRenderer );
331 }
332 else
333 {
334 oldRenderer.reset( mLayer->renderer()->clone() );
335 }
336
337 // get rid of old active widget (if any)
338 if ( mActiveWidget )
339 {
340 stackedWidget->removeWidget( mActiveWidget );
341
342 delete mActiveWidget;
343 mActiveWidget = nullptr;
344 }
345
346 QgsPointCloudRendererWidget *widget = nullptr;
347 QgsPointCloudRendererAbstractMetadata *rendererMetadata = QgsApplication::pointCloudRendererRegistry()->rendererMetadata( rendererName );
348 if ( rendererMetadata )
349 widget = rendererMetadata->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
350 oldRenderer.reset();
351
352 if ( widget )
353 {
354 // instantiate the widget and set as active
355 mActiveWidget = widget;
356 stackedWidget->addWidget( mActiveWidget );
357 stackedWidget->setCurrentWidget( mActiveWidget );
358
359 if ( mMapCanvas || mMessageBar )
360 {
361 QgsSymbolWidgetContext context;
362 context.setMapCanvas( mMapCanvas );
363 context.setMessageBar( mMessageBar );
364 mActiveWidget->setContext( context );
365 }
366
369 widget->setDockMode( dockMode() );
370 }
371 else
372 {
373 // set default "no edit widget available" page
374 stackedWidget->setCurrentWidget( pageNoWidget );
375 }
376 emitWidgetChanged();
377}
378
379void QgsPointCloudRendererPropertiesWidget::emitWidgetChanged()
380{
381 if ( !mBlockChangedSignal )
382 emit widgetChanged();
383}
384
385void QgsPointCloudRendererPropertiesWidget::setOverviewSwitchingScale( double scale )
386{
387 mOverviewSwitchingScale->setCurrentIndex( mOverviewSwitchingScale->findData( scale ) );
388}
389
390double QgsPointCloudRendererPropertiesWidget::overviewSwitchingScale() const
391{
392 return mOverviewSwitchingScaleMap.key( mOverviewSwitchingScale->currentText() );
393}
PointCloudSymbol
Rendering symbols for point cloud points.
Definition qgis.h:4387
@ Circle
Renders points as circles.
Definition qgis.h:4389
@ Square
Renders points as squares.
Definition qgis.h:4388
PointCloudDrawOrder
Pointcloud rendering order for 2d views.
Definition qgis.h:4399
@ BottomToTop
Draw points with larger Z values last.
Definition qgis.h:4401
@ Default
Draw points in the order they are stored.
Definition qgis.h:4400
@ TopToBottom
Draw points with larger Z values first.
Definition qgis.h:4402
PointCloudZoomOutRenderBehavior
Point cloud zoom out options.
Definition qgis.h:6443
@ RenderOverviewAndExtents
Render point cloud extents over overview point cloud.
Definition qgis.h:6446
@ RenderExtents
Render only point cloud extents when zoomed out.
Definition qgis.h:6444
@ RenderOverview
Render overview point cloud when zoomed out.
Definition qgis.h:6445
@ Millimeters
Millimeters.
Definition qgis.h:5341
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5345
@ MapUnits
Map units.
Definition qgis.h:5342
@ Pixels
Pixels.
Definition qgis.h:5343
@ Inches
Inches.
Definition qgis.h:5346
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5348
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 *)