Skip to content

Commit

Permalink
Add unit tests for QgsRubberBand3D
Browse files Browse the repository at this point in the history
  • Loading branch information
Withalion committed Feb 21, 2025
1 parent 61d6e9f commit fbde06e
Show file tree
Hide file tree
Showing 18 changed files with 309 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/3d/qgsrubberband3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
/// @cond PRIVATE


QgsRubberBand3D::QgsRubberBand3D( Qgs3DMapSettings &map, QgsWindow3DEngine *engine, Qt3DCore::QEntity *parentEntity, const Qgis::GeometryType geometryType )
QgsRubberBand3D::QgsRubberBand3D( Qgs3DMapSettings &map, QgsAbstract3DEngine *engine, Qt3DCore::QEntity *parentEntity, const Qgis::GeometryType geometryType )
: mMapSettings( &map )
, mEngine( engine )
, mGeometryType( geometryType )
Expand Down Expand Up @@ -91,7 +91,7 @@ void QgsRubberBand3D::setupMarker( Qt3DCore::QEntity *parentEntity )
mMarkerEntity->addComponent( mMarkerGeometryRenderer );
}

void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity, QgsWindow3DEngine *engine )
void QgsRubberBand3D::setupLine( Qt3DCore::QEntity *parentEntity, QgsAbstract3DEngine *engine )
{
mLineEntity = new Qt3DCore::QEntity( parentEntity );

Expand Down
8 changes: 4 additions & 4 deletions src/3d/qgsrubberband3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
//


class QgsAbstract3DEngine;
class QgsPoint;
class QgsPhongMaterialSettings;
class QgsMaterial;
class QgsTessellatedPolygonGeometry;
class QgsWindow3DEngine;
class QgsLineMaterial;
class Qgs3DMapSettings;
class QgsBillboardGeometry;
Expand Down Expand Up @@ -94,7 +94,7 @@ class _3D_EXPORT QgsRubberBand3D
Circle
};

QgsRubberBand3D( Qgs3DMapSettings &map, QgsWindow3DEngine *engine, Qt3DCore::QEntity *parentEntity, Qgis::GeometryType geometryType = Qgis::GeometryType::Line );
QgsRubberBand3D( Qgs3DMapSettings &map, QgsAbstract3DEngine *engine, Qt3DCore::QEntity *parentEntity, Qgis::GeometryType geometryType = Qgis::GeometryType::Line );
~QgsRubberBand3D();

//! Returns the rubber band width in pixels
Expand Down Expand Up @@ -205,7 +205,7 @@ class _3D_EXPORT QgsRubberBand3D
void updateGeometry();
void updateMarkerMaterial();
void setupMarker( Qt3DCore::QEntity *parentEntity );
void setupLine( Qt3DCore::QEntity *parentEntity, QgsWindow3DEngine *engine );
void setupLine( Qt3DCore::QEntity *parentEntity, QgsAbstract3DEngine *engine );
void setupPolygon( Qt3DCore::QEntity *parentEntity );

const float DEFAULT_POLYGON_OPACITY = 0.25;
Expand All @@ -214,7 +214,7 @@ class _3D_EXPORT QgsRubberBand3D
bool mHideLastMarker = false;

Qgs3DMapSettings *mMapSettings = nullptr; // not owned
QgsWindow3DEngine *mEngine = nullptr;
QgsAbstract3DEngine *mEngine = nullptr;
Qgis::GeometryType mGeometryType = Qgis::GeometryType::Line;

