QGIS API Documentation 3.31.0-Master (9f23a2c1dc)
qgslayoutitemelevationprofile.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutitemelevationprofile.cpp
3 ---------------------------------
4 begin : January 2023
5 copyright : (C) 2023 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
20#include "qgsplot.h"
21#include "qgslayout.h"
22#include "qgsmessagelog.h"
24#include "qgscurve.h"
25#include "qgsprofilerequest.h"
27#include "qgsterrainprovider.h"
28#include "qgsprofilerenderer.h"
29#include "qgslayoututils.h"
30#include "qgsvectorlayer.h"
33
34#include <QTimer>
35
36#define CACHE_SIZE_LIMIT 5000
37
39class QgsLayoutItemElevationProfilePlot : public Qgs2DPlot
40{
41 public:
42
43 QgsLayoutItemElevationProfilePlot()
44 {
45 }
46
47 void setRenderer( QgsProfilePlotRenderer *renderer )
48 {
49 // cppcheck-suppress danglingLifetime
50 mRenderer = renderer;
51 }
52
53 void renderContent( QgsRenderContext &rc, const QRectF &plotArea ) override
54 {
55 if ( mRenderer )
56 {
57 rc.painter()->translate( plotArea.left(), plotArea.top() );
58 mRenderer->render( rc, plotArea.width(), plotArea.height(), xMinimum(), xMaximum(), yMinimum(), yMaximum() );
59 rc.painter()->translate( -plotArea.left(), -plotArea.top() );
60 }
61 }
62
63 private:
64
65 QgsProfilePlotRenderer *mRenderer = nullptr;
66
67};
69
71 : QgsLayoutItem( layout )
72 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
73{
74 mBackgroundUpdateTimer = new QTimer( this );
75 mBackgroundUpdateTimer->setSingleShot( true );
76 connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
77
78 setCacheMode( QGraphicsItem::NoCache );
79
80 if ( mLayout )
81 {
83 }
84
85 connect( this, &QgsLayoutItem::sizePositionChanged, this, [ = ]
86 {
88 } );
89
90 //default to no background
91 setBackgroundEnabled( false );
92}
93
95{
96 if ( mRenderJob )
97 {
98 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
100 mRenderJob->cancelGeneration(); // blocks
101 mPainter->end();
102 }
103}
104
106{
108}
109
111{
113}
114
116{
117 return QgsApplication::getThemeIcon( QStringLiteral( "mLayoutItemElevationProfile.svg" ) );
118}
119
121{
123
124 bool forceUpdate = false;
125
128 {
129 double value = mTolerance;
130
131 bool ok = false;
133
134 if ( !ok )
135 {
136 QgsMessageLog::logMessage( tr( "Elevation profile tolerance expression eval error" ) );
137 }
138 else
139 {
140 mTolerance = value;
141 }
142
143 forceUpdate = true;
144 }
145
148 {
149 double value = mPlot->xMinimum();
150
151 bool ok = false;
153
154 if ( !ok )
155 {
156 QgsMessageLog::logMessage( tr( "Elevation profile minimum distance expression eval error" ) );
157 }
158 else
159 {
160 mPlot->setXMinimum( value );
161 }
162
163 forceUpdate = true;
164 }
165
168 {
169 double value = mPlot->xMaximum();
170
171 bool ok = false;
173
174 if ( !ok )
175 {
176 QgsMessageLog::logMessage( tr( "Elevation profile maximum distance expression eval error" ) );
177 }
178 else
179 {
180 mPlot->setXMaximum( value );
181 }
182
183 forceUpdate = true;
184 }
185
188 {
189 double value = mPlot->yMinimum();
190
191 bool ok = false;
193
194 if ( !ok )
195 {
196 QgsMessageLog::logMessage( tr( "Elevation profile minimum elevation expression eval error" ) );
197 }
198 else
199 {
200 mPlot->setYMinimum( value );
201 }
202
203 forceUpdate = true;
204 }
205
208 {
209 double value = mPlot->yMaximum();
210
211 bool ok = false;
213
214 if ( !ok )
215 {
216 QgsMessageLog::logMessage( tr( "Elevation profile maximum elevation expression eval error" ) );
217 }
218 else
219 {
220 mPlot->setYMaximum( value );
221 }
222
223 forceUpdate = true;
224 }
225
228 {
229 double value = mPlot->xAxis().gridIntervalMajor();
230
231 bool ok = false;
233
234 if ( !ok )
235 {
236 QgsMessageLog::logMessage( tr( "Elevation profile distance axis major interval expression eval error" ) );
237 }
238 else
239 {
240 mPlot->xAxis().setGridIntervalMajor( value );
241 }
242
243 forceUpdate = true;
244 }
245
248 {
249 double value = mPlot->xAxis().gridIntervalMinor();
250
251 bool ok = false;
253
254 if ( !ok )
255 {
256 QgsMessageLog::logMessage( tr( "Elevation profile distance axis minor interval expression eval error" ) );
257 }
258 else
259 {
260 mPlot->xAxis().setGridIntervalMinor( value );
261 }
262
263 forceUpdate = true;
264 }
265
268 {
269 double value = mPlot->xAxis().labelInterval();
270
271 bool ok = false;
273
274 if ( !ok )
275 {
276 QgsMessageLog::logMessage( tr( "Elevation profile distance axis label interval expression eval error" ) );
277 }
278 else
279 {
280 mPlot->xAxis().setLabelInterval( value );
281 }
282
283 forceUpdate = true;
284 }
285
288 {
289 double value = mPlot->yAxis().gridIntervalMajor();
290
291 bool ok = false;
293
294 if ( !ok )
295 {
296 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis major interval expression eval error" ) );
297 }
298 else
299 {
300 mPlot->yAxis().setGridIntervalMajor( value );
301 }
302
303 forceUpdate = true;
304 }
305
308 {
309 double value = mPlot->yAxis().gridIntervalMinor();
310
311 bool ok = false;
313
314 if ( !ok )
315 {
316 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis minor interval expression eval error" ) );
317 }
318 else
319 {
320 mPlot->yAxis().setGridIntervalMinor( value );
321 }
322
323 forceUpdate = true;
324 }
325
328 {
329 double value = mPlot->yAxis().labelInterval();
330
331 bool ok = false;
333
334 if ( !ok )
335 {
336 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis label interval expression eval error" ) );
337 }
338 else
339 {
340 mPlot->yAxis().setLabelInterval( value );
341 }
342
343 forceUpdate = true;
344 }
345
346 if ( ( property == QgsLayoutObject::MarginLeft || property == QgsLayoutObject::AllProperties )
348 {
349 double value = mPlot->margins().left();
350
351 bool ok = false;
353
354 if ( !ok )
355 {
356 QgsMessageLog::logMessage( tr( "Elevation profile left margin expression eval error" ) );
357 }
358 else
359 {
360 QgsMargins margins = mPlot->margins();
361 margins.setLeft( value );
362 mPlot->setMargins( margins );
363 }
364
365 forceUpdate = true;
366 }
367
368 if ( ( property == QgsLayoutObject::MarginRight || property == QgsLayoutObject::AllProperties )
370 {
371 double value = mPlot->margins().right();
372
373 bool ok = false;
375
376 if ( !ok )
377 {
378 QgsMessageLog::logMessage( tr( "Elevation profile right margin expression eval error" ) );
379 }
380 else
381 {
382 QgsMargins margins = mPlot->margins();
383 margins.setRight( value );
384 mPlot->setMargins( margins );
385 }
386
387 forceUpdate = true;
388 }
389
390 if ( ( property == QgsLayoutObject::MarginTop || property == QgsLayoutObject::AllProperties )
392 {
393 double value = mPlot->margins().top();
394
395 bool ok = false;
397
398 if ( !ok )
399 {
400 QgsMessageLog::logMessage( tr( "Elevation profile top margin expression eval error" ) );
401 }
402 else
403 {
404 QgsMargins margins = mPlot->margins();
405 margins.setTop( value );
406 mPlot->setMargins( margins );
407 }
408
409 forceUpdate = true;
410 }
411
412 if ( ( property == QgsLayoutObject::MarginBottom || property == QgsLayoutObject::AllProperties )
414 {
415 double value = mPlot->margins().bottom();
416
417 bool ok = false;
419
420 if ( !ok )
421 {
422 QgsMessageLog::logMessage( tr( "Elevation profile bottom margin expression eval error" ) );
423 }
424 else
425 {
426 QgsMargins margins = mPlot->margins();
427 margins.setBottom( value );
428 mPlot->setMargins( margins );
429 }
430
431 forceUpdate = true;
432 }
433
434 if ( forceUpdate )
435 {
436 mCacheInvalidated = true;
437
439 update();
440 }
441
443}
444
446{
448}
449
451{
452 return mPlot.get();
453}
454
456{
457 return mPlot.get();
458}
459
460QList<QgsMapLayer *> QgsLayoutItemElevationProfile::layers() const
461{
462 return _qgis_listRefToRaw( mLayers );
463}
464
465void QgsLayoutItemElevationProfile::setLayers( const QList<QgsMapLayer *> &layers )
466{
467 if ( layers == _qgis_listRefToRaw( mLayers ) )
468 return;
469
470 mLayers = _qgis_listRawToRef( layers );
472}
473
475{
476 mCurve.reset( curve );
478}
479
481{
482 return mCurve.get();
483}
484
486{
487 if ( mCrs == crs )
488 return;
489
490 mCrs = crs;
492}
493
495{
496 return mCrs;
497}
498
500{
501 if ( mTolerance == tolerance )
502 return;
503
504 mTolerance = tolerance;
506}
507
509{
510 return mTolerance;
511}
512
514{
515 mAtlasDriven = enabled;
516}
517
519{
520 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
521
522 req.setCrs( mCrs );
523 req.setTolerance( mTolerance );
525 if ( mLayout )
526 {
527 if ( QgsProject *project = mLayout->project() )
528 {
529 req.setTransformContext( project->transformContext() );
530 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
531 {
532 req.setTerrainProvider( provider->clone() );
533 }
534 }
535 }
536 return req;
537}
538
539void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
540{
541 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
542 {
543 return;
544 }
545 if ( !shouldDrawItem() )
546 {
547 return;
548 }
549
550 QRectF thisPaintRect = rect();
551 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
552 return;
553
554 if ( mLayout->renderContext().isPreviewRender() )
555 {
558
559 QgsScopedQPainterState painterState( painter );
560 painter->setClipRect( thisPaintRect );
561 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
562 {
563 // No initial render available - so draw some preview text alerting user
564 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
565 painter->drawRect( thisPaintRect );
566 painter->setBrush( Qt::NoBrush );
567 QFont messageFont;
568 messageFont.setPointSize( 12 );
569 painter->setFont( messageFont );
570 painter->setPen( QColor( 255, 255, 255, 255 ) );
571 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
572
573 if (
574 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
575 ||
576 ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
577 )
578 {
579
580 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
581 mBackgroundUpdateTimer->start( 1 );
582 }
583 }
584 else
585 {
586 if ( mCacheInvalidated && !mDrawingPreview )
587 {
588 // cache was invalidated - trigger a background update
589 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
590 mBackgroundUpdateTimer->start( 1 );
591 }
592
593 //Background color is already included in cached image, so no need to draw
594
595 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
596 double scale = rect().width() / imagePixelWidth;
597
598 QgsScopedQPainterState rotatedPainterState( painter );
599
600 painter->scale( scale, scale );
601 painter->drawImage( 0, 0, *mCacheFinalImage );
602 }
603
604 painter->setClipRect( thisPaintRect, Qt::NoClip );
605
606 if ( frameEnabled() )
607 {
609 }
610 }
611 else
612 {
613 if ( mDrawing )
614 return;
615
616 mDrawing = true;
617 QPaintDevice *paintDevice = painter->device();
618 if ( !paintDevice )
619 return;
620
621 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
622
623 if ( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagLosslessImageRendering )
624 painter->setRenderHint( QPainter::LosslessImageRendering, true );
625
628
629 // Fill with background color
630 if ( hasBackground() )
631 {
633 }
634
635 QgsScopedQPainterState painterState( painter );
636
637 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
638 {
639 QgsScopedQPainterState stagedPainterState( painter );
640 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
641 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
642 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
643
644 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) / layoutSize.width();
645 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
646
647 QList< QgsAbstractProfileSource * > sources;
648 for ( const QgsMapLayerRef &layer : std::as_const( mLayers ) )
649 {
650 if ( QgsAbstractProfileSource *source = dynamic_cast< QgsAbstractProfileSource * >( layer.get() ) )
651 sources.append( source );
652 }
653
654 QgsProfilePlotRenderer renderer( sources, profileRequest() );
655
656 // TODO
657 // we should be able to call renderer.start()/renderer.waitForFinished() here and
658 // benefit from parallel source generation. BUT
659 // for some reason the QtConcurrent::map call in start() never triggers
660 // the actual background thread execution.
661 // So for now just generate the results one by one
662 renderer.generateSynchronously();
663 mPlot->setRenderer( &renderer );
664
665 // size must be in pixels, not layout units
666 mPlot->setSize( layoutSize );
667
668 mPlot->render( rc );
669
670 mPlot->setRenderer( nullptr );
671
672 painter->setClipRect( thisPaintRect, Qt::NoClip );
673 }
674
675 if ( frameEnabled() )
676 {
678 }
679 mDrawing = false;
680 }
681}
682
684{
685 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
686 {
687 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
688 {
689 mCrs = layer->crs();
690 }
691 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
692 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
693 {
694 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
695 {
696 mCurve.reset( curve->clone() );
697 }
698 }
699 }
702}
703
705{
706 if ( mDrawing )
707 return;
708
709 mCacheInvalidated = true;
710 update();
711}
712
714{
715}
716
717bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
718{
719 {
720 QDomElement plotElement = doc.createElement( QStringLiteral( "plot" ) );
721 mPlot->writeXml( plotElement, doc, rwContext );
722 layoutProfileElem.appendChild( plotElement );
723 }
724
725 layoutProfileElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
726 layoutProfileElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
727 if ( mCrs.isValid() )
728 {
729 QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
730 mCrs.writeXml( crsElem, doc );
731 layoutProfileElem.appendChild( crsElem );
732 }
733 if ( mCurve )
734 {
735 QDomElement curveElem = doc.createElement( QStringLiteral( "curve" ) );
736 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
737 layoutProfileElem.appendChild( curveElem );
738 }
739
740 {
741 QDomElement layersElement = doc.createElement( QStringLiteral( "layers" ) );
742 for ( const QgsMapLayerRef &layer : mLayers )
743 {
744 QDomElement layerElement = doc.createElement( QStringLiteral( "layer" ) );
745 layer.writeXml( layerElement, rwContext );
746 layersElement.appendChild( layerElement );
747 }
748 layoutProfileElem.appendChild( layersElement );
749 }
750
751 return true;
752}
753
754bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
755{
756 const QDomElement plotElement = itemElem.firstChildElement( QStringLiteral( "plot" ) );
757 if ( !plotElement.isNull() )
758 {
759 mPlot->readXml( plotElement, context );
760 }
761
762 const QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
764 if ( !crsNodeList.isEmpty() )
765 {
766 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
767 crs.readXml( crsElem );
768 }
769 mCrs = crs;
770
771 const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral( "curve" ) );
772 if ( !curveNodeList.isEmpty() )
773 {
774 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
775 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
776 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
777 {
778 mCurve.reset( curveGeom->clone() );
779 }
780 else
781 {
782 mCurve.reset();
783 }
784 }
785
786 mTolerance = itemElem.attribute( QStringLiteral( "tolerance" ) ).toDouble();
787 mAtlasDriven = static_cast< bool >( itemElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ).toInt() );
788
789 {
790 mLayers.clear();
791 const QDomElement layersElement = itemElem.firstChildElement( QStringLiteral( "layers" ) );
792 QDomElement layerElement = layersElement.firstChildElement( QStringLiteral( "layer" ) );
793 while ( !layerElement.isNull() )
794 {
795 QgsMapLayerRef ref;
796 ref.readXml( layerElement, context );
797 ref.resolveWeakly( mLayout->project() );
798 mLayers.append( ref );
799
800 layerElement = layerElement.nextSiblingElement( QStringLiteral( "layer" ) );
801 }
802 }
803
804 return true;
805}
806
807void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
808{
809 if ( mRenderJob )
810 {
811 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
812 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
813 QPainter *oldPainter = mPainter.release();
814 QImage *oldImage = mCacheRenderingImage.release();
815 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage]
816 {
817 oldJob->deleteLater();
818 delete oldPainter;
819 delete oldImage;
820 } );
822 }
823 else
824 {
825 mCacheRenderingImage.reset( nullptr );
827 }
828
829 Q_ASSERT( !mRenderJob );
830 Q_ASSERT( !mPainter );
831 Q_ASSERT( !mCacheRenderingImage );
832
833 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
834 double widthLayoutUnits = layoutSize.width();
835 double heightLayoutUnits = layoutSize.height();
836
837 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
838 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
839
840 // limit size of image for better performance
841 if ( w > 5000 || h > 5000 )
842 {
843 if ( w > h )
844 {
845 w = 5000;
846 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
847 }
848 else
849 {
850 h = 5000;
851 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
852 }
853 }
854
855 if ( w <= 0 || h <= 0 )
856 return;
857
858 mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
859
860 // set DPI of the image
861 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
862 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
863
864 //start with empty fill to avoid artifacts
865 mCacheRenderingImage->fill( Qt::transparent );
866 if ( hasBackground() )
867 {
868 //Initially fill image with specified background color
869 mCacheRenderingImage->fill( backgroundColor().rgba() );
870 }
871
872 mCacheInvalidated = false;
873 mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
874
875 QList< QgsAbstractProfileSource * > sources;
876 for ( const QgsMapLayerRef &layer : std::as_const( mLayers ) )
877 {
878 if ( QgsAbstractProfileSource *source = dynamic_cast< QgsAbstractProfileSource * >( layer.get() ) )
879 sources.append( source );
880 }
881
882 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sources, profileRequest() );
883 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
884 mRenderJob->startGeneration();
885
886 mDrawingPreview = false;
887}
888
889void QgsLayoutItemElevationProfile::profileGenerationFinished()
890{
891 mPlot->setRenderer( mRenderJob.get() );
892
894
895 const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) /
896 mCacheRenderingImage->size().width();
897 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
898
899 // size must be in pixels, not layout units
900 mPlot->setSize( mCacheRenderingImage->size() );
901
902 mPlot->render( rc );
903
904 mPlot->setRenderer( nullptr );
905
906 mPainter->end();
907 mRenderJob.reset( nullptr );
908 mPainter.reset( nullptr );
909 mCacheFinalImage = std::move( mCacheRenderingImage );
911 update();
912}
913
Base class for 2-dimensional plot/chart/graphs.
Definition: qgsplot.h:235
double yMaximum() const
Returns the maximum value of the y axis.
Definition: qgsplot.h:347
double xMaximum() const
Returns the maximum value of the x axis.
Definition: qgsplot.h:333
double yMinimum() const
Returns the minimum value of the y axis.
Definition: qgsplot.h:319
virtual void renderContent(QgsRenderContext &context, const QRectF &plotArea)
Renders the plot content.
Definition: qgsplot.cpp:358
Abstract base class for all geometries.
Interface for classes which can generate elevation profiles.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Abstract base class for terrain providers.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
A layout item subclass for elevation profile plots.
static QgsLayoutItemElevationProfile * create(QgsLayout *layout)
Returns a new elevation profile item for the specified layout.
QgsLayoutItemElevationProfile(QgsLayout *layout)
Constructor for QgsLayoutItemElevationProfile, with the specified parent layout.
QgsCurve * profileCurve() const
Returns the cross section profile curve, which represents the line along which the profile should be ...
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of map layers participating in the elevation profile.
QList< QgsMapLayer * > layers() const
Returns the list of map layers participating in the elevation profile.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the desired Coordinate Reference System (crs) for the profile.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
QgsLayoutItem::Flags itemFlags() const override
Returns the item's flags, which indicate how the item behaves.
Qgs2DPlot * plot()
Returns a reference to the elevation plot object, which can be used to set plot appearance and proper...
void setTolerance(double tolerance)
Sets the tolerance of the request (in crs() units).
QgsCoordinateReferenceSystem crs() const
Returns the desired Coordinate Reference System for the profile.
void setAtlasDriven(bool enabled)
Sets whether the profile curve will follow the current atlas feature.
double tolerance() const
Returns the tolerance of the request (in crs() units).
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
QIcon icon() const override
Returns the item's icon.
void setProfileCurve(QgsCurve *curve)
Sets the cross section profile curve, which represents the line along which the profile should be gen...
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
QgsProfileRequest profileRequest() const
Returns the profile request used to generate the elevation profile.
@ LayoutElevationProfile
Elevation profile item (since QGIS 3.30)
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
Base class for graphical items within a QgsLayout.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
void refreshItemSize()
Refreshes an item's size by rechecking it against any possible item fixed or minimum sizes.
QColor backgroundColor() const
Returns the background color for this item.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual void drawBackground(QgsRenderContext &context)
Draws the background for the item.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
@ FlagOverridesPaint
Item overrides the default layout item painting method.
void sizePositionChanged()
Emitted when the item's size or position changes.
bool frameEnabled() const
Returns true if the item includes a frame.
bool hasBackground() const
Returns true if the item has a background.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
void backgroundTaskCountChanged(int count)
Emitted whenever the number of background tasks an item is executing changes.
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
QPointer< QgsLayout > mLayout
DataDefinedProperty
Data defined properties for different item types.
@ ElevationProfileTolerance
Tolerance distance for elevation profiles (since QGIS 3.30)
@ ElevationProfileElevationLabelInterval
Label interval for elevation profile elevation axis (since QGIS 3.30)
@ ElevationProfileDistanceMajorInterval
Major grid line interval for elevation profile distance axis (since QGIS 3.30)
@ MarginTop
Top margin (since QGIS 3.30)
@ ElevationProfileDistanceLabelInterval
Label interval for elevation profile distance axis (since QGIS 3.30)
@ ElevationProfileElevationMinorInterval
Minor grid line interval for elevation profile elevation axis (since QGIS 3.30)
@ AllProperties
All properties for item.
@ MarginLeft
Left margin (since QGIS 3.30)
@ ElevationProfileMaximumDistance
Maximum distance value for elevation profile (since QGIS 3.30)
@ MarginRight
Right margin (since QGIS 3.30)
@ ElevationProfileMinimumElevation
Minimum elevation value for elevation profile (since QGIS 3.30)
@ ElevationProfileElevationMajorInterval
Major grid line interval for elevation profile elevation axis (since QGIS 3.30)
@ ElevationProfileMinimumDistance
Minimum distance value for elevation profile (since QGIS 3.30)
@ MarginBottom
Bottom margin (since QGIS 3.30)
@ ElevationProfileDistanceMinorInterval
Minor grid line interval for elevation profile distance axis (since QGIS 3.30)
@ ElevationProfileMaximumElevation
Maximum elevation value for elevation profile (since QGIS 3.30)
@ FlagLosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static Q_DECL_DEPRECATED double scaleFactorFromItemStyle(const QStyleOptionGraphicsItem *style)
Extracts the scale factor from an item style.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:38
void setBottom(double bottom)
Sets the bottom margin to bottom.
Definition: qgsmargins.h:114
void setLeft(double left)
Sets the left margin to left.
Definition: qgsmargins.h:96
void setRight(double right)
Sets the right margin to right.
Definition: qgsmargins.h:108
void setTop(double top)
Sets the top margin to top.
Definition: qgsmargins.h:102
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Generates and renders elevation profile plots.
void cancelGenerationWithoutBlocking()
Triggers cancellation of the generation job without blocking.
void generateSynchronously()
Generate the profile results synchronously in this thread.
void generationFinished()
Emitted when the profile generation is finished (or canceled).
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QgsProfileRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate expressions.
QgsProfileRequest & setTransformContext(const QgsCoordinateTransformContext &context)
Sets the transform context, for use when transforming coordinates from a source to the request's crs(...
QgsProfileRequest & setTerrainProvider(QgsAbstractTerrainProvider *provider)
Sets the terrain provider.
QgsProfileRequest & setTolerance(double tolerance)
Sets the tolerance of the request (in crs() units).
QgsProfileRequest & setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the desired Coordinate Reference System (crs) for the profile.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Scoped object for saving and restoring a QPainter object's state.
Represents a vector layer which manages a vector based data sets.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3903
const QgsCoordinateReferenceSystem & crs
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the layer's properties from an XML element.