QGIS API Documentation 4.1.0-Master (64dc32379c2)
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 connect( this, &QgsMapLayer::dataChanged, this, [this] { triggerRepaint(); } );
78}
79
81{
82 if ( QgsTask *task = QgsApplication::taskManager()->task( mStatsCalculationTask ) )
83 {
84 mStatsCalculationTask = 0;
85 task->cancel();
86 task->waitForFinished();
87 }
88}
89
91{
93
94 QgsPointCloudLayer *layer = new QgsPointCloudLayer( source(), name(), mProviderKey, mLayerOptions );
95 QgsMapLayer::clone( layer );
96
97 if ( mRenderer )
98 layer->setRenderer( mRenderer->clone() );
99
100 layer->mElevationProperties = mElevationProperties->clone();
101 layer->mElevationProperties->setParent( layer );
102
103 layer->mLayerOptions = mLayerOptions;
104 layer->mSync3DRendererTo2DRenderer = mSync3DRendererTo2DRenderer;
105
106 return layer;
107}
108
110{
112
113 if ( !mDataProvider )
114 return QgsRectangle();
115
116 return mDataProvider->extent();
117}
118
120{
122
123 if ( mRenderer->type() != "extent"_L1 )
124 loadIndexesForRenderContext( rendererContext );
125
126 return new QgsPointCloudLayerRenderer( this, rendererContext );
127}
128
130{
132
133 if ( mElevationProperties && mElevationProperties->type() == Qgis::PointCloudProfileType::TriangulatedSurface )
134 {
135 return new QgsTriangulatedPointCloudLayerProfileGenerator( this, request );
136 }
137
138 return new QgsPointCloudLayerProfileGenerator( this, request );
139}
140
147
149{
151
152 return mDataProvider.get();
153}
154
155bool QgsPointCloudLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
156{
158
159 // create provider
160 const QDomNode pkeyNode = layerNode.namedItem( u"provider"_s );
161 mProviderKey = pkeyNode.toElement().text();
162
164 {
165 const QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
167 // read extent
169 {
170 const QDomNode extentNode = layerNode.namedItem( u"extent"_s );
171 if ( !extentNode.isNull() )
172 {
173 // get the extent
174 const QgsRectangle mbr = QgsXmlUtils::readRectangle( extentNode.toElement() );
175
176 // store the extent
177 setExtent( mbr );
178 }
179 }
180
182 const QDomNode subset = layerNode.namedItem( u"subset"_s );
183 const QString subsetText = subset.toElement().text();
184 if ( !subsetText.isEmpty() )
185 setSubsetString( subsetText );
186 }
187
188 if ( !isValid() )
189 {
190 return false;
191 }
192
193 QString errorMsg;
194 if ( !readSymbology( layerNode, errorMsg, context ) )
195 return false;
196
197 readStyleManager( layerNode );
198 return true;
199}
200
201bool QgsPointCloudLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
202{
204
205 QDomElement mapLayerNode = layerNode.toElement();
206 mapLayerNode.setAttribute( u"type"_s, QgsMapLayerFactory::typeToString( Qgis::LayerType::PointCloud ) );
207
208 if ( !subsetString().isEmpty() )
209 {
210 QDomElement subset = doc.createElement( u"subset"_s );
211 const QDomText subsetText = doc.createTextNode( subsetString() );
212 subset.appendChild( subsetText );
213 layerNode.appendChild( subset );
214 }
215 if ( mDataProvider )
216 {
217 QDomElement provider = doc.createElement( u"provider"_s );
218 const QDomText providerText = doc.createTextNode( providerType() );
219 provider.appendChild( providerText );
220 layerNode.appendChild( provider );
221 }
222
223 writeStyleManager( layerNode, doc );
224
225 QString errorMsg;
226 return writeSymbology( layerNode, doc, errorMsg, context );
227}
228
229bool QgsPointCloudLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
230{
232
233 const QDomElement elem = node.toElement();
234
235 readCommonStyle( elem, context, categories );
236
237 readStyle( node, errorMessage, context, categories );
238
239 if ( categories.testFlag( CustomProperties ) )
240 readCustomProperties( node, u"variable"_s );
241
242 if ( categories.testFlag( Legend ) )
243 {
244 QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Legend" ) );
245
246 const QDomElement legendElem = node.firstChildElement( u"legend"_s );
247 if ( QgsMapLayerLegend *l = legend(); l && !legendElem.isNull() )
248 {
249 l->readXml( legendElem, context );
250 }
251 }
252
253 return true;
254}
255
256bool QgsPointCloudLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
257{
259
260 bool result = true;
261
262 if ( categories.testFlag( Symbology3D ) )
263 {
264 bool ok;
265 bool sync = node.attributes().namedItem( u"sync3DRendererTo2DRenderer"_s ).nodeValue().toInt( &ok );
266 if ( ok )
268 }
269
270 if ( categories.testFlag( Symbology ) )
271 {
272 QDomElement rendererElement = node.firstChildElement( u"renderer"_s );
273 if ( !rendererElement.isNull() )
274 {
275 std::unique_ptr< QgsPointCloudRenderer > r( QgsPointCloudRenderer::load( rendererElement, context ) );
276 if ( r )
277 {
278 setRenderer( r.release() );
279 }
280 else
281 {
282 result = false;
283 }
284 }
285 // make sure layer has a renderer - if none exists, fallback to a default renderer
286 if ( !mRenderer )
287 {
289 }
290 }
291
292 if ( categories.testFlag( Symbology ) )
293 {
294 // get and set the blend mode if it exists
295 const QDomNode blendModeNode = node.namedItem( u"blendMode"_s );
296 if ( !blendModeNode.isNull() )
297 {
298 const QDomElement e = blendModeNode.toElement();
299 setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
300 }
301 }
302
303 // get and set the layer transparency and scale visibility if they exists
304 if ( categories.testFlag( Rendering ) )
305 {
306 const QDomNode layerOpacityNode = node.namedItem( u"layerOpacity"_s );
307 if ( !layerOpacityNode.isNull() )
308 {
309 const QDomElement e = layerOpacityNode.toElement();
310 setOpacity( e.text().toDouble() );
311 }
312
313 const bool hasScaleBasedVisibiliy { node.attributes().namedItem( u"hasScaleBasedVisibilityFlag"_s ).nodeValue() == '1' };
314 setScaleBasedVisibility( hasScaleBasedVisibiliy );
315 bool ok;
316 const double maxScale { node.attributes().namedItem( u"maxScale"_s ).nodeValue().toDouble( &ok ) };
317 if ( ok )
318 {
319 setMaximumScale( maxScale );
320 }
321 const double minScale { node.attributes().namedItem( u"minScale"_s ).nodeValue().toDouble( &ok ) };
322 if ( ok )
323 {
324 setMinimumScale( minScale );
325 }
326 }
327 return result;
328}
329
330bool QgsPointCloudLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
331{
333
334 Q_UNUSED( errorMessage )
335
336 QDomElement elem = node.toElement();
337 writeCommonStyle( elem, doc, context, categories );
338
339 ( void ) writeStyle( node, doc, errorMessage, context, categories );
340
341 if ( categories.testFlag( Legend ) && legend() )
342 {
343 QDomElement legendElement = legend()->writeXml( doc, context );
344 if ( !legendElement.isNull() )
345 node.appendChild( legendElement );
346 }
347
348 return true;
349}
350
351bool QgsPointCloudLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
352{
354
355 QDomElement mapLayerNode = node.toElement();
356
357 if ( categories.testFlag( Symbology3D ) )
358 {
359 mapLayerNode.setAttribute( u"sync3DRendererTo2DRenderer"_s, mSync3DRendererTo2DRenderer ? 1 : 0 );
360 }
361
362 if ( categories.testFlag( Symbology ) )
363 {
364 if ( mRenderer )
365 {
366 const QDomElement rendererElement = mRenderer->save( doc, context );
367 node.appendChild( rendererElement );
368 }
369 }
370
371 //save customproperties
372 if ( categories.testFlag( CustomProperties ) )
373 {
374 writeCustomProperties( node, doc );
375 }
376
377 if ( categories.testFlag( Symbology ) )
378 {
379 // add the blend mode field
380 QDomElement blendModeElem = doc.createElement( u"blendMode"_s );
381 const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
382 blendModeElem.appendChild( blendModeText );
383 node.appendChild( blendModeElem );
384 }
385
386 // add the layer opacity and scale visibility
387 if ( categories.testFlag( Rendering ) )
388 {
389 QDomElement layerOpacityElem = doc.createElement( u"layerOpacity"_s );
390 const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
391 layerOpacityElem.appendChild( layerOpacityText );
392 node.appendChild( layerOpacityElem );
393
394 mapLayerNode.setAttribute( u"hasScaleBasedVisibilityFlag"_s, hasScaleBasedVisibility() ? 1 : 0 );
395 mapLayerNode.setAttribute( u"maxScale"_s, maximumScale() );
396 mapLayerNode.setAttribute( u"minScale"_s, minimumScale() );
397 }
398 return true;
399}
400
402{
404
405 if ( mDataProvider )
406 mDataProvider->setTransformContext( transformContext );
408}
409
410void QgsPointCloudLayer::setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, Qgis::DataProviderReadFlags flags )
411{
413
414 if ( mDataProvider )
415 {
416 disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
417 disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
418 }
419
420 setName( baseName );
421 mProviderKey = provider;
422 mDataSource = dataSource;
423
424 if ( mPreloadedProvider )
425 {
426 mDataProvider.reset( qobject_cast< QgsPointCloudDataProvider * >( mPreloadedProvider.release() ) );
427 }
428 else
429 {
430 std::unique_ptr< QgsScopedRuntimeProfile > profile;
431 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
432 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), u"projectload"_s );
433 mDataProvider.reset( qobject_cast<QgsPointCloudDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) ) );
434 }
435
436 if ( !mDataProvider )
437 {
438 QgsDebugError( u"Unable to get point cloud data provider"_s );
439 setValid( false );
440 return;
441 }
442
443 mIsVpc = qobject_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() ) != nullptr;
444
445 mDataProvider->setParent( this );
446 QgsDebugMsgLevel( u"Instantiated the point cloud data provider plugin"_s, 2 );
447
448 setValid( mDataProvider->isValid() );
449 if ( !isValid() )
450 {
451 QgsDebugError( u"Invalid point cloud provider plugin %1"_s.arg( QString( mDataSource.toUtf8() ) ) );
452 setError( mDataProvider->error() );
453 return;
454 }
455
456 connect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
457 connect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
458
459 // Load initial extent, crs and renderer
460 setCrs( mDataProvider->crs() );
462 {
463 setExtent3D( mDataProvider->extent3D() );
464 }
465
466 bool loadDefaultStyleFlag = false;
468 {
469 loadDefaultStyleFlag = true;
470 }
471
472 if ( !mLayerOptions.skipIndexGeneration && mDataProvider && mDataProvider->indexingState() != QgsPointCloudDataProvider::PointCloudIndexGenerationState::Indexed && mDataProvider->pointCount() > 0 )
473 {
474 mDataProvider->generateIndex();
475 }
476
477 if ( !mLayerOptions.skipStatisticsCalculation && mDataProvider && mDataProvider->indexingState() == QgsPointCloudDataProvider::PointCloudIndexGenerationState::Indexed && mDataProvider->pointCount() > 0 )
478 {
479 calculateStatistics();
480 }
481
482 if ( !mRenderer || loadDefaultStyleFlag )
483 {
484 std::unique_ptr< QgsScopedRuntimeProfile > profile;
485 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
486 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), u"projectload"_s );
487
488 bool defaultLoadedFlag = false;
489
490 if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
491 {
492 // first try to create a renderer directly from the data provider
493 std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
494 if ( defaultRenderer )
495 {
496 defaultLoadedFlag = true;
497 setRenderer( defaultRenderer.release() );
498 }
499 }
500
501 if ( !defaultLoadedFlag && loadDefaultStyleFlag )
502 {
503 loadDefaultStyle( defaultLoadedFlag );
504 }
505
506 if ( !defaultLoadedFlag )
507 {
508 // all else failed, create default renderer
510 }
511 }
512}
513
520
521QString QgsPointCloudLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
522{
524
526}
527
528void QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged( QgsPointCloudDataProvider::PointCloudIndexGenerationState state )
529{
531
532 switch ( state )
533 {
535 {
536 resetRenderer();
537 break;
538 }
540 {
541 QgsError providerError = mDataProvider->error();
542 if ( !providerError.isEmpty() )
543 {
544 setError( providerError );
545 emit raiseError( providerError.summary() );
546 }
547 break;
548 }
550 break;
551 }
552}
553
554
555QString QgsPointCloudLayer::loadDefaultStyle( bool &resultFlag )
556{
558
559 if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
560 {
561 // first try to create a renderer directly from the data provider
562 std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
563 if ( defaultRenderer )
564 {
565 resultFlag = true;
566 setRenderer( defaultRenderer.release() );
567 return QString();
568 }
569 }
570
571 return QgsMapLayer::loadDefaultStyle( resultFlag );
572}
573
575{
577
578 const QgsLayerMetadataFormatter htmlFormatter( metadata() );
579 QString myMetadata = u"<html>\n<body>\n"_s;
580
581 myMetadata += generalHtmlMetadata();
582
583 // Begin Provider section
584 myMetadata += u"<h1>"_s + tr( "Information from provider" ) + u"</h1>\n<hr>\n"_s;
585 myMetadata += "<table class=\"list-view\">\n"_L1;
586
587 // Extent
588 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Extent" ) + u"</td><td>"_s + extent().toString() + u"</td></tr>\n"_s;
589
590 // feature count
591 QLocale locale = QLocale();
592 locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
593 const qint64 pointCount = mDataProvider ? mDataProvider->pointCount() : -1;
594 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;
595
596 if ( const QgsPointCloudDataProvider *provider = dataProvider() )
597 {
598 myMetadata += provider->htmlMetadata();
599 }
600
601 myMetadata += "</table>\n<br><br>"_L1;
602
603 // CRS
604 myMetadata += crsHtmlMetadata();
605
606 // provider metadata section
607 myMetadata += u"<h1>"_s + tr( "Metadata" ) + u"</h1>\n<hr>\n"_s + u"<table class=\"list-view\">\n"_s;
608 const QVariantMap originalMetadata = mDataProvider ? mDataProvider->originalMetadata() : QVariantMap();
609
610 if ( originalMetadata.value( u"creation_year"_s ).toInt() > 0 && originalMetadata.contains( u"creation_doy"_s ) )
611 {
612 QDate creationDate( originalMetadata.value( u"creation_year"_s ).toInt(), 1, 1 );
613 creationDate = creationDate.addDays( originalMetadata.value( u"creation_doy"_s ).toInt() );
614
615 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Creation date" ) + u"</td><td>"_s + creationDate.toString( Qt::ISODate ) + u"</td></tr>\n"_s;
616 }
617 if ( originalMetadata.contains( u"major_version"_s ) && originalMetadata.contains( u"minor_version"_s ) )
618 {
619 myMetadata += u"<tr><td class=\"highlight\">"_s
620 + tr( "Version" )
621 + u"</td><td>"_s
622 + u"%1.%2"_s.arg( originalMetadata.value( u"major_version"_s ).toString(), originalMetadata.value( u"minor_version"_s ).toString() )
623 + u"</td></tr>\n"_s;
624 }
625
626 if ( !originalMetadata.value( u"dataformat_id"_s ).toString().isEmpty() )
627 {
628 myMetadata += u"<tr><td class=\"highlight\">"_s
629 + tr( "Data format" )
630 + u"</td><td>"_s
631 + u"%1 (%2)"_s
632 .arg( QgsPointCloudDataProvider::translatedDataFormatIds().value( originalMetadata.value( u"dataformat_id"_s ).toInt() ), originalMetadata.value( u"dataformat_id"_s ).toString() )
633 .trimmed()
634 + u"</td></tr>\n"_s;
635 }
636
637 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;
638 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;
639 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;
640
641 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;
642 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;
643 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;
644
645 if ( !originalMetadata.value( u"project_id"_s ).toString().isEmpty() )
646 {
647 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;
648 }
649
650 if ( !originalMetadata.value( u"system_id"_s ).toString().isEmpty() )
651 {
652 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;
653 }
654
655 if ( !originalMetadata.value( u"software_id"_s ).toString().isEmpty() )
656 {
657 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;
658 }
659
660 // End Provider section
661 myMetadata += "</table>\n<br><br>"_L1;
662
663 // identification section
664 myMetadata += u"<h1>"_s + tr( "Identification" ) + u"</h1>\n<hr>\n"_s;
665 myMetadata += htmlFormatter.identificationSectionHtml();
666 myMetadata += "<br><br>\n"_L1;
667
668 // extent section
669 myMetadata += u"<h1>"_s + tr( "Extent" ) + u"</h1>\n<hr>\n"_s;
670 myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
671 myMetadata += "<br><br>\n"_L1;
672
673 // Start the Access section
674 myMetadata += u"<h1>"_s + tr( "Access" ) + u"</h1>\n<hr>\n"_s;
675 myMetadata += htmlFormatter.accessSectionHtml();
676 myMetadata += "<br><br>\n"_L1;
677
678 // Attributes section
679 myMetadata += u"<h1>"_s + tr( "Attributes" ) + u"</h1>\n<hr>\n<table class=\"list-view\">\n"_s;
680
682
683 // count attributes
684 myMetadata += u"<tr><td class=\"highlight\">"_s + tr( "Count" ) + u"</td><td>"_s + QString::number( attrs.count() ) + u"</td></tr>\n"_s;
685
686 myMetadata += "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n"_L1;
687 myMetadata += "<tr><th>"_L1 + tr( "Attribute" ) + "</th><th>"_L1 + tr( "Type" ) + "</th></tr>\n"_L1;
688
689 for ( int i = 0; i < attrs.count(); ++i )
690 {
691 const QgsPointCloudAttribute attribute = attrs.at( i );
692 QString rowClass;
693 if ( i % 2 )
694 rowClass = u"class=\"odd-row\""_s;
695 myMetadata += "<tr "_L1 + rowClass + "><td>"_L1 + attribute.name() + "</td><td>"_L1 + attribute.displayType() + "</td></tr>\n"_L1;
696 }
697
698 //close field list
699 myMetadata += "</table>\n<br><br>"_L1;
700
701
702 // Start the contacts section
703 myMetadata += u"<h1>"_s + tr( "Contacts" ) + u"</h1>\n<hr>\n"_s;
704 myMetadata += htmlFormatter.contactsSectionHtml();
705 myMetadata += "<br><br>\n"_L1;
706
707 // Start the links section
708 myMetadata += u"<h1>"_s + tr( "Links" ) + u"</h1>\n<hr>\n"_s;
709 myMetadata += htmlFormatter.linksSectionHtml();
710 myMetadata += "<br><br>\n"_L1;
711
712 // Start the history section
713 myMetadata += u"<h1>"_s + tr( "History" ) + u"</h1>\n<hr>\n"_s;
714 myMetadata += htmlFormatter.historySectionHtml();
715 myMetadata += "<br><br>\n"_L1;
716
717 myMetadata += customPropertyHtmlMetadata();
718
719 myMetadata += "\n</body>\n</html>\n"_L1;
720 return myMetadata;
721}
722
729
731{
733
734 return mDataProvider ? mDataProvider->attributes() : QgsPointCloudAttributeCollection();
735}
736
738{
740
741 return mDataProvider ? mDataProvider->pointCount() : 0;
742}
743
750
752{
754
755 return mRenderer.get();
756}
757
759{
761
762 if ( renderer == mRenderer.get() )
763 return;
764
765 mRenderer.reset( renderer );
766 emit rendererChanged();
768
769 if ( mSync3DRendererTo2DRenderer )
771}
772
773bool QgsPointCloudLayer::setSubsetString( const QString &subset )
774{
776
777 if ( !isValid() || !mDataProvider )
778 {
779 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
780 setCustomProperty( u"storedSubsetString"_s, subset );
781 return false;
782 }
783 else if ( subset == mDataProvider->subsetString() )
784 return true;
785
786 bool res = mDataProvider->setSubsetString( subset );
787 if ( res )
788 {
789 emit subsetStringChanged();
791 }
792 return res;
793}
794
796{
798
799 if ( !isValid() || !mDataProvider )
800 {
801 QgsDebugMsgLevel( u"invoked with invalid layer or null mDataProvider"_s, 3 );
802 return customProperty( u"storedSubsetString"_s ).toString();
803 }
804 return mDataProvider->subsetString();
805}
806
808{
810
811 bool result = false;
813 {
814 std::unique_ptr< QgsAbstractPointCloud3DRenderer > newRenderer( static_cast< QgsAbstractPointCloud3DRenderer * >( r->clone() ) );
815 result = newRenderer->convertFrom2DRenderer( renderer() );
816 setRenderer3D( newRenderer.release() );
818 }
819 return result;
820}
821
823{
825
826 return mSync3DRendererTo2DRenderer;
827}
828
830{
832
833 mSync3DRendererTo2DRenderer = sync;
834 if ( sync )
836}
837
838void QgsPointCloudLayer::calculateStatistics()
839{
841
842 if ( !mDataProvider.get() || !mDataProvider->hasValidIndex() )
843 {
844 QgsMessageLog::logMessage( QObject::tr( "Failed to calculate statistics of the point cloud %1" ).arg( this->name() ) );
845 return;
846 }
847 if ( mStatsCalculationTask )
848 {
849 QgsMessageLog::logMessage( QObject::tr( "A statistics calculation task for the point cloud %1 is already in progress" ).arg( this->name() ) );
850 return;
851 }
852
853 QgsPointCloudStatistics indexStats = mDataProvider->metadataStatistics();
854 QList<QString> indexStatsAttributes = indexStats.statisticsMap().keys();
855 QVector<QgsPointCloudAttribute> attributes = mDataProvider->attributes().attributes();
856 // Do not calculate stats for attributes that the index gives us stats for
857 for ( int i = 0; i < attributes.size(); ++i )
858 {
859 if ( indexStatsAttributes.contains( attributes[i].name() ) )
860 {
861 attributes.remove( i );
862 --i;
863 }
864 }
865
866 // Use the layer statistics for now, until we can calculate complete ones
867 mStatistics = indexStats;
868 if ( attributes.empty() && indexStats.sampledPointsCount() > 0 )
869 {
870 // All attributes are covered by the saved stats, skip calculating anything
872 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
873 resetRenderer();
874 return;
875 }
876
877 QgsPointCloudStatsCalculationTask *task = new QgsPointCloudStatsCalculationTask( mDataProvider->index(), attributes, 1000000 );
878 connect( task, &QgsTask::taskCompleted, this, [this, task, indexStats, indexStatsAttributes]() {
879 mStatistics = task->calculationResults();
880
881 // Fetch what we can directly from the index
882 QMap<QString, QgsPointCloudAttributeStatistics> statsMap = mStatistics.statisticsMap();
883 for ( const QString &attribute : indexStatsAttributes )
884 {
885 statsMap[attribute] = indexStats.statisticsOf( attribute );
886 }
887 mStatistics = QgsPointCloudStatistics( mStatistics.sampledPointsCount(), statsMap );
888
890 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
891 resetRenderer();
892 mStatsCalculationTask = 0;
893#ifdef HAVE_COPC
894 if ( mDataProvider && mDataProvider->index() && mDataProvider->index().isValid() && mDataProvider->name() == "pdal"_L1 && mStatistics.sampledPointsCount() != 0 )
895 {
896 mDataProvider->index().writeStatistics( mStatistics );
897 }
898#endif
899 } );
900
901 // In case the statistics calculation fails, QgsTask::taskTerminated will be called
902 connect( task, &QgsTask::taskTerminated, this, [this]() {
903 if ( mStatsCalculationTask )
904 {
905 QgsMessageLog::logMessage( QObject::tr( "Failed to calculate statistics of the point cloud %1" ).arg( this->name() ) );
906 mStatsCalculationTask = 0;
907 }
908 } );
909
910 mStatsCalculationTask = QgsApplication::taskManager()->addTask( task );
911
913 emit statisticsCalculationStateChanged( mStatisticsCalculationState );
914}
915
916void QgsPointCloudLayer::resetRenderer()
917{
919
920 mDataProvider->loadIndex();
922 {
923 calculateStatistics();
924 }
925 if ( !mRenderer || mRenderer->type() == "extent"_L1 )
926 {
928 }
930
931 emit rendererChanged();
932}
933
934void QgsPointCloudLayer::loadIndexesForRenderContext( QgsRenderContext &rendererContext ) const
935{
936 if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::ContainSubIndexes )
937 {
938 QgsRectangle renderExtent;
939 try
940 {
941 renderExtent = rendererContext.coordinateTransform().transformBoundingBox( rendererContext.mapExtent(), Qgis::TransformDirection::Reverse );
942 }
943 catch ( QgsCsException & )
944 {
945 QgsDebugError( u"Transformation of extent failed!"_s );
946 }
947
948 const QVector<QgsPointCloudSubIndex> subIndex = mDataProvider->subIndexes();
949 if ( const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() ) )
950 {
951 for ( int i = 0; i < subIndex.size(); ++i )
952 {
953 // no need to load as it's there
954 if ( subIndex.at( i ).index() )
955 continue;
956
957 const double overviewSwitchingScale = mRenderer ? mRenderer->overviewSwitchingScale() : 1.0;
958 const double widthThreshold = vpcProvider->averageSubIndexWidth() * overviewSwitchingScale;
959 const double heightThreshold = vpcProvider->averageSubIndexHeight() * overviewSwitchingScale;
960
961 if ( subIndex.at( i ).extent().intersects( renderExtent ) && ( renderExtent.width() < widthThreshold || renderExtent.height() < heightThreshold ) )
962 {
963 mDataProvider->loadSubIndex( i, true );
964 }
965 }
966 }
967 }
968}
969
971{
973 if ( !mDataProvider || mEditable )
974 return false;
975
976 if ( mIsVpc )
977 {
978 QgsVirtualPointCloudProvider *vpcProvider = qobject_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() );
979 const QVector<QgsPointCloudSubIndex> subIndexes = vpcProvider->subIndexes();
980
981 for ( int i = 0; i < subIndexes.size(); ++i )
982 {
983 const QgsPointCloudSubIndex &subIndex = subIndexes.at( i );
984 QgsPointCloudIndex index = subIndex.index();
985
986 if ( !index.isValid() )
987 {
988 continue;
989 }
990
992 mEditingIndexes[i] = editIndex;
993 }
994 }
995 else
996 {
997 mEditIndex = QgsPointCloudIndex( new QgsPointCloudEditingIndex( mDataProvider->index() ) );
998 if ( !mEditIndex.isValid() )
999 {
1000 mEditIndex = QgsPointCloudIndex();
1001 return false;
1002 }
1003 }
1004
1005 mEditable = true;
1006 emit editingStarted();
1007 return true;
1008}
1009
1011{
1013
1014 if ( mIsVpc )
1015 {
1016 for ( QgsPointCloudIndex &index : mEditingIndexes )
1017 if ( index.isModified() && !index.commitChanges( &mCommitError ) )
1018 return false;
1019 }
1020 else
1021 {
1022 if ( mEditIndex.isModified() && !mEditIndex.commitChanges( &mCommitError ) )
1023 return false;
1024
1025 // emitting layerModified() is not required as that's done automatically
1026 // when undo stack index changes
1027 }
1028
1029 undoStack()->clear();
1030
1031 if ( stopEditing )
1032 {
1033 if ( mIsVpc )
1034 mEditingIndexes.clear();
1035 else
1036 mEditIndex = QgsPointCloudIndex();
1037
1038 mEditable = false;
1039 emit editingStopped();
1040 }
1041
1042 return true;
1043}
1044
1046{
1048 return mCommitError;
1049}
1050
1052{
1054 if ( !mEditable )
1055 return false;
1056
1057 if ( mIsVpc )
1058 {
1059 if ( mEditingIndexes.isEmpty() )
1060 return false;
1061
1062 QVector<QPair<int, QList<QgsPointCloudNodeId>>> queuedUpdates;
1063 queuedUpdates.reserve( mEditingIndexes.size() );
1064 for ( auto [position, index] : mEditingIndexes.asKeyValueRange() )
1065 {
1066 if ( !index.isValid() )
1067 continue;
1068 const QList<QgsPointCloudNodeId> updatedNodes = index.updatedNodes();
1069 if ( !updatedNodes.isEmpty() )
1070 queuedUpdates.push_back( qMakePair( position, updatedNodes ) );
1071 }
1072
1073 undoStack()->clear();
1074 mEditable = false;
1075 mEditingIndexes.clear();
1076 emit editingStopped();
1077
1078 for ( const QPair<int, QList<QgsPointCloudNodeId>> &pair : std::as_const( queuedUpdates ) )
1079 {
1080 const int position = pair.first;
1081 const QList<QgsPointCloudNodeId> &nodes = pair.second;
1082 for ( QgsPointCloudNodeId n : nodes )
1083 emit chunkAttributeValuesChanged( n, position );
1084 }
1085 }
1086 else
1087 {
1088 if ( !mEditIndex )
1089 return false;
1090
1091 const QList<QgsPointCloudNodeId> updatedNodes = mEditIndex.updatedNodes();
1092
1093 undoStack()->clear();
1094
1095 mEditIndex = QgsPointCloudIndex();
1096 mEditable = false;
1097 emit editingStopped();
1098
1099 for ( QgsPointCloudNodeId n : updatedNodes )
1100 emit chunkAttributeValuesChanged( n, -1 );
1101
1102 // emitting layerModified() is not required as that's done automatically
1103 // when undo stack index changes
1104 }
1105 return true;
1106}
1107
1109{
1111 return mDataProvider && mDataProvider->capabilities() & QgsPointCloudDataProvider::Capability::ChangeAttributeValues;
1112}
1113
1115{
1117
1118 return mEditable;
1119}
1120
1122{
1124 if ( !mEditable )
1125 return false;
1126
1127 if ( mIsVpc )
1128 {
1129 for ( const QgsPointCloudIndex &index : std::as_const( mEditingIndexes ) )
1130 {
1131 if ( index.isModified() )
1132 return true;
1133 }
1134 return false;
1135 }
1136 else
1137 {
1138 if ( !mEditIndex )
1139 return false;
1140 return mEditIndex.isModified();
1141 }
1142}
1143
1144bool QgsPointCloudLayer::changeAttributeValue( QgsPointCloudNodeId n, const QVector<int> &points, const QgsPointCloudAttribute &attribute, double value )
1145{
1146 if ( mIsVpc )
1147 return false;
1148
1149 // for regular point clouds, we send -1 for the position parameter
1150 return this->changeAttributeValue( { { -1, { { n, points } } } }, attribute, value );
1151}
1152
1153bool QgsPointCloudLayer::changeAttributeValue( const QHash<int, QHash<QgsPointCloudNodeId, QVector<int>>> &mappedPoints, const QgsPointCloudAttribute &attribute, double value )
1154{
1156
1157 QgsEventTracing::ScopedEvent _trace( u"PointCloud"_s, u"QgsPointCloudLayer::changeAttributeValue"_s );
1158
1159 if ( !mEditable )
1160 return false;
1161
1162 QVector<QgsPointCloudSubIndex> subs = subIndexes();
1163
1164 for ( auto it = mappedPoints.constBegin(); it != mappedPoints.constEnd(); it++ )
1165 {
1166 const int position = it.key();
1167 QHash<QgsPointCloudNodeId, QVector<int>> nodesAndPoints = it.value();
1168 QgsPointCloudIndex editIndex;
1169
1170 // NOLINTBEGIN(bugprone-branch-clone)
1171 if ( mIsVpc )
1172 {
1173 if ( position >= subs.size() || position < 0 )
1174 return false;
1175
1176 QgsPointCloudIndex index = subs.at( position ).index();
1177 if ( !index || !index.isValid() )
1178 return false;
1179
1180 editIndex = index;
1181 }
1182 else
1183 {
1184 editIndex = mEditIndex;
1185 }
1186 // NOLINTEND(bugprone-branch-clone)
1187
1188 // Cannot allow x,y,z editing as points may get moved outside the node extents
1189 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 )
1190 return false;
1191
1192 const QgsPointCloudAttributeCollection attributeCollection = editIndex.attributes();
1193
1194 int attributeOffset;
1195 const QgsPointCloudAttribute *at = attributeCollection.find( attribute.name(), attributeOffset );
1196
1197 if ( !at || at->size() != attribute.size() || at->type() != attribute.type() )
1198 {
1199 return false;
1200 }
1201
1202 if ( !QgsPointCloudLayerEditUtils::isAttributeValueValid( attribute, value ) )
1203 {
1204 return false;
1205 }
1206
1207 for ( auto it = nodesAndPoints.constBegin(); it != nodesAndPoints.constEnd(); it++ )
1208 {
1209 QgsPointCloudNodeId n = it.key();
1210 QVector<int> points = it.value();
1211
1212 if ( !n.isValid() || !editIndex.hasNode( n ) ) // todo: should not have to check if n.isValid
1213 return false;
1214
1215 if ( points.isEmpty() )
1216 continue;
1217
1218 int pointsMin = std::numeric_limits<int>::max();
1219 int pointsMax = std::numeric_limits<int>::min();
1220 for ( int pt : std::as_const( points ) )
1221 {
1222 if ( pt < pointsMin )
1223 pointsMin = pt;
1224 if ( pt > pointsMax )
1225 pointsMax = pt;
1226 }
1227
1228 if ( pointsMin < 0 || pointsMax >= editIndex.getNode( n ).pointCount() )
1229 return false;
1230 }
1231 }
1232
1233 undoStack()->push( new QgsPointCloudLayerUndoCommandChangeAttribute( this, mappedPoints, attribute, value ) );
1234
1235 return true;
1236}
1237
1239{
1241 if ( mEditIndex )
1242 return mEditIndex;
1243
1244 if ( mDataProvider )
1245 return mDataProvider->index();
1246
1247 return QgsPointCloudIndex();
1248}
1249
1250QVector<QgsPointCloudSubIndex> QgsPointCloudLayer::subIndexes() const
1251{
1253
1254 if ( !mDataProvider )
1255 return QVector<QgsPointCloudSubIndex>();
1256
1257 const QVector<QgsPointCloudSubIndex> subs = mDataProvider->subIndexes();
1258
1259 if ( !mEditable )
1260 {
1261 return subs;
1262 }
1263
1264 QVector<QgsPointCloudSubIndex> indexes;
1265 indexes.reserve( subs.size() );
1266
1267 for ( qsizetype i = 0; i < subs.size(); i++ )
1268 {
1269 QgsPointCloudSubIndex sub = subs.at( i );
1270 QgsPointCloudIndex index = sub.index();
1271
1272 if ( index.isValid() )
1273 {
1274 if ( !mEditingIndexes.contains( i ) )
1275 {
1277 mEditingIndexes[i] = editIndex;
1278 }
1279 sub.setIndex( mEditingIndexes[i] );
1280 }
1281 indexes.append( sub );
1282 }
1283
1284 return indexes;
1285}
1286
1288{
1289 if ( !mDataProvider || !mIsVpc )
1290 return QgsPointCloudIndex();
1291
1292 const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() );
1293
1294 if ( vpcProvider->overviews().isEmpty() )
1295 return QgsPointCloudIndex();
1296
1297 return vpcProvider->overviews().first();
1298}
1299
1300QVector<QgsPointCloudIndex> QgsPointCloudLayer::overviews() const
1301{
1302 if ( !mDataProvider || !mIsVpc )
1303 return {};
1304
1305 const QgsVirtualPointCloudProvider *vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider *>( mDataProvider.get() );
1306 return vpcProvider->overviews();
1307}
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:5257
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:4491
@ 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:2833
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(QgsPointCloudNodeId id) const
Returns object for a given node.
bool hasNode(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 chunkAttributeValuesChanged(QgsPointCloudNodeId n, const int position)
Emitted when a node gets some attribute values of some points changed.
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...
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.
bool changeAttributeValue(QgsPointCloudNodeId n, const QVector< int > &points, const QgsPointCloudAttribute &attribute, double value)
Attempts to modify attribute values for specific points in the editing buffer.
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.
Q_DECL_DEPRECATED 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< QgsPointCloudIndex > overviews() const
Returns a list of all overview point cloud indexes associated with the layer (only if the layer has a...
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.
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.