Skip to content

Commit

Permalink
initial implementation of remote ept
Browse files Browse the repository at this point in the history
  • Loading branch information
NEDJIMAbelgacem authored and wonder-sk committed Apr 8, 2021
1 parent b695f06 commit e870065
Show file tree
Hide file tree
Showing 15 changed files with 879 additions and 31 deletions.
Expand Up @@ -89,7 +89,7 @@ has been processed.
Called to start the download
%End

protected:
public:
~QgsFileDownloader();

};
Expand Down
4 changes: 4 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -639,6 +639,7 @@ set(QGIS_CORE_SRCS
pointcloud/qgspointcloudextentrenderer.cpp
pointcloud/qgspointcloudrequest.cpp
pointcloud/qgspointcloudblock.cpp
pointcloud/qgspointcloudblockhandle.cpp
pointcloud/qgspointcloudlayer.cpp
pointcloud/qgspointcloudlayerelevationproperties.cpp
pointcloud/qgspointcloudlayerrenderer.cpp
Expand Down Expand Up @@ -1345,6 +1346,7 @@ set(QGIS_CORE_HDRS
pointcloud/qgspointcloudextentrenderer.h
pointcloud/qgspointcloudrequest.h
pointcloud/qgspointcloudblock.h
pointcloud/qgspointcloudblockhandle.h
pointcloud/qgspointcloudlayer.h
pointcloud/qgspointcloudlayerelevationproperties.h
pointcloud/qgspointcloudlayerrenderer.h
Expand Down Expand Up @@ -1700,12 +1702,14 @@ if (WITH_EPT)
providers/ept/qgseptprovider.cpp
pointcloud/qgseptdecoder.cpp
pointcloud/qgseptpointcloudindex.cpp
pointcloud/qgsremoteeptpointcloudindex.cpp
)
set(QGIS_CORE_HDRS ${QGIS_CORE_HDRS}
providers/ept/qgseptdataitems.h
providers/ept/qgseptprovider.h
pointcloud/qgseptdecoder.h
pointcloud/qgseptpointcloudindex.h
pointcloud/qgsremoteeptpointcloudindex.h
)
endif()

Expand Down
2 changes: 1 addition & 1 deletion src/core/network/qgsfiledownloader.h
Expand Up @@ -108,7 +108,7 @@ class CORE_EXPORT QgsFileDownloader : public QObject
void onSslErrors( QNetworkReply *reply, const QList<QSslError> &errors );
#endif

protected:
public:
~QgsFileDownloader() override;

private:
Expand Down
34 changes: 34 additions & 0 deletions src/core/pointcloud/qgseptdecoder.cpp
Expand Up @@ -209,6 +209,11 @@ QgsPointCloudBlock *QgsEptDecoder::decompressBinary( const QString &filename, co
return _decompressBinary( dataUncompressed, attributes, requestedAttributes );
}

QgsPointCloudBlock *QgsEptDecoder::decompressBinary( const QByteArray &data, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes )
{
return _decompressBinary( data, attributes, requestedAttributes );
}

/* *************************************************************************************** */

QByteArray decompressZtdStream( const QByteArray &dataCompressed )
Expand Down Expand Up @@ -254,6 +259,12 @@ QgsPointCloudBlock *QgsEptDecoder::decompressZStandard( const QString &filename,
return _decompressBinary( dataUncompressed, attributes, requestedAttributes );
}

QgsPointCloudBlock *QgsEptDecoder::decompressZStandard( const QByteArray &data, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes )
{
QByteArray dataUncompressed = decompressZtdStream( data );
return _decompressBinary( dataUncompressed, attributes, requestedAttributes );
}

/* *************************************************************************************** */

QgsPointCloudBlock *QgsEptDecoder::decompressLaz( const QString &filename,
Expand Down Expand Up @@ -466,4 +477,27 @@ QgsPointCloudBlock *QgsEptDecoder::decompressLaz( const QString &filename,
);
}

#include <QDebug>

QgsPointCloudBlock *QgsEptDecoder::decompressLaz( const QByteArray &byteArrayData,
const QgsPointCloudAttributeCollection &attributes,
const QgsPointCloudAttributeCollection &requestedAttributes )
{
QString filename = "/tmp/node.txt";
{
std::ofstream file( filename.toStdString(), std::ios::binary | std::ios::out );
if ( file.is_open() )
{
file.write( byteArrayData.constData(), byteArrayData.size() );
file.close();
}
else
{
qDebug() << "Couldn't open " << filename;
return nullptr;
}
}
return QgsEptDecoder::decompressLaz( filename, attributes, requestedAttributes );
}

///@endcond
3 changes: 3 additions & 0 deletions src/core/pointcloud/qgseptdecoder.h
Expand Up @@ -32,8 +32,11 @@
namespace QgsEptDecoder
{
QgsPointCloudBlock *decompressBinary( const QString &filename, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
QgsPointCloudBlock *decompressBinary( const QByteArray &data, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
QgsPointCloudBlock *decompressZStandard( const QString &filename, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
QgsPointCloudBlock *decompressZStandard( const QByteArray &data, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
QgsPointCloudBlock *decompressLaz( const QString &filename, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
QgsPointCloudBlock *decompressLaz( const QByteArray &data, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes );
};

///@endcond
Expand Down
22 changes: 15 additions & 7 deletions src/core/pointcloud/qgseptpointcloudindex.h
Expand Up @@ -47,15 +47,23 @@ class CORE_EXPORT QgsEptPointCloudIndex: public QgsPointCloudIndex
void load( const QString &fileName ) override;

QgsPointCloudBlock *nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override;
QgsPointCloudBlockHandle *asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) override
{
Q_UNUSED( n );
Q_UNUSED( request );
Q_ASSERT( false );
return nullptr;
}

QgsCoordinateReferenceSystem crs() const override;
int pointCount() const override;
QVariant metadataStatistic( const QString &attribute, QgsStatisticalSummary::Statistic statistic ) const override;
QVariantList metadataClasses( const QString &attribute ) const override;
QVariant metadataClassStatistic( const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic ) const override;
QVariantMap originalMetadata() const override { return mOriginalMetadata; }

QgsCoordinateReferenceSystem crs() const;
int pointCount() const;
QVariant metadataStatistic( const QString &attribute, QgsStatisticalSummary::Statistic statistic ) const;
QVariantList metadataClasses( const QString &attribute ) const;
QVariant metadataClassStatistic( const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic ) const;

QVariantMap originalMetadata() const { return mOriginalMetadata; }
bool isValid() const override;
QgsPointCloudIndex::AccessType accessType() const override { return QgsPointCloudIndex::Local; };

private:
bool loadSchema( QFile &f );
Expand Down
46 changes: 46 additions & 0 deletions src/core/pointcloud/qgspointcloudblockhandle.cpp
@@ -0,0 +1,46 @@
#include "qgspointcloudblockhandle.h"

#include "qgstiledownloadmanager.h"
#include "qgseptdecoder.h"

//
// QgsPointCloudBlockHandle
//

///@cond PRIVATE

QgsPointCloudBlockHandle::QgsPointCloudBlockHandle( const QString &dataType, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, QgsTileDownloadManagerReply *tileDownloadManagerReply )
: mDataType( dataType ), mAttributes( attributes ), mRequestedAttributes( requestedAttributes ), mTileDownloadManagetReply( tileDownloadManagerReply )
{
connect( mTileDownloadManagetReply, &QgsTileDownloadManagerReply::finished, this, &QgsPointCloudBlockHandle::blockFinishedLoading );
}

void QgsPointCloudBlockHandle::blockFinishedLoading()
{
if ( mTileDownloadManagetReply->error() == QNetworkReply::NetworkError::NoError )
{
QgsPointCloudBlock *block = nullptr;
if ( mDataType == QLatin1String( "binary" ) )
{
block = QgsEptDecoder::decompressBinary( mTileDownloadManagetReply->data(), mAttributes, mRequestedAttributes );
}
else if ( mDataType == QLatin1String( "zstandard" ) )
{
block = QgsEptDecoder::decompressZStandard( mTileDownloadManagetReply->data(), mAttributes, mRequestedAttributes );
}
else if ( mDataType == QLatin1String( "laszip" ) )
{
block = QgsEptDecoder::decompressLaz( mTileDownloadManagetReply->data(), mAttributes, mRequestedAttributes );
}
if ( block == nullptr )
emit blockLoadingFailed( QStringLiteral( "unknown data type %1;" ).arg( mDataType ) + mTileDownloadManagetReply->errorString() );
else
emit blockLoadingSucceeded( block );
}
else
{
emit blockLoadingFailed( mTileDownloadManagetReply->errorString() );
}
}

///@endcond
29 changes: 29 additions & 0 deletions src/core/pointcloud/qgspointcloudblockhandle.h
@@ -0,0 +1,29 @@
#ifndef QGSPOINTCLOUDBLOCKHANDLE_H
#define QGSPOINTCLOUDBLOCKHANDLE_H

#include <QObject>

#include "qgspointcloudattribute.h"

class QgsTileDownloadManagerReply;
class QgsPointCloudAttributeCollection;
class QgsPointCloudBlock;

class QgsPointCloudBlockHandle : public QObject
{
Q_OBJECT
public:
QgsPointCloudBlockHandle( const QString &dataType, const QgsPointCloudAttributeCollection &attributes, const QgsPointCloudAttributeCollection &requestedAttributes, QgsTileDownloadManagerReply *tileDownloadManagerReply );
signals:
void blockLoadingSucceeded( QgsPointCloudBlock *block );
void blockLoadingFailed( const QString &errorStr );
private:
QString mDataType;
QgsPointCloudAttributeCollection mAttributes;
QgsPointCloudAttributeCollection mRequestedAttributes;
QgsTileDownloadManagerReply *mTileDownloadManagetReply = nullptr;
private slots:
void blockFinishedLoading();
};

#endif // QGSPOINTCLOUDBLOCKHANDLE_H
3 changes: 2 additions & 1 deletion src/core/pointcloud/qgspointcloudindex.cpp
Expand Up @@ -25,6 +25,8 @@
#include <QTime>
#include <QtDebug>

#include "qgstiledownloadmanager.h"

IndexedPointCloudNode::IndexedPointCloudNode():
mD( -1 ),
mX( 0 ),
Expand Down Expand Up @@ -141,7 +143,6 @@ QgsDoubleRange QgsPointCloudDataBounds::zRange( const QgsVector3D &offset, const

///@endcond


//
// QgsPointCloudIndex
//
Expand Down
39 changes: 38 additions & 1 deletion src/core/pointcloud/qgspointcloudindex.h
Expand Up @@ -31,11 +31,15 @@
#include "qgis_sip.h"
#include "qgspointcloudblock.h"
#include "qgsrange.h"
#include "qgspointcloudattribute.h"
#include "qgsstatisticalsummary.h"

#define SIP_NO_FILE

class QgsPointCloudRequest;
class QgsPointCloudAttributeCollection;
class QgsCoordinateReferenceSystem;
class QgsPointCloudBlockHandle;

/**
* \ingroup core
Expand Down Expand Up @@ -135,7 +139,6 @@ class CORE_EXPORT QgsPointCloudDataBounds
qint32 mXMin, mYMin, mZMin, mXMax, mYMax, mZMax;
};


/**
* \ingroup core
*
Expand All @@ -149,6 +152,13 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject
{
Q_OBJECT
public:
//! The access type of the data, local is for local files and remote for remote files (over HTTP)
enum AccessType
{
Local,
Remote
};

//! Constructs index
explicit QgsPointCloudIndex();
~QgsPointCloudIndex();
Expand All @@ -159,6 +169,21 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject
//! Returns whether index is loaded and valid
virtual bool isValid() const = 0;

/**
* Returns the access type of the data
* If the access type is Remote, data will be fetched from an HTTP server either synchronously or asynchronously
* If the access type is local, the data is stored locally as a file and will only be fetch synchronously ( blocking request with nodeData only )
* \note Always make sure to check before trying to use asyncNodeData since it is not supported in the case of local access type
*/
virtual AccessType accessType() const = 0;

virtual QgsCoordinateReferenceSystem crs() const = 0;
virtual int pointCount() const = 0;
virtual QVariant metadataStatistic( const QString &attribute, QgsStatisticalSummary::Statistic statistic ) const = 0;
virtual QVariantList metadataClasses( const QString &attribute ) const = 0;
virtual QVariant metadataClassStatistic( const QString &attribute, const QVariant &value, QgsStatisticalSummary::Statistic statistic ) const = 0;
virtual QVariantMap originalMetadata() const = 0;

//! Returns root node of the index
IndexedPointCloudNode root() { return IndexedPointCloudNode( 0, 0, 0, 0 ); }

Expand All @@ -183,6 +208,18 @@ class CORE_EXPORT QgsPointCloudIndex: public QObject
*/
virtual QgsPointCloudBlock *nodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) = 0;

/**
* Returns a handle responsible for loading a node data block
*
* e.g. positions (needs to be scaled and offset applied to get coordinates) or
* classification, intensity or custom attributes
*
* It is caller responsibility to free the handle and the block issued by the handle if the loading succeeds.
*
* May return nullptr in case the node is not present or any other problem with loading
*/
virtual QgsPointCloudBlockHandle *asyncNodeData( const IndexedPointCloudNode &n, const QgsPointCloudRequest &request ) = 0;

//! Returns extent of the data
QgsRectangle extent() const { return mExtent; }

Expand Down

0 comments on commit e870065

Please sign in to comment.