mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
Implement virtual point cloud overviews in 2D
Load overview if it exists either by ref from vpc file or look for overview file. Render overview instead of extends by default when zoomed out.
This commit is contained in:
parent
c45551b26e
commit
a0fb608f69
@ -45,6 +45,9 @@
|
||||
#include "qgscopcpointcloudindex.h"
|
||||
#endif
|
||||
|
||||
#include "qgsvirtualpointcloudprovider.h"
|
||||
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
QgsPointCloudLayer::QgsPointCloudLayer( const QString &uri,
|
||||
@ -956,6 +959,7 @@ void QgsPointCloudLayer::loadIndexesForRenderContext( QgsRenderContext &renderer
|
||||
}
|
||||
|
||||
const QVector<QgsPointCloudSubIndex> subIndex = mDataProvider->subIndexes();
|
||||
const QgsVirtualPointCloudProvider &vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider &>( *mDataProvider );
|
||||
for ( int i = 0; i < subIndex.size(); ++i )
|
||||
{
|
||||
// no need to load as it's there
|
||||
@ -963,7 +967,8 @@ void QgsPointCloudLayer::loadIndexesForRenderContext( QgsRenderContext &renderer
|
||||
continue;
|
||||
|
||||
if ( subIndex.at( i ).extent().intersects( renderExtent ) &&
|
||||
renderExtent.width() < subIndex.at( i ).extent().width() )
|
||||
renderExtent.width() < vpcProvider.averageSubIndexWidth() &&
|
||||
renderExtent.height() < vpcProvider.averageSubIndexHeight() )
|
||||
{
|
||||
mDataProvider->loadSubIndex( i );
|
||||
}
|
||||
|
@ -300,4 +300,4 @@ class CORE_EXPORT QgsPointCloudLayer : public QgsMapLayer, public QgsAbstractPro
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSPOINTCLOUDPLAYER_H
|
||||
#endif // QGSPOINTCLOUDLAYER_H
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include "qgspointcloudrequest.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsruntimeprofiler.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsvirtualpointcloudprovider.h"
|
||||
|
||||
#include <delaunator.hpp>
|
||||
|
||||
@ -198,37 +200,52 @@ bool QgsPointCloudLayerRenderer::render()
|
||||
}
|
||||
else
|
||||
{
|
||||
mSubIndexExtentRenderer->startRender( context );
|
||||
const QgsVirtualPointCloudProvider &vpcProvider = dynamic_cast<QgsVirtualPointCloudProvider &>( *mLayer->dataProvider() );
|
||||
QVector< QgsPointCloudSubIndex > visibleIndexes;
|
||||
for ( const auto &si : mSubIndexes )
|
||||
{
|
||||
if ( canceled )
|
||||
break;
|
||||
if ( renderExtent.intersects( si.extent() ) )
|
||||
{
|
||||
visibleIndexes.append( si );
|
||||
}
|
||||
}
|
||||
// if the overview of virtual point cloud exists we render it when we are zoomed out
|
||||
if ( vpcProvider.overview() != nullptr &&
|
||||
renderExtent.width() > vpcProvider.averageSubIndexWidth() &&
|
||||
renderExtent.height() > vpcProvider.averageSubIndexHeight() )
|
||||
{
|
||||
renderIndex( vpcProvider.overview() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mSubIndexExtentRenderer->startRender( context );
|
||||
for ( const auto &si : visibleIndexes )
|
||||
{
|
||||
if ( canceled )
|
||||
break;
|
||||
|
||||
QgsPointCloudIndex pc = si.index();
|
||||
|
||||
if ( !renderExtent.intersects( si.extent() ) )
|
||||
continue;
|
||||
|
||||
if ( !pc || !pc.isValid() || renderExtent.width() > si.extent().width() )
|
||||
{
|
||||
// when dealing with virtual point clouds, we want to render the individual extents when zoomed out
|
||||
// and only use the selected renderer when zoomed in
|
||||
mSubIndexExtentRenderer->renderExtent( si.polygonBounds(), context );
|
||||
// render the label of point cloud tile
|
||||
if ( mSubIndexExtentRenderer->showLabels() )
|
||||
if ( !pc || !pc.isValid() )
|
||||
{
|
||||
mSubIndexExtentRenderer->renderLabel(
|
||||
context.renderContext().mapToPixel().transformBounds( si.extent().toRectF() ),
|
||||
si.uri().section( "/", -1 ).section( ".", 0, 0 ),
|
||||
context );
|
||||
// TODO: render the individual extents when zoomed out and users requests them
|
||||
mSubIndexExtentRenderer->renderExtent( si.polygonBounds(), context );
|
||||
// render the label of point cloud tile
|
||||
if ( mSubIndexExtentRenderer->showLabels() )
|
||||
{
|
||||
mSubIndexExtentRenderer->renderLabel(
|
||||
context.renderContext().mapToPixel().transformBounds( si.extent().toRectF() ),
|
||||
si.uri().section( "/", -1 ).section( ".", 0, 0 ),
|
||||
context );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
canceled = !renderIndex( pc );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
canceled = !renderIndex( pc );
|
||||
}
|
||||
mSubIndexExtentRenderer->stopRender( context );
|
||||
}
|
||||
mSubIndexExtentRenderer->stopRender( context );
|
||||
}
|
||||
|
||||
mRenderer->stopRender( context );
|
||||
|
@ -177,6 +177,8 @@ void QgsVirtualPointCloudProvider::parseFile()
|
||||
}
|
||||
|
||||
QSet<QString> attributeNames;
|
||||
double subIndexesWidth = 0.0;
|
||||
double subIndexesHeight = 0.0;
|
||||
|
||||
for ( const auto &f : data["features"] )
|
||||
{
|
||||
@ -202,12 +204,35 @@ void QgsVirtualPointCloudProvider::parseFile()
|
||||
QgsGeometry geometry;
|
||||
QgsDoubleRange zRange;
|
||||
|
||||
for ( const auto &asset : f["assets"] )
|
||||
// look directly for link to data file
|
||||
if ( f["assets"].find( "data" ) != f["assets"].end() )
|
||||
{
|
||||
if ( asset.contains( "href" ) )
|
||||
if ( f["assets"]["data"].contains( "href" ) )
|
||||
{
|
||||
uri = QString::fromStdString( asset["href"] );
|
||||
break;
|
||||
uri = QString::fromStdString( f["assets"]["data"]["href"] );
|
||||
}
|
||||
}
|
||||
|
||||
// look for vpc overview reference
|
||||
if ( mOverview == nullptr && f["assets"].find( "overview" ) != f["assets"].end() )
|
||||
{
|
||||
if ( f["assets"]["overview"].contains( "href" ) )
|
||||
{
|
||||
mOverview = std::make_unique<QgsCopcPointCloudIndex>();
|
||||
mOverview->load( fInfo.absoluteDir().absoluteFilePath( QString::fromStdString( f["assets"]["overview"]["href"] ) ) );
|
||||
}
|
||||
}
|
||||
// if it doesn't exist look for overview file in the directory
|
||||
else if ( mOverview == nullptr )
|
||||
{
|
||||
QDir vpcDir = fInfo.absoluteDir();
|
||||
QStringList nameFilter = { "*overview.*laz" };
|
||||
vpcDir.setNameFilters( nameFilter );
|
||||
vpcDir.setFilter( QDir::Files );
|
||||
if ( !vpcDir.entryList().empty() )
|
||||
{
|
||||
mOverview = std::make_unique<QgsCopcPointCloudIndex>();
|
||||
mOverview->load( vpcDir.absoluteFilePath( vpcDir.entryList().first() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,12 +389,16 @@ void QgsVirtualPointCloudProvider::parseFile()
|
||||
}
|
||||
}
|
||||
|
||||
subIndexesWidth += extent.width();
|
||||
subIndexesHeight += extent.height();
|
||||
mPolygonBounds->addPart( geometry );
|
||||
mPointCount += count;
|
||||
QgsPointCloudSubIndex si( uri, geometry, extent, zRange, count );
|
||||
mSubLayers.push_back( si );
|
||||
}
|
||||
mExtent = mPolygonBounds->boundingBox();
|
||||
mAverageSubIndexWidth = subIndexesWidth / mSubLayers.size();
|
||||
mAverageSubIndexHeight = subIndexesHeight / mSubLayers.size();
|
||||
populateAttributeCollection( attributeNames );
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,26 @@ class CORE_EXPORT QgsVirtualPointCloudProvider: public QgsPointCloudDataProvider
|
||||
QgsPointCloudRenderer *createRenderer( const QVariantMap &configuration = QVariantMap() ) const override SIP_FACTORY;
|
||||
bool renderInPreview( const QgsDataProvider::PreviewContext & ) override { return false; }
|
||||
|
||||
/**
|
||||
* Returns pointer to the overview index. May be NULLPTR if it doesn't exist.
|
||||
* \since QGIS 3.42
|
||||
*/
|
||||
QgsPointCloudIndex *overview() const { return mOverview.get(); }
|
||||
|
||||
/**
|
||||
* Returns the calculated average width of point clouds.
|
||||
* \note We use this value to calculate when to switch between overview and point clouds
|
||||
* \since QGIS 3.42
|
||||
*/
|
||||
double averageSubIndexWidth() const { return mAverageSubIndexWidth; }
|
||||
|
||||
/**
|
||||
* Returns the calculated average height of point clouds.
|
||||
* \note We use this value to calculate when to switch between overview and point clouds
|
||||
* \since QGIS 3.42
|
||||
*/
|
||||
double averageSubIndexHeight() const { return mAverageSubIndexHeight; }
|
||||
|
||||
signals:
|
||||
void subIndexLoaded( int i );
|
||||
|
||||
@ -70,11 +90,14 @@ class CORE_EXPORT QgsVirtualPointCloudProvider: public QgsPointCloudDataProvider
|
||||
QVector<QgsPointCloudSubIndex> mSubLayers;
|
||||
std::unique_ptr<QgsGeometry> mPolygonBounds;
|
||||
QgsPointCloudAttributeCollection mAttributes;
|
||||
std::unique_ptr<QgsPointCloudIndex> mOverview;
|
||||
|
||||
QStringList mUriList;
|
||||
QgsRectangle mExtent;
|
||||
qint64 mPointCount = 0;
|
||||
QgsCoordinateReferenceSystem mCrs;
|
||||
double mAverageSubIndexWidth = 0;
|
||||
double mAverageSubIndexHeight = 0;
|
||||
};
|
||||
|
||||
class QgsVirtualPointCloudProviderMetadata : public QgsProviderMetadata
|
||||
|
Loading…
x
Reference in New Issue
Block a user