QGIS API Documentation 4.3.0-Master (52aa6503bed)
Loading...
Searching...
No Matches
qgsabstractfeaturebasedchunkedentity.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsabstractfeaturebasedchunkedentity.cpp
3 --------------------------------------
4 Date : March 2026
5 Copyright : (C) 2026 by Jean Felder
6 Email : jean dot felder at oslandia dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgs3dmapsettings.h"
19#include "qgs3dutils.h"
20#include "qgschunknode.h"
21#include "qgsfeatureid.h"
22#include "qgsgeotransform.h"
23#include "qgsraycastcontext.h"
24#include "qgsraycastingutils.h"
26
27#include <QString>
28#include <Qt3DCore/QTransform>
29#include <Qt3DRender/QGeometryRenderer>
30
31#include "moc_qgsabstractfeaturebasedchunkedentity.cpp"
32
33using namespace Qt::StringLiterals;
34
36
37QgsAbstractFeatureBasedChunkedEntity::QgsAbstractFeatureBasedChunkedEntity( Qgs3DMapSettings *mapSettings, float tau, QgsChunkLoader *loader, bool ownsLoader, int primitivesBudget, Qt3DCore::QNode *parent )
38 : QgsChunkedEntity( mapSettings, tau, loader, ownsLoader, primitivesBudget, parent )
39{
40 mTransform = new Qt3DCore::QTransform;
41 this->addComponent( mTransform );
42
43 connect( mapSettings, &Qgs3DMapSettings::terrainSettingsChanged, this, &QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged );
44}
45
46void QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged()
47{
48 QgsDebugMsgLevel( u"QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged"_s, 2 );
49
50 float newOffset = static_cast<float>( mMapSettings->terrainSettings()->elevationOffset() );
51 if ( !applyTerrainOffset() )
52 {
53 newOffset = 0.0;
54 }
55 mTransform->setTranslation( QVector3D( 0.0f, 0.0f, newOffset ) );
56}
57
58QList<QgsRayCastHit> QgsAbstractFeatureBasedChunkedEntity::rayIntersection( const QgsRay3D &ray, const QgsRayCastContext &context ) const
59{
60 return rayIntersection( activeNodes(), mTransform->matrix(), ray, context, mMapSettings->origin() );
61}
62
63QList<QgsRayCastHit> QgsAbstractFeatureBasedChunkedEntity::rayIntersection(
64 const QList<QgsChunkNode *> &activeNodes, const QMatrix4x4 &transformMatrix, const QgsRay3D &ray, const QgsRayCastContext &context, const QgsVector3D &origin
65) const
66{
67 QgsDebugMsgLevel( u"Ray cast on vector layer"_s, 2 );
68#ifdef QGISDEBUG
69 int nodeUsed = 0;
70 int nodesAll = 0;
71 int hits = 0;
72 int ignoredGeometries = 0;
73#endif
74 QList<QgsRayCastHit> result;
75
76 float minDist = -1;
77 QVector3D intersectionPoint;
78 QgsFeatureId nearestFid = FID_NULL;
79
80 for ( QgsChunkNode *node : activeNodes )
81 {
82#ifdef QGISDEBUG
83 nodesAll++;
84#endif
85
86 QgsAABB nodeBbox = Qgs3DUtils::mapToWorldExtent( node->box3D(), origin );
87
88 if ( node->entity() && ( minDist < 0 || nodeBbox.distanceFromPoint( ray.origin() ) < minDist ) && QgsRayCastingUtils::rayBoxIntersection( ray, nodeBbox ) )
89 {
90#ifdef QGISDEBUG
91 nodeUsed++;
92#endif
93 const QList<Qt3DRender::QGeometryRenderer *> rendLst = node->entity()->findChildren<Qt3DRender::QGeometryRenderer *>();
94 for ( const auto &rend : rendLst )
95 {
96 auto *geom = rend->geometry();
97 QgsTessellatedPolygonGeometry *polygonGeom = qobject_cast<QgsTessellatedPolygonGeometry *>( geom );
98 if ( !polygonGeom )
99 {
100#ifdef QGISDEBUG
101 ignoredGeometries++;
102#endif
103 continue; // other QGeometry types are not supported for now
104 }
105
106 QVector3D nodeIntPoint;
107 int triangleIndex = -1;
108
109 // the node geometry has been translated by chunkOrigin
110 // This translation is stored in the QTransform component
111 // this needs to be taken into account to get the whole transformation
112 const QMatrix4x4 nodeTransformMatrix = node->entity()->findChild<QgsGeoTransform *>()->matrix();
113 const QMatrix4x4 fullTransformMatrix = transformMatrix * nodeTransformMatrix;
114 if ( QgsRayCastingUtils::rayMeshIntersection( rend, ray, context.maximumDistance(), fullTransformMatrix, nodeIntPoint, triangleIndex ) )
115 {
116#ifdef QGISDEBUG
117 hits++;
118#endif
119 float dist = ( ray.origin() - nodeIntPoint ).length();
120 if ( minDist < 0 || dist < minDist )
121 {
122 minDist = dist;
123 intersectionPoint = nodeIntPoint;
124 nearestFid = polygonGeom->triangleIndexToFeatureId( triangleIndex );
125 }
126 }
127 }
128 }
129 }
130 if ( !FID_IS_NULL( nearestFid ) )
131 {
132 QgsRayCastHit hit;
133 hit.setDistance( minDist );
134 hit.setMapCoordinates( Qgs3DUtils::worldToMapCoordinates( intersectionPoint, origin ) );
135 hit.setProperties( { { u"fid"_s, nearestFid } } );
136 result.append( hit );
137 }
138#ifdef QGISDEBUG
139 QgsDebugMsgLevel( u"Active Nodes: %1, checked nodes: %2, hits found: %3, incompatible geometries: %4"_s.arg( nodesAll ).arg( nodeUsed ).arg( hits ).arg( ignoredGeometries ), 2 );
140#endif
141 return result;
142}
143
Definition of the world.
void terrainSettingsChanged()
Emitted when the terrain settings are changed.
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 QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords, const QgsVector3D &origin)
Converts 3D world coordinates to map coordinates (applies offset).
Axis-aligned bounding box - in world coords.
Definition qgsaabb.h:33
float distanceFromPoint(float x, float y, float z) const
Returns shortest distance from the box to a point.
Definition qgsaabb.cpp:50
A representation of a ray in 3D.
Definition qgsray3d.h:31
QVector3D origin() const
Returns the origin of the ray.
Definition qgsray3d.h:43
Responsible for defining parameters of the ray casting operations in 3D map canvases.
float maximumDistance() const
The maximum distance from ray origin to look for hits when casting a ray.
Contains details about the ray intersecting entities when ray casting in a 3D map canvas.
void setProperties(const QVariantMap &attributes)
Sets the point cloud point attributes, empty map if hit was not on a point cloud point.
void setMapCoordinates(const QgsVector3D &point)
Sets the hit point position in 3d map coordinates.
void setDistance(double distance)
Sets the hit's distance from the ray's origin.
Qt3DRender::QGeometry subclass that represents polygons tessellated into 3D geometry.
QgsFeatureId triangleIndexToFeatureId(uint triangleIndex) const
Returns ID of the feature to which given triangle index belongs (used for picking).
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
bool rayBoxIntersection(const QgsRay3D &ray, const QgsAABB &nodeBbox)
Tests whether an axis aligned box is intersected by a ray.
bool rayMeshIntersection(Qt3DRender::QGeometryRenderer *geometryRenderer, const QgsRay3D &r, float maxDist, const QMatrix4x4 &worldTransform, QVector3D &intPt, int &triangleIndex)
Tests whether a triangular mesh is intersected by a ray.
#define FID_NULL
#define FID_IS_NULL(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80