QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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"
20 #include "qgspointcloudindex.h"
21 #include "qgsrectangle.h"
23 #include "qgsproviderregistry.h"
24 #include "qgslogger.h"
26 #include "qgspointcloudrenderer.h"
27 #include "qgsruntimeprofiler.h"
28 #include "qgsapplication.h"
29 #include "qgspainting.h"
32 #include "qgsmaplayerlegend.h"
33 #include "qgsmaplayerfactory.h"
34 #include <QUrl>
35 
37  const QString &baseName,
38  const QString &providerLib,
39  const QgsPointCloudLayer::LayerOptions &options )
40  : QgsMapLayer( QgsMapLayerType::PointCloudLayer, baseName, path )
41  , mElevationProperties( new QgsPointCloudLayerElevationProperties( this ) )
42 {
43 
44  if ( !path.isEmpty() && !providerLib.isEmpty() )
45  {
46  QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
47  setDataSource( path, baseName, providerLib, providerOptions, options.loadDefaultStyle );
48 
49  if ( !options.skipIndexGeneration && mDataProvider && mDataProvider->isValid() )
50  mDataProvider.get()->generateIndex();
51  }
52 
54 }
55 
57 
59 {
60  LayerOptions options;
61  options.loadDefaultStyle = false;
63  options.skipCrsValidation = true;
64 
65  QgsPointCloudLayer *layer = new QgsPointCloudLayer( source(), name(), mProviderKey, options );
66  QgsMapLayer::clone( layer );
67 
68  if ( mRenderer )
69  layer->setRenderer( mRenderer->clone() );
70 
71  return layer;
72 }
73 
75 {
76  if ( !mDataProvider )
77  return QgsRectangle();
78 
79  return mDataProvider->extent();
80 }
81 
83 {
84  return new QgsPointCloudLayerRenderer( this, rendererContext );
85 }
86 
88 {
89  return mDataProvider.get();
90 }
91 
93 {
94  return mDataProvider.get();
95 }
96 
97 bool QgsPointCloudLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
98 {
99  // create provider
100  QDomNode pkeyNode = layerNode.namedItem( QStringLiteral( "provider" ) );
101  mProviderKey = pkeyNode.toElement().text();
102 
104  {
105  QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
106  setDataSource( mDataSource, mLayerName, mProviderKey, providerOptions, false );
107  }
108 
109  if ( !isValid() )
110  {
111  return false;
112  }
113 
114  QString errorMsg;
115  if ( !readSymbology( layerNode, errorMsg, context ) )
116  return false;
117 
118  readStyleManager( layerNode );
119  return true;
120 }
121 
122 bool QgsPointCloudLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
123 {
124  QDomElement mapLayerNode = layerNode.toElement();
125  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::PointCloudLayer ) );
126 
127  if ( mDataProvider )
128  {
129  QDomElement provider = doc.createElement( QStringLiteral( "provider" ) );
130  QDomText providerText = doc.createTextNode( providerType() );
131  provider.appendChild( providerText );
132  layerNode.appendChild( provider );
133  }
134 
135  writeStyleManager( layerNode, doc );
136 
137  QString errorMsg;
138  return writeSymbology( layerNode, doc, errorMsg, context );
139 }
140 
141 bool QgsPointCloudLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
142 {
143  QDomElement elem = node.toElement();
144 
145  readCommonStyle( elem, context, categories );
146 
147  readStyle( node, errorMessage, context, categories );
148 
149  if ( categories.testFlag( CustomProperties ) )
150  readCustomProperties( node, QStringLiteral( "variable" ) );
151 
152  return true;
153 }
154 
155 bool QgsPointCloudLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
156 {
157  bool result = true;
158 
159  if ( categories.testFlag( Symbology ) )
160  {
161  QDomElement rendererElement = node.firstChildElement( QStringLiteral( "renderer" ) );
162  if ( !rendererElement.isNull() )
163  {
164  std::unique_ptr< QgsPointCloudRenderer > r( QgsPointCloudRenderer::load( rendererElement, context ) );
165  if ( r )
166  {
167  setRenderer( r.release() );
168  }
169  else
170  {
171  result = false;
172  }
173  }
174  // make sure layer has a renderer - if none exists, fallback to a default renderer
175  if ( !mRenderer )
176  {
177  setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
178  }
179  }
180 
181  if ( categories.testFlag( Symbology ) )
182  {
183  // get and set the blend mode if it exists
184  QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
185  if ( !blendModeNode.isNull() )
186  {
187  QDomElement e = blendModeNode.toElement();
188  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
189  }
190  }
191 
192  // get and set the layer transparency and scale visibility if they exists
193  if ( categories.testFlag( Rendering ) )
194  {
195  QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
196  if ( !layerOpacityNode.isNull() )
197  {
198  QDomElement e = layerOpacityNode.toElement();
199  setOpacity( e.text().toDouble() );
200  }
201 
202  const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
203  setScaleBasedVisibility( hasScaleBasedVisibiliy );
204  bool ok;
205  const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
206  if ( ok )
207  {
208  setMaximumScale( maxScale );
209  }
210  const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
211  if ( ok )
212  {
213  setMinimumScale( minScale );
214  }
215  }
216  return result;
217 }
218 
219 bool QgsPointCloudLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
220  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
221 {
222  Q_UNUSED( errorMessage )
223 
224  QDomElement elem = node.toElement();
225  writeCommonStyle( elem, doc, context, categories );
226 
227  ( void )writeStyle( node, doc, errorMessage, context, categories );
228 
229  return true;
230 }
231 
232 bool QgsPointCloudLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
233 {
234  QDomElement mapLayerNode = node.toElement();
235 
236  if ( categories.testFlag( Symbology ) )
237  {
238  if ( mRenderer )
239  {
240  QDomElement rendererElement = mRenderer->save( doc, context );
241  node.appendChild( rendererElement );
242  }
243  }
244 
245  //save customproperties
246  if ( categories.testFlag( CustomProperties ) )
247  {
248  writeCustomProperties( node, doc );
249  }
250 
251  if ( categories.testFlag( Symbology ) )
252  {
253  // add the blend mode field
254  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
255  QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
256  blendModeElem.appendChild( blendModeText );
257  node.appendChild( blendModeElem );
258  }
259 
260  // add the layer opacity and scale visibility
261  if ( categories.testFlag( Rendering ) )
262  {
263  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
264  QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
265  layerOpacityElem.appendChild( layerOpacityText );
266  node.appendChild( layerOpacityElem );
267 
268  mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
269  mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
270  mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
271  }
272 
273  return true;
274 }
275 
277 {
278  if ( mDataProvider )
279  mDataProvider->setTransformContext( transformContext );
280 }
281 
282 void QgsPointCloudLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
283  const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
284 {
285  if ( mDataProvider )
286  {
287  disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
288  disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
289  }
290 
291  setName( baseName );
292  mProviderKey = provider;
293  mDataSource = dataSource;
294 
295  QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
297  {
299  }
300 
301  mDataProvider.reset( qobject_cast<QgsPointCloudDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) ) );
302  if ( !mDataProvider )
303  {
304  QgsDebugMsg( QStringLiteral( "Unable to get point cloud data provider" ) );
305  setValid( false );
306  emit dataSourceChanged();
307  return;
308  }
309 
310  mDataProvider->setParent( this );
311  QgsDebugMsgLevel( QStringLiteral( "Instantiated the point cloud data provider plugin" ), 2 );
312 
313  setValid( mDataProvider->isValid() );
314  if ( !isValid() )
315  {
316  QgsDebugMsg( QStringLiteral( "Invalid point cloud provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ) );
317  emit dataSourceChanged();
318  return;
319  }
320 
321  connect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
322  connect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
323 
324  // Load initial extent, crs and renderer
325  setCrs( mDataProvider->crs() );
326  setExtent( mDataProvider->extent() );
327 
328  if ( !mRenderer || loadDefaultStyleFlag )
329  {
330  std::unique_ptr< QgsScopedRuntimeProfile > profile;
331  if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
332  profile = qgis::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
333 
334  bool defaultLoadedFlag = false;
335 
336  if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
337  {
338  // first try to create a renderer directly from the data provider
339  std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
340  if ( defaultRenderer )
341  {
342  defaultLoadedFlag = true;
343  setRenderer( defaultRenderer.release() );
344  }
345  }
346 
347  if ( !defaultLoadedFlag && loadDefaultStyleFlag )
348  {
349  loadDefaultStyle( defaultLoadedFlag );
350  }
351 
352  if ( !defaultLoadedFlag )
353  {
354  // all else failed, create default renderer
355  setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
356  }
357  }
358 
359  emit dataSourceChanged();
360  triggerRepaint();
361 }
362 
363 QString QgsPointCloudLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
364 {
365  QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerType(), source );
366  if ( parts.contains( QStringLiteral( "path" ) ) )
367  {
368  parts.insert( QStringLiteral( "path" ), context.pathResolver().writePath( parts.value( QStringLiteral( "path" ) ).toString() ) );
370  }
371  else
372  {
373  return source;
374  }
375 }
376 
377 QString QgsPointCloudLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
378 {
379  QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( dataProvider, source );
380  if ( parts.contains( QStringLiteral( "path" ) ) )
381  {
382  parts.insert( QStringLiteral( "path" ), context.pathResolver().readPath( parts.value( QStringLiteral( "path" ) ).toString() ) );
384  }
385  else
386  {
387  return source;
388  }
389 }
390 
391 void QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged( QgsPointCloudDataProvider::PointCloudIndexGenerationState state )
392 {
393  if ( state == QgsPointCloudDataProvider::Indexed )
394  {
395  mDataProvider.get()->loadIndex();
396  if ( mRenderer->type() == QLatin1String( "extent" ) )
397  {
398  setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
399  }
400  triggerRepaint();
401 
402  emit rendererChanged();
403  }
404 }
405 
406 QString QgsPointCloudLayer::loadDefaultStyle( bool &resultFlag )
407 {
408  if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
409  {
410  // first try to create a renderer directly from the data provider
411  std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
412  if ( defaultRenderer )
413  {
414  resultFlag = true;
415  setRenderer( defaultRenderer.release() );
416  return QString();
417  }
418  }
419 
420  return QgsMapLayer::loadDefaultStyle( resultFlag );
421 }
422 
424 {
425  QgsLayerMetadataFormatter htmlFormatter( metadata() );
426  QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
427 
428  // Begin Provider section
429  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
430  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
431 
432  // name
433  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
434 
435  // local path
436  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
437  QString path;
438  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
439  {
440  path = uriComponents[QStringLiteral( "path" )].toString();
441  if ( QFile::exists( path ) )
442  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Path" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( path ).toString(), QDir::toNativeSeparators( path ) ) ) + QStringLiteral( "</td></tr>\n" );
443  }
444  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
445  {
446  const QString url = uriComponents[QStringLiteral( "url" )].toString();
447  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "URL" ) + QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), url ) ) + QStringLiteral( "</td></tr>\n" );
448  }
449 
450  // data source
451  if ( publicSource() != path )
452  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
453 
454  // EPSG
455  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
456  if ( crs().isValid() )
457  {
458  myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
459  if ( crs().isGeographic() )
460  myMetadata += tr( "Geographic" );
461  else
462  myMetadata += tr( "Projected" );
463  }
464  myMetadata += QLatin1String( "</td></tr>\n" );
465 
466  // Extent
467  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
468 
469  // unit
470  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
471 
472  // feature count
473  QLocale locale = QLocale();
474  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
475  const int pointCount = mDataProvider ? mDataProvider->pointCount() : -1;
476  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
477  + tr( "Point count" ) + QStringLiteral( "</td><td>" )
478  + ( pointCount < 0 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( pointCount ) ) )
479  + QStringLiteral( "</td></tr>\n" );
480 
481  const QVariantMap originalMetadata = mDataProvider ? mDataProvider->originalMetadata() : QVariantMap();
482 
483  if ( originalMetadata.value( QStringLiteral( "creation_year" ) ).toInt() > 0 && originalMetadata.contains( QStringLiteral( "creation_doy" ) ) )
484  {
485  QDate creationDate( originalMetadata.value( QStringLiteral( "creation_year" ) ).toInt(), 1, 1 );
486  creationDate = creationDate.addDays( originalMetadata.value( QStringLiteral( "creation_doy" ) ).toInt() );
487 
488  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
489  + tr( "Creation date" ) + QStringLiteral( "</td><td>" )
490  + creationDate.toString( Qt::ISODate )
491  + QStringLiteral( "</td></tr>\n" );
492  }
493  if ( originalMetadata.contains( QStringLiteral( "major_version" ) ) && originalMetadata.contains( QStringLiteral( "minor_version" ) ) )
494  {
495  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
496  + tr( "Version" ) + QStringLiteral( "</td><td>" )
497  + QStringLiteral( "%1.%2" ).arg( originalMetadata.value( QStringLiteral( "major_version" ) ).toString(),
498  originalMetadata.value( QStringLiteral( "minor_version" ) ).toString() )
499  + QStringLiteral( "</td></tr>\n" );
500  }
501 
502  if ( !originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toString().isEmpty() )
503  {
504  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
505  + tr( "Data format" ) + QStringLiteral( "</td><td>" )
506  + QStringLiteral( "%1 (%2)" ).arg( QgsPointCloudDataProvider::translatedDataFormatIds().value( originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toInt() ),
507  originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toString() ).trimmed()
508  + QStringLiteral( "</td></tr>\n" );
509  }
510 
511  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
512  + tr( "Scale X" ) + QStringLiteral( "</td><td>" )
513  + QString::number( originalMetadata.value( QStringLiteral( "scale_x" ) ).toDouble() )
514  + QStringLiteral( "</td></tr>\n" );
515  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
516  + tr( "Scale Y" ) + QStringLiteral( "</td><td>" )
517  + QString::number( originalMetadata.value( QStringLiteral( "scale_y" ) ).toDouble() )
518  + QStringLiteral( "</td></tr>\n" );
519  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
520  + tr( "Scale Z" ) + QStringLiteral( "</td><td>" )
521  + QString::number( originalMetadata.value( QStringLiteral( "scale_z" ) ).toDouble() )
522  + QStringLiteral( "</td></tr>\n" );
523 
524  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
525  + tr( "Offset X" ) + QStringLiteral( "</td><td>" )
526  + QString::number( originalMetadata.value( QStringLiteral( "offset_x" ) ).toDouble() )
527  + QStringLiteral( "</td></tr>\n" );
528  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
529  + tr( "Offset Y" ) + QStringLiteral( "</td><td>" )
530  + QString::number( originalMetadata.value( QStringLiteral( "offset_y" ) ).toDouble() )
531  + QStringLiteral( "</td></tr>\n" );
532  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
533  + tr( "Offset Z" ) + QStringLiteral( "</td><td>" )
534  + QString::number( originalMetadata.value( QStringLiteral( "offset_z" ) ).toDouble() )
535  + QStringLiteral( "</td></tr>\n" );
536 
537  if ( !originalMetadata.value( QStringLiteral( "project_id" ) ).toString().isEmpty() )
538  {
539  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
540  + tr( "Project ID" ) + QStringLiteral( "</td><td>" )
541  + originalMetadata.value( QStringLiteral( "project_id" ) ).toString()
542  + QStringLiteral( "</td></tr>\n" );
543  }
544 
545  if ( !originalMetadata.value( QStringLiteral( "system_id" ) ).toString().isEmpty() )
546  {
547  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
548  + tr( "System ID" ) + QStringLiteral( "</td><td>" )
549  + originalMetadata.value( QStringLiteral( "system_id" ) ).toString()
550  + QStringLiteral( "</td></tr>\n" );
551  }
552 
553  if ( !originalMetadata.value( QStringLiteral( "software_id" ) ).toString().isEmpty() )
554  {
555  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
556  + tr( "Software ID" ) + QStringLiteral( "</td><td>" )
557  + originalMetadata.value( QStringLiteral( "software_id" ) ).toString()
558  + QStringLiteral( "</td></tr>\n" );
559  }
560 
561  // End Provider section
562  myMetadata += QLatin1String( "</table>\n<br><br>" );
563 
564  // identification section
565  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
566  myMetadata += htmlFormatter.identificationSectionHtml( );
567  myMetadata += QLatin1String( "<br><br>\n" );
568 
569  // extent section
570  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
571  myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
572  myMetadata += QLatin1String( "<br><br>\n" );
573 
574  // Start the Access section
575  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
576  myMetadata += htmlFormatter.accessSectionHtml( );
577  myMetadata += QLatin1String( "<br><br>\n" );
578 
579  // Attributes section
580  myMetadata += QStringLiteral( "<h1>" ) + tr( "Attributes" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
581 
583 
584  // count attributes
585  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( attrs.count() ) + QStringLiteral( "</td></tr>\n" );
586 
587  myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
588  myMetadata += QLatin1String( "<tr><th>" ) + tr( "Attribute" ) + QLatin1String( "</th><th>" ) + tr( "Type" ) + QLatin1String( "</th></tr>\n" );
589 
590  for ( int i = 0; i < attrs.count(); ++i )
591  {
592  const QgsPointCloudAttribute attribute = attrs.at( i );
593  QString rowClass;
594  if ( i % 2 )
595  rowClass = QStringLiteral( "class=\"odd-row\"" );
596  myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + attribute.name() + QLatin1String( "</td><td>" ) + attribute.displayType() + QLatin1String( "</td></tr>\n" );
597  }
598 
599  //close field list
600  myMetadata += QLatin1String( "</table>\n<br><br>" );
601 
602 
603  // Start the contacts section
604  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
605  myMetadata += htmlFormatter.contactsSectionHtml( );
606  myMetadata += QLatin1String( "<br><br>\n" );
607 
608  // Start the links section
609  myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
610  myMetadata += htmlFormatter.linksSectionHtml( );
611  myMetadata += QLatin1String( "<br><br>\n" );
612 
613  // Start the history section
614  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
615  myMetadata += htmlFormatter.historySectionHtml( );
616  myMetadata += QLatin1String( "<br><br>\n" );
617 
618  myMetadata += QLatin1String( "\n</body>\n</html>\n" );
619  return myMetadata;
620 }
621 
623 {
624  return mElevationProperties;
625 }
626 
628 {
629  return mDataProvider ? mDataProvider->attributes() : QgsPointCloudAttributeCollection();
630 }
631 
633 {
634  return mDataProvider ? mDataProvider->pointCount() : 0;
635 }
636 
638 {
639  return mRenderer.get();
640 }
641 
643 {
644  return mRenderer.get();
645 }
646 
648 {
649  if ( renderer == mRenderer.get() )
650  return;
651 
652  mRenderer.reset( renderer );
653  emit rendererChanged();
654  emit styleChanged();
655 }
static QgsPointCloudRendererRegistry * pointCloudRendererRegistry()
Returns the application's point cloud renderer registry, used for managing point cloud layer 2D rende...
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
@ FullString
Full definition – possibly a very lengthy string, e.g. with no truncation of custom WKT definitions.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Contains information about the context in which a coordinate transform is executed.
@ FlagTrustDataSource
Trust datasource config (primary key unicity, geometry type and srid, etc). Improves provider load ti...
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider'...
Class for metadata formatter.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
QString extentSectionHtml(const bool showSpatialExtent=true) const
Formats the "Extents" section according to a metadata object (extent and temporal).
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
QString identificationSectionHtml() const
Formats the "Identification" section according to a metadata object.
QString historySectionHtml() const
Formats the "History" section according to a metadata object.
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
Base class for storage of map layer elevation properties.
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
static QgsMapLayerLegend * defaultPointCloudLegend(QgsPointCloudLayer *layer)
Create new legend implementation for a point cloud layer.
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QString name
Definition: qgsmaplayer.h:88
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...
void writeStyleManager(QDomNode &layerNode, QDomDocument &doc) const
Write style manager's configuration (if exists). To be called by subclasses.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:91
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...
QString mLayerName
Name of the layer - used for display.
Definition: qgsmaplayer.h:1615
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:90
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.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1658
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
void rendererChanged()
Signal emitted when renderer is changed.
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
void dataChanged()
Data of layer changed.
void setName(const QString &name)
Set the display name of the layer.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
bool isValid
Definition: qgsmaplayer.h:93
QString mDataSource
Data source description string, varies by layer type.
Definition: qgsmaplayer.h:1612
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:585
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:584
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.
Definition: qgsmaplayer.h:1663
double minimumScale() const
Returns the minimum map scale (i.e.
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
double opacity
Definition: qgsmaplayer.h:94
@ Symbology
Symbology.
Definition: qgsmaplayer.h:170
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:179
@ CustomProperties
Custom properties (by plugins for instance)
Definition: qgsmaplayer.h:180
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 setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:37
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Collection of point cloud attributes.
int count() const
Returns the number of attributes present in the collection.
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
Attribute for point cloud data pair of name and size in bytes.
QString displayType() const
Returns the type to use when displaying this field.
QString name() const
Returns name of the attribute.
Base class for providing data for QgsPointCloudLayer.
@ CreateRenderer
Provider can create 2D renderers using backend-specific formatting information. See QgsPointCloudData...
static QMap< int, QString > translatedDataFormatIds()
Returns the map of LAS data format ID to translated string value.
PointCloudIndexGenerationState
Point cloud index state.
@ Indexed
The index is ready to be used.
void indexGenerationStateChanged(PointCloudIndexGenerationState state)
Emitted when point cloud generation state is changed.
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
Implementation of threaded rendering for point cloud layers.
Represents a map layer supporting display of point clouds.
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.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
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.
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...
QgsPointCloudRenderer * renderer()
Returns the 2D renderer for the point cloud.
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the docment provided.
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag=false) override
Updates the data source of the layer.
QgsPointCloudDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
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.
~QgsPointCloudLayer() override
int pointCount() const
Returns the total number of points available in the layer.
bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
QgsPointCloudLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
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.
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.
void setRenderer(QgsPointCloudRenderer *renderer)
Sets the 2D renderer for the point cloud.
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...
QgsPointCloudAttributeCollection attributes() const
Returns the attributes available from the layer.
void setTransformContext(const QgsCoordinateTransformContext &transformContext) override
Sets the coordinate transform context to transformContext.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
QgsPointCloudLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib=QStringLiteral("pointcloud"), const QgsPointCloudLayer::LayerOptions &options=QgsPointCloudLayer::LayerOptions())
Constructor - creates a point cloud layer.
Abstract base class for 2d point cloud renderers.
static QgsPointCloudRenderer * load(QDomElement &element, const QgsReadWriteContext &context)
Creates a renderer from an XML element.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString encodeUri(const QString &providerKey, const QVariantMap &parts)
Reassembles a provider data source URI from its component paths (e.g.
The class is used as a container of context for various read/write operations on other objects.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Contains information about the context of a rendering operation.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:69
@ PointCloudLayer
Added in 3.18.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Setting options for creating vector data providers.
Setting options for loading point cloud layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
bool skipIndexGeneration
Set to true if point cloud index generation should be skipped.
QgsCoordinateTransformContext transformContext
Coordinate transform context.