Skip to content

Commit 4cf8344

Browse files
ptitjanonyalldawson
authored andcommittedSep 22, 2023
qgsmesh3geometry: Limit geometry to 3d scenes' 2d extent
This is a follow-up of #51304 which did not handle mesh layers. This commit adds this support. The meshes displayed in a 3d view do not take into account the scene 2d extent. This issue is fixed by filtering the faces which are used to build the Qt3D geometry. By using `mesh.faceIndexesForRectangle( extent )`, it is possible to keep the faces inside `extent`. This list is then used to populate the `IndexAttribute` of the qt3d geometry. This way, only the faces inside the extent are displayed.
1 parent 4f345e7 commit 4cf8344

File tree

5 files changed

+84
-26
lines changed

5 files changed

+84
-26
lines changed
 

‎src/3d/mesh/qgsmesh3dentity_p.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void QgsMeshDataset3DEntity::buildGeometry()
5454
return;
5555

5656
Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer;
57-
mesh->setGeometry( new QgsMeshDataset3DGeometry( mTriangularMesh, layer(), mMapSettings.temporalRange(), mMapSettings.origin(), mSymbol.get(), mesh ) );
57+
mesh->setGeometry( new QgsMeshDataset3DGeometry( mTriangularMesh, layer(), mMapSettings.temporalRange(), mMapSettings.origin(), mMapSettings.extent(), mSymbol.get(), mesh ) );
5858
addComponent( mesh );
5959
}
6060

