QGIS API Documentation 3.43.0-Master (b60ef06885e)
qgs3daxisrenderview.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgs3daxisrenderview.cpp
3 --------------------------------------
4 Date : June 2024
5 Copyright : (C) 2024 by Benoit De Mezzo
6 Email : benoit dot de dot mezzo 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
16#include "qgs3daxisrenderview.h"
17
18#include "qgsframegraph.h"
19#include <Qt3DCore/QEntity>
20#include <Qt3DExtras/QText2DEntity>
21#include <Qt3DRender/QCamera>
22#include <Qt3DRender/QViewport>
23#include <Qt3DRender/QPickEvent>
24#include <Qt3DRender/QScreenRayCaster>
25#include <Qt3DRender/qsubtreeenabler.h>
26#include <Qt3DRender/QSortPolicy>
27
28#include <QVector3D>
29#include <QVector2D>
30#include <QScreen>
31
32#include <Qt3DRender/QLayer>
33#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
34#include <Qt3DRender/QBuffer>
35typedef Qt3DRender::QBuffer Qt3DQBuffer;
36#else
37#include <Qt3DCore/QBuffer>
38typedef Qt3DCore::QBuffer Qt3DQBuffer;
39#endif
40#include <Qt3DRender/QGeometryRenderer>
41
42#include "qgsmapsettings.h"
43#include "qgs3dmapsettings.h"
44#include "qgs3dmapcanvas.h"
45#include "qgscameracontroller.h"
46#include "qgs3daxis.h"
47
48
49Qgs3DAxisRenderView::Qgs3DAxisRenderView( const QString &viewName, Qgs3DMapCanvas *canvas, //
50 QgsCameraController *cameraCtrl, Qgs3DMapSettings *settings, //
51 Qgs3DAxis *axis3D )
52 : QgsAbstractRenderView( viewName )
53 , mCanvas( canvas )
54 , mMapSettings( settings )
55 , m3DAxis( axis3D )
56{
57 mViewport = new Qt3DRender::QViewport( mRendererEnabler );
58 mViewport->setObjectName( mViewName + "::Viewport" );
59
60 mObjectLayer = new Qt3DRender::QLayer;
61 mObjectLayer->setObjectName( mViewName + "::ObjectLayer" );
62 mObjectLayer->setRecursive( true );
63
64 mLabelLayer = new Qt3DRender::QLayer;
65 mLabelLayer->setObjectName( mViewName + "::LabelLayer" );
66 mLabelLayer->setRecursive( true );
67
68 // render pass for the object (axis or cube)
69 Qt3DRender::QLayerFilter *objectFilter = new Qt3DRender::QLayerFilter( mViewport );
70 objectFilter->addLayer( mObjectLayer );
71
72 mObjectCamera = new Qt3DRender::QCamera;
73 mObjectCamera->setObjectName( mViewName + "::ObjectCamera" );
74 mObjectCamera->setProjectionType( cameraCtrl->camera()->projectionType() );
75 mObjectCamera->lens()->setFieldOfView( cameraCtrl->camera()->lens()->fieldOfView() * 0.5f );
76
77 Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector( objectFilter );
78 cameraSelector->setCamera( mObjectCamera );
79
80 // This ensures to have the label (Text2DEntity) rendered after the other objects and therefore
81 // avoid any transparency issue on the label.
82 Qt3DRender::QSortPolicy *objectSortPolicy = new Qt3DRender::QSortPolicy( cameraSelector );
83 QVector<Qt3DRender::QSortPolicy::SortType> objectSortTypes = QVector<Qt3DRender::QSortPolicy::SortType>();
84 objectSortTypes << Qt3DRender::QSortPolicy::BackToFront;
85 objectSortPolicy->setSortTypes( objectSortTypes );
86
87 Qt3DRender::QClearBuffers *objectClearBuffers = new Qt3DRender::QClearBuffers( objectSortPolicy );
88 objectClearBuffers->setBuffers( Qt3DRender::QClearBuffers::DepthBuffer );
89
90 Qt3DRender::QLayerFilter *labelFilter = new Qt3DRender::QLayerFilter( mViewport );
91 labelFilter->addLayer( mLabelLayer );
92
93 mLabelCamera = new Qt3DRender::QCamera;
94 mLabelCamera->setObjectName( mViewName + "::LabelCamera" );
95 mLabelCamera->setProjectionType( Qt3DRender::QCameraLens::ProjectionType::OrthographicProjection );
96
97 Qt3DRender::QCameraSelector *labelCameraSelector = new Qt3DRender::QCameraSelector( labelFilter );
98 labelCameraSelector->setCamera( mLabelCamera );
99
100 // this ensures to have the label (Text2DEntity) rendered after the other objects and therefore
101 // avoid any transparency issue on the label.
102 Qt3DRender::QSortPolicy *labelSortPolicy = new Qt3DRender::QSortPolicy( labelCameraSelector );
103 QVector<Qt3DRender::QSortPolicy::SortType> labelSortTypes = QVector<Qt3DRender::QSortPolicy::SortType>();
104 labelSortTypes << Qt3DRender::QSortPolicy::BackToFront;
105 labelSortPolicy->setSortTypes( labelSortTypes );
106
107 Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers( labelSortPolicy );
108 clearBuffers->setBuffers( Qt3DRender::QClearBuffers::DepthBuffer );
109
110 // update viewport size
112}
113
114Qt3DRender::QViewport *Qgs3DAxisRenderView::viewport() const
115{
116 return mViewport;
117}
118
119Qt3DRender::QLayer *Qgs3DAxisRenderView::objectLayer() const
120{
121 return mObjectLayer;
122}
123
124Qt3DRender::QLayer *Qgs3DAxisRenderView::labelLayer() const
125{
126 return mLabelLayer;
127}
128
129Qt3DRender::QCamera *Qgs3DAxisRenderView::objectCamera() const
130{
131 return mObjectCamera;
132}
133
134Qt3DRender::QCamera *Qgs3DAxisRenderView::labelCamera() const
135{
136 return mLabelCamera;
137}
138
139void Qgs3DAxisRenderView::updateWindowResize( int width, int height )
140{
141 onViewportSizeUpdate( width, height );
142}
143
144
145void Qgs3DAxisRenderView::onViewportSizeUpdate( int width, int height )
146{
147 Qgs3DAxisSettings settings = mMapSettings->get3DAxisSettings();
148 double windowWidth = static_cast<double>( width < 0 ? mCanvas->width() : width );
149 double windowHeight = static_cast<double>( height < 0 ? mCanvas->height() : height );
150
151 if ( 2 <= QgsLogger::debugLevel() )
152 {
153 QgsMapSettings set;
154 QgsDebugMsgLevel( QString( "onViewportSizeUpdate window w/h: %1px / %2px" ).arg( windowWidth ).arg( windowHeight ), 2 );
155 QgsDebugMsgLevel( QString( "onViewportSizeUpdate window physicalDpi %1 (%2, %3)" ).arg( mCanvas->screen()->physicalDotsPerInch() ).arg( mCanvas->screen()->physicalDotsPerInchX() ).arg( mCanvas->screen()->physicalDotsPerInchY() ), 2 );
156 QgsDebugMsgLevel( QString( "onViewportSizeUpdate window logicalDotsPerInch %1 (%2, %3)" ).arg( mCanvas->screen()->logicalDotsPerInch() ).arg( mCanvas->screen()->logicalDotsPerInchX() ).arg( mCanvas->screen()->logicalDotsPerInchY() ), 2 );
157
158 QgsDebugMsgLevel( QString( "onViewportSizeUpdate window pixel ratio %1" ).arg( mCanvas->screen()->devicePixelRatio() ), 2 );
159
160 QgsDebugMsgLevel( QString( "onViewportSizeUpdate set pixel ratio %1" ).arg( set.devicePixelRatio() ), 2 );
161 QgsDebugMsgLevel( QString( "onViewportSizeUpdate set outputDpi %1" ).arg( set.outputDpi() ), 2 );
162 QgsDebugMsgLevel( QString( "onViewportSizeUpdate set dpiTarget %1" ).arg( set.dpiTarget() ), 2 );
163 }
164
165 // default viewport size in pixel according to 92 dpi
166 double defaultViewportPixelSize = ( ( double ) settings.defaultViewportSize() / 25.4 ) * 92.0;
167
168 // computes the viewport size according to screen dpi but as the viewport size growths too fast
169 // then we limit the growth by using a factor on the dpi difference.
170 double viewportPixelSize = defaultViewportPixelSize + ( ( double ) settings.defaultViewportSize() / 25.4 ) * ( mCanvas->screen()->physicalDotsPerInch() - 92.0 ) * 0.7;
171 QgsDebugMsgLevel( QString( "onViewportSizeUpdate viewportPixelSize %1" ).arg( viewportPixelSize ), 2 );
172 double widthRatio = viewportPixelSize / windowWidth;
173 double heightRatio = widthRatio * windowWidth / windowHeight;
174
175 QgsDebugMsgLevel( QString( "3DAxis viewport ratios width: %1% / height: %2%" ).arg( widthRatio * 100.0 ).arg( heightRatio * 100.0 ), 2 );
176
177 if ( heightRatio * windowHeight < viewportPixelSize )
178 {
179 heightRatio = viewportPixelSize / windowHeight;
180 widthRatio = heightRatio * windowHeight / windowWidth;
181 QgsDebugMsgLevel( QString( "3DAxis viewport, height too small, ratios adjusted to width: %1% / height: %2%" ).arg( widthRatio * 100.0 ).arg( heightRatio * 100.0 ), 2 );
182 }
183
184 if ( heightRatio > settings.maxViewportRatio() || widthRatio > settings.maxViewportRatio() )
185 {
186 QgsDebugMsgLevel( QString( "3DAxis viewport takes too much place into the 3d view, disabling it (maxViewportRatio: %1)." ).arg( settings.maxViewportRatio() ), 2 );
187 // take too much place into the 3d view
188 mViewport->setEnabled( false );
189 m3DAxis->onViewportScaleFactorChanged( 0.0 );
190 }
191 else
192 {
193 if ( !mViewport->isEnabled() )
194 {
195 // will be used to adjust the axis label translations/sizes
196 m3DAxis->onViewportScaleFactorChanged( viewportPixelSize / defaultViewportPixelSize );
197 }
198 mViewport->setEnabled( true );
199
200 float xRatio = 1.0f;
201 float yRatio = 1.0f;
202 if ( settings.horizontalPosition() == Qt::AnchorPoint::AnchorLeft )
203 xRatio = 0.0f;
204 else if ( settings.horizontalPosition() == Qt::AnchorPoint::AnchorHorizontalCenter )
205 xRatio = 0.5f - static_cast<float>( widthRatio ) / 2.0f;
206 else
207 xRatio = 1.0f - static_cast<float>( widthRatio );
208
209 if ( settings.verticalPosition() == Qt::AnchorPoint::AnchorTop )
210 yRatio = 0.0f;
211 else if ( settings.verticalPosition() == Qt::AnchorPoint::AnchorVerticalCenter )
212 yRatio = 0.5f - static_cast<float>( heightRatio ) / 2.0f;
213 else
214 yRatio = 1.0f - static_cast<float>( heightRatio );
215
216 QgsDebugMsgLevel( QString( "Qgs3DAxis: update viewport: %1 x %2 x %3 x %4" ).arg( xRatio ).arg( yRatio ).arg( widthRatio ).arg( heightRatio ), 2 );
217 mViewport->setNormalizedRect( QRectF( xRatio, yRatio, widthRatio, heightRatio ) );
218
219 if ( settings.mode() == Qgs3DAxisSettings::Mode::Crs )
220 {
221 const float halfWidthSize = static_cast<float>( windowWidth * widthRatio / 2.0 );
222 const float halfHeightSize = static_cast<float>( windowWidth * widthRatio / 2.0 );
223 mLabelCamera->lens()->setOrthographicProjection(
224 -halfWidthSize, halfWidthSize,
225 -halfHeightSize, halfHeightSize,
226 mLabelCamera->lens()->nearPlane(), mLabelCamera->lens()->farPlane()
227 );
228 }
229 }
230}
231
233{
234 Qgs3DAxisSettings axisSettings = mMapSettings->get3DAxisSettings();
235 axisSettings.setHorizontalPosition( pos );
236 mMapSettings->set3DAxisSettings( axisSettings );
238}
239
241{
242 Qgs3DAxisSettings axisSettings = mMapSettings->get3DAxisSettings();
243 axisSettings.setVerticalPosition( pos );
244 mMapSettings->set3DAxisSettings( axisSettings );
246}
Qt3DRender::QLayer * labelLayer() const
Returns the layer to be used by entities to be included in the label renderpass.
void onVerticalPositionChanged(Qt::AnchorPoint position)
Updates viewport vertical position.
Qt3DRender::QCamera * labelCamera() const
Returns camera used for billboarded labels.
Qt3DRender::QLayer * objectLayer() const
Returns main object layer.
Qgs3DAxisRenderView(const QString &viewName, Qgs3DMapCanvas *canvas, QgsCameraController *cameraCtrl, Qgs3DMapSettings *settings, Qgs3DAxis *axis3D)
Constructor for Qgs3DAxisRenderView with the specified parent object.
Qt3DRender::QViewport * viewport() const
Returns the viewport associated to this renderview.
void onViewportSizeUpdate(int width=-1, int height=-1)
Updates viewport size. Uses canvas size by default.
Qt3DRender::QCamera * objectCamera() const
Returns main object camera (used for axis or cube)
virtual void updateWindowResize(int width, int height) override
Called when 3D window is resized.
void onHorizontalPositionChanged(Qt::AnchorPoint position)
Updates viewport horizontal position.
Contains the configuration of a 3d axis.
double maxViewportRatio() const
Returns the maximal axis viewport ratio (see Qt3DRender::QViewport::normalizedRect())
@ Crs
Respect CRS directions.
Qt::AnchorPoint verticalPosition() const
Returns the vertical position for the 3d axis.
void setHorizontalPosition(Qt::AnchorPoint position)
Sets the horizontal position for the 3d axis.
int defaultViewportSize() const
Returns the default axis viewport size in millimeters.
Qgs3DAxisSettings::Mode mode() const
Returns the type of the 3daxis.
Qt::AnchorPoint horizontalPosition() const
Returns the horizontal position for the 3d axis.
void setVerticalPosition(Qt::AnchorPoint position)
Sets the vertical position for the 3d axis.
Display 3D ortho axis in the main 3D view.
Definition qgs3daxis.h:55
void onViewportScaleFactorChanged(double scaleFactor)
Used as callback from renderview when viewport scale factor changes.
Convenience wrapper to simplify the creation of a 3D window ready to be used with QGIS.
Definition of the world.
Qgs3DAxisSettings get3DAxisSettings() const
Returns the current configuration of 3d axis.
void set3DAxisSettings(const Qgs3DAxisSettings &axisSettings, bool force=false)
Sets the current configuration of 3d axis.
Base class for 3D render view.
Qt3DRender::QSubtreeEnabler * mRendererEnabler
Object that controls camera movement based on user input.
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
static int debugLevel()
Reads the environment variable QGIS_DEBUG and converts it to int.
Definition qgslogger.h:112
Contains configuration for rendering maps.
double dpiTarget() const
Returns the target DPI (dots per inch) to be taken into consideration when rendering.
float devicePixelRatio() const
Returns the device pixel ratio.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
Qt3DCore::QBuffer Qt3DQBuffer
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41