21#include "qgsvirtualpointcloudprovider.h"
23#include "moc_qgsvirtualpointcloudentity_p.cpp"
28QgsVirtualPointCloudEntity::QgsVirtualPointCloudEntity(
33 float maximumScreenSpaceError,
34 bool showBoundingBoxes,
39 : Qgs3DMapSceneEntity( map, nullptr )
41 , mCoordinateTransform( coordinateTransform )
42 , mZValueScale( zValueScale )
43 , mZValueOffset( zValueOffset )
44 , mPointBudget( pointBudget )
45 , mMaximumScreenSpaceError( maximumScreenSpaceError )
46 , mShowBoundingBoxes( showBoundingBoxes )
48 mSymbol.reset( symbol );
50 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
51 for (
int i = 0; i < subIndexes.size(); ++i )
53 const QgsPointCloudSubIndex &si = subIndexes.at( i );
56 mBboxes <<
QgsBox3D( intersection, si.zRange().lower(), si.zRange().upper() );
58 createChunkedEntityForSubIndex( i );
61 if ( provider()->overview() )
63 mOverviewEntity =
new QgsPointCloudLayerChunkedEntity(
66 provider()->overview(),
69 mMaximumScreenSpaceError,
75 mOverviewEntity->setParent(
this );
76 connect( mOverviewEntity, &QgsChunkedEntity::pendingJobsCountChanged,
this, &Qgs3DMapSceneEntity::pendingJobsCountChanged );
77 connect( mOverviewEntity, &QgsChunkedEntity::newEntityCreated,
this, &Qgs3DMapSceneEntity::newEntityCreated );
78 emit newEntityCreated( mOverviewEntity );
84 mBboxesEntity =
new QgsChunkBoundsEntity( boundsEntityOrigin,
this );
86 connect(
this, &QgsVirtualPointCloudEntity::subIndexNeedsLoading, provider(), &QgsVirtualPointCloudProvider::loadSubIndex, Qt::QueuedConnection );
87 connect( provider(), &QgsVirtualPointCloudProvider::subIndexLoaded,
this, &QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex );
90QgsVirtualPointCloudEntity::~QgsVirtualPointCloudEntity()
92 qDeleteAll( mChunkedEntitiesMap );
93 mChunkedEntitiesMap.clear();
95 delete mOverviewEntity;
96 mOverviewEntity =
nullptr;
99QList<QgsChunkedEntity *> QgsVirtualPointCloudEntity::chunkedEntities()
const
101 return mChunkedEntitiesMap.values();
104QgsVirtualPointCloudProvider *QgsVirtualPointCloudEntity::provider()
const
106 return qobject_cast<QgsVirtualPointCloudProvider *>( mLayer->dataProvider() );
109void QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex(
int i )
111 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
112 const QgsPointCloudSubIndex &si = subIndexes.at( i );
115 if ( !si.index() || mBboxes.at( i ).isEmpty() || !si.index().isValid() )
118 QgsPointCloudLayerChunkedEntity *newChunkedEntity =
new QgsPointCloudLayerChunkedEntity(
122 mCoordinateTransform,
124 mMaximumScreenSpaceError,
131 mChunkedEntitiesMap.insert( i, newChunkedEntity );
132 newChunkedEntity->setParent(
this );
133 connect( newChunkedEntity, &QgsChunkedEntity::pendingJobsCountChanged,
this, &Qgs3DMapSceneEntity::pendingJobsCountChanged );
134 connect( newChunkedEntity, &QgsChunkedEntity::newEntityCreated,
this, &Qgs3DMapSceneEntity::newEntityCreated );
135 emit newEntityCreated( newChunkedEntity );
138void QgsVirtualPointCloudEntity::handleSceneUpdate(
const SceneContext &sceneContext )
141 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
142 for (
int i = 0; i < subIndexes.size(); ++i )
147 bool needsUpdate = mChunkedEntitiesMap.contains( i ) && mChunkedEntitiesMap[i]->needsUpdate();
149 const QgsBox3D &box3D = mBboxes.at( i );
151 if ( !needsUpdate && box3D.
isEmpty() )
159 constexpr int SPAN = 256;
160 const float epsilon =
static_cast<float>( std::min( box3D.
width(), box3D.
height() ) ) / SPAN;
161 const float distance =
static_cast<float>( box3D.
distanceTo( cameraPosMapCoords ) );
163 constexpr float THRESHOLD = .2;
167 const bool displayAsBbox = sceneContext.cameraPos.isNull() || sse < THRESHOLD;
168 if ( !displayAsBbox && !subIndexes.at( i ).index() )
169 emit subIndexNeedsLoading( i );
171 setRenderSubIndexAsBbox( i, displayAsBbox );
172 if ( !displayAsBbox && mChunkedEntitiesMap.contains( i ) )
173 mChunkedEntitiesMap[i]->handleSceneUpdate( sceneContext );
180 mOverviewEntity->handleSceneUpdate( sceneContext );
184QgsRange<float> QgsVirtualPointCloudEntity::getNearFarPlaneRange(
const QMatrix4x4 &viewMatrix )
const
189 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
191 if ( entity->isEnabled() )
193 const QgsRange<float> range = entity->getNearFarPlaneRange( viewMatrix );
194 ffar = std::max( range.
upper(), ffar );
195 fnear = std::min( range.
lower(), fnear );
200 if ( fnear == 1e9 && ffar == 0 )
202 for (
const QgsBox3D &box : mBboxes )
208 fnear = std::min( fnear, bboxfnear );
209 ffar = std::max( ffar, bboxffar );
216int QgsVirtualPointCloudEntity::pendingJobsCount()
const
219 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
221 if ( entity->isEnabled() )
222 jobs += entity->pendingJobsCount();
227bool QgsVirtualPointCloudEntity::needsUpdate()
const
229 for ( QgsChunkedEntity *entity : mChunkedEntitiesMap )
231 if ( entity->isEnabled() && entity->needsUpdate() )
237void QgsVirtualPointCloudEntity::updateBboxEntity()
239 QList<QgsBox3D> bboxes;
244 const QVector<QgsPointCloudSubIndex> subIndexes = provider()->subIndexes();
245 for (
int i = 0; i < subIndexes.size(); ++i )
247 if ( mChunkedEntitiesMap.contains( i ) && mChunkedEntitiesMap[i]->isEnabled() )
250 if ( mBboxes.at( i ).isEmpty() )
253 bboxes << mBboxes.at( i );
257 mBboxesEntity->setBoxes( bboxes );
260void QgsVirtualPointCloudEntity::setRenderSubIndexAsBbox(
int i,
bool asBbox )
262 if ( !mChunkedEntitiesMap.contains( i ) )
265 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.
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...