@@ -89,7 +89,7 @@ QgsMesh3DTerrainTileEntity::QgsMesh3DTerrainTileEntity(
8989
void QgsMesh3DTerrainTileEntity::buildGeometry()
9090
{
9191
Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer;
92-
mesh->setGeometry( new QgsMeshTerrain3DGeometry( mTriangularMesh, mMapSettings.origin(), mSymbol.get()->verticalScale(), mesh ) );
92+
mesh->setGeometry( new QgsMeshTerrain3DGeometry( mTriangularMesh, mMapSettings.origin(), mMapSettings.extent(), mSymbol.get()->verticalScale(), mesh ) );
9393
addComponent( mesh );
9494
}
9595

‎src/3d/mesh/qgsmesh3dgeometry_p.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -132,25 +132,25 @@ static QByteArray createDatasetVertexData(
132132
return bufferBytes;
133133
}
134134

135-
static QByteArray createIndexData( const QgsTriangularMesh &mesh )
135+
static QByteArray createIndexData( const QgsTriangularMesh &mesh, const QgsRectangle &extent )
136136
{
137-
const int faces = mesh.triangles().count();
138-
const quint32 indices = static_cast<quint32>( 3 * faces );
137+
const QList<int> facesInExtent = mesh.faceIndexesForRectangle( extent );
138+
const quint32 indices = static_cast<quint32>( 3 * facesInExtent.count() );
139139
Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
140140

141141
// count non void faces
142142
int nonVoidFaces = 0;
143-
for ( int i = 0; i < faces; ++i )
144-
if ( !mesh.triangles().at( i ).isEmpty() )
143+
for ( const int nativeFaceIndex : facesInExtent )
144+
if ( !mesh.triangles().at( nativeFaceIndex ).isEmpty() )
145145
nonVoidFaces++;
146146

147147
QByteArray indexBytes;
148148
indexBytes.resize( int( nonVoidFaces * 3 * sizeof( quint32 ) ) );
149149
quint32 *indexPtr = reinterpret_cast<quint32 *>( indexBytes.data() );
150150

151-
for ( int i = 0; i < faces; ++i )
151+
for ( const int nativeFaceIndex : facesInExtent )
152152
{
153-
const QgsMeshFace &face = mesh.triangles().at( i );
153+
const QgsMeshFace &face = mesh.triangles().at( nativeFaceIndex );
154154
if ( face.isEmpty() )
155155
continue;
156156
for ( int j = 0; j < 3; ++j )
@@ -160,36 +160,34 @@ static QByteArray createIndexData( const QgsTriangularMesh &mesh )
160160
return indexBytes;
161161
}
162162

163-
static QByteArray createDatasetIndexData( const QgsTriangularMesh &mesh, const QgsMeshDataBlock &mActiveFaceFlagValues )
163+
static QByteArray createDatasetIndexData( const QgsTriangularMesh &mesh, const QgsMeshDataBlock &mActiveFaceFlagValues, const QgsRectangle &extent )
164164
{
165+
const QList<int> facesInExtent = mesh.faceIndexesForRectangle( extent );
165166
int activeFaceCount = 0;
166167

167168
// First we need to know about the count of active faces
168169
if ( mActiveFaceFlagValues.active().isEmpty() )
169-
activeFaceCount = mesh.triangles().count();
170+
activeFaceCount = facesInExtent.count();
170171
else
171172
{
172-
for ( int i = 0; i < mesh.triangles().count(); ++i )
173+
for ( const int nativeFaceIndex : facesInExtent )
173174
{
174-
const int nativeIndex = mesh.trianglesToNativeFaces()[i];
175-
if ( mActiveFaceFlagValues.active( nativeIndex ) )
175+
if ( mActiveFaceFlagValues.active( nativeFaceIndex ) )
176176
activeFaceCount++;
177177
}
178178
}
179179

180-
const int trianglesCount = mesh.triangles().count();
181180
const quint32 indices = static_cast<quint32>( 3 * activeFaceCount );
182181
QByteArray indexBytes;
183182
indexBytes.resize( int( indices * sizeof( quint32 ) ) );
184183
quint32 *indexPtr = reinterpret_cast<quint32 *>( indexBytes.data() );
185184

186-
for ( int i = 0; i < trianglesCount; ++i )
185+
for ( const int nativeFaceIndex : facesInExtent )
187186
{
188-
const int nativeFaceIndex = mesh.trianglesToNativeFaces()[i];
189187
const bool isActive = mActiveFaceFlagValues.active().isEmpty() || mActiveFaceFlagValues.active( nativeFaceIndex );
190188
if ( !isActive )
191189
continue;
192-
const QgsMeshFace &face = mesh.triangles().at( i );
190+
const QgsMeshFace &face = mesh.triangles().at( nativeFaceIndex );
193191
for ( int j = 0; j < 3; ++j )
194192
*indexPtr++ = quint32( face.at( j ) );
195193
}
@@ -199,6 +197,7 @@ static QByteArray createDatasetIndexData( const QgsTriangularMesh &mesh, const Q
199197

200198
QgsMesh3DGeometry::QgsMesh3DGeometry( const QgsTriangularMesh &triangularMesh,
201199
const QgsVector3D &origin,
200+
const QgsRectangle &extent,
202201
double verticalScale,
203202
Qt3DCore::QNode *parent )
204203
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -207,6 +206,7 @@ QgsMesh3DGeometry::QgsMesh3DGeometry( const QgsTriangularMesh &triangularMesh,
207206
: Qt3DCore::QGeometry( parent )
208207
#endif
209208
, mOrigin( origin )
209+
, mExtent( extent )
210210
, mVertScale( verticalScale )
211211
, mTriangulaMesh( triangularMesh )
212212
{
@@ -219,9 +219,10 @@ QgsMeshDataset3DGeometry::QgsMeshDataset3DGeometry(
219219
QgsMeshLayer *layer,
220220
const QgsDateTimeRange &timeRange,
221221
const QgsVector3D &origin,
222+
const QgsRectangle &extent,
222223
const QgsMesh3DSymbol *symbol,
223224
Qt3DCore::QNode *parent )
224-
: QgsMesh3DGeometry( triangularMesh, origin, symbol->verticalScale(), parent )
225+
: QgsMesh3DGeometry( triangularMesh, origin, extent, symbol->verticalScale(), parent )
225226
, mIsVerticalMagnitudeRelative( symbol->isVerticalMagnitudeRelative() )
226227
, mVerticalGroupDatasetIndex( symbol->verticalDatasetGroupIndex() )
227228
, mTimeRange( timeRange )
@@ -310,7 +311,7 @@ void QgsMeshDataset3DGeometry::prepareData()
310311
data.activeFaceFlagValues = layer->areFacesActive( scalarDatasetIndex, 0, nativeMesh.faces.count() );
311312
data.isVerticalMagnitudeRelative = mIsVerticalMagnitudeRelative;
312313

313-
mBuilder = new QgsMeshDataset3DGeometryBuilder( mTriangulaMesh, nativeMesh, mOrigin, mVertScale, data, this );
314+
mBuilder = new QgsMeshDataset3DGeometryBuilder( mTriangulaMesh, nativeMesh, mOrigin, mExtent, mVertScale, data, this );
314315
connect( mBuilder, &QgsMeshDataset3DGeometryBuilder::dataIsReady, this, &QgsMeshDataset3DGeometry::getData );
315316

316317
mBuilder->start();
@@ -319,9 +320,10 @@ void QgsMeshDataset3DGeometry::prepareData()
319320

320321
QgsMeshTerrain3DGeometry::QgsMeshTerrain3DGeometry( const QgsTriangularMesh &triangularMesh,
321322
const QgsVector3D &origin,
323+
const QgsRectangle &extent,
322324
double verticalScale,
323325
Qt3DCore::QNode *parent )
324-
: QgsMesh3DGeometry( triangularMesh, origin, verticalScale, parent )
326+
: QgsMesh3DGeometry( triangularMesh, origin, extent, verticalScale, parent )
325327
{
326328

327329
const int stride = ( 3 /*position*/ +
@@ -331,7 +333,7 @@ QgsMeshTerrain3DGeometry::QgsMeshTerrain3DGeometry( const QgsTriangularMesh &tri
331333
prepareVerticesNormalAttribute( mVertexBuffer, stride, 3 );
332334
prepareIndexesAttribute( mIndexBuffer );
333335

334-
mBuilder = new QgsMesh3DGeometryBuilder( triangularMesh, origin, mVertScale, this );
336+
mBuilder = new QgsMesh3DGeometryBuilder( triangularMesh, origin, extent, mVertScale, this );
335337
connect( mBuilder, &QgsMesh3DGeometryBuilder::dataIsReady, this, &QgsMeshTerrain3DGeometry::getData );
336338
mBuilder->start();
337339
}
@@ -416,10 +418,11 @@ void QgsMesh3DGeometry::prepareIndexesAttribute( Qt3DQBuffer *buffer )
416418
}
417419

418420

419-
QgsMesh3DGeometryBuilder::QgsMesh3DGeometryBuilder( const QgsTriangularMesh &mesh, const QgsVector3D &origin, float vertScale, QObject *parent ):
421+
QgsMesh3DGeometryBuilder::QgsMesh3DGeometryBuilder( const QgsTriangularMesh &mesh, const QgsVector3D &origin, const QgsRectangle &extent, float vertScale, QObject *parent ):
420422
QObject( parent )
421423
, mMesh( mesh )
422424
, mOrigin( origin )
425+
, mExtent( extent )
423426
, mVertScale( vertScale )
424427
{}
425428

@@ -434,7 +437,7 @@ void QgsMesh3DGeometryBuilder::start()
434437

435438
mWatcherIndex = new QFutureWatcher<QByteArray>( this );
436439
connect( mWatcherIndex, &QFutureWatcher<int>::finished, this, &QgsMesh3DGeometryBuilder::indexFinished );
437-
mFutureIndex = QtConcurrent::run( createIndexData, mMesh );
440+
mFutureIndex = QtConcurrent::run( createIndexData, mMesh, mExtent );
438441
mWatcherIndex->setFuture( mFutureIndex );
439442
}
440443

@@ -462,10 +465,11 @@ QgsMeshDataset3DGeometryBuilder::QgsMeshDataset3DGeometryBuilder
462465
( const QgsTriangularMesh &mesh,
463466
const QgsMesh &nativeMesh,
464467
const QgsVector3D &origin,
468+
const QgsRectangle &extent,
465469
float vertScale,
466470
const QgsMeshDataset3DGeometry::VertexData &vertexData,
467471
QObject *parent ):
468-
QgsMesh3DGeometryBuilder( mesh, origin, vertScale, parent )
472+
QgsMesh3DGeometryBuilder( mesh, origin, extent, vertScale, parent )
469473
, mNativeMesh( nativeMesh )
470474
, mVertexData( vertexData )
471475
{}
@@ -482,6 +486,6 @@ void QgsMeshDataset3DGeometryBuilder::start()
482486
mWatcherIndex = new QFutureWatcher<QByteArray>( this );
483487
connect( mWatcherIndex, &QFutureWatcher<int>::finished, this, &QgsMeshDataset3DGeometryBuilder::indexFinished );
484488

485-
mFutureIndex = QtConcurrent::run( createDatasetIndexData, mMesh, mVertexData.activeFaceFlagValues );
489+
mFutureIndex = QtConcurrent::run( createDatasetIndexData, mMesh, mVertexData.activeFaceFlagValues, mExtent );
486490
mWatcherIndex->setFuture( mFutureIndex );
487491
}

‎src/3d/mesh/qgsmesh3dgeometry_p.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "qgsmaplayerref.h"
3434
#include "qgsmesh3dsymbol.h"
35+
#include "qgsrectangle.h"
3536
#include "qgstriangularmesh.h"
3637

3738
///@cond PRIVATE
@@ -72,6 +73,7 @@ class QgsMesh3DGeometryBuilder: public QObject
7273
public:
7374
QgsMesh3DGeometryBuilder( const QgsTriangularMesh &mesh,
7475
const QgsVector3D &origin,
76+
const QgsRectangle &extent,
7577
float vertScale,
7678
QObject *parent );
7779

@@ -95,6 +97,7 @@ class QgsMesh3DGeometryBuilder: public QObject
9597

9698
QgsTriangularMesh mMesh;
9799
QgsVector3D mOrigin;
100+
QgsRectangle mExtent;
98101
float mVertScale;
99102

100103
mutable QMutex mMutex;
@@ -118,6 +121,7 @@ class QgsMesh3DGeometry: public Qt3DCore::QGeometry
118121
//! Constructor
119122
explicit QgsMesh3DGeometry( const QgsTriangularMesh &triangularMesh,
120123
const QgsVector3D &origin,
124+
const QgsRectangle &extent,
121125
double verticalScale,
122126
QNode *parent );
123127

@@ -134,6 +138,7 @@ class QgsMesh3DGeometry: public Qt3DCore::QGeometry
134138
#endif
135139

136140
QgsVector3D mOrigin;
141+
QgsRectangle mExtent;
137142
float mVertScale;
138143
QgsTriangularMesh mTriangulaMesh;
139144

@@ -179,6 +184,7 @@ class QgsMeshDataset3DGeometry: public QgsMesh3DGeometry
179184
QgsMeshLayer *layer,
180185
const QgsDateTimeRange &timeRange,
181186
const QgsVector3D &origin,
187+
const QgsRectangle &extent,
182188
const QgsMesh3DSymbol *symbol,
183189
QNode *parent );
184190

@@ -230,6 +236,7 @@ class QgsMeshDataset3DGeometryBuilder: public QgsMesh3DGeometryBuilder
230236
QgsMeshDataset3DGeometryBuilder( const QgsTriangularMesh &mesh,
231237
const QgsMesh &nativeMesh,
232238
const QgsVector3D &origin,
239+
const QgsRectangle &extent,
233240
float vertScale,
234241
const QgsMeshDataset3DGeometry::VertexData &vertexData,
235242
QObject *parent );
@@ -253,6 +260,7 @@ class QgsMeshTerrain3DGeometry: public QgsMesh3DGeometry
253260
//! Constructs a mesh layer geometry from triangular mesh.
254261
explicit QgsMeshTerrain3DGeometry( const QgsTriangularMesh &triangularMesh,
255262
const QgsVector3D &origin,
263+
const QgsRectangle &extent,
256264
double verticalScale,
257265
QNode *parent );
258266
};

‎tests/src/3d/testqgs3drendering.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class TestQgs3DRendering : public QgsTest
9595
void testFilteredFlatTerrain();
9696
void testFilteredDemTerrain();
9797
void testFilteredExtrudedPolygons();
98+
void testFilteredMesh();
9899
void testDepthBuffer();
99100
void testAmbientOcclusion();
100101
void testDebugMap();
@@ -1456,6 +1457,51 @@ void TestQgs3DRendering::testFilteredExtrudedPolygons()
14561457
QVERIFY( imageCheck( "polygon3d_extrusion_filtered", "polygon3d_extrusion_filtered", img, QString(), 40, QSize( 0, 0 ), 2 ) );
14571458
}
14581459

1460+
void TestQgs3DRendering::testFilteredMesh()
1461+
{
1462+
const QgsRectangle fullExtent = mLayerMeshDataset->extent();
1463+
const QgsRectangle filteredExtent = QgsRectangle( fullExtent.xMinimum(), fullExtent.yMinimum(),
1464+
fullExtent.xMinimum() + fullExtent.width() / 3.0, fullExtent.yMinimum() + fullExtent.height() / 4.0 );
1465+
1466+
QgsMesh3DSymbol *symbolMesh3d = new QgsMesh3DSymbol;
1467+
symbolMesh3d->setVerticalDatasetGroupIndex( 0 );
1468+
symbolMesh3d->setVerticalScale( 10 );
1469+
symbolMesh3d->setRenderingStyle( QgsMesh3DSymbol::ColorRamp2DRendering );
1470+
symbolMesh3d->setArrowsEnabled( true );
1471+
symbolMesh3d->setArrowsSpacing( 300 );
1472+
QgsMeshLayer3DRenderer *meshDatasetRenderer3d = new QgsMeshLayer3DRenderer( symbolMesh3d );
1473+
mLayerMeshDataset->setRenderer3D( meshDatasetRenderer3d );
1474+
1475+
Qgs3DMapSettings *map = new Qgs3DMapSettings;
1476+
map->setCrs( mProject->crs() );
1477+
map->setExtent( filteredExtent );
1478+
map->setLayers( QList<QgsMapLayer *>() << mLayerMeshDataset );
1479+
QgsPointLightSettings defaultLight;
1480+
defaultLight.setIntensity( 0.5 );
1481+
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
1482+
map->setLightSources( { defaultLight.clone() } );
1483+
1484+
QgsFlatTerrainGenerator *flatTerrain = new QgsFlatTerrainGenerator;
1485+
flatTerrain->setCrs( map->crs() );
1486+
map->setTerrainGenerator( flatTerrain );
1487+
1488+
QgsOffscreen3DEngine engine;
1489+
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
1490+
engine.setRootEntity( scene );
1491+
scene->cameraController()->setLookingAtPoint( QgsVector3D( 0, 0, 0 ), 3000, 25, 45 );
1492+
1493+
// When running the test on Travis, it would initially return empty rendered image.
1494+
// Capturing the initial image and throwing it away fixes that. Hopefully we will
1495+
// find a better fix in the future.
1496+
Qgs3DUtils::captureSceneImage( engine, scene );
1497+
1498+
QImage img = Qgs3DUtils::captureSceneImage( engine, scene );
1499+
delete scene;
1500+
delete map;
1501+
1502+
QVERIFY( imageCheck( "mesh3d_filtered", "mesh3d_filtered", img, QString(), 40, QSize( 0, 0 ), 2 ) );
1503+
}
1504+
14591505
void TestQgs3DRendering::testAmbientOcclusion()
14601506
{
14611507
// =============================================
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.