71#include <QOpenGLContext>
72#include <QOpenGLFunctions>
77#include <Qt3DExtras/QDiffuseSpecularMaterial>
78#include <Qt3DExtras/QForwardRenderer>
79#include <Qt3DExtras/QPhongAlphaMaterial>
80#include <Qt3DExtras/QPhongMaterial>
81#include <Qt3DExtras/QSphereMesh>
82#include <Qt3DLogic/QFrameAction>
83#include <Qt3DRender/QCamera>
84#include <Qt3DRender/QCullFace>
85#include <Qt3DRender/QDepthTest>
86#include <Qt3DRender/QEffect>
87#include <Qt3DRender/QMesh>
88#include <Qt3DRender/QRenderPass>
89#include <Qt3DRender/QRenderSettings>
90#include <Qt3DRender/QRenderState>
91#include <Qt3DRender/QSceneLoader>
92#include <Qt3DRender/QTechnique>
95#include "moc_qgs3dmapscene.cpp"
97using namespace Qt::StringLiterals;
106 onBackgroundColorChanged();
111 mEngine->renderSettings()->setRenderPolicy( Qt3DRender::QRenderSettings::OnDemand );
113 QRect viewportRect( QPoint( 0, 0 ), mEngine->size() );
119 float aspectRatio = ( float ) viewportRect.width() / viewportRect.height();
120 mEngine->camera()->lens()->setPerspectiveProjection( mMap.fieldOfView(), aspectRatio, 10.f, 10000.0f );
122 mFrameAction =
new Qt3DLogic::QFrameAction();
123 connect( mFrameAction, &Qt3DLogic::QFrameAction::triggered,
this, &Qgs3DMapScene::onFrameTriggered );
124 addComponent( mFrameAction );
130 mCameraController->resetGlobe( 10'000'000 );
132 mCameraController->resetView( 1000 );
134 addCameraViewCenterEntity( mEngine->camera() );
135 addCameraRotationCenterEntity( mCameraController );
140 createTerrainDeferred();
175 const QList<QgsMapLayer *> modelVectorLayers = mModelVectorLayers;
181 if ( renderer->
type() ==
"vector"_L1 )
184 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
186 removeLayerEntity( layer );
187 addLayerEntity( layer );
190 else if ( renderer->
type() ==
"rulebased"_L1 )
196 if ( pointSymbol && pointSymbol->
shapeProperty( u
"model"_s ).toString() == url )
198 removeLayerEntity( layer );
199 addLayerEntity( layer );
214 onSkyboxSettingsChanged();
215 onGradientBackgroundChanged();
220 onEyeDomeShadingSettingsChanged();
222 onDebugShadowMapSettingsChanged();
223 onDebugDepthMapSettingsChanged();
225 onAmbientOcclusionSettingsChanged();
227 onMsaaEnabledChanged();
232 mOverlayUpdateTimer =
new QTimer(
this );
233 mOverlayUpdateTimer->setSingleShot(
true );
234 mOverlayUpdateTimer->setInterval( 250 );
235 connect( mOverlayUpdateTimer, &QTimer::timeout,
this, &Qgs3DMapScene::applyPendingOverlayUpdate );
238 onShowMapOverlayChanged();
240 onCameraMovementSpeedChanged();
242 on3DAxisSettingsChanged();
249 mCameraController->resetGlobe( 10'000'000 );
255 const double side = std::max( extent.
width(), extent.
height() );
256 double d = side / 2 / std::tan(
cameraController()->camera()->fieldOfView() / 2 * M_PI / 180 );
258 mCameraController->resetView(
static_cast<float>( d ) );
269 const double xSide = std::abs( p1.
x() - p2.
x() );
270 const double ySide = std::abs( p1.
y() - p2.
y() );
271 const double side = std::max( xSide, ySide );
273 const double fov = qDegreesToRadians(
cameraController()->camera()->fieldOfView() );
274 double distance = side / 2.0f / std::tan( fov / 2.0f );
279 distance += zRange.
upper();
283 mCameraController->setViewFromTop(
284 static_cast<float>( center.
x() - origin.
x() ),
285 static_cast<float>( center.
y() - origin.
y() ),
286 static_cast<float>( distance )
293 Qt3DRender::QCamera *camera = mCameraController->camera();
294 QVector<QgsPointXY> extent;
295 QVector<int> pointsOrder = { 0, 1, 3, 2 };
296 for (
int i : pointsOrder )
298 const QPoint p( ( ( i >> 0 ) & 1 ) ? 0 : mEngine->size().width(), ( ( i >> 1 ) & 1 ) ? 0 : mEngine->size().height() );
301 if ( dir.z() == 0.0 )
302 dir.setZ( 0.000001 );
303 double t = -ray.
origin().z() / dir.z();
307 t = camera->farPlane();
312 t = std::min<float>( t, camera->farPlane() );
314 QVector3D planePoint = ray.
origin() + t * dir;
315 QgsVector3D pMap = mMap.worldToMapCoordinates( planePoint );
324 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
325 count += entity->pendingJobsCount();
331 Qt3DRender::QCamera *camera = mCameraController->camera();
332 const double fov = camera->fieldOfView();
333 const QSize size = mEngine->size();
334 const int screenSizePx = std::max( size.width(), size.height() );
338 const double frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
339 const double err = frustumWidthAtDistance * epsilon / screenSizePx;
343void Qgs3DMapScene::onCameraChanged()
346 updateCameraNearFarPlanes();
348 onShadowSettingsChanged();
352 schedule2DMapOverlayUpdate();
360 constexpr float ORIGIN_SHIFT_THRESHOLD = 10'000;
361 if ( mSceneOriginShiftEnabled && mEngine->
camera()->position().length() > ORIGIN_SHIFT_THRESHOLD )
369bool Qgs3DMapScene::updateScene(
bool forceUpdate )
371 if ( !mSceneUpdatesEnabled )
377 QgsEventTracing::ScopedEvent traceEvent( u
"3D"_s, forceUpdate ? u
"Force update scene"_s : u
"Update scene"_s );
379 Qgs3DMapSceneEntity::SceneContext sceneContext;
380 Qt3DRender::QCamera *camera = mEngine->camera();
381 sceneContext.cameraFov = camera->fieldOfView();
382 sceneContext.cameraPos = camera->position();
383 const QSize size = mEngine->size();
384 sceneContext.screenSizePx = std::max( size.width(), size.height() );
392 QMatrix4x4 projMatrix;
393 switch ( mMap.projectionType() )
395 case Qt3DRender::QCameraLens::PerspectiveProjection:
397 float fovRadians = ( camera->fieldOfView() / 2.0f ) *
static_cast<float>( M_PI ) / 180.0f;
398 float fovCotan = std::cos( fovRadians ) / std::sin( fovRadians );
401 fovCotan / camera->aspectRatio(), 0, 0, 0,
409 case Qt3DRender::QCameraLens::OrthographicProjection:
411 Qt3DRender::QCameraLens *lens = camera->lens();
414 2.0f / ( lens->right() - lens->left() ), 0, 0, 0,
415 0, 2.0f / ( lens->top() - lens->bottom() ), 0, 0,
417 -( lens->left() + lens->right() ) / ( lens->right() - lens->left() ), -( lens->top() + lens->bottom() ) / ( lens->top() - lens->bottom() ), -1.0f, 1.0f
424 projMatrix = camera->projectionMatrix();
426 sceneContext.viewProjectionMatrix = projMatrix * camera->viewMatrix();
429 bool anyUpdated =
false;
430 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
432 if ( forceUpdate || ( entity->isEnabled() && entity->needsUpdate() ) )
435 entity->handleSceneUpdate( sceneContext );
436 if ( entity->hasReachedGpuMemoryLimit() )
446bool Qgs3DMapScene::updateCameraNearFarPlanes()
461 QMatrix4x4 viewMatrix = camera->viewMatrix();
467 for ( Qgs3DMapSceneEntity *se : std::as_const( mSceneEntities ) )
469 const QgsRange<float> depthRange = se->getNearFarPlaneRange( viewMatrix );
471 fnear = std::min( fnear, depthRange.
lower() );
472 ffar = std::max( ffar, depthRange.
upper() );
481 if ( fnear == 1e9 && ffar == 0 )
484 sceneZRange = sceneZRange.
isInfinite() ? QgsDoubleRange( 0.0, 0.0 ) : sceneZRange;
491 std::swap( fnear, ffar );
494 float newFar = ffar * 2;
495 float newNear = fnear / 2;
498 camera->setFarPlane( newFar );
499 camera->setNearPlane( newNear );
506void Qgs3DMapScene::onFrameTriggered(
float dt )
508 QgsEventTracing::addEvent( QgsEventTracing::EventType::Instant, u
"3D"_s, u
"Frame begins"_s );
510 mCameraController->frameTriggered( dt );
515 updateCameraNearFarPlanes();
518 static int frameCount = 0;
519 static float accumulatedTime = 0.0f;
521 if ( !mMap.isFpsCounterEnabled() )
529 accumulatedTime += dt;
530 if ( accumulatedTime >= 0.2f )
532 float fps = ( float ) frameCount / accumulatedTime;
534 accumulatedTime = 0.0f;
539void Qgs3DMapScene::update2DMapOverlay(
const QVector<QgsPointXY> &extent2DAsPoints )
541 QgsFrameGraph *frameGraph = mEngine->frameGraph();
544 if ( !mMap.is2DMapOverlayEnabled() )
546 if ( mMapOverlayEntity )
548 mMapOverlayEntity.reset();
550 overlayRenderView.
setEnabled( mMap.debugShadowMapEnabled() || mMap.debugDepthMapEnabled() );
554 if ( !mMapOverlayEntity )
556 QgsWindow3DEngine *
engine = qobject_cast<QgsWindow3DEngine *>( mEngine );
557 mMapOverlayEntity.reset(
new QgsMapOverlayEntity(
engine, &overlayRenderView, &mMap,
this ) );
558 mMapOverlayEntity->setEnabled(
true );
563 Qt3DRender::QCamera *camera = mEngine->camera();
564 const QgsVector3D extentCenter3D = mMap.worldToMapCoordinates( camera->position() );
565 const QgsPointXY extentCenter2D( extentCenter3D.
x(), extentCenter3D.
y() );
572 double minHalfExtent = std::numeric_limits<double>::max();
573 double maxHalfExtent = 0.0;
574 for (
const QgsPointXY &extentPoint : extent2DAsPoints )
576 const double distance = extentCenter2D.distance( extentPoint );
577 minHalfExtent = std::min( minHalfExtent, distance );
578 maxHalfExtent = std::max( maxHalfExtent, distance );
582 const double sceneHalfExtent = 0.6 * std::max( fullExtent.
width(), fullExtent.
height() );
584 minHalfExtent = std::min( 50., minHalfExtent );
585 maxHalfExtent = std::min( 100., maxHalfExtent );
586 const double smoothFactor = std::sin( mCameraController->pitch() / 90.0 * M_PI_2 );
589 const double adjustedHalfExtent = std::min( 3.0 * ( minHalfExtent + smoothFactor * maxHalfExtent ), sceneHalfExtent );
592 const bool showFrustum = mMap.viewFrustumVisualizationEnabled();
593 mMapOverlayEntity->update( overviewExtent, extent2DAsPoints, mCameraController->yaw(), showFrustum );
596void Qgs3DMapScene::createTerrain()
600 mSceneEntities.removeOne( mTerrain );
608 mSceneEntities.removeOne( mGlobe );
614 if ( !mTerrainUpdateScheduled )
617 QTimer::singleShot( 0,
this, &Qgs3DMapScene::createTerrainDeferred );
618 mTerrainUpdateScheduled =
true;
627void Qgs3DMapScene::createTerrainDeferred()
629 QgsChunkedEntity *terrainOrGlobe =
nullptr;
633 mGlobe =
new QgsGlobeEntity( &mMap );
634 terrainOrGlobe = mGlobe;
636 else if ( mMap.sceneMode() ==
Qgis::SceneMode::Local && mMap.terrainRenderingEnabled() && mMap.terrainGenerator() )
638 double tile0width = mMap.terrainGenerator()->rootChunkExtent().width();
639 int maxZoomLevel =
Qgs3DUtils::maxZoomLevel( tile0width, mMap.terrainSettings()->mapTileResolution(), mMap.terrainSettings()->maximumGroundError() );
640 const QgsBox3D rootBox3D = mMap.terrainGenerator()->rootChunkBox3D( mMap );
641 float rootError = mMap.terrainGenerator()->rootChunkError( mMap );
642 const QgsBox3D clippingBox3D( mMap.extent(), rootBox3D.
zMinimum(), rootBox3D.
zMaximum() );
643 mMap.terrainGenerator()->setupQuadtree( rootBox3D, rootError, maxZoomLevel, clippingBox3D );
645 mTerrain =
new QgsTerrainEntity( &mMap );
646 terrainOrGlobe = mTerrain;
649 if ( terrainOrGlobe )
652 QgsFrameGraph *frameGraph = mEngine->frameGraph();
656 terrainOrGlobe->setParent(
this );
657 terrainOrGlobe->setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
659 mSceneEntities << terrainOrGlobe;
662 connect( terrainOrGlobe, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
664 const QList<QgsGeoTransform *> transforms = entity->findChildren<QgsGeoTransform *>();
665 for ( QgsGeoTransform *transform : transforms )
667 transform->setOrigin( mMap.origin() );
671 handleClippingOnEntity( entity );
676 const QList<QgsMapLayer *>
layers = mMap.layers();
677 for ( QgsMapLayer *layer :
layers )
680 removeLayerEntity( layer );
683 addLayerEntity( layer );
688 mTerrainUpdateScheduled =
false;
691void Qgs3DMapScene::onBackgroundColorChanged()
693 mEngine->setClearColor( mMap.backgroundColor() );
696void Qgs3DMapScene::updateLights()
698 for ( Qt3DCore::QEntity *entity : std::as_const( mLightEntities ) )
699 entity->deleteLater();
700 mLightEntities.clear();
702 QgsFrameGraph *frameGraph = mEngine->frameGraph();
703 const QList<QgsLightSource *> newLights = mMap.lightSources();
704 for (
const QgsLightSource *source : newLights )
706 Qt3DCore::QEntity *entity = source->createEntity( mMap,
this );
708 mLightEntities.append( entity );
711 onShadowSettingsChanged();
714void Qgs3DMapScene::updateCameraLens()
716 mEngine->camera()->lens()->setFieldOfView( mMap.fieldOfView() );
717 mEngine->camera()->lens()->setProjectionType( mMap.projectionType() );
721void Qgs3DMapScene::onLayerRenderer3DChanged()
723 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
727 removeLayerEntity( layer );
730 addLayerEntity( layer );
733void Qgs3DMapScene::onLayersChanged()
735 QSet<QgsMapLayer *> layersBefore = qgis::listToSet( mLayerEntities.keys() );
736 QList<QgsMapLayer *> layersAdded;
737 const QList<QgsMapLayer *>
layers = mMap.layers();
738 for ( QgsMapLayer *layer :
layers )
740 if ( !layersBefore.contains( layer ) )
742 layersAdded << layer;
746 layersBefore.remove( layer );
751 for ( QgsMapLayer *layer : std::as_const( layersBefore ) )
753 removeLayerEntity( layer );
756 for ( QgsMapLayer *layer : std::as_const( layersAdded ) )
758 addLayerEntity( layer );
764 const QList<QgsMapLayer *>
layers = mLayerEntities.keys();
769 if ( temporalProperties->isActive() )
771 removeLayerEntity( layer );
772 addLayerEntity( layer );
780 Q_ASSERT( sceneNewEntity );
782 mSceneEntities.append( sceneNewEntity );
784 sceneNewEntity->setParent(
this );
786 finalizeNewEntity( sceneNewEntity );
788 connect( sceneNewEntity, &Qgs3DMapSceneEntity::newEntityCreated,
this, [
this]( Qt3DCore::QEntity *entity ) {
789 finalizeNewEntity( entity );
791 updateCameraNearFarPlanes();
801 Q_ASSERT( sceneEntity );
803 mSceneEntities.removeOne( sceneEntity );
805 sceneEntity->deleteLater();
809void Qgs3DMapScene::addLayerEntity(
QgsMapLayer *layer )
821 if ( renderer->
type() ==
"vector"_L1 )
829 mModelVectorLayers.append( layer );
833 else if ( renderer->
type() ==
"rulebased"_L1 )
836 for (
auto rule : rules )
838 const QgsPoint3DSymbol *pointSymbol =
dynamic_cast<const QgsPoint3DSymbol *
>( rule->symbol() );
841 mModelVectorLayers.append( layer );
849 QgsMeshLayer3DRenderer *meshRenderer =
static_cast<QgsMeshLayer3DRenderer *
>( renderer );
850 meshRenderer->
setLayer(
static_cast<QgsMeshLayer *
>( layer ) );
854 QgsMesh3DSymbol *sym = meshRenderer->
symbol()->
clone();
860 QgsPointCloudLayer3DRenderer *pointCloudRenderer =
static_cast<QgsPointCloudLayer3DRenderer *
>( renderer );
861 pointCloudRenderer->
setLayer(
static_cast<QgsPointCloudLayer *
>( layer ) );
865 QgsTiledSceneLayer3DRenderer *tiledSceneRenderer =
static_cast<QgsTiledSceneLayer3DRenderer *
>( renderer );
866 tiledSceneRenderer->
setLayer(
static_cast<QgsTiledSceneLayer *
>( layer ) );
870 auto annotationLayerRenderer = qgis::down_cast<QgsAnnotationLayer3DRenderer *>( renderer );
871 annotationLayerRenderer->setLayer( qobject_cast<QgsAnnotationLayer *>( layer ) );
874 Qt3DCore::QEntity *newEntity = renderer->
createEntity( &mMap );
877 mLayerEntities.insert( layer, newEntity );
879 if ( Qgs3DMapSceneEntity *sceneNewEntity = qobject_cast<Qgs3DMapSceneEntity *>( newEntity ) )
886 newEntity->setParent(
this );
887 finalizeNewEntity( newEntity );
896 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
909 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
915void Qgs3DMapScene::removeLayerEntity(
QgsMapLayer *layer )
917 Qt3DCore::QEntity *entity = mLayerEntities.take( layer );
919 if ( Qgs3DMapSceneEntity *sceneEntity = qobject_cast<Qgs3DMapSceneEntity *>( entity ) )
927 entity->deleteLater();
934 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
938 mModelVectorLayers.removeAll( layer );
948 QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( layer );
955void Qgs3DMapScene::finalizeNewEntity( Qt3DCore::QEntity *newEntity )
958 const QList<QgsGeoTransform *> transforms = newEntity->findChildren<QgsGeoTransform *>();
959 for ( QgsGeoTransform *transform : transforms )
961 transform->setOrigin( mMap.origin() );
965 handleClippingOnEntity( newEntity );
969 const QList<QgsLineMaterial *> childLineMaterials = newEntity->findChildren<QgsLineMaterial *>();
970 for ( QgsLineMaterial *lm : childLineMaterials )
974 lm->setViewportSize( mEngine->size() );
977 const QList<QgsPoint3DBillboardMaterial *> childBillboardMaterials = newEntity->findChildren<QgsPoint3DBillboardMaterial *>();
978 for ( QgsPoint3DBillboardMaterial *bm : childBillboardMaterials )
982 bm->setViewportSize( mEngine->size() );
985 QgsFrameGraph *frameGraph = mEngine->frameGraph();
989 const QVector<Qt3DRender::QLayer *>
layers = newEntity->componentsOfType<Qt3DRender::QLayer>();
999 const QList<Qt3DRender::QMaterial *> childMaterials = newEntity->findChildren<Qt3DRender::QMaterial *>();
1000 for ( Qt3DRender::QMaterial *material : childMaterials )
1003 if ( Qt3DExtras::QDiffuseSpecularMaterial *ph = qobject_cast<Qt3DExtras::QDiffuseSpecularMaterial *>( material ) )
1005 if ( ph->diffuse().value<QColor>().alphaF() != 1.0f )
1007 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( ph->parent() );
1008 if ( entity && !entity->components().contains( transparentLayer ) )
1010 entity->addComponent( transparentLayer );
1031 else if ( QgsPoint3DBillboardMaterial *billboardMaterial = qobject_cast<QgsPoint3DBillboardMaterial *>( material ) )
1033 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( billboardMaterial->parent() );
1034 if ( entity && !entity->components().contains( transparentLayer ) )
1036 entity->addComponent( transparentLayer );
1043 Qt3DRender::QEffect *effect = material->effect();
1046 const QVector<Qt3DRender::QParameter *> parameters = effect->parameters();
1047 for (
const Qt3DRender::QParameter *parameter : parameters )
1049 if ( parameter->name() ==
"opacity" && parameter->value() != 1.0f )
1051 Qt3DCore::QEntity *entity = qobject_cast<Qt3DCore::QEntity *>( material->parent() );
1052 if ( entity && !entity->components().contains( transparentLayer ) )
1054 entity->addComponent( transparentLayer );
1064int Qgs3DMapScene::maximumTextureSize()
const
1066 QSurface *surface = mEngine->surface();
1067 QOpenGLContext context;
1069 bool success = context.makeCurrent( surface );
1073 QOpenGLFunctions openglFunctions = QOpenGLFunctions( &context );
1076 openglFunctions.initializeOpenGLFunctions();
1077 openglFunctions.glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );
1086void Qgs3DMapScene::addCameraViewCenterEntity( Qt3DRender::QCamera *camera )
1088 mEntityCameraViewCenter =
new Qt3DCore::QEntity;
1090 Qt3DCore::QTransform *trCameraViewCenter =
new Qt3DCore::QTransform;
1091 mEntityCameraViewCenter->addComponent( trCameraViewCenter );
1092 connect( camera, &Qt3DRender::QCamera::viewCenterChanged,
this, [trCameraViewCenter, camera] { trCameraViewCenter->setTranslation( camera->viewCenter() ); } );
1094 Qt3DExtras::QPhongMaterial *materialCameraViewCenter =
new Qt3DExtras::QPhongMaterial;
1095 materialCameraViewCenter->setAmbient( Qt::red );
1096 mEntityCameraViewCenter->addComponent( materialCameraViewCenter );
1098 Qt3DExtras::QSphereMesh *rendererCameraViewCenter =
new Qt3DExtras::QSphereMesh;
1099 rendererCameraViewCenter->setRadius( 10 );
1100 mEntityCameraViewCenter->addComponent( rendererCameraViewCenter );
1102 mEntityCameraViewCenter->setEnabled( mMap.showCameraViewCenter() );
1103 mEntityCameraViewCenter->setParent(
this );
1110 if ( mSceneState == state )
1112 mSceneState = state;
1116void Qgs3DMapScene::updateSceneState()
1118 if ( mTerrainUpdateScheduled )
1124 for ( Qgs3DMapSceneEntity *entity : std::as_const( mSceneEntities ) )
1126 if ( entity->isEnabled() && entity->pendingJobsCount() > 0 )
1133 setSceneState(
Ready );
1136void Qgs3DMapScene::onSkyboxSettingsChanged()
1138 QgsSkyboxSettings skyboxSettings = mMap.skyboxSettings();
1141 mSkybox->deleteLater();
1147 QMap<QString, QString> faces;
1152 mSkybox =
new QgsCubeFacesSkyboxEntity( skyboxSettings.
cubeMapping(), faces[u
"posX"_s], faces[u
"posY"_s], faces[u
"posZ"_s], faces[u
"negX"_s], faces[u
"negY"_s], faces[u
"negZ"_s],
this );
1155 case Qgis::SkyboxType::Panoramic:
1156 mSkybox =
new QgsPanoramicSkyboxEntity( skyboxSettings.panoramicTexturePath(),
this );
1160 QgsFrameGraph *frameGraph = mEngine->frameGraph();
1166void Qgs3DMapScene::onGradientBackgroundChanged()
1168 if ( mGradientBackground )
1170 mGradientBackground->deleteLater();
1171 mGradientBackground =
nullptr;
1176 mGradientBackground =
new QgsGradientBackgroundEntity( mMap.gradientBackgroundTopColor(), mMap.gradientBackgroundBottomColor(),
this );
1177 QgsFrameGraph *frameGraph = mEngine->frameGraph();
1183void Qgs3DMapScene::onShadowSettingsChanged()
1185 mEngine->frameGraph()->updateShadowSettings( mMap.shadowSettings(), mMap.lightSources() );
1188void Qgs3DMapScene::onAmbientOcclusionSettingsChanged()
1190 mEngine->frameGraph()->updateAmbientOcclusionSettings( mMap.ambientOcclusionSettings() );
1193void Qgs3DMapScene::onDebugShadowMapSettingsChanged()
1195 mEngine->frameGraph()->updateDebugShadowMapSettings( mMap );
1198void Qgs3DMapScene::onDebugDepthMapSettingsChanged()
1200 mEngine->frameGraph()->updateDebugDepthMapSettings( mMap );
1203void Qgs3DMapScene::onDebugOverlayEnabledChanged()
1205 mEngine->frameGraph()->setDebugOverlayEnabled( mMap.isDebugOverlayEnabled() );
1206 mEngine->renderSettings()->setRenderPolicy( mMap.isDebugOverlayEnabled() ? Qt3DRender::QRenderSettings::Always : Qt3DRender::QRenderSettings::OnDemand );
1209void Qgs3DMapScene::onEyeDomeShadingSettingsChanged()
1211 mEngine->frameGraph()->updateEyeDomeSettings( mMap );
1214void Qgs3DMapScene::onMsaaEnabledChanged()
1216 mEngine->frameGraph()->setMsaaEnabled( mMap.isMsaaEnabled() );
1219void Qgs3DMapScene::onShowMapOverlayChanged()
1222 update2DMapOverlay( extent2D );
1225void Qgs3DMapScene::onCameraMovementSpeedChanged()
1227 mCameraController->setCameraMovementSpeed( mMap.cameraMovementSpeed() );
1230void Qgs3DMapScene::onCameraNavigationModeChanged()
1232 mCameraController->setCameraNavigationMode( mMap.cameraNavigationMode() );
1237 QVector<QString> notParsedLayers;
1248 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1251 Qt3DCore::QEntity *rootEntity = it.value();
1253 switch ( layerType )
1257 notParsedLayers.push_back( layer->
name() );
1267 notParsedLayers.push_back( layer->
name() );
1281 if ( !notParsedLayers.empty() )
1283 QString message = tr(
"The following layers were not exported:" ) +
"\n";
1284 for (
const QString &layerName : notParsedLayers )
1285 message += layerName +
"\n";
1294 QVector<const QgsChunkNode *> chunks;
1295 if ( !mLayerEntities.contains( layer ) )
1297 if ( QgsChunkedEntity *
c = qobject_cast<QgsChunkedEntity *>( mLayerEntities[layer] ) )
1299 const QList<QgsChunkNode *> activeNodes =
c->activeNodes();
1300 for ( QgsChunkNode *n : activeNodes )
1301 chunks.push_back( n );
1308 return mMap.extent();
1313 double zMin = std::numeric_limits<double>::max();
1314 double zMax = std::numeric_limits<double>::lowest();
1315 if ( mMap.terrainRenderingEnabled() && mTerrain && !ignoreTerrain )
1317 const QgsBox3D box3D = mTerrain->rootNode()->box3D();
1318 zMin = std::min( zMin, box3D.
zMinimum() );
1319 zMax = std::max( zMax, box3D.
zMaximum() );
1322 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); it++ )
1325 switch ( layer->
type() )
1331 zMin = std::min( zMin, zRange.
lower() );
1332 zMax = std::max( zMax, zRange.
upper() );
1337 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
1345 zMin = std::min( zMin, verticalGroupMetadata.
minimum() * verticalScale );
1346 zMax = std::max( zMax, verticalGroupMetadata.
maximum() * verticalScale );
1356 zMin = std::min( zMin, zRange.
lower() );
1357 zMax = std::max( zMax, zRange.
upper() );
1370 const QgsDoubleRange zRange( std::min( zMin, std::numeric_limits<double>::max() ), std::max( zMax, std::numeric_limits<double>::lowest() ) );
1381 mEntityRotationCenter =
new Qt3DCore::QEntity;
1383 Qt3DCore::QTransform *trRotationCenter =
new Qt3DCore::QTransform;
1384 mEntityRotationCenter->addComponent( trRotationCenter );
1385 Qt3DExtras::QPhongMaterial *materialRotationCenter =
new Qt3DExtras::QPhongMaterial;
1386 materialRotationCenter->setAmbient( Qt::blue );
1387 mEntityRotationCenter->addComponent( materialRotationCenter );
1388 Qt3DExtras::QSphereMesh *rendererRotationCenter =
new Qt3DExtras::QSphereMesh;
1389 rendererRotationCenter->setRadius( 10 );
1390 mEntityRotationCenter->addComponent( rendererRotationCenter );
1391 mEntityRotationCenter->setEnabled(
false );
1392 mEntityRotationCenter->setParent(
this );
1399void Qgs3DMapScene::on3DAxisSettingsChanged()
1403 m3DAxis->onAxisSettingsChanged();
1407 if ( QgsWindow3DEngine *
engine =
dynamic_cast<QgsWindow3DEngine *
>( mEngine ) )
1409 m3DAxis =
new Qgs3DAxis(
static_cast<Qgs3DMapCanvas *
>(
engine->window() ),
engine->root(),
this, mCameraController, &mMap );
1414void Qgs3DMapScene::onOriginChanged()
1416 const QList<QgsGeoTransform *> geoTransforms = findChildren<QgsGeoTransform *>();
1417 for ( QgsGeoTransform *transform : geoTransforms )
1419 transform->setOrigin( mMap.origin() );
1422 const QList<QgsGeoTransform *> rubberBandGeoTransforms = mEngine->frameGraph()->rubberBandsRootEntity()->findChildren<QgsGeoTransform *>();
1423 for ( QgsGeoTransform *transform : rubberBandGeoTransforms )
1425 transform->setOrigin( mMap.origin() );
1428 const QgsVector3D oldOrigin = mCameraController->origin();
1429 mCameraController->setOrigin( mMap.origin() );
1431 if ( !mClipPlanesEquations.isEmpty() )
1440 QList<QVector4D> newPlanes;
1441 QgsVector3D originShift = mMap.origin() - oldOrigin;
1442 for ( QVector4D plane : std::as_const( mClipPlanesEquations ) )
1444 plane.setW( originShift.
x() * plane.x() + originShift.
y() * plane.y() + originShift.
z() * plane.z() + plane.w() );
1445 newPlanes.append( plane );
1451void Qgs3DMapScene::handleClippingOnEntity( QEntity *entity )
const
1453 if ( mClipPlanesEquations.isEmpty() )
1455 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1457 material->disableClipping();
1462 for ( QgsMaterial *material : entity->componentsOfType<QgsMaterial>() )
1464 material->enableClipping( mClipPlanesEquations );
1470 for ( QObject *child : entity->children() )
1472 Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>( child );
1475 handleClippingOnEntity( childEntity );
1480void Qgs3DMapScene::handleClippingOnAllEntities()
const
1484 for (
auto it = mLayerEntities.constBegin(); it != mLayerEntities.constEnd(); ++it )
1486 handleClippingOnEntity( it.value() );
1490 handleClippingOnEntity( mTerrain );
1494 handleClippingOnEntity( mGlobe );
1502 QgsDebugMsgLevel( u
"Qgs3DMapScene::enableClipping: it is not possible to use more than %1 clipping planes."_s.arg( mMaxClipPlanes ), 2 );
1510 handleClippingOnAllEntities();
1515 mClipPlanesEquations.clear();
1518 mEngine->frameGraph()->removeClipPlanes();
1521 handleClippingOnAllEntities();
1524void Qgs3DMapScene::onStopUpdatesChanged()
1529void Qgs3DMapScene::schedule2DMapOverlayUpdate()
1532 if ( mMap.is2DMapOverlayEnabled() && mOverlayUpdateTimer && !mOverlayUpdateTimer->isActive() )
1534 mOverlayUpdateTimer->start();
1538void Qgs3DMapScene::applyPendingOverlayUpdate()
1540 if ( mMap.is2DMapOverlayEnabled() )
1543 update2DMapOverlay( extent2D );
@ DistinctTextures
Cube map built from distinct textures.
LayerType
Types of layers that can be added to a map.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ Globe
Scene is represented as a globe using a geocentric CRS.
@ Local
Local scene based on a projected CRS.
Manages the various settings the user can choose from when exporting a 3D scene.
bool exportNormals() const
Returns whether normals will be exported.
int terrrainResolution() const
Returns the terrain resolution.
QString sceneFolderPath() const
Returns the scene folder path.
float scale() const
Returns the scale of the exported model.
int terrainTextureResolution() const
Returns the terrain texture resolution.
bool terrainExportEnabled() const
Returns whether terrain export is enabled.
QString sceneName() const
Returns the scene name.
bool smoothEdges() const
Returns whether triangles edges will look smooth.
bool exportTextures() const
Returns whether textures will be exported.
Qgis::Export3DSceneFormat exportFormat() const
Returns the export format for the 3D scene.
void viewed2DExtentFrom3DChanged(QVector< QgsPointXY > extent)
Emitted when the viewed 2D extent seen by the 3D camera has changed.
QList< QVector4D > clipPlaneEquations() const
Returns list of clipping planes if clipping is enabled, otherwise an empty list.
static std::function< QMap< QString, Qgs3DMapScene * >()> sOpenScenesFunction
Static function for returning open 3D map scenes.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent extent (top view).
void disableClipping()
Disables OpenGL clipping.
QVector< const QgsChunkNode * > getLayerActiveChunkNodes(QgsMapLayer *layer) SIP_SKIP
Returns the active chunk nodes of layer.
void gpuMemoryLimitReached()
Emitted when one of the entities reaches its GPU memory limit and it is not possible to lower the GPU...
static Q_DECL_DEPRECATED QMap< QString, Qgs3DMapScene * > openScenes() SIP_DEPRECATED
Returns a map of 3D map scenes (by name) open in the QGIS application.
QgsCameraController * cameraController() const
Returns camera controller.
SceneState
Enumeration of possible states of the 3D scene.
@ Ready
The scene is fully loaded/updated.
@ Updating
The scene is still being loaded/updated.
bool exportScene(const Qgs3DMapExportSettings &exportSettings)
Exports the scene according to the scene export settings Returns false if the operation failed.
int totalPendingJobsCount() const
Returns number of pending jobs for all chunked entities.
QList< QgsMapLayer * > layers() const SIP_SKIP
Returns the layers that contain chunked entities.
void addSceneEntity(Qgs3DMapSceneEntity *entity) SIP_SKIP
Adds a 3D map scene entity to the scene.
void updateTemporal()
Updates the temporale entities.
void totalPendingJobsCountChanged()
Emitted when the total number of pending jobs changes.
Qgs3DMapScene(Qgs3DMapSettings &map, QgsAbstract3DEngine *engine) SIP_SKIP
Constructs a 3D scene based on map settings and Qt 3D renderer configuration.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is activated or deactivated.
void removeSceneEntity(Qgs3DMapSceneEntity *entity) SIP_SKIP
Removes a 3D scene entity for the scene.
QgsDoubleRange elevationRange(bool ignoreTerrain=false) const
Returns the scene's elevation range.
QgsRectangle sceneExtent() const
Returns the scene extent in the map's CRS.
void sceneStateChanged()
Emitted when the scene's state has changed.
QgsAbstract3DEngine * engine() const SIP_SKIP
Returns the abstract 3D engine.
QVector< QgsPointXY > viewFrustum2DExtent() const
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
void enableClipping(const QList< QVector4D > &clipPlaneEquations)
Enables OpenGL clipping based on the planes equations defined in clipPlaneEquations.
void terrainEntityChanged()
Emitted when the current terrain entity is replaced by a new one.
void viewZoomFull()
Resets camera view to show the whole scene (top view).
double worldSpaceError(double epsilon, double distance) const
Given screen error (in pixels) and distance from camera (in 3D world coordinates),...
void extentChanged()
Emitted when the 3d view's 2d extent has changed.
void originChanged()
Emitted when the world's origin point has been shifted.
void eyeDomeLightingDistanceChanged()
Emitted when the eye dome lighting distance has changed.
void terrainShadingChanged()
Emitted when terrain shading enabled flag or terrain shading material has changed.
void debugDepthMapSettingsChanged()
Emitted when depth map debugging has changed.
void backgroundColorChanged()
Emitted when the background color has changed.
void backgroundTypeChanged()
Emitted when the background type or gradient colors change.
void showCameraRotationCenterChanged()
Emitted when the flag whether camera's rotation center is shown has changed.
void cameraNavigationModeChanged()
Emitted when the camera navigation mode was changed.
void shadowSettingsChanged()
Emitted when shadow rendering settings are changed.
void show2DMapOverlayChanged()
Emitted when the 2D map overlay is enabled or disabled.
bool stopUpdates() const
Returns whether the scene updates on camera movement.
void eyeDomeLightingEnabledChanged()
Emitted when the flag whether eye dome lighting is used has changed.
void debugOverlayEnabledChanged(bool debugOverlayEnabled)
Emitted when the debug overaly is enabled or disabled.
void setOrigin(const QgsVector3D &origin)
Sets coordinates in map CRS at which our 3D world has origin (0,0,0).
void skyboxSettingsChanged()
Emitted when skybox settings are changed.
void msaaEnabledChanged()
Emitted when the MSAA enabled flag has changed.
void projectionTypeChanged()
Emitted when the camera lens projection type changes.
void stopUpdatesChanged()
Emitted when the flag whether to keep updating scene has changed.
void lightSourcesChanged()
Emitted when any of the light source settings in the map changes.
void showLightSourceOriginsChanged()
Emitted when the flag whether light source origins are shown has changed.
void terrainSettingsChanged()
Emitted when the terrain settings are changed.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is enabled or disabled.
void axisSettingsChanged()
Emitted when 3d axis rendering settings are changed.
void viewFrustumVisualizationEnabledChanged()
Emitted when the camera's view frustum visualization on the main 2D map canvas is enabled or disabled...
void ambientOcclusionSettingsChanged()
Emitted when ambient occlusion rendering settings are changed.
void layersChanged()
Emitted when the list of map layers for 3d rendering has changed.
void eyeDomeLightingStrengthChanged()
Emitted when the eye dome lighting strength has changed.
void cameraMovementSpeedChanged()
Emitted when the camera movement speed was changed.
void fieldOfViewChanged()
Emitted when the camera lens field of view changes.
void terrainGeneratorChanged()
Emitted when the terrain generator has changed.
void debugShadowMapSettingsChanged()
Emitted when shadow map debugging has changed.
void showCameraViewCenterChanged()
Emitted when the flag whether camera's view center is shown has changed.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
Entity that handles the exporting of 3D scenes.
void setExportTextures(bool exportTextures)
Sets whether the textures will be exported.
void parseTerrain(QgsTerrainEntity *terrain, const QString &layer)
Creates terrain export objects from the terrain entity.
void setTerrainResolution(int resolution)
Sets the terrain resolution.
void setTerrainTextureResolution(int resolution)
Sets the terrain texture resolution.
bool parseVectorLayerEntity(Qt3DCore::QEntity *entity, QgsVectorLayer *layer)
Creates necessary export objects from entity if it represents valid vector layer entity Returns false...
void setScale(float scale)
Sets the scale of the exported 3D model.
bool save(QString sceneName, QString sceneFolderPath, const Qgis::Export3DSceneFormat &exportFormat=Qgis::Export3DSceneFormat::Obj, int precision=6) const
Saves the scene to a file Returns false if the operation failed.
void setExportNormals(bool exportNormals)
Sets whether the normals will be exported.
void setSmoothEdges(bool smoothEdges)
Sets whether the triangles will look smooth.
void setTerrainExportEnabled(bool enabled)
Sets whether terrain export is enabled.
static int maxZoomLevel(double tile0width, double tileResolution, double maxError)
Calculates the highest needed zoom level for tiles in quad-tree given width of the base tile (zoom le...
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 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 ...
static QgsRay3D rayFromScreenPoint(const QPoint &point, const QSize &windowSize, Qt3DRender::QCamera *camera)
Convert from clicked point on the screen to a ray in world coordinates.
static int openGlMaxClipPlanes(QSurface *surface)
Gets the maximum number of clip planes that can be used.
Base class for 3D engine implementation.
void sizeChanged()
Emitted after a call to setSize().
virtual Qt3DRender::QCamera * camera()=0
Returns pointer to the engine's camera entity.
Base class for all renderers that participate in 3D views.
virtual QString type() const =0
Returns unique identifier of the renderer class (used to identify subclass).
virtual Qt3DCore::QEntity * createEntity(Qgs3DMapSettings *map) const =0
Returns a 3D entity that will be used to show renderer's data in 3D scene.
virtual void setEnabled(bool enable)
Enable or disable via enable the render view sub tree.
Base class for 3D renderers that are based on vector layers.
static QgsSourceCache * sourceCache()
Returns the application's source cache, used for caching embedded and remote source strings as local ...
A 3-dimensional box composed of x, y, z coordinates.
double zMaximum() const
Returns the maximum z value.
double zMinimum() const
Returns the minimum z value.
Object that controls camera movement based on user input.
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
void cameraChanged()
Emitted when camera has been updated.
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
QgsRange which stores a range of double values.
bool isInfinite() const
Returns true if the range consists of all possible values.
Qt3DRender::QLayer * renderLayer()
Returns a layer object used to indicate that the object is transparent.
Qt3DRender::QLayer * transparentObjectLayer()
Returns a layer object used to indicate that the object is transparent.
Qt3DRender::QLayer * backgroundLayer()
Returns a layer object used for skybox and background gradient entities.
QgsHighlightsRenderView & highlightsRenderView()
Returns the highlights renderview, used for rendering highlight overlays of identified features.
QgsForwardRenderView & forwardRenderView()
Returns forward renderview.
QgsOverlayTextureRenderView & overlayTextureRenderView()
Returns overlay texture renderview.
QgsShadowRenderView & shadowRenderView()
Returns shadow renderview.
Qt3DRender::QLayer * highlightsLayer()
Returns a layer that should be attached to entities meant to be rendered by QgsHighlightsRenderView.
virtual QgsDoubleRange calculateZRange(QgsMapLayer *layer) const
Attempts to calculate the overall elevation or z range for the specified layer, using the settings de...
Base class for storage of map layer temporal properties.
Base class for all map layer types.
QgsAbstract3DRenderer * renderer3D() const
Returns 3D renderer associated with the layer.
void request3DUpdate()
Signal emitted when a layer requires an update in any 3D maps.
void renderer3DChanged()
Signal emitted when 3D renderer associated with the layer has changed.
void rendererChanged()
Signal emitted when renderer is changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
void layerModified()
Emitted when modifications has been done on layer.
double verticalScale() const
Returns mesh vertical scale.
int verticalDatasetGroupIndex() const
Returns the index of the dataset group that will be used to render the vertical component of the 3D m...
void setMaximumTextureSize(int maximumTextureSize)
Sets the maximum texture size supported by the hardware Used to store the GL_MAX_TEXTURE_SIZE value t...
QgsMesh3DSymbol * clone() const override SIP_FACTORY
Returns a new instance of the symbol with the same settings.
3D renderer that renders all mesh triangles of a mesh layer.
void setSymbol(QgsMesh3DSymbol *symbol)
Sets 3D symbol associated with the renderer.
const QgsMesh3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
void setLayer(QgsMeshLayer *layer)
Sets vector layer associated with the renderer.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
3D symbol that draws point geometries as 3D objects using one of the predefined shapes.
Qgis::Point3DShape shape() const
Returns 3D shape for points.
QVariant shapeProperty(const QString &property) const
Returns the value for a specific shape property.
void setLayer(QgsPointCloudLayer *layer)
Sets point cloud layer associated with the renderer.
Represents a map layer supporting display of point clouds.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
T lower() const
Returns the lower bound of the range.
T upper() const
Returns the upper bound of the range.
bool isEmpty() const
Returns true if the range is empty, ie the lower bound equals (or exceeds) the upper bound and either...
A representation of a ray in 3D.
QVector3D origin() const
Returns the origin of the ray.
QVector3D direction() const
Returns the direction of the ray see setDirection().
A rectangle specified with double values.
static QgsRectangle fromCenterAndSize(const QgsPointXY ¢er, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
A child rule for a QgsRuleBased3DRenderer.
QList< QgsRuleBased3DRenderer::Rule * > RuleList
Qt3DRender::QLayer * entityCastingShadowsLayer() const
Returns the layer to be used by entities to be included in this renderview.
QMap< QString, QString > cubeMapFacesPaths() const
Returns a map containing the path of each texture specified by the user.
Qgis::SkyboxType skyboxType() const
Returns the type of the skybox.
Qgis::SkyboxCubeMapping cubeMapping() const
Returns the cube face mapping scheme.
void remoteSourceFetched(const QString &url)
Emitted when the cache has finished retrieving a 3D model from a remote url.
void setLayer(QgsTiledSceneLayer *layer)
Sets tiled scene layer associated with the renderer.
Represents a map layer supporting display of tiled scene objects.
QgsMapLayerElevationProperties * elevationProperties() override
Returns the layer's elevation properties.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
QString toString(int precision=17) const
Returns a string representation of the 3D vector.
double x() const
Returns X coordinate.
3D renderer that renders all features of a vector layer with the same 3D symbol.
const QgsAbstract3DSymbol * symbol() const
Returns 3D symbol associated with the renderer.
Represents a vector layer which manages a vector based dataset.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsFloatNear(float a, float b, float epsilon=4 *FLT_EPSILON)
Compare two floats (but allow some difference).
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)