QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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 mRenderer = renderer;
50 }
51
52 void renderContent( QgsRenderContext &rc, const QRectF &plotArea ) override
53 {
54 if ( mRenderer )
55 {
56 rc.painter()->translate( plotArea.left(), plotArea.top() );
57 mRenderer->render( rc, plotArea.width(), plotArea.height(), xMinimum(), xMaximum(), yMinimum(), yMaximum() );
58 rc.painter()->translate( -plotArea.left(), -plotArea.top() );
59 }
60 }
61
62 private:
63
64 QgsProfilePlotRenderer *mRenderer = nullptr;
65
66};
68
70 : QgsLayoutItem( layout )
71 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
72{
73 mBackgroundUpdateTimer = new QTimer( this );
74 mBackgroundUpdateTimer->setSingleShot( true );
75 connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
76
77 setCacheMode( QGraphicsItem::NoCache );
78
79 if ( mLayout )
80 {
82 }
83
84 connect( this, &QgsLayoutItem::sizePositionChanged, this, [ = ]
85 {
87 } );
88
89 //default to no background
90 setBackgroundEnabled( false );
91}
92
94{
95 if ( mRenderJob )
96 {
97 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
99 mRenderJob->cancelGeneration(); // blocks
100 mPainter->end();
101 }
102}
103
105{
107}
108
110{
112}
113
115{
116 return QgsApplication::getThemeIcon( QStringLiteral( "mLayoutItemElevationProfile.svg" ) );
117}
118
120{
122
123 bool forceUpdate = false;
124
127 {
128 double value = mTolerance;
129
130 bool ok = false;
132
133 if ( !ok )
134 {
135 QgsMessageLog::logMessage( tr( "Elevation profile tolerance expression eval error" ) );
136 }
137 else
138 {
139 mTolerance = value;
140 }
141
142 forceUpdate = true;
143 }
144
147 {
148 double value = mPlot->xMinimum();
149
150 bool ok = false;
152
153 if ( !ok )
154 {
155 QgsMessageLog::logMessage( tr( "Elevation profile minimum distance expression eval error" ) );
156 }
157 else
158 {
159 mPlot->setXMinimum( value );
160 }
161
162 forceUpdate = true;
163 }
164
167 {
168 double value = mPlot->xMaximum();
169
170 bool ok = false;
172
173 if ( !ok )
174 {
175 QgsMessageLog::logMessage( tr( "Elevation profile maximum distance expression eval error" ) );
176 }
177 else
178 {
179 mPlot->setXMaximum( value );
180 }
181
182 forceUpdate = true;
183 }
184
187 {
188 double value = mPlot->yMinimum();
189
190 bool ok = false;
192
193 if ( !ok )
194 {
195 QgsMessageLog::logMessage( tr( "Elevation profile minimum elevation expression eval error" ) );
196 }
197 else
198 {
199 mPlot->setYMinimum( value );
200 }
201
202 forceUpdate = true;
203 }
204
207 {
208 double value = mPlot->yMaximum();
209
210 bool ok = false;
212
213 if ( !ok )
214 {
215 QgsMessageLog::logMessage( tr( "Elevation profile maximum elevation expression eval error" ) );
216 }
217 else
218 {
219 mPlot->setYMaximum( value );
220 }
221
222 forceUpdate = true;
223 }
224
227 {
228 double value = mPlot->xAxis().gridIntervalMajor();
229
230 bool ok = false;
232
233 if ( !ok )
234 {
235 QgsMessageLog::logMessage( tr( "Elevation profile distance axis major interval expression eval error" ) );
236 }
237 else
238 {
239 mPlot->xAxis().setGridIntervalMajor( value );
240 }
241
242 forceUpdate = true;
243 }
244
247 {
248 double value = mPlot->xAxis().gridIntervalMinor();
249
250 bool ok = false;
252
253 if ( !ok )
254 {
255 QgsMessageLog::logMessage( tr( "Elevation profile distance axis minor interval expression eval error" ) );
256 }
257 else
258 {
259 mPlot->xAxis().setGridIntervalMinor( value );
260 }
261
262 forceUpdate = true;
263 }
264
267 {
268 double value = mPlot->xAxis().labelInterval();
269
270 bool ok = false;
272
273 if ( !ok )
274 {
275 QgsMessageLog::logMessage( tr( "Elevation profile distance axis label interval expression eval error" ) );
276 }
277 else
278 {
279 mPlot->xAxis().setLabelInterval( value );
280 }
281
282 forceUpdate = true;
283 }
284
287 {
288 double value = mPlot->yAxis().gridIntervalMajor();
289
290 bool ok = false;
292
293 if ( !ok )
294 {
295 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis major interval expression eval error" ) );
296 }
297 else
298 {
299 mPlot->yAxis().setGridIntervalMajor( value );
300 }
301
302 forceUpdate = true;
303 }
304
307 {
308 double value = mPlot->yAxis().gridIntervalMinor();
309
310 bool ok = false;
312
313 if ( !ok )
314 {
315 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis minor interval expression eval error" ) );
316 }
317 else
318 {
319 mPlot->yAxis().setGridIntervalMinor( value );
320 }
321
322 forceUpdate = true;
323 }
324
327 {
328 double value = mPlot->yAxis().labelInterval();
329
330 bool ok = false;
332
333 if ( !ok )
334 {
335 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis label interval expression eval error" ) );
336 }
337 else
338 {
339 mPlot->yAxis().setLabelInterval( value );
340 }
341
342 forceUpdate = true;
343 }
344
345 if ( ( property == QgsLayoutObject::MarginLeft || property == QgsLayoutObject::AllProperties )
347 {
348 double value = mPlot->margins().left();
349
350 bool ok = false;
352
353 if ( !ok )
354 {
355 QgsMessageLog::logMessage( tr( "Elevation profile left margin expression eval error" ) );
356 }
357 else
358 {
359 QgsMargins margins = mPlot->margins();
360 margins.setLeft( value );
361 mPlot->setMargins( margins );
362 }
363
364 forceUpdate = true;
365 }
366
367 if ( ( property == QgsLayoutObject::MarginRight || property == QgsLayoutObject::AllProperties )
369 {
370 double value = mPlot->margins().right();
371
372 bool ok = false;
374
375 if ( !ok )
376 {
377 QgsMessageLog::logMessage( tr( "Elevation profile right margin expression eval error" ) );
378 }
379 else
380 {
381 QgsMargins margins = mPlot->margins();
382 margins.setRight( value );
383 mPlot->setMargins( margins );
384 }
385
386 forceUpdate = true;
387 }
388
389 if ( ( property == QgsLayoutObject::MarginTop || property == QgsLayoutObject::AllProperties )
391 {
392 double value = mPlot->margins().top();
393
394 bool ok = false;
396
397 if ( !ok )
398 {
399 QgsMessageLog::logMessage( tr( "Elevation profile top margin expression eval error" ) );
400 }
401 else
402 {
403 QgsMargins margins = mPlot->margins();
404 margins.setTop( value );
405 mPlot->setMargins( margins );
406 }
407
408 forceUpdate = true;
409 }
410
411 if ( ( property == QgsLayoutObject::MarginBottom || property == QgsLayoutObject::AllProperties )
413 {
414 double value = mPlot->margins().bottom();
415
416 bool ok = false;
418
419 if ( !ok )
420 {
421 QgsMessageLog::logMessage( tr( "Elevation profile bottom margin expression eval error" ) );
422 }
423 else
424 {
425 QgsMargins margins = mPlot->margins();
426 margins.setBottom( value );
427 mPlot->setMargins( margins );
428 }
429
430 forceUpdate = true;
431 }
432
433 if ( forceUpdate )
434 {
435 mCacheInvalidated = true;
436
438 update();
439 }
440
442}
443
445{
447}
448
450{
451 return mPlot.get();
452}
453
455{
456 return mPlot.get();
457}
458
459QList<QgsMapLayer *> QgsLayoutItemElevationProfile::layers() const
460{
461 return _qgis_listRefToRaw( mLayers );
462}
463
464void QgsLayoutItemElevationProfile::setLayers( const QList<QgsMapLayer *> &layers )
465{
466 if ( layers == _qgis_listRefToRaw( mLayers ) )
467 return;
468
469 mLayers = _qgis_listRawToRef( layers );
471}
472
474{
475 mCurve.reset( curve );
477}
478
480{
481 return mCurve.get();
482}
483
485{
486 if ( mCrs == crs )
487 return;
488
489 mCrs = crs;
491}
492
494{
495 return mCrs;
496}
497
499{
500 if ( mTolerance == tolerance )
501 return;
502
503 mTolerance = tolerance;
505}
506
508{
509 return mTolerance;
510}
511
513{
514 mAtlasDriven = enabled;
515}
516
518{
519 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
520
521 req.setCrs( mCrs );
522 req.setTolerance( mTolerance );
524 if ( mLayout )
525 {
526 if ( QgsProject *project = mLayout->project() )
527 {
528 req.setTransformContext( project->transformContext() );
529 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
530 {
531 req.setTerrainProvider( provider->clone() );
532 }
533 }
534 }
535 return req;
536}
537
538void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
539{
540 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
541 {
542 return;
543 }
544 if ( !shouldDrawItem() )
545 {
546 return;
547 }
548
549 QRectF thisPaintRect = rect();
550 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
551 return;
552
553 if ( mLayout->renderContext().isPreviewRender() )
554 {
557
558 QgsScopedQPainterState painterState( painter );
559 painter->setClipRect( thisPaintRect );
560 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
561 {
562 // No initial render available - so draw some preview text alerting user
563 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
564 painter->drawRect( thisPaintRect );
565 painter->setBrush( Qt::NoBrush );
566 QFont messageFont;
567 messageFont.setPointSize( 12 );
568 painter->setFont( messageFont );
569 painter->setPen( QColor( 255, 255, 255, 255 ) );
570 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
571
572 if (
573 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
574 ||
575 ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
576 )
577 {
578
579 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
580 mBackgroundUpdateTimer->start( 1 );
581 }
582 }
583 else
584 {
585 if ( mCacheInvalidated && !mDrawingPreview )
586 {
587 // cache was invalidated - trigger a background update
588 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
589 mBackgroundUpdateTimer->start( 1 );
590 }
591
592 //Background color is already included in cached image, so no need to draw
593
594 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
595 double scale = rect().width() / imagePixelWidth;
596
597 QgsScopedQPainterState rotatedPainterState( painter );
598
599 painter->scale( scale, scale );
600 painter->drawImage( 0, 0, *mCacheFinalImage );
601 }
602
603 painter->setClipRect( thisPaintRect, Qt::NoClip );
604
605 if ( frameEnabled() )
606 {
608 }
609 }
610 else
611 {
612 if ( mDrawing )
613 return;
614
615 mDrawing = true;
616 QPaintDevice *paintDevice = painter->device();
617 if ( !paintDevice )
618 return;
619
620 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
621
622 if ( mLayout && mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagLosslessImageRendering )
623 painter->setRenderHint( QPainter::LosslessImageRendering, true );
624
627
628 // Fill with background color
629 if ( hasBackground() )
630 {
632 }
633
634 QgsScopedQPainterState painterState( painter );
635
636 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
637 {
638 QgsScopedQPainterState stagedPainterState( painter );
639 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
640 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
641 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
642
643 QList< QgsAbstractProfileSource * > sources;
644 for ( const QgsMapLayerRef &layer : std::as_const( mLayers ) )
645 {
646 if ( QgsAbstractProfileSource *source = dynamic_cast< QgsAbstractProfileSource * >( layer.get() ) )
647 sources.append( source );
648 }
649
650 QgsProfilePlotRenderer renderer( sources, profileRequest() );
651
652 // TODO
653 // we should be able to call renderer.start()/renderer.waitForFinished() here and
654 // benefit from parallel source generation. BUT
655 // for some reason the QtConcurrent::map call in start() never triggers
656 // the actual background thread execution.
657 // So for now just generate the results one by one
658 renderer.generateSynchronously();
659 mPlot->setRenderer( &renderer );
660
661 // size must be in pixels, not layout units
662 mPlot->setSize( layoutSize );
663
664 mPlot->render( rc );
665
666 mPlot->setRenderer( nullptr );
667
668 painter->setClipRect( thisPaintRect, Qt::NoClip );
669 }
670
671 if ( frameEnabled() )
672 {
674 }
675 mDrawing = false;
676 }
677}
678
680{
681 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
682 {
683 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
684 {
685 mCrs = layer->crs();
686 }
687 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
688 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
689 {
690 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
691 {
692 mCurve.reset( curve->clone() );
693 }
694 }
695 }
698}
699
701{
702 if ( mDrawing )
703 return;
704
705 mCacheInvalidated = true;
706 update();
707}
708
710{
711}
712
713bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
714{
715 {
716 QDomElement plotElement = doc.createElement( QStringLiteral( "plot" ) );
717 mPlot->writeXml( plotElement, doc, rwContext );
718 layoutProfileElem.appendChild( plotElement );
719 }
720
721 layoutProfileElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
722 layoutProfileElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
723 if ( mCrs.isValid() )
724 {
725 QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
726 mCrs.writeXml( crsElem, doc );
727 layoutProfileElem.appendChild( crsElem );
728 }
729 if ( mCurve )
730 {
731 QDomElement curveElem = doc.createElement( QStringLiteral( "curve" ) );
732 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
733 layoutProfileElem.appendChild( curveElem );
734 }
735
736 {
737 QDomElement layersElement = doc.createElement( QStringLiteral( "layers" ) );
738 for ( const QgsMapLayerRef &layer : mLayers )
739 {
740 QDomElement layerElement = doc.createElement( QStringLiteral( "layer" ) );
741 layer.writeXml( layerElement, rwContext );
742 layersElement.appendChild( layerElement );
743 }
744 layoutProfileElem.appendChild( layersElement );
745 }
746
747 return true;
748}
749
750bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
751{
752 const QDomElement plotElement = itemElem.firstChildElement( QStringLiteral( "plot" ) );
753 if ( !plotElement.isNull() )
754 {
755 mPlot->readXml( plotElement, context );
756 }
757
758 const QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
760 if ( !crsNodeList.isEmpty() )
761 {
762 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
763 crs.readXml( crsElem );
764 }
765 mCrs = crs;
766
767 const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral( "curve" ) );
768 if ( !curveNodeList.isEmpty() )
769 {
770 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
771 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
772 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
773 {
774 mCurve.reset( curveGeom->clone() );
775 }
776 else
777 {
778 mCurve.reset();
779 }
780 }
781
782 mTolerance = itemElem.attribute( QStringLiteral( "tolerance" ) ).toDouble();
783 mAtlasDriven = static_cast< bool >( itemElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ).toInt() );
784
785 {
786 mLayers.clear();
787 const QDomElement layersElement = itemElem.firstChildElement( QStringLiteral( "layers" ) );
788 QDomElement layerElement = layersElement.firstChildElement( QStringLiteral( "layer" ) );
789 while ( !layerElement.isNull() )
790 {
791 QgsMapLayerRef ref;
792 ref.readXml( layerElement, context );
793 ref.resolveWeakly( mLayout->project() );
794 mLayers.append( ref );
795
796 layerElement = layerElement.nextSiblingElement( QStringLiteral( "layer" ) );
797 }
798 }
799
800 return true;
801}
802
803void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
804{
805 if ( mRenderJob )
806 {
807 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
808 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
809 QPainter *oldPainter = mPainter.release();
810 QImage *oldImage = mCacheRenderingImage.release();
811 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage]
812 {
813 oldJob->deleteLater();
814 delete oldPainter;
815 delete oldImage;
816 } );
818 }
819 else
820 {
821 mCacheRenderingImage.reset( nullptr );
823 }
824
825 Q_ASSERT( !mRenderJob );
826 Q_ASSERT( !mPainter );
827 Q_ASSERT( !mCacheRenderingImage );
828
829 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
830 double widthLayoutUnits = layoutSize.width();
831 double heightLayoutUnits = layoutSize.height();
832
833 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
834 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
835
836 // limit size of image for better performance
837 if ( w > 5000 || h > 5000 )
838 {
839 if ( w > h )
840 {
841 w = 5000;
842 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
843 }
844 else
845 {
846 h = 5000;
847 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
848 }
849 }
850
851 if ( w <= 0 || h <= 0 )
852 return;
853
854 mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
855
856 // set DPI of the image
857 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
858 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
859
860 //start with empty fill to avoid artifacts
861 mCacheRenderingImage->fill( Qt::transparent );
862 if ( hasBackground() )
863 {
864 //Initially fill image with specified background color
865 mCacheRenderingImage->fill( backgroundColor().rgba() );
866 }
867
868 mCacheInvalidated = false;
869 mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
870
871 QList< QgsAbstractProfileSource * > sources;
872 for ( const QgsMapLayerRef &layer : std::as_const( mLayers ) )
873 {
874 if ( QgsAbstractProfileSource *source = dynamic_cast< QgsAbstractProfileSource * >( layer.get() ) )
875 sources.append( source );
876 }
877
878 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sources, profileRequest() );
879 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
880 mRenderJob->startGeneration();
881
882 mDrawingPreview = false;
883}
884
885void QgsLayoutItemElevationProfile::profileGenerationFinished()
886{
887 mPlot->setRenderer( mRenderJob.get() );
888
890
891 // size must be in pixels, not layout units
892 mPlot->setSize( mCacheRenderingImage->size() );
893
894 mPlot->render( rc );
895
896 mPlot->setRenderer( nullptr );
897
898 mPainter->end();
899 mRenderJob.reset( nullptr );
900 mPainter.reset( nullptr );
901 mCacheFinalImage = std::move( mCacheRenderingImage );
903 update();
904}
905
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.
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:105
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 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:3509
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.