17#include "qgsvirtualpointcloudprovider.h"
29 float maximumScreenSpaceError,
30 bool showBoundingBoxes,
34 : Qgs3DMapSceneEntity( nullptr )
37 , mCoordinateTransform( coordinateTransform )
38 , mZValueScale( zValueScale )
39 , mZValueOffset( zValueOffset )
40 , mPointBudget( pointBudget )
41 , mMaximumScreenSpaceError( maximumScreenSpaceError )
42 , mShowBoundingBoxes( showBoundingBoxes )
44 mSymbol.reset( symbol );
45 mBboxesEntity =
new QgsChunkBoundsEntity(
this );
47 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
48 for (
int i = 0; i < subIndexes.size(); ++i )
50 const QgsPointCloudSubIndex &si = subIndexes.at( i );
55 createChunkedEntityForSubIndex( i );
59 connect( provider(), &QgsVirtualPointCloudProvider::subIndexLoaded,
this, &QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex );
62QList<QgsChunkedEntity *> QgsVirtualPointCloudEntity::chunkedEntities()
const
64 return mChunkedEntitiesMap.values();
67QgsVirtualPointCloudProvider *QgsVirtualPointCloudEntity::provider()
const
69 return qobject_cast<QgsVirtualPointCloudProvider *>( mLayer->dataProvider() );
72QgsAABB QgsVirtualPointCloudEntity::boundingBox(
int i )
const
74 return mBboxes.at( i );
77void QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex(
int i )
79 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
80 const QgsPointCloudSubIndex &si = subIndexes.at( i );
83 if ( !si.index() || mBboxes.at( i ).isEmpty() )
86 QgsPointCloudLayerChunkedEntity *newChunkedEntity =
new QgsPointCloudLayerChunkedEntity( si.index(),
90 mMaximumScreenSpaceError,
96 mChunkedEntitiesMap.insert( i, newChunkedEntity );
97 newChunkedEntity->setParent(
this );
98 connect( newChunkedEntity, &QgsChunkedEntity::pendingJobsCountChanged,
this, &Qgs3DMapSceneEntity::pendingJobsCountChanged );
99 emit newEntityCreated( newChunkedEntity );
102void QgsVirtualPointCloudEntity::handleSceneUpdate(
const SceneState &state )
104 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
105 for (
int i = 0; i < subIndexes.size(); ++i )
107 const QgsAABB &bbox = mBboxes.at( i );
113 constexpr int SPAN = 256;
114 const float epsilon = std::min( bbox.
xExtent(), bbox.
yExtent() ) / SPAN;
117 constexpr float THRESHOLD = .2;
118 const bool displayAsBbox = sse < THRESHOLD;
119 if ( !displayAsBbox && !subIndexes.at( i ).index() )
120 provider()->loadSubIndex( i );
122 setRenderSubIndexAsBbox( i, displayAsBbox );
123 if ( !displayAsBbox && mChunkedEntitiesMap.contains( i ) )
124 mChunkedEntitiesMap[i]->handleSceneUpdate( state );
129QgsRange<float> QgsVirtualPointCloudEntity::getNearFarPlaneRange(
const QMatrix4x4 &viewMatrix )
const
134 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
136 if ( entity->isEnabled() )
138 const QgsRange<float> range = entity->getNearFarPlaneRange( viewMatrix );
139 ffar = std::max( range.
upper(), ffar );
140 fnear = std::min( range.
lower(), fnear );
145 if ( fnear == 1e9 && ffar == 0 )
147 for (
const QgsAABB &bbox : mBboxes )
149 for (
int i = 0; i < 8; ++i )
151 const QVector4D p( ( ( i >> 0 ) & 1 ) ? bbox.
xMin : bbox.
xMax,
152 ( ( i >> 1 ) & 1 ) ? bbox.
yMin : bbox.
yMax,
153 ( ( i >> 2 ) & 1 ) ? bbox.
zMin : bbox.
zMax, 1 );
155 const QVector4D pc = viewMatrix * p;
157 const float dst = -pc.z();
158 fnear = std::min( fnear, dst );
159 ffar = std::max( ffar, dst );
167int QgsVirtualPointCloudEntity::pendingJobsCount()
const
170 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
172 if ( entity->isEnabled() )
173 jobs += entity->pendingJobsCount();
178bool QgsVirtualPointCloudEntity::needsUpdate()
const
180 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
182 if ( entity->isEnabled() && entity->needsUpdate() )
188void QgsVirtualPointCloudEntity::updateBboxEntity()
190 QList<QgsAABB> bboxes;
191 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
192 for (
int i = 0; i < subIndexes.size(); ++i )
194 if ( mChunkedEntitiesMap.contains( i ) && mChunkedEntitiesMap[i]->isEnabled() )
197 if ( mBboxes.at( i ).isEmpty() )
200 bboxes << mBboxes.at( i );
203 mBboxesEntity->setBoxes( bboxes );
206void QgsVirtualPointCloudEntity::setRenderSubIndexAsBbox(
int i,
bool asBbox )
208 if ( !mChunkedEntitiesMap.contains( i ) )
211 mChunkedEntitiesMap[i]->setEnabled( !asBbox );
static QgsAABB mapToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsVector3D &mapOrigin)
Converts map extent to axis aligned bounding box in 3D world coordinates.
static QgsRectangle tryReprojectExtent2D(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs1, const QgsCoordinateReferenceSystem &crs2, const QgsCoordinateTransformContext &context)
Reprojects extent from crs1 to crs2 coordinate reference system with context context.
static float screenSpaceError(float epsilon, float distance, float screenSize, float fov)
This routine approximately calculates how an error (epsilon) of an object in world coordinates at giv...
float yExtent() const
Returns box width in Y axis.
float xExtent() const
Returns box width in X axis.
bool isEmpty() const
Returns true if any of xExtent(), yExtent() or zExtent() is zero, false otherwise.
float distanceFromPoint(float x, float y, float z) const
Returns shortest distance from the box to a point.
QgsCoordinateReferenceSystem crs
Represents a map layer supporting display of point clouds.
A template based class for storing ranges (lower to upper values).
T lower() const
Returns the lower bound of the range.
T upper() const
Returns the upper bound of the range.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.