QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgspointcloudlayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointcloudlayer.cpp
3 --------------------
4 begin : October 2020
5 copyright : (C) 2020 by Peter Petrik
6 email : zilolv at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgspointcloudlayer.h"
19
21#include "qgsapplication.h"
22#include "qgseventtracing.h"
24#include "qgslogger.h"
25#include "qgsmaplayerfactory.h"
26#include "qgsmaplayerlegend.h"
27#include "qgsmessagelog.h"
28#include "qgspainting.h"
31#include "qgspointcloudindex.h"
42#include "qgsproviderregistry.h"
43#include "qgsrectangle.h"
44#include "qgsruntimeprofiler.h"
45#include "qgstaskmanager.h"
46#include "qgsthreadingutils.h"
47#include "qgsvirtualpointcloudprovider.h"
48#include "qgsxmlutils.h"
49
50#include <QString>
51#include <QUrl>
52
53#include "moc_qgspointcloudlayer.cpp"
54
55using namespace Qt::StringLiterals;
56
57QgsPointCloudLayer::QgsPointCloudLayer( const QString &uri, const QString &baseName, const QString &providerLib, const QgsPointCloudLayer::LayerOptions &options )
58 : QgsMapLayer( Qgis::LayerType::PointCloud, baseName, uri )
59 , mElevationProperties( new QgsPointCloudLayerElevationProperties( this ) )
60 , mLayerOptions( options )
61{
62 if ( !uri.isEmpty() && !providerLib.isEmpty() )
63 {
64 const QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
65 Qgis::DataProviderReadFlags providerFlags;
66 if ( options.loadDefaultStyle )
67 {
68 providerFlags |= Qgis::DataProviderReadFlag::LoadDefaultStyle;
69 }
70 setDataSource( uri, baseName, providerLib, providerOptions, providerFlags );
71 }
72
75 connect( undoStack(), &QUndoStack::indexChanged, this, &QgsMapLayer::layerModified );
76 connect( this, &QgsMapLayer::layerModified, this, [this] { triggerRepaint(); } );
77}
78
80{
81 if ( QgsTask *task = QgsApplication::taskManager()->task( mStatsCalculationTask ) )
82 {
83 mStatsCalculationTask = 0;
84 task->cancel();
85 task->waitForFinished();
86 }
87}
88
90{
92
93 QgsPointCloudLayer *layer = new QgsPointCloudLayer( source(), name(), mProviderKey, mLayerOptions );
94 QgsMapLayer::clone( layer );
95
96 if ( mRenderer )
97 layer->setRenderer( mRenderer->clone() );
98
99 layer->mElevationProperties = mElevationProperties->clone();
100 layer->mElevationProperties->setParent( layer );
101
102 layer->mLayerOptions = mLayerOptions;
103 layer->mSync3DRendererTo2DRenderer = mSync3DRendererTo2DRenderer;
104
105 return layer;
106}
107
109{
111
112 if ( !mDataProvider )
113 return QgsRectangle();
114
115 return mDataProvider->extent();
116}
117
119{
121
122 if ( mRenderer->type() != "extent"_L1 )
123 loadIndexesForRenderContext( rendererContext );
124
125 return new QgsPointCloudLayerRenderer( this, rendererContext );
126}
127
129{
131
132 if ( mElevationProperties && mElevationProperties->type() == Qgis::PointCloudProfileType::TriangulatedSurface )
133 {
134 return new QgsTriangulatedPointCloudLayerProfileGenerator( this, request );
135 }
136
137 return new QgsPointCloudLayerProfileGenerator( this, request );
138}
139
146
148{
150
151 return mDataProvider.get();
152}
153
154bool QgsPointCloudLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
155{
157
158 // create provider
159 const QDomNode pkeyNode = layerNode.namedItem( u"provider"_s );
160 mProviderKey = pkeyNode.toElement().text();
161
163 {
164 const QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
166 // read extent
168 {
169 const QDomNode extentNode = layerNode.namedItem( u"extent"_s );
170 if ( !extentNode.isNull() )
171 {
172 // get the extent
173 const QgsRectangle mbr = QgsXmlUtils::readRectangle( extentNode.toElement() );
174
175 // store the extent
176 setExtent( mbr );
177 }
178 }
179
181 const QDomNode subset = layerNode.namedItem( u"subset"_s );
182 const QString subsetText = subset.toElement().text();
183 if ( !subsetText.isEmpty() )
184 setSubsetString( subsetText );
185 }
186
187 if ( !isValid() )
188 {
189 return false;
190 }
191
192 QString errorMsg;
193 if ( !readSymbology( layerNode, errorMsg, context ) )
194 return false;
195
196 readStyleManager( layerNode );
197 return true;
198}
199
200bool QgsPointCloudLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
201{
203
204 QDomElement mapLayerNode = layerNode.toElement();
205 mapLayerNode.setAttribute( u"type"_s, QgsMapLayerFactory::typeToString( Qgis::LayerType::PointCloud ) );
206
207 if ( !subsetString().isEmpty() )
208 {
209 QDomElement subset = doc.createElement( u"subset"_s );
210 const QDomText subsetText = doc.createTextNode( subsetString() );
211 subset.appendChild( subsetText );
212 layerNode.appendChild( subset );
213 }
214 if ( mDataProvider )
215 {
216 QDomElement provider = doc.createElement( u"provider"_s );
217 const QDomText providerText = doc.createTextNode( providerType() );
218 provider.appendChild( providerText );
219 layerNode.appendChild( provider );
220 }
221
222 writeStyleManager( layerNode, doc );
223
224 QString errorMsg;
225 return writeSymbology( layerNode, doc, errorMsg, context );
226}
227
228bool QgsPointCloudLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
229{
231
232 const QDomElement elem = node.toElement();
233
234 readCommonStyle( elem, context, categories );
235
236 readStyle( node, errorMessage, context, categories );
237
238 if ( categories.testFlag( CustomProperties ) )
239 readCustomProperties( node, u"variable"_s );
240
241 if ( categories.testFlag( Legend ) )
242 {
243 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
244
245 const QDomElement legendElem = node.firstChildElement( u"legend"_s );
246 if ( QgsMapLayerLegend *l = legend(); l && !legendElem.isNull() )
247 {
248 l->readXml( legendElem, context );
249 }
250 }
251
252 return true;
253}
254
255bool QgsPointCloudLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
256{
258
259 bool result = true;
260
261 if ( categories.testFlag( Symbology3D ) )
262 {
263 bool ok;
264 bool sync = node.attributes().namedItem( u"sync3DRendererTo2DRenderer"_s ).nodeValue().toInt( &ok );
265 if ( ok )
267 }
268
269 if ( categories.testFlag( Symbology ) )
270 {
271 QDomElement rendererElement = node.firstChildElement( u"renderer"_s );
272 if ( !rendererElement.isNull() )
273 {
274 std::unique_ptr< QgsPointCloudRenderer > r( QgsPointCloudRenderer::load( rendererElement, context ) );
275 if ( r )
276 {
277 setRenderer( r.release() );
278 }
279 else
280 {
281 result = false;
282 }
283 }
284 // make sure layer has a renderer - if none exists, fallback to a default renderer
285 if ( !mRenderer )
286 {
288 }
289 }
290
291 if ( categories.testFlag( Symbology ) )
292 {
293 // get and set the blend mode if it exists
294 const QDomNode blendModeNode = node.namedItem( u"blendMode"_s );
295 if ( !blendModeNode.isNull() )
296 {
297 const QDomElement e = blendModeNode.toElement();
298 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
299 }
300 }
301
302 // get and set the layer transparency and scale visibility if they exists
303 if ( categories.testFlag( Rendering ) )
304 {
305 const QDomNode layerOpacityNode = node.namedItem( u"layerOpacity"_s );
306 if ( !layerOpacityNode.isNull() )
307 {
308 const QDomElement e = layerOpacityNode.toElement();
309 setOpacity( e.text().toDouble() );
310 }
311
312 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( u"hasScaleBasedVisibilityFlag"_s ).nodeValue() == '1' };
313 setScaleBasedVisibility( hasScaleBasedVisibiliy );
314 bool ok;
315 const double maxScale { node.attributes().namedItem( u"maxScale"_s ).nodeValue().toDouble( &ok ) };
316 if ( ok )
317 {
318 setMaximumScale( maxScale );
319 }
320 const double minScale { node.attributes().namedItem( u"minScale"_s ).nodeValue().toDouble( &ok ) };
321 if ( ok )
322 {
323 setMinimumScale( minScale );
324 }
325 }
326 return result;
327}
328
329bool QgsPointCloudLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
330{
332
333 Q_UNUSED( errorMessage )
334
335 QDomElement elem = node.toElement();
336 writeCommonStyle( elem, doc, context, categories );
337
338 ( void ) writeStyle( node, doc, errorMessage, context, categories );
339
340 if ( categories.testFlag( Legend ) && legend() )
341 {
342 QDomElement legendElement = legend()->writeXml( doc, context );
343 if ( !legendElement.isNull() )
344 node.appendChild( legendElement );
345 }
346
347 return true;
348}
349
350bool QgsPointCloudLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
351{
353
354 QDomElement mapLayerNode = node.toElement();
355
356 if ( categories.testFlag( Symbology3D ) )
357 {
358 mapLayerNode.setAttribute( u"sync3DRendererTo2DRenderer"_s, mSync3DRendererTo2DRenderer ? 1 : 0 );
359 }
360
361 if ( categories.testFlag( Symbology ) )
362 {
363 if ( mRenderer )
364 {
365 const QDomElement rendererElement = mRenderer->save( doc, context );
366 node.appendChild( rendererElement );
367 }
368 }
369
370 //save customproperties
371 if ( categories.testFlag( CustomProperties ) )
372 {
373 writeCustomProperties( node, doc );
374 }
375
376 if ( categories.testFlag( Symbology ) )
377 {
378 // add the blend mode field
379 QDomElement blendModeElem = doc.createElement( u"blendMode"_s );
380 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
381 blendModeElem.appendChild( blendModeText );
382 node.appendChild( blendModeElem );
383 }
384
385 // add the layer opacity and scale visibility
386 if ( categories.testFlag( Rendering ) )
387 {
388 QDomElement layerOpacityElem = doc.createElement( u"layerOpacity"_s );
389 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
390 layerOpacityElem.appendChild( layerOpacityText );
391 node.appendChild( layerOpacityElem );
392
393 mapLayerNode.setAttribute( u"hasScaleBasedVisibilityFlag"_s, hasScaleBasedVisibility() ? 1 : 0 );
394 mapLayerNode.setAttribute( u"maxScale"_s, maximumScale() );
395 mapLayerNode.setAttribute( u"minScale"_s, minimumScale() );
396 }
397 return true;
398}
399
401{
403
404 if ( mDataProvider )
405 mDataProvider->setTransformContext( transformContext );
407}
408
409void QgsPointCloudLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
410{
412
413 if ( mDataProvider )
414 {
415 disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
416 disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
417 }
418
419 setName( baseName );
420 mProviderKey = provider;
421 mDataSource = dataSource;
422
423 if ( mPreloadedProvider )
424 {
425 mDataProvider.reset( qobject_cast< QgsPointCloudDataProvider * >( mPreloadedProvider.release() ) );
426 }
427 else
428 {
429 std::unique_ptr< QgsScopedRuntimeProfile > profile;
430 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
431 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), u"projectload"_s );
432 mDataProvider.reset( qobject_cast<QgsPointCloudDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) ) );
433 }
434
435 if ( !mDataProvider )
436 {
437 QgsDebugError( u"Unable to get point cloud data provider"_s );
438 setValid( false );
439 return;
440 }
441
442 mIsVpc = qobject_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() ) != nullptr;
443
444 mDataProvider->setParent( this );
445 QgsDebugMsgLevel( u"Instantiated the point cloud data provider plugin"_s, 2 );
446
447 setValid( mDataProvider->isValid() );
448 if ( !isValid() )
449 {
450 QgsDebugError( u"Invalid point cloud provider plugin %1"_s.arg( QString( mDataSource.toUtf8() ) ) );
451 setError( mDataProvider->error() );
452 return;
453 }
454
455 connect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
456 connect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
457
458 // Load initial extent, crs and renderer
459 setCrs( mDataProvider->crs() );
461 {
462 setExtent3D( mDataProvider->extent3D() );
463 }
464
465 bool loadDefaultStyleFlag = false;
467 {
468 loadDefaultStyleFlag = true;
469 }
470
471 if ( !mLayerOptions.skipIndexGeneration && mDataProvider && mDataProvider->indexingState() != QgsPointCloudDataProvider::PointCloudIndexGenerationState::Indexed && mDataProvider->pointCount() > 0 )
472 {
473 mDataProvider->generateIndex();
474 }
475
476 if ( !mLayerOptions.skipStatisticsCalculation && mDataProvider && mDataProvider->indexingState() == QgsPointCloudDataProvider::PointCloudIndexGenerationState::Indexed && mDataProvider->pointCount() > 0 )
477 {
478 calculateStatistics();
479 }
480
481 if ( !mRenderer || loadDefaultStyleFlag )
482 {
483 std::unique_ptr< QgsScopedRuntimeProfile > profile;
484 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
485 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), u"projectload"_s );
486
487 bool defaultLoadedFlag = false;
488
489 if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
490 {
491 // first try to create a renderer directly from the data provider
492 std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
493 if ( defaultRenderer )
494 {
495 defaultLoadedFlag = true;
496 setRenderer( defaultRenderer.release() );
497 }
498 }
499
500 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
501 {
502 loadDefaultStyle( defaultLoadedFlag );
503 }
504
505 if ( !defaultLoadedFlag )
506 {
507 // all else failed, create default renderer
509 }
510 }
511}
512
519
520QString QgsPointCloudLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
521{
523
525}
526
527void QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged( QgsPointCloudDataProvider::PointCloudIndexGenerationState state )
528{
530
531 switch ( state )
532 {
534 {
535 resetRenderer();
536 break;
537 }
539 {
540 QgsError providerError = mDataProvider->error();
541 if ( !providerError.isEmpty() )
542 {
543 setError( providerError );
544 emit raiseError( providerError.summary() );
545 }
546 break;
547 }
549 break;
550 }
551}
552
553
554QString QgsPointCloudLayer::loadDefaultStyle( bool &resultFlag )
555{
557
558 if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
559 {
560 // first try to create a renderer directly from the data provider
561 std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
562 if ( defaultRenderer )
563 {
564 resultFlag = true;
565 setRenderer( defaultRenderer.release() );
566 return QString();
567 }
568 }
569
570 return QgsMapLayer::loadDefaultStyle( resultFlag );
571}
572
574{
576
577 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
578 QString myMetadata = u"<html>\n<body>\n"_s;
579
580 myMetadata += generalHtmlMetadata();
581
582 // Begin Provider section
583 myMetadata += u"<h1>"_s + tr( "Information from provider" ) + u"</h1>\n<hr>\n"_s;
584 myMetadata += "<table class=\"list-view\">\n"_L1;
585
586 // Extent
587 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Extent" ) + u"</td><td>"_s + extent().toString() + u"</td></tr>\n"_s;
588
589 // feature count
590 QLocale locale = QLocale();
591 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
592 const qint64 pointCount = mDataProvider ? mDataProvider->pointCount() : -1;
593 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Point count" ) + u"</td><td>"_s + ( pointCount < 0 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( pointCount ) ) ) + u"</td></tr>\n"_s;
594
595 if ( const QgsPointCloudDataProvider *provider = dataProvider() )
596 {
597 myMetadata += provider->htmlMetadata();
598 }
599
600 myMetadata += "</table>\n<br><br>"_L1;
601
602 // CRS
603 myMetadata += crsHtmlMetadata();
604
605 // provider metadata section
606 myMetadata += u"<h1>"_s + tr( "Metadata" ) + u"</h1>\n<hr>\n"_s + u"<table class=\"list-view\">\n"_s;
607 const QVariantMap originalMetadata = mDataProvider ? mDataProvider->originalMetadata() : QVariantMap();
608
609 if ( originalMetadata.value( u"creation_year"_s ).toInt() > 0 && originalMetadata.contains( u"creation_doy"_s ) )
610 {
611 QDate creationDate( originalMetadata.value( u"creation_year"_s ).toInt(), 1, 1 );
612 creationDate = creationDate.addDays( originalMetadata.value( u"creation_doy"_s ).toInt() );
613
614 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Creation date" ) + u"</td><td>"_s + creationDate.toString( Qt::ISODate ) + u"</td></tr>\n"_s;
615 }
616 if ( originalMetadata.contains( u"major_version"_s ) && originalMetadata.contains( u"minor_version"_s ) )
617 {
618 myMetadata += u"<tr><td class=\"highlight\">"_s
619 + tr( "Version" )
620 + u"</td><td>"_s
621 + u"%1.%2"_s.arg( originalMetadata.value( u"major_version"_s ).toString(), originalMetadata.value( u"minor_version"_s ).toString() )
622 + u"</td></tr>\n"_s;
623 }
624
625 if ( !originalMetadata.value( u"dataformat_id"_s ).toString().isEmpty() )
626 {
627 myMetadata += u"<tr><td class=\"highlight\">"_s
628 + tr( "Data format" )
629 + u"</td><td>"_s
630 + u"%1 (%2)"_s
631 .arg( QgsPointCloudDataProvider::translatedDataFormatIds().value( originalMetadata.value( u"dataformat_id"_s ).toInt() ), originalMetadata.value( u"dataformat_id"_s ).toString() )
632 .trimmed()
633 + u"</td></tr>\n"_s;
634 }
635
636 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Scale X" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"scale_x"_s ).toDouble() ) + u"</td></tr>\n"_s;
637 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Scale Y" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"scale_y"_s ).toDouble() ) + u"</td></tr>\n"_s;
638 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Scale Z" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"scale_z"_s ).toDouble() ) + u"</td></tr>\n"_s;
639
640 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Offset X" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"offset_x"_s ).toDouble() ) + u"</td></tr>\n"_s;
641 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Offset Y" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"offset_y"_s ).toDouble() ) + u"</td></tr>\n"_s;
642 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Offset Z" ) + u"</td><td>"_s + QString::number( originalMetadata.value( u"offset_z"_s ).toDouble() ) + u"</td></tr>\n"_s;
643
644 if ( !originalMetadata.value( u"project_id"_s ).toString().isEmpty() )
645 {
646 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Project ID" ) + u"</td><td>"_s + originalMetadata.value( u"project_id"_s ).toString() + u"</td></tr>\n"_s;
647 }
648
649 if ( !originalMetadata.value( u"system_id"_s ).toString().isEmpty() )
650 {
651 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "System ID" ) + u"</td><td>"_s + originalMetadata.value( u"system_id"_s ).toString() + u"</td></tr>\n"_s;
652 }
653
654 if ( !originalMetadata.value( u"software_id"_s ).toString().isEmpty() )
655 {
656 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Software ID" ) + u"</td><td>"_s + originalMetadata.value( u"software_id"_s ).toString() + u"</td></tr>\n"_s;
657 }
658
659 // End Provider section
660 myMetadata += "</table>\n<br><br>"_L1;
661
662 // identification section
663 myMetadata += u"<h1>"_s + tr( "Identification" ) + u"</h1>\n<hr>\n"_s;
664 myMetadata += htmlFormatter.identificationSectionHtml();
665 myMetadata += "<br><br>\n"_L1;
666
667 // extent section
668 myMetadata += u"<h1>"_s + tr( "Extent" ) + u"</h1>\n<hr>\n"_s;
669 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
670 myMetadata += "<br><br>\n"_L1;
671
672 // Start the Access section
673 myMetadata += u"<h1>"_s + tr( "Access" ) + u"</h1>\n<hr>\n"_s;
674 myMetadata += htmlFormatter.accessSectionHtml();
675 myMetadata += "<br><br>\n"_L1;
676
677 // Attributes section
678 myMetadata += u"<h1>"_s + tr( "Attributes" ) + u"</h1>\n<hr>\n<table class=\"list-view\">\n"_s;
679
681
682 // count attributes
683 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Count" ) + u"</td><td>"_s + QString::number( attrs.count() ) + u"</td></tr>\n"_s;
684
685 myMetadata += "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n"_L1;
686 myMetadata += "<tr><th>"_L1 + tr( "Attribute" ) + "</th><th>"_L1 + tr( "Type" ) + "</th></tr>\n"_L1;
687
688 for ( int i = 0; i < attrs.count(); ++i )
689 {
690 const QgsPointCloudAttribute attribute = attrs.at( i );
691 QString rowClass;
692 if ( i % 2 )
693 rowClass = u"class=\"odd-row\""_s;
694 myMetadata += "<tr "_L1 + rowClass + "><td>"_L1 + attribute.name() + "</td><td>"_L1 + attribute.displayType() + "</td></tr>\n"_L1;
695 }
696
697 //close field list
698 myMetadata += "</table>\n<br><br>"_L1;
699
700
701 // Start the contacts section
702 myMetadata += u"<h1>"_s + tr( "Contacts" ) + u"</h1>\n<hr>\n"_s;
703 myMetadata += htmlFormatter.contactsSectionHtml();
704 myMetadata += "<br><br>\n"_L1;
705
706 // Start the links section
707 myMetadata += u"<h1>"_s + tr( "Links" ) + u"</h1>\n<hr>\n"_s;
708 myMetadata += htmlFormatter.linksSectionHtml();
709 myMetadata += "<br><br>\n"_L1;
710
711 // Start the history section
712 myMetadata += u"<h1>"_s + tr( "History" ) + u"</h1>\n<hr>\n"_s;
713 myMetadata += htmlFormatter.historySectionHtml();
714 myMetadata += "<br><br>\n"_L1;
715
716 myMetadata += customPropertyHtmlMetadata();
717
718 myMetadata += "\n</body>\n</html>\n"_L1;
719 return myMetadata;
720}
721
728
730{
732
733 return mDataProvider ? mDataProvider->attributes() : QgsPointCloudAttributeCollection();
734}
735
737{
739
740 return mDataProvider ? mDataProvider->pointCount() : 0;
741}
742
749
751{
753
754 return mRenderer.get();
755}
756
758{
760
761 if ( renderer == mRenderer.get() )
762 return;
763
764 mRenderer.reset( renderer );
765 emit rendererChanged();
767
768 if ( mSync3DRendererTo2DRenderer )
770}
771
772bool QgsPointCloudLayer::setSubsetString( const QString &subset )
773{
775
776 if ( !isValid() || !mDataProvider )
777 {
778 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
779 setCustomProperty( u"storedSubsetString"_s, subset );
780 return false;
781 }
782 else if ( subset == mDataProvider->subsetString() )
783 return true;
784
785 bool res = mDataProvider->setSubsetString( subset );
786 if ( res )
787 {
788 emit subsetStringChanged();
790 }
791 return res;
792}
793
795{
797
798 if ( !isValid() || !mDataProvider )
799 {
800 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
801 return customProperty( u"storedSubsetString"_s ).toString();
802 }
803 return mDataProvider->subsetString();
804}
805
807{
809
810 bool result = false;
812 {
813 std::unique_ptr< QgsAbstractPointCloud3DRenderer > newRenderer( static_cast< QgsAbstractPointCloud3DRenderer * >( r->clone() ) );
814 result = newRenderer->convertFrom2DRenderer( renderer() );
815 setRenderer3D( newRenderer.release() );
817 }
818 return result;
819}
820
822{
824
825 return mSync3DRendererTo2DRenderer;
826}
827
829{
831
832 mSync3DRendererTo2DRenderer = sync;
833 if ( sync )
835}
836
837void QgsPointCloudLayer::calculateStatistics()
838{
840
841 if ( !mDataProvider.get() || !mDataProvider->hasValidIndex() )
842 {
843 QgsMessageLog::logMessage( QObject::tr( "Failed to calculate statistics of the point cloud %1" ).arg( this->name() ) );
844 return;
845 }
846 if ( mStatsCalculationTask )
847 {
848 QgsMessageLog::logMessage( QObject::tr( "A statistics calculation task for the point cloud %1 is already in progress" ).arg( this->name() ) );
849 return;
850 }
851
852 QgsPointCloudStatistics indexStats = mDataProvider->metadataStatistics();
853 QList<QString> indexStatsAttributes = indexStats.statisticsMap().keys();
854 QVector<QgsPointCloudAttribute> attributes = mDataProvider->attributes().attributes();
855 // Do not calculate stats for attributes that the index gives us stats for
856 for ( int i = 0; i < attributes.size(); ++i )
857 {
858 if ( indexStatsAttributes.contains( attributes[i].name() ) )
859 {
860 attributes.remove( i );
861 --i;
862 }
863 }
864
865 // Use the layer statistics for now, until we can calculate complete ones
866 mStatistics = indexStats;
867 if ( attributes.empty() && indexStats.sampledPointsCount() > 0 )
868 {
869 // All attributes are covered by the saved stats, skip calculating anything
871 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
872 resetRenderer();
873 return;
874 }
875
876 QgsPointCloudStatsCalculationTask *task = new QgsPointCloudStatsCalculationTask( mDataProvider->index(), attributes, 1000000 );
877 connect( task, &QgsTask::taskCompleted, this, [this, task, indexStats, indexStatsAttributes]() {
878 mStatistics = task->calculationResults();
879
880 // Fetch what we can directly from the index
881 QMap<QString, QgsPointCloudAttributeStatistics> statsMap = mStatistics.statisticsMap();
882 for ( const QString &attribute : indexStatsAttributes )
883 {
884 statsMap[attribute] = indexStats.statisticsOf( attribute );
885 }
886 mStatistics = QgsPointCloudStatistics( mStatistics.sampledPointsCount(), statsMap );
887
889 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
890 resetRenderer();
891 mStatsCalculationTask = 0;
892#ifdef HAVE_COPC
893 if ( mDataProvider && mDataProvider->index() && mDataProvider->index().isValid() && mDataProvider->name() == "pdal"_L1 && mStatistics.sampledPointsCount() != 0 )
894 {
895 mDataProvider->index().writeStatistics( mStatistics );
896 }
897#endif
898 } );
899
900 // In case the statistics calculation fails, QgsTask::taskTerminated will be called
901 connect( task, &QgsTask::taskTerminated, this, [this]() {
902 if ( mStatsCalculationTask )
903 {
904 QgsMessageLog::logMessage( QObject::tr( "Failed to calculate statistics of the point cloud %1" ).arg( this->name() ) );
905 mStatsCalculationTask = 0;
906 }
907 } );
908
909 mStatsCalculationTask = QgsApplication::taskManager()->addTask( task );
910
912 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
913}
914
915void QgsPointCloudLayer::resetRenderer()
916{
918
919 mDataProvider->loadIndex();
921 {
922 calculateStatistics();
923 }
924 if ( !mRenderer || mRenderer->type() == "extent"_L1 )
925 {
927 }
929
930 emit rendererChanged();
931}
932
933void QgsPointCloudLayer::loadIndexesForRenderContext( QgsRenderContext &rendererContext ) const
934{
935 if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::ContainSubIndexes )
936 {
937 QgsRectangle renderExtent;
938 try
939 {
940 renderExtent = rendererContext.coordinateTransform().transformBoundingBox( rendererContext.mapExtent(), Qgis::TransformDirection::Reverse );
941 }
942 catch ( QgsCsException & )
943 {
944 QgsDebugError( u"Transformation of extent failed!"_s );
945 }
946
947 const QVector<QgsPointCloudSubIndex> subIndex = mDataProvider->subIndexes();
948 if ( const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() ) )
949 {
950 for ( int i = 0; i < subIndex.size(); ++i )
951 {
952 // no need to load as it's there
953 if ( subIndex.at( i ).index() )
954 continue;
955
956 const double overviewSwitchingScale = mRenderer ? mRenderer->overviewSwitchingScale() : 1.0;
957 const double widthThreshold = vpcProvider->averageSubIndexWidth() * overviewSwitchingScale;
958 const double heightThreshold = vpcProvider->averageSubIndexHeight() * overviewSwitchingScale;
959
960 if ( subIndex.at( i ).extent().intersects( renderExtent ) && ( renderExtent.width() < widthThreshold || renderExtent.height() < heightThreshold ) )
961 {
962 mDataProvider->loadSubIndex( i );
963 }
964 }
965 }
966 }
967}
968
970{
972 if ( !mDataProvider || mEditable )
973 return false;
974
975 if ( mIsVpc )
976 {
977 QgsVirtualPointCloudProvider *vpcProvider = qobject_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() );
978 const QVector<QgsPointCloudSubIndex> subIndexes = vpcProvider->subIndexes();
979
980 for ( int i = 0; i < subIndexes.size(); ++i )
981 {
982 const QgsPointCloudSubIndex &subIndex = subIndexes.at( i );
983 QgsPointCloudIndex index = subIndex.index();
984
985 if ( !index.isValid() )
986 {
987 continue;
988 }
989
991 mEditingIndexes[i] = editIndex;
992 }
993 }
994 else
995 {
996 mEditIndex = QgsPointCloudIndex( new QgsPointCloudEditingIndex( mDataProvider->index() ) );
997 if ( !mEditIndex.isValid() )
998 {
999 mEditIndex = QgsPointCloudIndex();
1000 return false;
1001 }
1002 }
1003
1004 mEditable = true;
1005 emit editingStarted();
1006 return true;
1007}
1008
1010{
1012
1013 if ( mIsVpc )
1014 {
1015 for ( QgsPointCloudIndex &index : mEditingIndexes )
1016 if ( index.isModified() && !index.commitChanges( &mCommitError ) )
1017 return false;
1018 }
1019 else
1020 {
1021 if ( mEditIndex.isModified() && !mEditIndex.commitChanges( &mCommitError ) )
1022 return false;
1023
1024 // emitting layerModified() is not required as that's done automatically
1025 // when undo stack index changes
1026 }
1027
1028 undoStack()->clear();
1029
1030 if ( stopEditing )
1031 {
1032 if ( mIsVpc )
1033 mEditingIndexes.clear();
1034 else
1035 mEditIndex = QgsPointCloudIndex();
1036
1037 mEditable = false;
1038 emit editingStopped();
1039 }
1040
1041 return true;
1042}
1043
1045{
1047 return mCommitError;
1048}
1049
1051{
1053 if ( !mEditable )
1054 return false;
1055
1056 if ( mIsVpc )
1057 {
1058 if ( mEditingIndexes.isEmpty() )
1059 return false;
1060
1061 QVector<QPair<int, QList<QgsPointCloudNodeId>>> queuedUpdates;
1062 queuedUpdates.reserve( mEditingIndexes.size() );
1063 for ( auto [position, index] : mEditingIndexes.asKeyValueRange() )
1064 {
1065 if ( !index.isValid() )
1066 continue;
1067 const QList<QgsPointCloudNodeId> updatedNodes = index.updatedNodes();
1068 if ( !updatedNodes.isEmpty() )
1069 queuedUpdates.push_back( qMakePair( position, updatedNodes ) );
1070 }
1071
1072 undoStack()->clear();
1073 mEditable = false;
1074 mEditingIndexes.clear();
1075 emit editingStopped();
1076
1077 for ( const QPair<int, QList<QgsPointCloudNodeId>> &pair : std::as_const( queuedUpdates ) )
1078 {
1079 const int position = pair.first;
1080 const QList<QgsPointCloudNodeId> &nodes = pair.second;
1081 for ( const QgsPointCloudNodeId &n : nodes )
1082 emit chunkAttributeValuesChanged( n, position );
1083 }
1084 }
1085 else
1086 {
1087 if ( !mEditIndex )
1088 return false;
1089
1090 const QList<QgsPointCloudNodeId> updatedNodes = mEditIndex.updatedNodes();
1091
1092 undoStack()->clear();
1093
1094 mEditIndex = QgsPointCloudIndex();
1095 mEditable = false;
1096 emit editingStopped();
1097
1098 for ( const QgsPointCloudNodeId &n : updatedNodes )
1099 emit chunkAttributeValuesChanged( n, -1 );
1100
1101 // emitting layerModified() is not required as that's done automatically
1102 // when undo stack index changes
1103 }
1104 return true;
1105}
1106
1108{
1110 return mDataProvider && mDataProvider->capabilities() & QgsPointCloudDataProvider::Capability::ChangeAttributeValues;
1111}
1112
1114{
1116
1117 return mEditable;
1118}
1119
1121{
1123 if ( !mEditable )
1124 return false;
1125
1126 if ( mIsVpc )
1127 {
1128 for ( const QgsPointCloudIndex &index : std::as_const( mEditingIndexes ) )
1129 {
1130 if ( index.isModified() )
1131 return true;
1132 }
1133 return false;
1134 }
1135 else
1136 {
1137 if ( !mEditIndex )
1138 return false;
1139 return mEditIndex.isModified();
1140 }
1141}
1142
1143bool QgsPointCloudLayer::changeAttributeValue( const QgsPointCloudNodeId &n, const QVector<int> &points, const QgsPointCloudAttribute &attribute, double value )
1144{
1145 if ( mIsVpc )
1146 return false;
1147
1148 // for regular point clouds, we send -1 for the position parameter
1149 return this->changeAttributeValue( { { -1, { { n, points } } } }, attribute, value );
1150}
1151
1152bool QgsPointCloudLayer::changeAttributeValue( const QHash<int, QHash<QgsPointCloudNodeId, QVector<int>>> &mappedPoints, const QgsPointCloudAttribute &attribute, double value )
1153{
1155
1156 QgsEventTracing::ScopedEvent _trace( u"PointCloud"_s, u"QgsPointCloudLayer::changeAttributeValue"_s );
1157
1158 if ( !mEditable )
1159 return false;
1160
1161 QVector<QgsPointCloudSubIndex> subs = subIndexes();
1162
1163 for ( auto it = mappedPoints.constBegin(); it != mappedPoints.constEnd(); it++ )
1164 {
1165 const int position = it.key();
1166 QHash<QgsPointCloudNodeId, QVector<int>> nodesAndPoints = it.value();
1167 QgsPointCloudIndex editIndex;
1168
1169 // NOLINTBEGIN(bugprone-branch-clone)
1170 if ( mIsVpc )
1171 {
1172 if ( position >= subs.size() || position < 0 )
1173 return false;
1174
1175 QgsPointCloudIndex index = subs.at( position ).index();
1176 if ( !index || !index.isValid() )
1177 return false;
1178
1179 editIndex = index;
1180 }
1181 else
1182 {
1183 editIndex = mEditIndex;
1184 }
1185 // NOLINTEND(bugprone-branch-clone)
1186
1187 // Cannot allow x,y,z editing as points may get moved outside the node extents
1188 if ( attribute.name().compare( 'X'_L1, Qt::CaseInsensitive ) == 0 || attribute.name().compare( 'Y'_L1, Qt::CaseInsensitive ) == 0 || attribute.name().compare( 'Z'_L1, Qt::CaseInsensitive ) == 0 )
1189 return false;
1190
1191 const QgsPointCloudAttributeCollection attributeCollection = editIndex.attributes();
1192
1193 int attributeOffset;
1194 const QgsPointCloudAttribute *at = attributeCollection.find( attribute.name(), attributeOffset );
1195
1196 if ( !at || at->size() != attribute.size() || at->type() != attribute.type() )
1197 {
1198 return false;
1199 }
1200
1201 if ( !QgsPointCloudLayerEditUtils::isAttributeValueValid( attribute, value ) )
1202 {
1203 return false;
1204 }
1205
1206 for ( auto it = nodesAndPoints.constBegin(); it != nodesAndPoints.constEnd(); it++ )
1207 {
1208 QgsPointCloudNodeId n = it.key();
1209 QVector<int> points = it.value();
1210
1211 if ( !n.isValid() || !editIndex.hasNode( n ) ) // todo: should not have to check if n.isValid
1212 return false;
1213
1214 if ( points.isEmpty() )
1215 continue;
1216
1217 int pointsMin = std::numeric_limits<int>::max();
1218 int pointsMax = std::numeric_limits<int>::min();
1219 for ( int pt : std::as_const( points ) )
1220 {
1221 if ( pt < pointsMin )
1222 pointsMin = pt;
1223 if ( pt > pointsMax )
1224 pointsMax = pt;
1225 }
1226
1227 if ( pointsMin < 0 || pointsMax >= editIndex.getNode( n ).pointCount() )
1228 return false;
1229 }
1230 }
1231
1232 undoStack()->push( new QgsPointCloudLayerUndoCommandChangeAttribute( this, mappedPoints, attribute, value ) );
1233
1234 return true;
1235}
1236
1238{
1240 if ( mEditIndex )
1241 return mEditIndex;
1242
1243 if ( mDataProvider )
1244 return mDataProvider->index();
1245
1246 return QgsPointCloudIndex();
1247}
1248
1249QVector<QgsPointCloudSubIndex> QgsPointCloudLayer::subIndexes() const
1250{
1252
1253 if ( !mDataProvider )
1254 return QVector<QgsPointCloudSubIndex>();
1255
1256 const QVector<QgsPointCloudSubIndex> subs = mDataProvider->subIndexes();
1257
1258 if ( !mEditable )
1259 {
1260 return subs;
1261 }
1262
1263 QVector<QgsPointCloudSubIndex> indexes;
1264 indexes.reserve( subs.size() );
1265
1266 for ( qsizetype i = 0; i < subs.size(); i++ )
1267 {
1268 QgsPointCloudSubIndex sub = subs.at( i );
1269 QgsPointCloudIndex index = sub.index();
1270
1271 if ( index.isValid() )
1272 {
1273 if ( !mEditingIndexes.contains( i ) )
1274 {
1276 mEditingIndexes[i] = editIndex;
1277 }
1278 sub.setIndex( mEditingIndexes[i] );
1279 }
1280 indexes.append( sub );
1281 }
1282
1283 return indexes;
1284}
1285
1287{
1288 if ( !mDataProvider || !mIsVpc )
1289 return QgsPointCloudIndex();
1290
1291 const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() );
1292 return vpcProvider->overview();
1293}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
BlendMode
Blending modes defining the available composition modes that can be used when painting.
Definition qgis.h:5087
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:512
@ TriangulatedSurface
Create a TIN from the point cloud using Delaunay triangulation.
Definition qgis.h:4349
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:213
@ LoadDefaultStyle
Reset the layer's style to the default for the datasource.
Definition qgis.h:495
@ SkipGetExtent
Skip the extent from provider.
Definition qgis.h:496
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2766
Base class for point cloud 3D renderers.
Abstract base class for objects which generate elevation profiles.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Contains information about the context in which a coordinate transform is executed.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
bool isEmpty() const
Test if no error is set.
Definition qgserror.h:111
QString summary() const
Short error description, usually the first error in chain, the real error.
Definition qgserror.cpp:132
Formats layer metadata into HTML.
Base class for storage of map layer elevation properties.
static QString typeToString(Qgis::LayerType type)
Converts a map layer type to a string value.
An abstract interface for implementations of legends for one map layer.
static QgsMapLayerLegend * defaultPointCloudLegend(QgsPointCloudLayer *layer)
Create new legend implementation for a point cloud layer.
virtual QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Writes configuration to a DOM element, to be used later with readXml().
Base class for utility classes that encapsulate information necessary for rendering of map layers.
QString name
Definition qgsmaplayer.h:87
void readStyleManager(const QDomNode &layerNode)
Read style manager's configuration (if any). To be called by subclasses.
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
void setError(const QgsError &error)
Sets error message.
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QgsMapLayerLegend * legend() const
Can be nullptr.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QString source() const
Returns the source for the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
virtual void setExtent3D(const QgsBox3D &box)
Sets the extent.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void configChanged()
Emitted whenever the configuration is changed.
void trigger3DUpdate()
Will advise any 3D maps that this layer requires to be updated in the scene.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
static Qgis::DataProviderReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
void editingStarted()
Emitted when editing on this layer has started.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QString mLayerName
Name of the layer - used for display.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QString crsHtmlMetadata() const
Returns a HTML fragment containing the layer's CRS metadata, for use in the htmlMetadata() method.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:89
QgsMapLayer(Qgis::LayerType type=Qgis::LayerType::Vector, const QString &name=QString(), const QString &source=QString())
Constructor for QgsMapLayer.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
QFlags< StyleCategory > StyleCategories
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString mProviderKey
Data provider key (name of the data provider).
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
std::unique_ptr< QgsDataProvider > mPreloadedProvider
Optionally used when loading a project, it is released when the layer is effectively created.
void rendererChanged()
Signal emitted when renderer is changed.
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
QgsMapLayer::LayerFlags flags
Definition qgsmaplayer.h:99
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
void dataChanged()
Data of layer changed.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
QString mDataSource
Data source description string, varies by layer type.
@ FlagReadExtentFromXml
Read extent from xml and skip get extent from provider.
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
void setValid(bool valid)
Sets whether layer is valid or not.
void readCommonStyle(const QDomElement &layerElement, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories)
Read style data common to all layer types.
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
double minimumScale() const
Returns the minimum map scale (i.e.
double opacity
Definition qgsmaplayer.h:95
@ Symbology
Symbology.
@ Rendering
Rendering: scale visibility, simplify method, opacity.
@ Symbology3D
3D symbology
@ CustomProperties
Custom properties (by plugins for instance).
@ Legend
Legend settings.
void layerModified()
Emitted when modifications has been done on layer.
void setRenderer3D(QgsAbstract3DRenderer *renderer)
Sets 3D renderer for the layer.
QString customPropertyHtmlMetadata() const
Returns an HTML fragment containing custom property information, for use in the htmlMetadata() method...
QString generalHtmlMetadata() const
Returns an HTML fragment containing general metadata information, for use in the htmlMetadata() metho...
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
double maximumScale() const
Returns the maximum map scale (i.e.
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static Qgis::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a Qgis::BlendMode corresponding to a QPainter::CompositionMode.
static QPainter::CompositionMode getCompositionMode(Qgis::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a Qgis::BlendMode.
A collection of point cloud attributes.
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
int count() const
Returns the number of attributes present in the collection.
Attribute for point cloud data pair of name and size in bytes.
QString displayType() const
Returns the type to use when displaying this field.
int size() const
Returns size of the attribute in bytes.
QString name() const
Returns name of the attribute.
DataType type() const
Returns the data type.
Base class for providing data for QgsPointCloudLayer.
@ CreateRenderer
Provider can create 2D renderers using backend-specific formatting information. See QgsPointCloudData...
@ ChangeAttributeValues
Provider can modify the values of point attributes.
@ ContainSubIndexes
Provider can contain multiple indexes. Virtual point cloud files for example.
static QMap< int, QString > translatedDataFormatIds()
Returns the map of LAS data format ID to translated string value.
void indexGenerationStateChanged(QgsPointCloudDataProvider::PointCloudIndexGenerationState state)
Emitted when point cloud generation state is changed.
PointCloudIndexGenerationState
Point cloud index state.
@ NotIndexed
Provider has no index available.
@ Indexing
Provider try to index the source data.
@ Indexed
The index is ready to be used.
A QgsPointCloudIndex that is used as an editing buffer when editing point cloud data.
Smart pointer for QgsAbstractPointCloudIndex.
QgsPointCloudNode getNode(const QgsPointCloudNodeId &id) const
Returns object for a given node.
bool hasNode(const QgsPointCloudNodeId &id) const
Returns whether the octree contain given node.
QgsPointCloudAttributeCollection attributes() const
Returns all attributes that are stored in the file.
static bool isAttributeValueValid(const QgsPointCloudAttribute &attribute, double value)
Check if value is within proper range for the attribute.
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
Implementation of QgsAbstractProfileGenerator for point cloud layers.
Implementation of threaded rendering for point cloud layers.
An undo command subclass for changing point attribute values in a point cloud index.
QString decodedSource(const QString &source, const QString &dataProvider, const QgsReadWriteContext &context) const override
Called by readLayerXML(), used by derived classes to decode provider's specific data source from proj...
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
void setSync3DRendererTo2DRenderer(bool sync)
Sets whether this layer's 3D renderer should be automatically updated with changes applied to the lay...
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
@ Calculated
The statistics calculation task is done and statistics are available.
@ NotStarted
The statistics calculation task has not been started.
@ Calculating
The statistics calculation task is running.
bool sync3DRendererTo2DRenderer() const
Returns whether this layer's 3D renderer should be automatically updated with changes applied to the ...
bool writeXml(QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files.
QgsRectangle extent() const override
Returns the extent of the layer.
bool isModified() const override
Returns true if the layer has been modified since last commit/save.
QString encodedSource(const QString &source, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by derived classes to encode provider's specific data source to proje...
bool changeAttributeValue(const QgsPointCloudNodeId &n, const QVector< int > &points, const QgsPointCloudAttribute &attribute, double value)
Attempts to modify attribute values for specific points in the editing buffer.
QString loadDefaultStyle(bool &resultFlag) final
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
bool convertRenderer3DFromRenderer2D()
Updates the layer's 3D renderer's symbol to match that of the layer's 2D renderer.
qint64 pointCount() const
Returns the total number of points available in the layer.
QgsPointCloudIndex index() const
Returns the point cloud index associated with the layer.
bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the document provided.
void raiseError(const QString &msg)
Signals an error related to this point cloud layer.
PointCloudStatisticsCalculationState statisticsCalculationState() const
Returns the status of point cloud statistics calculation.
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
bool isEditable() const override
Returns true if the layer can be edited.
void statisticsCalculationStateChanged(QgsPointCloudLayer::PointCloudStatisticsCalculationState state)
Emitted when statistics calculation state has changed.
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
bool rollBack()
Stops a current editing operation and discards any uncommitted edits.
bool writeStyle(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const final
Write just the symbology information for the layer into the document.
QgsPointCloudIndex overview() const
Returns the overview point cloud index associated with the layer (only if the layer has a virtual poi...
QgsPointCloudLayer(const QString &uri=QString(), const QString &baseName=QString(), const QString &providerLib=u"pointcloud"_s, const QgsPointCloudLayer::LayerOptions &options=QgsPointCloudLayer::LayerOptions())
Constructor - creates a point cloud layer.
bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QString subsetString() const
Returns the string used to define a subset of the layer.
bool setSubsetString(const QString &subset)
Sets the string used to define a subset of the layer.
QString commitError() const
Returns the last error message generated when attempting to commit changes to the layer.
QgsPointCloudLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
QVector< QgsPointCloudSubIndex > subIndexes() const
Returns point cloud indexes associated with the layer (only if the layer has a virtual point cloud da...
void setRenderer(QgsPointCloudRenderer *renderer)
Sets the 2D renderer for the point cloud.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes available from the layer.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
bool startEditing()
Makes the layer editable.
bool supportsEditing() const override
Returns whether the layer supports editing or not.
void chunkAttributeValuesChanged(const QgsPointCloudNodeId &n, const int position)
Emitted when a node gets some attribute values of some points changed.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) final
Read the style for the current layer from the DOM node supplied.
QgsAbstractProfileGenerator * createProfileGenerator(const QgsProfileRequest &request) override
Given a profile request, returns a new profile generator ready for generating elevation profiles.
Represents an indexed point cloud node's position in octree.
bool isValid() const
Returns whether node is valid.
qint64 pointCount() const
Returns number of points contained in node data.
static QgsPointCloudRenderer * defaultRenderer(const QgsPointCloudLayer *layer)
Returns a new default point cloud renderer for a specified layer.
Abstract base class for 2d point cloud renderers.
static QgsPointCloudRenderer * load(QDomElement &element, const QgsReadWriteContext &context)
Creates a renderer from an XML element.
int sampledPointsCount() const
Returns the number of points used to calculate the statistics.
QMap< QString, QgsPointCloudAttributeStatistics > statisticsMap() const
Returns a map object containing all the statistics.
QgsPointCloudAttributeStatistics statisticsOf(const QString &attribute) const
Returns the calculated statistics of attribute attribute.
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QString absoluteToRelativeUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts absolute path(s) to relative path(s) in the given provider-specific URI.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString relativeToAbsoluteUri(const QString &providerKey, const QString &uri, const QgsReadWriteContext &context) const
Converts relative path(s) to absolute path(s) in the given provider-specific URI.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
Contains information about the context of a rendering operation.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Abstract base class for long running background tasks.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
Implementation of QgsAbstractProfileGenerator for triangulated point cloud layers.
static QgsRectangle readRectangle(const QDomElement &element)
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.
Setting options for loading point cloud layers.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.