22#include "qgsvirtualpointcloudprovider.h"
24#include "moc_qgsvirtualpointcloudentity_p.cpp"
29QgsVirtualPointCloudEntity::QgsVirtualPointCloudEntity(
34 float maximumScreenSpaceError,
35 bool showBoundingBoxes,
40 : Qgs3DMapSceneEntity( map, nullptr )
42 , mCoordinateTransform( coordinateTransform )
43 , mZValueScale( zValueScale )
44 , mZValueOffset( zValueOffset )
45 , mPointBudget( pointBudget )
46 , mMaximumScreenSpaceError( maximumScreenSpaceError )
47 , mShowBoundingBoxes( showBoundingBoxes )
49 mSymbol.reset( symbol );
51 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
52 for (
int i = 0; i < subIndexes.size(); ++i )
54 const QgsPointCloudSubIndex &si = subIndexes.at( i );
57 mBboxes <<
QgsBox3D( intersection, si.zRange().lower(), si.zRange().upper() );
59 createChunkedEntityForSubIndex( i );
62 const QVector<QgsPointCloudIndex> overviews( provider()->overviews() );
63 for (
int i = 0; i < overviews.size(); ++i )
66 const int ovId = -i - 2;
67 QgsPointCloudLayerChunkedEntity *ovEnt(
68 new QgsPointCloudLayerChunkedEntity( mapSettings(), mLayer, ovId, mCoordinateTransform,
dynamic_cast<QgsPointCloud3DSymbol *
>( mSymbol->clone() ), mMaximumScreenSpaceError,
false, mZValueScale, mZValueOffset, mPointBudget )
70 ovEnt->setParent(
this );
71 connect( ovEnt, &QgsChunkedEntity::pendingJobsCountChanged,
this, &Qgs3DMapSceneEntity::pendingJobsCountChanged );
72 connect( ovEnt, &QgsChunkedEntity::newEntityCreated,
this, &Qgs3DMapSceneEntity::newEntityCreated );
73 mOverviewEntities.append( ovEnt );
74 emit newEntityCreated( ovEnt );
80 mBboxesEntity =
new QgsChunkBoundsEntity( boundsEntityOrigin,
this );
82 connect(
this, &QgsVirtualPointCloudEntity::subIndexNeedsLoading, provider(), &QgsVirtualPointCloudProvider::loadSubIndex, Qt::QueuedConnection );
83 connect( provider(), &QgsVirtualPointCloudProvider::subIndexLoaded,
this, &QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex );
86QgsVirtualPointCloudEntity::~QgsVirtualPointCloudEntity()
88 qDeleteAll( mChunkedEntitiesMap );
89 mChunkedEntitiesMap.clear();
91 qDeleteAll( mOverviewEntities );
92 mOverviewEntities.clear();
95QList<QgsChunkedEntity *> QgsVirtualPointCloudEntity::chunkedEntities()
const
97 return mChunkedEntitiesMap.values();
100QgsVirtualPointCloudProvider *QgsVirtualPointCloudEntity::provider()
const
102 return qobject_cast<QgsVirtualPointCloudProvider *>( mLayer->dataProvider() );
105void QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex(
int i )
107 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
108 const QgsPointCloudSubIndex &si = subIndexes.at( i );
111 if ( !si.index() || mBboxes.at( i ).isEmpty() || !si.index().isValid() )
114 QgsPointCloudLayerChunkedEntity *newChunkedEntity
115 =
new QgsPointCloudLayerChunkedEntity( mapSettings(), mLayer, i, mCoordinateTransform,
static_cast<QgsPointCloud3DSymbol *
>( mSymbol->clone() ), mMaximumScreenSpaceError, mShowBoundingBoxes, mZValueScale, mZValueOffset, mPointBudget );
117 mChunkedEntitiesMap.insert( i, newChunkedEntity );
118 newChunkedEntity->setParent(
this );
119 connect( newChunkedEntity, &QgsChunkedEntity::pendingJobsCountChanged,
this, &Qgs3DMapSceneEntity::pendingJobsCountChanged );
120 connect( newChunkedEntity, &QgsChunkedEntity::newEntityCreated,
this, &Qgs3DMapSceneEntity::newEntityCreated );
121 emit newEntityCreated( newChunkedEntity );
124void QgsVirtualPointCloudEntity::handleSceneUpdate(
const SceneContext &sceneContext )
127 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
131 qsizetype subIndexesRendered = 0;
133 for (
int i = 0; i < subIndexes.size(); ++i )
138 bool needsUpdate = mChunkedEntitiesMap.contains( i ) && mChunkedEntitiesMap[i]->needsUpdate();
140 const QgsBox3D &box3D = mBboxes.at( i );
142 if ( !needsUpdate && box3D.
isEmpty() )
150 constexpr int SPAN = 256;
151 const float epsilon =
static_cast<float>( std::min( box3D.
width(), box3D.
height() ) ) / SPAN;
152 const float distance =
static_cast<float>( box3D.
distanceTo( cameraPosMapCoords ) );
154 const double THRESHOLD = 0.2 / overviewSwitchingScale;
158 const bool displayAsBbox = sceneContext.cameraPos.isNull() || sse < static_cast<float>( THRESHOLD );
159 if ( !displayAsBbox )
161 subIndexesRendered += 1;
162 if ( !subIndexes.at( i ).index() )
163 emit subIndexNeedsLoading( i );
165 setRenderSubIndexAsBbox( i, displayAsBbox );
166 if ( !displayAsBbox && mChunkedEntitiesMap.contains( i ) )
167 mChunkedEntitiesMap[i]->handleSceneUpdate( sceneContext );
171 if ( !provider()->overviews().isEmpty()
175 const bool allSubIndexesVisible = !mChunkedEntitiesMap.isEmpty() && subIndexesRendered == mChunkedEntitiesMap.size();
176 for (
const auto &ovEnt : std::as_const( mOverviewEntities ) )
179 ovEnt->setEnabled( !allSubIndexesVisible );
180 ovEnt->handleSceneUpdate( sceneContext );
185QgsRange<float> QgsVirtualPointCloudEntity::getNearFarPlaneRange(
const QMatrix4x4 &viewMatrix )
const
190 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
192 if ( entity->isEnabled() )
194 const QgsRange<float> range = entity->getNearFarPlaneRange( viewMatrix );
195 ffar = std::max( range.
upper(), ffar );
196 fnear = std::min( range.
lower(), fnear );
201 if ( fnear == 1e9 && ffar == 0 )
203 for (
const QgsBox3D &box : mBboxes )
209 fnear = std::min( fnear, bboxfnear );
210 ffar = std::max( ffar, bboxffar );
217int QgsVirtualPointCloudEntity::pendingJobsCount()
const
220 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
222 if ( entity->isEnabled() )
223 jobs += entity->pendingJobsCount();
228bool QgsVirtualPointCloudEntity::needsUpdate()
const
230 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
232 if ( entity->isEnabled() && entity->needsUpdate() )
238void QgsVirtualPointCloudEntity::updateBboxEntity()
240 QList<QgsBox3D> bboxes;
245 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
246 for (
int i = 0; i < subIndexes.size(); ++i )
248 if ( mChunkedEntitiesMap.contains( i ) && mChunkedEntitiesMap[i]->isEnabled() )
251 if ( mBboxes.at( i ).isEmpty() )
254 bboxes << mBboxes.at( i );
258 mBboxesEntity->setBoxes( bboxes );
261void QgsVirtualPointCloudEntity::setRenderSubIndexAsBbox(
int i,
bool asBbox )
263 if ( !mChunkedEntitiesMap.contains( i ) )
266 mChunkedEntitiesMap[i]->setEnabled( !asBbox );
@ RenderOverviewAndExtents
Render point cloud extents over overview point cloud.
@ RenderOverview
Render overview point cloud when zoomed out.
QgsRectangle extent() const
Returns the 3D scene's 2D extent in the 3D scene's CRS.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
static bool isCullable(const QgsAABB &bbox, const QMatrix4x4 &viewProjectionMatrix)
Returns true if bbox is completely outside the current viewing volume.
static float screenSpaceError(float epsilon, float distance, int screenSize, float fov)
This routine approximately calculates how an error (epsilon) of an object in world coordinates at giv...
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 void computeBoundingBoxNearFarPlanes(const QgsAABB &bbox, const QMatrix4x4 &viewMatrix, float &fnear, float &ffar)
This routine computes nearPlane farPlane from the closest and farthest corners point of bounding box ...
Axis-aligned bounding box - in world coords.
static QgsAABB fromBox3D(const QgsBox3D &box3D, const QgsVector3D &origin)
Constructs bounding box from QgsBox3D by subtracting origin 3D vector.
A 3-dimensional box composed of x, y, z coordinates.
Q_DECL_DEPRECATED double distanceTo(const QVector3D &point) const
Returns the smallest distance between the box and the point point (returns 0 if the point is inside t...
double width() const
Returns the width of the box.
double height() const
Returns the height of the box.
bool isEmpty() const
Returns true if the box is empty.
QgsCoordinateReferenceSystem crs
3D symbol that draws point cloud geometries as 3D objects.
3D renderer that renders all points from a point cloud layer.
double overviewSwitchingScale() const
Returns the overview switching scale.
Qgis::PointCloudZoomOutRenderBehavior zoomOutBehavior() const
Returns the renderer behavior when zoomed out.
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.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...