//! point and vertex marker type
Expand Down
1 change: 1 addition & 0 deletions tests/src/3d/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(TESTS
testqgsmaterialregistry.cpp
testqgsmesh3drendering.cpp
testqgspointcloud3drendering.cpp
testqgsrubberband3drendering.cpp
testqgstessellator.cpp
testqgstilingscheme.cpp
)
Expand Down
302 changes: 302 additions & 0 deletions tests/src/3d/testqgsrubberband3drendering.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
/***************************************************************************
testqgsrubberband3drendering.cpp
--------------------------------------
Date : February 2025
Copyright : (C) 2025 by Matej Bagar
Email : matej dot bagar at lutraconsulting dot co dot uk
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsoffscreen3dengine.h"
#include "qgstest.h"

#include "qgsproject.h"
#include "qgsapplication.h"
#include "qgs3d.h"
#include "qgspointcloudlayer.h"
#include "qgspointlightsettings.h"
#include "qgsstyle.h"
#include "qgs3dutils.h"
#include "qgs3dmapsettings.h"
#include "qgs3dmapscene.h"
#include "qgsframegraph.h"
#include "qgsrubberband3d.h"

class TestQgsRubberBand3DRendering : public QgsTest
{
Q_OBJECT
public:
TestQgsRubberBand3DRendering()
: QgsTest( QStringLiteral( "Rubberband 3D Rendering Tests" ), QStringLiteral( "3d" ) ) {}

private slots:
void initTestCase(); // will be called before the first testfunction is executed.
void cleanupTestCase(); // will be called after the last testfunction was executed.

void testRubberBandPoint();
void testRubberBandLine();
void testRubberBandPolygon();
void testRubberBandHiddenMarker();
void testRubberBandHiddenLastMarker();
void testRubberBandHiddenEdges();
void testRubberBandHiddenPolygonFill();

private:
std::unique_ptr<QgsProject> mProject;
QgsPointCloudLayer *mLayer;
QgsLineString *mPoints;
};

//runs before all tests
void TestQgsRubberBand3DRendering::initTestCase()
{
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();
Qgs3D::initialize();

mProject.reset( new QgsProject );

const QString dataDir( TEST_DATA_DIR );

mLayer = new QgsPointCloudLayer( dataDir + "/point_clouds/copc/rgb.copc.laz", "test", "copc" );
QVERIFY( mLayer->isValid() );
mProject->addMapLayer( mLayer );
mProject->setCrs( mLayer->crs() );

const QVector<QgsPoint> *points = new QVector<QgsPoint>( { QgsPoint( mLayer->extent().center().x() - 25, mLayer->extent().center().y() - 25, 0 ), QgsPoint( mLayer->extent().center().x() + 25, mLayer->extent().center().y() - 25, 0 ), QgsPoint( mLayer->extent().center().x() + 25, mLayer->extent().center().y() + 25, 0 ), QgsPoint( mLayer->extent().center().x() - 25, mLayer->extent().center().y() + 25, 0 ) } );
mPoints = new QgsLineString( *points );
}

//runs after all tests
void TestQgsRubberBand3DRendering::cleanupTestCase()
{
mProject.reset();
QgsApplication::exitQgis();
}

void TestQgsRubberBand3DRendering::testRubberBandPoint()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Point );
pointRubberBand.addPoint( QgsPoint( fullExtent.center().x() - 25, fullExtent.center().y() - 25, 0 ) );
pointRubberBand.addPoint( QgsPoint( fullExtent.center().x() + 25, fullExtent.center().y() - 25, 0 ) );
pointRubberBand.addPoint( QgsPoint( fullExtent.center().x() - 25, fullExtent.center().y() + 25, 0 ) );
pointRubberBand.addPoint( QgsPoint( fullExtent.center().x() + 25, fullExtent.center().y() + 25, 0 ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_point", "rubberband_3d_point", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandLine()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Line );
pointRubberBand.setGeometry( QgsGeometry( mPoints->clone() ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_line", "rubberband_3d_line", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandPolygon()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Polygon );
pointRubberBand.setGeometry( QgsGeometry( new QgsPolygon( mPoints->clone() ) ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_polygon", "rubberband_3d_polygon", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandHiddenMarker()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Polygon );
pointRubberBand.setMarkerEnabled( false );
pointRubberBand.setGeometry( QgsGeometry( new QgsPolygon( mPoints->clone() ) ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_hidden_marker", "rubberband_3d_hidden_marker", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandHiddenLastMarker()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Line );
pointRubberBand.setHideLastMarker( true );
pointRubberBand.setGeometry( QgsGeometry( mPoints->clone() ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_hidden_last_marker", "rubberband_3d_hidden_last_marker", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandHiddenEdges()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Polygon );
pointRubberBand.setEdgesEnabled( false );
pointRubberBand.setGeometry( QgsGeometry( new QgsPolygon( mPoints->clone() ) ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_hidden_edges", "rubberband_3d_hidden_edges", img, QString(), 80, QSize( 0, 0 ), 15 );
}

void TestQgsRubberBand3DRendering::testRubberBandHiddenPolygonFill()
{
const QgsRectangle fullExtent = mLayer->extent();

Qgs3DMapSettings *map = new Qgs3DMapSettings;
map->setCrs( mProject->crs() );
map->setOrigin( QgsVector3D( fullExtent.center().x(), fullExtent.center().y(), 0 ) );
map->setLayers( QList<QgsMapLayer *>() << mLayer );
QgsPointLightSettings defaultLight;
defaultLight.setIntensity( 0.5 );
defaultLight.setPosition( QgsVector3D( 0, 1000, 0 ) );
map->setLightSources( { defaultLight.clone() } );

QgsOffscreen3DEngine engine;
Qgs3DMapScene *scene = new Qgs3DMapScene( *map, &engine );
engine.setRootEntity( scene );

QgsRubberBand3D pointRubberBand( *map, &engine, engine.frameGraph()->rubberBandsRootEntity(), Qgis::GeometryType::Polygon );
pointRubberBand.setPolygonFillEnabled( false );
pointRubberBand.setGeometry( QgsGeometry( new QgsPolygon( mPoints->clone() ) ) );

scene->cameraController()->resetView( 90 );
Qgs3DUtils::captureSceneImage( engine, scene );
// When running the test on Travis, it would initially return empty rendered image.
// Capturing the initial image and throwing it away fixes that. Hopefully we will
// find a better fix in the future.
const QImage img = Qgs3DUtils::captureSceneImage( engine, scene );

QGSVERIFYIMAGECHECK( "rubberband_3d_hidden_fill", "rubberband_3d_hidden_fill", img, QString(), 80, QSize( 0, 0 ), 15 );
}

QGSTEST_MAIN( TestQgsRubberBand3DRendering )
#include "testqgsrubberband3drendering.moc"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fbde06e

Please sign in to comment.