Branch data Line data Source code
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 : : #include "qgspointcloudlayerrenderer.h"
20 : : #include "qgspointcloudindex.h"
21 : : #include "qgsrectangle.h"
22 : : #include "qgspointclouddataprovider.h"
23 : : #include "qgsproviderregistry.h"
24 : : #include "qgslogger.h"
25 : : #include "qgslayermetadataformatter.h"
26 : : #include "qgspointcloudrenderer.h"
27 : : #include "qgsruntimeprofiler.h"
28 : : #include "qgsapplication.h"
29 : : #include "qgspainting.h"
30 : : #include "qgspointcloudrendererregistry.h"
31 : : #include "qgspointcloudlayerelevationproperties.h"
32 : : #include "qgsmaplayerlegend.h"
33 : : #include "qgsmaplayerfactory.h"
34 : : #include <QUrl>
35 : :
36 : 0 : QgsPointCloudLayer::QgsPointCloudLayer( const QString &path,
37 : : const QString &baseName,
38 : : const QString &providerLib,
39 : : const QgsPointCloudLayer::LayerOptions &options )
40 : 0 : : QgsMapLayer( QgsMapLayerType::PointCloudLayer, baseName, path )
41 : 0 : , mElevationProperties( new QgsPointCloudLayerElevationProperties( this ) )
42 : 0 : {
43 : :
44 : 0 : if ( !path.isEmpty() && !providerLib.isEmpty() )
45 : : {
46 : 0 : QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
47 : 0 : setDataSource( path, baseName, providerLib, providerOptions, options.loadDefaultStyle );
48 : :
49 : 0 : if ( !options.skipIndexGeneration && mDataProvider && mDataProvider->isValid() )
50 : 0 : mDataProvider.get()->generateIndex();
51 : 0 : }
52 : :
53 : 0 : setLegend( QgsMapLayerLegend::defaultPointCloudLegend( this ) );
54 : 0 : }
55 : :
56 : 0 : QgsPointCloudLayer::~QgsPointCloudLayer() = default;
57 : :
58 : 0 : QgsPointCloudLayer *QgsPointCloudLayer::clone() const
59 : : {
60 : 0 : LayerOptions options;
61 : 0 : options.loadDefaultStyle = false;
62 : 0 : options.transformContext = transformContext();
63 : 0 : options.skipCrsValidation = true;
64 : :
65 : 0 : QgsPointCloudLayer *layer = new QgsPointCloudLayer( source(), name(), mProviderKey, options );
66 : 0 : QgsMapLayer::clone( layer );
67 : :
68 : 0 : if ( mRenderer )
69 : 0 : layer->setRenderer( mRenderer->clone() );
70 : :
71 : 0 : return layer;
72 : 0 : }
73 : :
74 : 0 : QgsRectangle QgsPointCloudLayer::extent() const
75 : : {
76 : 0 : if ( !mDataProvider )
77 : 0 : return QgsRectangle();
78 : :
79 : 0 : return mDataProvider->extent();
80 : 0 : }
81 : :
82 : 0 : QgsMapLayerRenderer *QgsPointCloudLayer::createMapRenderer( QgsRenderContext &rendererContext )
83 : : {
84 : 0 : return new QgsPointCloudLayerRenderer( this, rendererContext );
85 : 0 : }
86 : :
87 : 0 : QgsPointCloudDataProvider *QgsPointCloudLayer::dataProvider()
88 : : {
89 : 0 : return mDataProvider.get();
90 : : }
91 : :
92 : 0 : const QgsPointCloudDataProvider *QgsPointCloudLayer::dataProvider() const
93 : : {
94 : 0 : return mDataProvider.get();
95 : : }
96 : :
97 : 0 : bool QgsPointCloudLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
98 : : {
99 : : // create provider
100 : 0 : QDomNode pkeyNode = layerNode.namedItem( QStringLiteral( "provider" ) );
101 : 0 : mProviderKey = pkeyNode.toElement().text();
102 : :
103 : 0 : if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
104 : : {
105 : 0 : QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
106 : 0 : setDataSource( mDataSource, mLayerName, mProviderKey, providerOptions, false );
107 : 0 : }
108 : :
109 : 0 : if ( !isValid() )
110 : : {
111 : 0 : return false;
112 : : }
113 : :
114 : 0 : QString errorMsg;
115 : 0 : if ( !readSymbology( layerNode, errorMsg, context ) )
116 : 0 : return false;
117 : :
118 : 0 : readStyleManager( layerNode );
119 : 0 : return true;
120 : 0 : }
121 : :
122 : 0 : bool QgsPointCloudLayer::writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const
123 : : {
124 : 0 : QDomElement mapLayerNode = layerNode.toElement();
125 : 0 : mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::PointCloudLayer ) );
126 : :
127 : 0 : if ( mDataProvider )
128 : : {
129 : 0 : QDomElement provider = doc.createElement( QStringLiteral( "provider" ) );
130 : 0 : QDomText providerText = doc.createTextNode( providerType() );
131 : 0 : provider.appendChild( providerText );
132 : 0 : layerNode.appendChild( provider );
133 : 0 : }
134 : :
135 : 0 : writeStyleManager( layerNode, doc );
136 : :
137 : 0 : QString errorMsg;
138 : 0 : return writeSymbology( layerNode, doc, errorMsg, context );
139 : 0 : }
140 : :
141 : 0 : bool QgsPointCloudLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
142 : : {
143 : 0 : QDomElement elem = node.toElement();
144 : :
145 : 0 : readCommonStyle( elem, context, categories );
146 : :
147 : 0 : readStyle( node, errorMessage, context, categories );
148 : :
149 : 0 : if ( categories.testFlag( CustomProperties ) )
150 : 0 : readCustomProperties( node, QStringLiteral( "variable" ) );
151 : :
152 : : return true;
153 : 0 : }
154 : :
155 : 0 : bool QgsPointCloudLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
156 : : {
157 : 0 : bool result = true;
158 : :
159 : 0 : if ( categories.testFlag( Symbology ) )
160 : : {
161 : 0 : QDomElement rendererElement = node.firstChildElement( QStringLiteral( "renderer" ) );
162 : 0 : if ( !rendererElement.isNull() )
163 : : {
164 : 0 : std::unique_ptr< QgsPointCloudRenderer > r( QgsPointCloudRenderer::load( rendererElement, context ) );
165 : 0 : if ( r )
166 : : {
167 : 0 : setRenderer( r.release() );
168 : 0 : }
169 : : else
170 : : {
171 : 0 : result = false;
172 : : }
173 : 0 : }
174 : : // make sure layer has a renderer - if none exists, fallback to a default renderer
175 : 0 : if ( !mRenderer )
176 : : {
177 : 0 : setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
178 : 0 : }
179 : 0 : }
180 : :
181 : 0 : if ( categories.testFlag( Symbology ) )
182 : : {
183 : : // get and set the blend mode if it exists
184 : 0 : QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
185 : 0 : if ( !blendModeNode.isNull() )
186 : : {
187 : 0 : QDomElement e = blendModeNode.toElement();
188 : 0 : setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
189 : 0 : }
190 : 0 : }
191 : :
192 : : // get and set the layer transparency and scale visibility if they exists
193 : 0 : if ( categories.testFlag( Rendering ) )
194 : : {
195 : 0 : QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
196 : 0 : if ( !layerOpacityNode.isNull() )
197 : : {
198 : 0 : QDomElement e = layerOpacityNode.toElement();
199 : 0 : setOpacity( e.text().toDouble() );
200 : 0 : }
201 : :
202 : 0 : const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
203 : 0 : setScaleBasedVisibility( hasScaleBasedVisibiliy );
204 : : bool ok;
205 : 0 : const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
206 : 0 : if ( ok )
207 : : {
208 : 0 : setMaximumScale( maxScale );
209 : 0 : }
210 : 0 : const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
211 : 0 : if ( ok )
212 : : {
213 : 0 : setMinimumScale( minScale );
214 : 0 : }
215 : 0 : }
216 : 0 : return result;
217 : 0 : }
218 : :
219 : 0 : bool QgsPointCloudLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
220 : : const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
221 : : {
222 : 0 : Q_UNUSED( errorMessage )
223 : :
224 : 0 : QDomElement elem = node.toElement();
225 : 0 : writeCommonStyle( elem, doc, context, categories );
226 : :
227 : 0 : ( void )writeStyle( node, doc, errorMessage, context, categories );
228 : :
229 : : return true;
230 : 0 : }
231 : :
232 : 0 : bool QgsPointCloudLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
233 : : {
234 : 0 : QDomElement mapLayerNode = node.toElement();
235 : :
236 : 0 : if ( categories.testFlag( Symbology ) )
237 : : {
238 : 0 : if ( mRenderer )
239 : : {
240 : 0 : QDomElement rendererElement = mRenderer->save( doc, context );
241 : 0 : node.appendChild( rendererElement );
242 : 0 : }
243 : 0 : }
244 : :
245 : : //save customproperties
246 : 0 : if ( categories.testFlag( CustomProperties ) )
247 : : {
248 : 0 : writeCustomProperties( node, doc );
249 : 0 : }
250 : :
251 : 0 : if ( categories.testFlag( Symbology ) )
252 : : {
253 : : // add the blend mode field
254 : 0 : QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
255 : 0 : QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
256 : 0 : blendModeElem.appendChild( blendModeText );
257 : 0 : node.appendChild( blendModeElem );
258 : 0 : }
259 : :
260 : : // add the layer opacity and scale visibility
261 : 0 : if ( categories.testFlag( Rendering ) )
262 : : {
263 : 0 : QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
264 : 0 : QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
265 : 0 : layerOpacityElem.appendChild( layerOpacityText );
266 : 0 : node.appendChild( layerOpacityElem );
267 : :
268 : 0 : mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
269 : 0 : mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
270 : 0 : mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
271 : 0 : }
272 : :
273 : : return true;
274 : 0 : }
275 : :
276 : 0 : void QgsPointCloudLayer::setTransformContext( const QgsCoordinateTransformContext &transformContext )
277 : : {
278 : 0 : if ( mDataProvider )
279 : 0 : mDataProvider->setTransformContext( transformContext );
280 : 0 : invalidateWgs84Extent();
281 : 0 : }
282 : :
283 : 0 : void QgsPointCloudLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
284 : : const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
285 : : {
286 : 0 : if ( mDataProvider )
287 : : {
288 : 0 : disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
289 : 0 : disconnect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
290 : 0 : }
291 : :
292 : 0 : setName( baseName );
293 : 0 : mProviderKey = provider;
294 : 0 : mDataSource = dataSource;
295 : :
296 : 0 : QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
297 : 0 : if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
298 : : {
299 : 0 : flags |= QgsDataProvider::FlagTrustDataSource;
300 : 0 : }
301 : :
302 : 0 : mDataProvider.reset( qobject_cast<QgsPointCloudDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options, flags ) ) );
303 : 0 : if ( !mDataProvider )
304 : : {
305 : 0 : QgsDebugMsg( QStringLiteral( "Unable to get point cloud data provider" ) );
306 : 0 : setValid( false );
307 : 0 : emit dataSourceChanged();
308 : 0 : return;
309 : : }
310 : :
311 : 0 : mDataProvider->setParent( this );
312 : 0 : QgsDebugMsgLevel( QStringLiteral( "Instantiated the point cloud data provider plugin" ), 2 );
313 : :
314 : 0 : setValid( mDataProvider->isValid() );
315 : 0 : if ( !isValid() )
316 : : {
317 : 0 : QgsDebugMsg( QStringLiteral( "Invalid point cloud provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ) );
318 : 0 : emit dataSourceChanged();
319 : 0 : return;
320 : : }
321 : :
322 : 0 : connect( mDataProvider.get(), &QgsPointCloudDataProvider::indexGenerationStateChanged, this, &QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged );
323 : 0 : connect( mDataProvider.get(), &QgsPointCloudDataProvider::dataChanged, this, &QgsPointCloudLayer::dataChanged );
324 : :
325 : : // Load initial extent, crs and renderer
326 : 0 : setCrs( mDataProvider->crs() );
327 : 0 : setExtent( mDataProvider->extent() );
328 : :
329 : 0 : if ( !mRenderer || loadDefaultStyleFlag )
330 : : {
331 : 0 : std::unique_ptr< QgsScopedRuntimeProfile > profile;
332 : 0 : if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
333 : 0 : profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
334 : :
335 : 0 : bool defaultLoadedFlag = false;
336 : :
337 : 0 : if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
338 : : {
339 : : // first try to create a renderer directly from the data provider
340 : 0 : std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
341 : 0 : if ( defaultRenderer )
342 : : {
343 : 0 : defaultLoadedFlag = true;
344 : 0 : setRenderer( defaultRenderer.release() );
345 : 0 : }
346 : 0 : }
347 : :
348 : 0 : if ( !defaultLoadedFlag && loadDefaultStyleFlag )
349 : : {
350 : 0 : loadDefaultStyle( defaultLoadedFlag );
351 : 0 : }
352 : :
353 : 0 : if ( !defaultLoadedFlag )
354 : : {
355 : : // all else failed, create default renderer
356 : 0 : setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
357 : 0 : }
358 : 0 : }
359 : :
360 : 0 : emit dataSourceChanged();
361 : 0 : triggerRepaint();
362 : 0 : }
363 : :
364 : 0 : QString QgsPointCloudLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
365 : : {
366 : 0 : QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( providerType(), source );
367 : 0 : if ( parts.contains( QStringLiteral( "path" ) ) )
368 : : {
369 : 0 : parts.insert( QStringLiteral( "path" ), context.pathResolver().writePath( parts.value( QStringLiteral( "path" ) ).toString() ) );
370 : 0 : return QgsProviderRegistry::instance()->encodeUri( providerType(), parts );
371 : : }
372 : : else
373 : : {
374 : 0 : return source;
375 : : }
376 : 0 : }
377 : :
378 : 0 : QString QgsPointCloudLayer::decodedSource( const QString &source, const QString &dataProvider, const QgsReadWriteContext &context ) const
379 : : {
380 : 0 : QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( dataProvider, source );
381 : 0 : if ( parts.contains( QStringLiteral( "path" ) ) )
382 : : {
383 : 0 : parts.insert( QStringLiteral( "path" ), context.pathResolver().readPath( parts.value( QStringLiteral( "path" ) ).toString() ) );
384 : 0 : return QgsProviderRegistry::instance()->encodeUri( dataProvider, parts );
385 : : }
386 : : else
387 : : {
388 : 0 : return source;
389 : : }
390 : 0 : }
391 : :
392 : 0 : void QgsPointCloudLayer::onPointCloudIndexGenerationStateChanged( QgsPointCloudDataProvider::PointCloudIndexGenerationState state )
393 : : {
394 : 0 : if ( state == QgsPointCloudDataProvider::Indexed )
395 : : {
396 : 0 : mDataProvider.get()->loadIndex();
397 : 0 : if ( mRenderer->type() == QLatin1String( "extent" ) )
398 : : {
399 : 0 : setRenderer( QgsApplication::pointCloudRendererRegistry()->defaultRenderer( mDataProvider.get() ) );
400 : 0 : }
401 : 0 : triggerRepaint();
402 : :
403 : 0 : emit rendererChanged();
404 : 0 : }
405 : 0 : }
406 : :
407 : 0 : QString QgsPointCloudLayer::loadDefaultStyle( bool &resultFlag )
408 : : {
409 : 0 : if ( mDataProvider->capabilities() & QgsPointCloudDataProvider::CreateRenderer )
410 : : {
411 : : // first try to create a renderer directly from the data provider
412 : 0 : std::unique_ptr< QgsPointCloudRenderer > defaultRenderer( mDataProvider->createRenderer() );
413 : 0 : if ( defaultRenderer )
414 : : {
415 : 0 : resultFlag = true;
416 : 0 : setRenderer( defaultRenderer.release() );
417 : 0 : return QString();
418 : : }
419 : 0 : }
420 : :
421 : 0 : return QgsMapLayer::loadDefaultStyle( resultFlag );
422 : 0 : }
423 : :
424 : 0 : QString QgsPointCloudLayer::htmlMetadata() const
425 : : {
426 : 0 : QgsLayerMetadataFormatter htmlFormatter( metadata() );
427 : 0 : QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
428 : :
429 : : // Begin Provider section
430 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
431 : 0 : myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
432 : :
433 : : // name
434 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
435 : :
436 : : // local path
437 : 0 : QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
438 : 0 : QString path;
439 : 0 : if ( uriComponents.contains( QStringLiteral( "path" ) ) )
440 : : {
441 : 0 : path = uriComponents[QStringLiteral( "path" )].toString();
442 : 0 : if ( QFile::exists( path ) )
443 : 0 : 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" );
444 : 0 : }
445 : 0 : if ( uriComponents.contains( QStringLiteral( "url" ) ) )
446 : : {
447 : 0 : const QString url = uriComponents[QStringLiteral( "url" )].toString();
448 : 0 : 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" );
449 : 0 : }
450 : :
451 : : // data source
452 : 0 : if ( publicSource() != path )
453 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
454 : :
455 : : // EPSG
456 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
457 : 0 : if ( crs().isValid() )
458 : : {
459 : 0 : myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
460 : 0 : if ( crs().isGeographic() )
461 : 0 : myMetadata += tr( "Geographic" );
462 : : else
463 : 0 : myMetadata += tr( "Projected" );
464 : 0 : }
465 : 0 : myMetadata += QLatin1String( "</td></tr>\n" );
466 : :
467 : : // Extent
468 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
469 : :
470 : : // unit
471 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
472 : :
473 : : // feature count
474 : 0 : QLocale locale = QLocale();
475 : 0 : locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
476 : 0 : const int pointCount = mDataProvider ? mDataProvider->pointCount() : -1;
477 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
478 : 0 : + tr( "Point count" ) + QStringLiteral( "</td><td>" )
479 : 0 : + ( pointCount < 0 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( pointCount ) ) )
480 : 0 : + QStringLiteral( "</td></tr>\n" );
481 : :
482 : 0 : const QVariantMap originalMetadata = mDataProvider ? mDataProvider->originalMetadata() : QVariantMap();
483 : :
484 : 0 : if ( originalMetadata.value( QStringLiteral( "creation_year" ) ).toInt() > 0 && originalMetadata.contains( QStringLiteral( "creation_doy" ) ) )
485 : : {
486 : 0 : QDate creationDate( originalMetadata.value( QStringLiteral( "creation_year" ) ).toInt(), 1, 1 );
487 : 0 : creationDate = creationDate.addDays( originalMetadata.value( QStringLiteral( "creation_doy" ) ).toInt() );
488 : :
489 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
490 : 0 : + tr( "Creation date" ) + QStringLiteral( "</td><td>" )
491 : 0 : + creationDate.toString( Qt::ISODate )
492 : 0 : + QStringLiteral( "</td></tr>\n" );
493 : 0 : }
494 : 0 : if ( originalMetadata.contains( QStringLiteral( "major_version" ) ) && originalMetadata.contains( QStringLiteral( "minor_version" ) ) )
495 : : {
496 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
497 : 0 : + tr( "Version" ) + QStringLiteral( "</td><td>" )
498 : 0 : + QStringLiteral( "%1.%2" ).arg( originalMetadata.value( QStringLiteral( "major_version" ) ).toString(),
499 : 0 : originalMetadata.value( QStringLiteral( "minor_version" ) ).toString() )
500 : 0 : + QStringLiteral( "</td></tr>\n" );
501 : 0 : }
502 : :
503 : 0 : if ( !originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toString().isEmpty() )
504 : : {
505 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
506 : 0 : + tr( "Data format" ) + QStringLiteral( "</td><td>" )
507 : 0 : + QStringLiteral( "%1 (%2)" ).arg( QgsPointCloudDataProvider::translatedDataFormatIds().value( originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toInt() ),
508 : 0 : originalMetadata.value( QStringLiteral( "dataformat_id" ) ).toString() ).trimmed()
509 : 0 : + QStringLiteral( "</td></tr>\n" );
510 : 0 : }
511 : :
512 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
513 : 0 : + tr( "Scale X" ) + QStringLiteral( "</td><td>" )
514 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "scale_x" ) ).toDouble() )
515 : 0 : + QStringLiteral( "</td></tr>\n" );
516 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
517 : 0 : + tr( "Scale Y" ) + QStringLiteral( "</td><td>" )
518 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "scale_y" ) ).toDouble() )
519 : 0 : + QStringLiteral( "</td></tr>\n" );
520 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
521 : 0 : + tr( "Scale Z" ) + QStringLiteral( "</td><td>" )
522 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "scale_z" ) ).toDouble() )
523 : 0 : + QStringLiteral( "</td></tr>\n" );
524 : :
525 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
526 : 0 : + tr( "Offset X" ) + QStringLiteral( "</td><td>" )
527 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "offset_x" ) ).toDouble() )
528 : 0 : + QStringLiteral( "</td></tr>\n" );
529 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
530 : 0 : + tr( "Offset Y" ) + QStringLiteral( "</td><td>" )
531 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "offset_y" ) ).toDouble() )
532 : 0 : + QStringLiteral( "</td></tr>\n" );
533 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
534 : 0 : + tr( "Offset Z" ) + QStringLiteral( "</td><td>" )
535 : 0 : + QString::number( originalMetadata.value( QStringLiteral( "offset_z" ) ).toDouble() )
536 : 0 : + QStringLiteral( "</td></tr>\n" );
537 : :
538 : 0 : if ( !originalMetadata.value( QStringLiteral( "project_id" ) ).toString().isEmpty() )
539 : : {
540 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
541 : 0 : + tr( "Project ID" ) + QStringLiteral( "</td><td>" )
542 : 0 : + originalMetadata.value( QStringLiteral( "project_id" ) ).toString()
543 : 0 : + QStringLiteral( "</td></tr>\n" );
544 : 0 : }
545 : :
546 : 0 : if ( !originalMetadata.value( QStringLiteral( "system_id" ) ).toString().isEmpty() )
547 : : {
548 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
549 : 0 : + tr( "System ID" ) + QStringLiteral( "</td><td>" )
550 : 0 : + originalMetadata.value( QStringLiteral( "system_id" ) ).toString()
551 : 0 : + QStringLiteral( "</td></tr>\n" );
552 : 0 : }
553 : :
554 : 0 : if ( !originalMetadata.value( QStringLiteral( "software_id" ) ).toString().isEmpty() )
555 : : {
556 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
557 : 0 : + tr( "Software ID" ) + QStringLiteral( "</td><td>" )
558 : 0 : + originalMetadata.value( QStringLiteral( "software_id" ) ).toString()
559 : 0 : + QStringLiteral( "</td></tr>\n" );
560 : 0 : }
561 : :
562 : : // End Provider section
563 : 0 : myMetadata += QLatin1String( "</table>\n<br><br>" );
564 : :
565 : : // identification section
566 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
567 : 0 : myMetadata += htmlFormatter.identificationSectionHtml( );
568 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
569 : :
570 : : // extent section
571 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
572 : 0 : myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
573 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
574 : :
575 : : // Start the Access section
576 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
577 : 0 : myMetadata += htmlFormatter.accessSectionHtml( );
578 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
579 : :
580 : : // Attributes section
581 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Attributes" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
582 : :
583 : 0 : const QgsPointCloudAttributeCollection attrs = attributes();
584 : :
585 : : // count attributes
586 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( attrs.count() ) + QStringLiteral( "</td></tr>\n" );
587 : :
588 : 0 : myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
589 : 0 : myMetadata += QLatin1String( "<tr><th>" ) + tr( "Attribute" ) + QLatin1String( "</th><th>" ) + tr( "Type" ) + QLatin1String( "</th></tr>\n" );
590 : :
591 : 0 : for ( int i = 0; i < attrs.count(); ++i )
592 : : {
593 : 0 : const QgsPointCloudAttribute attribute = attrs.at( i );
594 : 0 : QString rowClass;
595 : 0 : if ( i % 2 )
596 : 0 : rowClass = QStringLiteral( "class=\"odd-row\"" );
597 : 0 : myMetadata += QLatin1String( "<tr " ) + rowClass + QLatin1String( "><td>" ) + attribute.name() + QLatin1String( "</td><td>" ) + attribute.displayType() + QLatin1String( "</td></tr>\n" );
598 : 0 : }
599 : :
600 : : //close field list
601 : 0 : myMetadata += QLatin1String( "</table>\n<br><br>" );
602 : :
603 : :
604 : : // Start the contacts section
605 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
606 : 0 : myMetadata += htmlFormatter.contactsSectionHtml( );
607 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
608 : :
609 : : // Start the links section
610 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
611 : 0 : myMetadata += htmlFormatter.linksSectionHtml( );
612 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
613 : :
614 : : // Start the history section
615 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
616 : 0 : myMetadata += htmlFormatter.historySectionHtml( );
617 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
618 : :
619 : 0 : myMetadata += QLatin1String( "\n</body>\n</html>\n" );
620 : 0 : return myMetadata;
621 : 0 : }
622 : :
623 : 0 : QgsMapLayerElevationProperties *QgsPointCloudLayer::elevationProperties()
624 : : {
625 : 0 : return mElevationProperties;
626 : : }
627 : :
628 : 0 : QgsPointCloudAttributeCollection QgsPointCloudLayer::attributes() const
629 : : {
630 : 0 : return mDataProvider ? mDataProvider->attributes() : QgsPointCloudAttributeCollection();
631 : : }
632 : :
633 : 0 : int QgsPointCloudLayer::pointCount() const
634 : : {
635 : 0 : return mDataProvider ? mDataProvider->pointCount() : 0;
636 : : }
637 : :
638 : 0 : QgsPointCloudRenderer *QgsPointCloudLayer::renderer()
639 : : {
640 : 0 : return mRenderer.get();
641 : : }
642 : :
643 : 0 : const QgsPointCloudRenderer *QgsPointCloudLayer::renderer() const
644 : : {
645 : 0 : return mRenderer.get();
646 : : }
647 : :
648 : 0 : void QgsPointCloudLayer::setRenderer( QgsPointCloudRenderer *renderer )
649 : : {
650 : 0 : if ( renderer == mRenderer.get() )
651 : 0 : return;
652 : :
653 : 0 : mRenderer.reset( renderer );
654 : 0 : emit rendererChanged();
655 : 0 : emit styleChanged();
656 : 0 : }
|