QGIS API Documentation 4.1.0-Master (01362494303)
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(
38 Qgs3DMapSettings *mapSettings, float tau, QgsChunkLoaderFactory *loaderFactory, bool ownsFactory, int primitivesBudget, Qt3DCore::QNode *parent
39)
40 : QgsChunkedEntity( mapSettings, tau, loaderFactory, ownsFactory, primitivesBudget, parent )
41{
42 mTransform = new Qt3DCore::QTransform;
43 this->addComponent( mTransform );
44
45 connect( mapSettings, &Qgs3DMapSettings::terrainSettingsChanged, this, &QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged );
46}
47
48void QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged()
49{
50 QgsDebugMsgLevel( u"QgsAbstractFeatureBasedChunkedEntity::onTerrainElevationOffsetChanged"_s, 2 );
51
52 float newOffset = static_cast<float>( mMapSettings->terrainSettings()->elevationOffset() );
53 if ( !applyTerrainOffset() )
54 {
55 newOffset = 0.0;
56 }
57 mTransform->setTranslation( QVector3D( 0.0f, 0.0f, newOffset ) );
58}
59
60QList<QgsRayCastHit> QgsAbstractFeatureBasedChunkedEntity::rayIntersection( const QgsRay3D &ray, const QgsRayCastContext &context ) const
61{
62 return rayIntersection( activeNodes(), mTransform->matrix(), ray, context, mMapSettings->origin() );
63}
64
65QList<QgsRayCastHit> QgsAbstractFeatureBasedChunkedEntity::rayIntersection(
66 const QList<QgsChunkNode *> &activeNodes, const QMatrix4x4 &transformMatrix, const QgsRay3D &ray, const QgsRayCastContext &context, const QgsVector3D &origin
67) const
68{
69 QgsDebugMsgLevel( u"Ray cast on vector layer"_s, 2 );
70#ifdef QGISDEBUG
71 int nodeUsed = 0;
72 int nodesAll = 0;
73 int hits = 0;
74 int ignoredGeometries = 0;
75#endif
76 QList<QgsRayCastHit> result;
77
78 float minDist = -1;
79 QVector3D intersectionPoint;
80 QgsFeatureId nearestFid = FID_NULL;
81
82 for ( QgsChunkNode *node : activeNodes )
83 {
84#ifdef QGISDEBUG
85 nodesAll++;
86#endif
87
88 QgsAABB nodeBbox = Qgs3DUtils::mapToWorldExtent( node->box3D(), origin );
89
90 if ( node->entity() && ( minDist < 0 || nodeBbox.distanceFromPoint( ray.origin() ) < minDist ) && QgsRayCastingUtils::rayBoxIntersection( ray, nodeBbox ) )
91 {
92#ifdef QGISDEBUG
93 nodeUsed++;
94#endif
95 const QList<Qt3DRender::QGeometryRenderer *> rendLst = node->entity()->findChildren<Qt3DRender::QGeometryRenderer *>();
96 for ( const auto &rend : rendLst )
97 {
98 auto *geom = rend->geometry();
99 QgsTessellatedPolygonGeometry *polygonGeom = qobject_cast<QgsTessellatedPolygonGeometry *>( geom );
100 if ( !polygonGeom )
101 {
102#ifdef QGISDEBUG
103 ignoredGeometries++;
104#endif
105 continue; // other QGeometry types are not supported for now
106 }
107
108 QVector3D nodeIntPoint;
109 int triangleIndex = -1;
110
111 // the node geometry has been translated by chunkOrigin
112 // This translation is stored in the QTransform component
113 // this needs to be taken into account to get the whole transformation
114 const QMatrix4x4 nodeTransformMatrix = node->entity()->findChild<QgsGeoTransform *>()->matrix();
115 const QMatrix4x4 fullTransformMatrix = transformMatrix * nodeTransformMatrix;
116 if ( QgsRayCastingUtils::rayMeshIntersection( rend, ray, context.maximumDistance(), fullTransformMatrix, nodeIntPoint, triangleIndex ) )
117 {
118#ifdef QGISDEBUG
119 hits++;
120#endif
121 float dist = ( ray.origin() - nodeIntPoint ).length();
122 if ( minDist < 0 || dist < minDist )
123 {
124 minDist = dist;
125 intersectionPoint = nodeIntPoint;
126 nearestFid = polygonGeom->triangleIndexToFeatureId( triangleIndex );
127 }
128 }
129 }
130 }
131 }
132 if ( !FID_IS_NULL( nearestFid ) )
133 {
134 QgsRayCastHit hit;
135 hit.setDistance( minDist );
136 hit.setMapCoordinates( Qgs3DUtils::worldToMapCoordinates( intersectionPoint, origin ) );
137 hit.setProperties( { { u"fid"_s, nearestFid } } );
138 result.append( hit );
139 }
140 QgsDebugMsgLevel( u"Active Nodes: %1, checked nodes: %2, hits found: %3, incompatible geometries: %4"_s.arg( nodesAll ).arg( nodeUsed ).arg( hits ).arg( ignoredGeometries ), 2 );
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:63