QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
19
20#include <memory>
21
22#include "qgscurve.h"
23#include "qgslayout.h"
27#include "qgslayoututils.h"
28#include "qgslinesymbol.h"
30#include "qgsmessagelog.h"
31#include "qgsplot.h"
32#include "qgsprofilerenderer.h"
33#include "qgsprofilerequest.h"
36#include "qgssymbollayerutils.h"
37#include "qgsterrainprovider.h"
38#include "qgsvectorlayer.h"
39
40#include <QTimer>
41
42#include "moc_qgslayoutitemelevationprofile.cpp"
43
44#define CACHE_SIZE_LIMIT 5000
45
47class QgsLayoutItemElevationProfilePlot : public Qgs2DXyPlot
48{
49 public:
50
51 QgsLayoutItemElevationProfilePlot()
52 {
53 }
54
55 void setRenderer( QgsProfilePlotRenderer *renderer )
56 {
57 // cppcheck-suppress danglingLifetime
58 mRenderer = renderer;
59 }
60
61 void renderContent( QgsRenderContext &rc, QgsPlotRenderContext &, const QRectF &plotArea, const QgsPlotData & ) override
62 {
63 if ( mRenderer )
64 {
65 const double distanceMin = xMinimum() * xScale;
66 const double distanceMax = xMaximum() * xScale;
67 rc.painter()->translate( plotArea.left(), plotArea.top() );
68 mRenderer->render( rc, plotArea.width(), plotArea.height(), distanceMin, distanceMax, yMinimum(), yMaximum() );
69 rc.painter()->translate( -plotArea.left(), -plotArea.top() );
70 mRenderer->renderSubsectionsIndicator( rc, plotArea, distanceMin, distanceMax, yMinimum(), yMaximum() );
71 }
72 }
73
74 double xScale = 1;
75
76 private:
77
78 QgsProfilePlotRenderer *mRenderer = nullptr;
79
80};
82
85 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
86{
87 mBackgroundUpdateTimer = new QTimer( this );
88 mBackgroundUpdateTimer->setSingleShot( true );
89 connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
90
91 setCacheMode( QGraphicsItem::NoCache );
92
93 if ( mLayout )
94 {
96 }
97
98 connect( this, &QgsLayoutItem::sizePositionChanged, this, [this]
99 {
101 } );
102
103 //default to no background
104 setBackgroundEnabled( false );
105
106 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceRegistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
107 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceUnregistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
108
109 setSourcesPrivate(); // Initialize with registered sources
110}
111
113{
114 if ( mRenderJob )
115 {
116 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
118 mRenderJob->cancelGeneration(); // blocks
119 mPainter->end();
120 }
121}
122
127
132
134{
135 return QgsApplication::getThemeIcon( QStringLiteral( "mLayoutItemElevationProfile.svg" ) );
136}
137
139{
141
142 bool forceUpdate = false;
143
146 {
147 double value = mTolerance;
148
149 bool ok = false;
151
152 if ( !ok )
153 {
154 QgsMessageLog::logMessage( tr( "Elevation profile tolerance expression eval error" ) );
155 }
156 else
157 {
158 mTolerance = value;
159 }
160
161 forceUpdate = true;
162 }
163
166 {
167 double value = mPlot->xMinimum();
168
169 bool ok = false;
171
172 if ( !ok )
173 {
174 QgsMessageLog::logMessage( tr( "Elevation profile minimum distance expression eval error" ) );
175 }
176 else
177 {
178 mPlot->setXMinimum( value );
179 }
180
181 forceUpdate = true;
182 }
183
186 {
187 double value = mPlot->xMaximum();
188
189 bool ok = false;
191
192 if ( !ok )
193 {
194 QgsMessageLog::logMessage( tr( "Elevation profile maximum distance expression eval error" ) );
195 }
196 else
197 {
198 mPlot->setXMaximum( value );
199 }
200
201 forceUpdate = true;
202 }
203
206 {
207 double value = mPlot->yMinimum();
208
209 bool ok = false;
211
212 if ( !ok )
213 {
214 QgsMessageLog::logMessage( tr( "Elevation profile minimum elevation expression eval error" ) );
215 }
216 else
217 {
218 mPlot->setYMinimum( value );
219 }
220
221 forceUpdate = true;
222 }
223
226 {
227 double value = mPlot->yMaximum();
228
229 bool ok = false;
231
232 if ( !ok )
233 {
234 QgsMessageLog::logMessage( tr( "Elevation profile maximum elevation expression eval error" ) );
235 }
236 else
237 {
238 mPlot->setYMaximum( value );
239 }
240
241 forceUpdate = true;
242 }
243
246 {
247 double value = mPlot->xAxis().gridIntervalMajor();
248
249 bool ok = false;
251
252 if ( !ok )
253 {
254 QgsMessageLog::logMessage( tr( "Elevation profile distance axis major interval expression eval error" ) );
255 }
256 else
257 {
258 mPlot->xAxis().setGridIntervalMajor( value );
259 }
260
261 forceUpdate = true;
262 }
263
266 {
267 double value = mPlot->xAxis().gridIntervalMinor();
268
269 bool ok = false;
271
272 if ( !ok )
273 {
274 QgsMessageLog::logMessage( tr( "Elevation profile distance axis minor interval expression eval error" ) );
275 }
276 else
277 {
278 mPlot->xAxis().setGridIntervalMinor( value );
279 }
280
281 forceUpdate = true;
282 }
283
286 {
287 double value = mPlot->xAxis().labelInterval();
288
289 bool ok = false;
291
292 if ( !ok )
293 {
294 QgsMessageLog::logMessage( tr( "Elevation profile distance axis label interval expression eval error" ) );
295 }
296 else
297 {
298 mPlot->xAxis().setLabelInterval( value );
299 }
300
301 forceUpdate = true;
302 }
303
306 {
307 double value = mPlot->yAxis().gridIntervalMajor();
308
309 bool ok = false;
311
312 if ( !ok )
313 {
314 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis major interval expression eval error" ) );
315 }
316 else
317 {
318 mPlot->yAxis().setGridIntervalMajor( value );
319 }
320
321 forceUpdate = true;
322 }
323
326 {
327 double value = mPlot->yAxis().gridIntervalMinor();
328
329 bool ok = false;
331
332 if ( !ok )
333 {
334 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis minor interval expression eval error" ) );
335 }
336 else
337 {
338 mPlot->yAxis().setGridIntervalMinor( value );
339 }
340
341 forceUpdate = true;
342 }
343
346 {
347 double value = mPlot->yAxis().labelInterval();
348
349 bool ok = false;
351
352 if ( !ok )
353 {
354 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis label interval expression eval error" ) );
355 }
356 else
357 {
358 mPlot->yAxis().setLabelInterval( value );
359 }
360
361 forceUpdate = true;
362 }
363
366 {
367 double value = mPlot->margins().left();
368
369 bool ok = false;
370 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginLeft, context, value, &ok );
371
372 if ( !ok )
373 {
374 QgsMessageLog::logMessage( tr( "Elevation profile left margin expression eval error" ) );
375 }
376 else
377 {
378 QgsMargins margins = mPlot->margins();
379 margins.setLeft( value );
380 mPlot->setMargins( margins );
381 }
382
383 forceUpdate = true;
384 }
385
388 {
389 double value = mPlot->margins().right();
390
391 bool ok = false;
392 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginRight, context, value, &ok );
393
394 if ( !ok )
395 {
396 QgsMessageLog::logMessage( tr( "Elevation profile right margin expression eval error" ) );
397 }
398 else
399 {
400 QgsMargins margins = mPlot->margins();
401 margins.setRight( value );
402 mPlot->setMargins( margins );
403 }
404
405 forceUpdate = true;
406 }
407
410 {
411 double value = mPlot->margins().top();
412
413 bool ok = false;
414 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginTop, context, value, &ok );
415
416 if ( !ok )
417 {
418 QgsMessageLog::logMessage( tr( "Elevation profile top margin expression eval error" ) );
419 }
420 else
421 {
422 QgsMargins margins = mPlot->margins();
423 margins.setTop( value );
424 mPlot->setMargins( margins );
425 }
426
427 forceUpdate = true;
428 }
429
432 {
433 double value = mPlot->margins().bottom();
434
435 bool ok = false;
436 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginBottom, context, value, &ok );
437
438 if ( !ok )
439 {
440 QgsMessageLog::logMessage( tr( "Elevation profile bottom margin expression eval error" ) );
441 }
442 else
443 {
444 QgsMargins margins = mPlot->margins();
445 margins.setBottom( value );
446 mPlot->setMargins( margins );
447 }
448
449 forceUpdate = true;
450 }
451
452 if ( forceUpdate )
453 {
454 mCacheInvalidated = true;
455
457 update();
458 }
459
461}
462
467
469{
470 return blendMode() != QPainter::CompositionMode_SourceOver;
471}
472
474{
475 return mEvaluatedOpacity < 1.0;
476}
477
479{
480 return mPlot.get();
481}
482
484{
485 return mPlot.get();
486}
487
488QList<QgsMapLayer *> QgsLayoutItemElevationProfile::layers() const
489{
490 return _qgis_listRefToRaw( mLayers );
491}
492
493void QgsLayoutItemElevationProfile::setLayers( const QList<QgsMapLayer *> &layers )
494{
495 if ( layers == _qgis_listRefToRaw( mLayers ) )
496 return;
497
498 mLayers = _qgis_listRawToRef( layers );
500}
501
502QList<QgsAbstractProfileSource *> QgsLayoutItemElevationProfile::sources() const
503{
504 if ( mSources.isEmpty() && !mLayers.isEmpty() )
505 {
506 // Legacy: If we have layers, extract their sources and return them.
507 // We don't set mSources here, because we want the previous check to
508 // continue failing if only layers are set.
509 // TODO: Remove in QGIS 5.0.
510 QList< QgsAbstractProfileSource * > sources;
511 const QList<QgsMapLayer *> layersToGenerate = layers();
512 sources.reserve( layersToGenerate.size() );
513
514 for ( QgsMapLayer *layer : layersToGenerate )
515 {
516 if ( QgsAbstractProfileSource *source = layer->profileSource() )
517 sources << source;
518 }
519
520 // More legacy: elevation profile layers are in opposite direction
521 // to what the layer tree requires, and are in the same direction as
522 // the renderer expects, but since we reverse sources() (i.e., layers)
523 // before passing them to the renderer, then we need to reverse here first.
524 std::reverse( sources.begin(), sources.end() );
525
526 return sources;
527 }
528
529 return mSources;
530}
531
532void QgsLayoutItemElevationProfile::setSources( const QList<QgsAbstractProfileSource *> &sources )
533{
534 mSources = sources;
536}
537
539{
540 mCurve.reset( curve );
542}
543
545{
546 return mCurve.get();
547}
548
550{
551 if ( mCrs == crs )
552 return;
553
554 mCrs = crs;
556}
557
562
564{
565 if ( mTolerance == tolerance )
566 return;
567
568 mTolerance = tolerance;
570}
571
573{
574 return mTolerance;
575}
576
578{
579 mAtlasDriven = enabled;
580}
581
583{
584 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
585
586 req.setCrs( mCrs );
587 req.setTolerance( mTolerance );
589 if ( mLayout )
590 {
591 if ( QgsProject *project = mLayout->project() )
592 {
593 req.setTransformContext( project->transformContext() );
594 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
595 {
596 req.setTerrainProvider( provider->clone() );
597 }
598 }
599 }
600 return req;
601}
602
603void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
604{
605 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
606 {
607 return;
608 }
609 if ( !shouldDrawItem() )
610 {
611 return;
612 }
613
614 QRectF thisPaintRect = rect();
615 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
616 return;
617
618 if ( mLayout->renderContext().isPreviewRender() )
619 {
622
623 QgsScopedQPainterState painterState( painter );
624 painter->setClipRect( thisPaintRect );
625 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
626 {
627 // No initial render available - so draw some preview text alerting user
628 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
629 painter->drawRect( thisPaintRect );
630 painter->setBrush( Qt::NoBrush );
631 QFont messageFont;
632 messageFont.setPointSize( 12 );
633 painter->setFont( messageFont );
634 painter->setPen( QColor( 255, 255, 255, 255 ) );
635 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
636
637 if (
638 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
639 ||
640 ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
641 )
642 {
643
644 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
645 mBackgroundUpdateTimer->start( 1 );
646 }
647 }
648 else
649 {
650 if ( mCacheInvalidated && !mDrawingPreview )
651 {
652 // cache was invalidated - trigger a background update
653 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
654 mBackgroundUpdateTimer->start( 1 );
655 }
656
657 //Background color is already included in cached image, so no need to draw
658
659 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
660 double scale = rect().width() / imagePixelWidth;
661
662 QgsScopedQPainterState rotatedPainterState( painter );
663
664 painter->scale( scale, scale );
665 painter->setCompositionMode( blendModeForRender() );
666 painter->drawImage( 0, 0, *mCacheFinalImage );
667 }
668
669 painter->setClipRect( thisPaintRect, Qt::NoClip );
670
671 if ( frameEnabled() )
672 {
674 }
675 }
676 else
677 {
678 if ( mDrawing )
679 return;
680
681 mDrawing = true;
682 QPaintDevice *paintDevice = painter->device();
683 if ( !paintDevice )
684 return;
685
686 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
687
688 if ( mLayout->renderContext().flags() & Qgis::LayoutRenderFlag::LosslessImageRendering )
689 painter->setRenderHint( QPainter::LosslessImageRendering, true );
690
691 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
692
693 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
694 {
695 const bool forceVector = mLayout && mLayout->renderContext().rasterizedRenderingPolicy() == Qgis::RasterizedRenderingPolicy::ForceVector;
696 if ( ( containsAdvancedEffects() || ( blendModeForRender() != QPainter::CompositionMode_SourceOver ) )
697 && !forceVector )
698 {
699 // rasterize
700 double destinationDpi = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter ) * 25.4;
701 double layoutUnitsInInches = mLayout ? mLayout->convertFromLayoutUnits( 1, Qgis::LayoutUnit::Inches ).length() : 1;
702 int widthInPixels = static_cast< int >( std::round( boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
703 int heightInPixels = static_cast< int >( std::round( boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
704 QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
705
706 image.fill( Qt::transparent );
707 image.setDotsPerMeterX( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
708 image.setDotsPerMeterY( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
709 double dotsPerMM = destinationDpi / 25.4;
710 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
711 QPainter p( &image );
712 preparePainter( &p );
713
716
717 p.scale( dotsPerMM, dotsPerMM );
718 if ( hasBackground() )
719 {
721 }
722
723 p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
724
725 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
726 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
727
728 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
729 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
730
731 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
732 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
733 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
734
735 renderer.generateSynchronously();
736 mPlot->setRenderer( &renderer );
737
738 // size must be in pixels, not layout units
739 mPlot->setSize( layoutSize );
740
741 QgsPlotRenderContext plotContext;
742 mPlot->render( rc, plotContext );
743
744 mPlot->setRenderer( nullptr );
745
746 p.scale( dotsPerMM, dotsPerMM );
747
748 if ( frameEnabled() )
749 {
751 }
752
753 QgsScopedQPainterState painterState( painter );
754 painter->setCompositionMode( blendModeForRender() );
755 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
756 painter->drawImage( 0, 0, image );
757 painter->scale( dotsPerMM, dotsPerMM );
758 }
759 else
760 {
763
764 // Fill with background color
765 if ( hasBackground() )
766 {
768 }
769
770 QgsScopedQPainterState painterState( painter );
771 QgsScopedQPainterState stagedPainterState( painter );
772 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
773 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
774 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
775
776 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
777 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
778
779 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
780 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
781
782 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
783 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
784 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
785
786 // TODO
787 // we should be able to call renderer.start()/renderer.waitForFinished() here and
788 // benefit from parallel source generation. BUT
789 // for some reason the QtConcurrent::map call in start() never triggers
790 // the actual background thread execution.
791 // So for now just generate the results one by one
792 renderer.generateSynchronously();
793 mPlot->setRenderer( &renderer );
794
795 // size must be in pixels, not layout units
796 mPlot->setSize( layoutSize );
797
798 QgsPlotRenderContext plotContext;
799 mPlot->render( rc, plotContext );
800
801 mPlot->setRenderer( nullptr );
802
803 painter->setClipRect( thisPaintRect, Qt::NoClip );
804
805 if ( frameEnabled() )
806 {
808 }
809 }
810 }
811
812 mDrawing = false;
813 }
814}
815
817{
818 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
819 {
820 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
821 {
822 mCrs = layer->crs();
823 }
824 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
825 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
826 {
827 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
828 {
829 mCurve.reset( curve->clone() );
830 }
831 }
832 }
835}
836
838{
839 if ( mDrawing )
840 return;
841
842 mCacheInvalidated = true;
843 update();
844}
845
849
850bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
851{
852 {
853 QDomElement plotElement = doc.createElement( QStringLiteral( "plot" ) );
854 mPlot->writeXml( plotElement, doc, rwContext );
855 layoutProfileElem.appendChild( plotElement );
856 }
857
858 layoutProfileElem.setAttribute( QStringLiteral( "distanceUnit" ), qgsEnumValueToKey( mDistanceUnit ) );
859
860 layoutProfileElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
861 layoutProfileElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
862 if ( mCrs.isValid() )
863 {
864 QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
865 mCrs.writeXml( crsElem, doc );
866 layoutProfileElem.appendChild( crsElem );
867 }
868 if ( mCurve )
869 {
870 QDomElement curveElem = doc.createElement( QStringLiteral( "curve" ) );
871 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
872 layoutProfileElem.appendChild( curveElem );
873 }
874
875 {
876 QDomElement layersElement = doc.createElement( QStringLiteral( "layers" ) );
877 for ( const QgsMapLayerRef &layer : mLayers )
878 {
879 QDomElement layerElement = doc.createElement( QStringLiteral( "layer" ) );
880 layer.writeXml( layerElement, rwContext );
881 layersElement.appendChild( layerElement );
882 }
883 layoutProfileElem.appendChild( layersElement );
884 }
885
886 {
887 QDomElement sourcesElement = doc.createElement( QStringLiteral( "profileSources" ) );
888 for ( QgsAbstractProfileSource *source : mSources )
889 {
890 if ( source )
891 {
892 if ( QgsApplication::profileSourceRegistry()->findSourceById( source->profileSourceId() ) )
893 {
894 QDomElement sourceElement = doc.createElement( QStringLiteral( "profileCustomSource" ) );
895 sourceElement.setAttribute( QStringLiteral( "id" ), source->profileSourceId() );
896 sourcesElement.appendChild( sourceElement );
897 }
898 else if ( auto layer = QgsMapLayerRef( dynamic_cast<QgsMapLayer *>( source ) ) )
899 {
900 QDomElement sourceElement = doc.createElement( QStringLiteral( "profileLayerSource" ) );
901 layer.writeXml( sourceElement, rwContext );
902 sourcesElement.appendChild( sourceElement );
903 }
904 }
905 }
906 layoutProfileElem.appendChild( sourcesElement );
907 }
908
909 if ( mSubsectionsSymbol )
910 {
911 QDomElement subsectionsElement = doc.createElement( QStringLiteral( "subsections" ) );
912 const QDomElement symbolElement = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "subsections" ), mSubsectionsSymbol.get(), doc, rwContext );
913 subsectionsElement.appendChild( symbolElement );
914 layoutProfileElem.appendChild( subsectionsElement );
915 }
916
917 return true;
918}
919
920bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
921{
922 const QDomElement plotElement = itemElem.firstChildElement( QStringLiteral( "plot" ) );
923 if ( !plotElement.isNull() )
924 {
925 mPlot->readXml( plotElement, context );
926 }
927
928 const QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
930 if ( !crsNodeList.isEmpty() )
931 {
932 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
933 crs.readXml( crsElem );
934 }
935 mCrs = crs;
936
937 setDistanceUnit( qgsEnumKeyToValue( itemElem.attribute( QStringLiteral( "distanceUnit" ) ), mCrs.mapUnits() ) );
938
939 const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral( "curve" ) );
940 if ( !curveNodeList.isEmpty() )
941 {
942 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
943 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
944 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
945 {
946 mCurve.reset( curveGeom->clone() );
947 }
948 else
949 {
950 mCurve.reset();
951 }
952 }
953
954 mTolerance = itemElem.attribute( QStringLiteral( "tolerance" ) ).toDouble();
955 mAtlasDriven = static_cast< bool >( itemElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ).toInt() );
956
957 {
958 mLayers.clear();
959 const QDomElement layersElement = itemElem.firstChildElement( QStringLiteral( "layers" ) );
960 QDomElement layerElement = layersElement.firstChildElement( QStringLiteral( "layer" ) );
961 while ( !layerElement.isNull() )
962 {
963 QgsMapLayerRef ref;
964 ref.readXml( layerElement, context );
965 ref.resolveWeakly( mLayout->project() );
966 mLayers.append( ref );
967
968 layerElement = layerElement.nextSiblingElement( QStringLiteral( "layer" ) );
969 }
970 }
971
972 {
973 mSources.clear();
974 const QDomElement sourcesElement = itemElem.firstChildElement( QStringLiteral( "profileSources" ) );
975 QDomElement sourceElement = sourcesElement.firstChildElement();
976 while ( !sourceElement.isNull() )
977 {
978 if ( sourceElement.tagName() == QLatin1String( "profileCustomSource" ) )
979 {
980 const QString sourceId = sourceElement.attribute( QStringLiteral( "id" ) );
981 if ( QgsAbstractProfileSource *profileSource = QgsApplication::profileSourceRegistry()->findSourceById( sourceId ) )
982 {
983 mSources.append( profileSource );
984 }
985 }
986 else if ( sourceElement.tagName() == QLatin1String( "profileLayerSource" ) )
987 {
988 QgsMapLayerRef ref;
989 ref.readXml( sourceElement, context );
990 ref.resolveWeakly( mLayout->project() );
991 if ( ref.get() )
992 {
993 mSources.append( ref.get()->profileSource() );
994 }
995 }
996
997 sourceElement = sourceElement.nextSiblingElement();
998 }
999 }
1000
1001 const QDomElement subsectionsElement = itemElem.firstChildElement( QStringLiteral( "subsections" ) );
1002 const QDomElement symbolsElement = subsectionsElement.firstChildElement( QStringLiteral( "symbol" ) );
1003 if ( !symbolsElement.isNull() )
1004 {
1005 std::unique_ptr< QgsLineSymbol > subSectionsSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol >( symbolsElement, context );
1006 if ( subSectionsSymbol )
1007 {
1008 setSubsectionsSymbol( subSectionsSymbol.release() );
1009 }
1010 }
1011
1012
1013 return true;
1014}
1015
1016void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
1017{
1018 if ( mRenderJob )
1019 {
1020 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1021 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
1022 QPainter *oldPainter = mPainter.release();
1023 QImage *oldImage = mCacheRenderingImage.release();
1024 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage]
1025 {
1026 oldJob->deleteLater();
1027 delete oldPainter;
1028 delete oldImage;
1029 } );
1031 }
1032 else
1033 {
1034 mCacheRenderingImage.reset( nullptr );
1036 }
1037
1038 Q_ASSERT( !mRenderJob );
1039 Q_ASSERT( !mPainter );
1040 Q_ASSERT( !mCacheRenderingImage );
1041
1042 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
1043 double widthLayoutUnits = layoutSize.width();
1044 double heightLayoutUnits = layoutSize.height();
1045
1046 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1047 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1048
1049 // limit size of image for better performance
1050 if ( w > 5000 || h > 5000 )
1051 {
1052 if ( w > h )
1053 {
1054 w = 5000;
1055 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1056 }
1057 else
1058 {
1059 h = 5000;
1060 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1061 }
1062 }
1063
1064 if ( w <= 0 || h <= 0 )
1065 return;
1066
1067 mCacheRenderingImage = std::make_unique<QImage>( w, h, QImage::Format_ARGB32 );
1068
1069 // set DPI of the image
1070 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1071 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1072
1073 //start with empty fill to avoid artifacts
1074 mCacheRenderingImage->fill( Qt::transparent );
1075 if ( hasBackground() )
1076 {
1077 //Initially fill image with specified background color
1078 mCacheRenderingImage->fill( backgroundColor().rgba() );
1079 }
1080
1081 mCacheInvalidated = false;
1082 mPainter = std::make_unique<QPainter>( mCacheRenderingImage.get() );
1083
1084 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
1085 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
1086
1087 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sourcesToRender, profileRequest() );
1088 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
1089 mRenderJob->setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
1090 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1091 mRenderJob->startGeneration();
1092
1093 mDrawingPreview = false;
1094}
1095
1096void QgsLayoutItemElevationProfile::profileGenerationFinished()
1097{
1098 mPlot->setRenderer( mRenderJob.get() );
1099
1100 QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( mLayout, mPainter.get() );
1101
1102 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
1103
1104 const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale /
1105 mCacheRenderingImage->size().width();
1106 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
1107
1108 // size must be in pixels, not layout units
1109 mPlot->setSize( mCacheRenderingImage->size() );
1110
1111 QgsPlotRenderContext plotContext;
1112 mPlot->render( rc, plotContext );
1113
1114 mPlot->setRenderer( nullptr );
1115
1116 mPainter->end();
1117 mRenderJob.reset( nullptr );
1118 mPainter.reset( nullptr );
1119 mCacheFinalImage = std::move( mCacheRenderingImage );
1121 update();
1122 emit previewRefreshed();
1123}
1124
1126{
1127 return mDistanceUnit;
1128}
1129
1131{
1132 mDistanceUnit = unit;
1133
1134 switch ( mDistanceUnit )
1135 {
1184 mPlot->xAxis().setLabelSuffix( QStringLiteral( " %1" ).arg( QgsUnitTypes::toAbbreviatedString( mDistanceUnit ) ) );
1185 break;
1186
1188 mPlot->xAxis().setLabelSuffix( QObject::tr( "°" ) );
1189 break;
1190
1192 mPlot->xAxis().setLabelSuffix( QString() );
1193 break;
1194 }
1195}
1196
1198{
1199 mSubsectionsSymbol.reset( symbol );
1200}
1201
1202void QgsLayoutItemElevationProfile::setSourcesPrivate()
1203{
1205}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2706
@ Inches
Inches.
Definition qgis.h:5207
DistanceUnit
Units of distance.
Definition qgis.h:5013
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated).
Definition qgis.h:5053
@ Feet
Imperial feet.
Definition qgis.h:5016
@ MilesUSSurvey
US Survey miles.
Definition qgis.h:5060
@ LinksBritishSears1922
British links (Sears 1922).
Definition qgis.h:5048
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A).
Definition qgis.h:5051
@ LinksBritishBenoit1895A
British links (Benoit 1895 A).
Definition qgis.h:5045
@ Centimeters
Centimeters.
Definition qgis.h:5021
@ YardsIndian1975
Indian yards (1975).
Definition qgis.h:5059
@ FeetUSSurvey
US Survey feet.
Definition qgis.h:5043
@ Millimeters
Millimeters.
Definition qgis.h:5022
@ FeetBritishSears1922
British feet (Sears 1922).
Definition qgis.h:5036
@ YardsClarkes
Clarke's yards.
Definition qgis.h:5055
@ YardsIndian
Indian yards.
Definition qgis.h:5056
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B).
Definition qgis.h:5034
@ Miles
Terrestrial miles.
Definition qgis.h:5019
@ LinksUSSurvey
US Survey links.
Definition qgis.h:5050
@ Meters
Meters.
Definition qgis.h:5014
@ ChainsUSSurvey
US Survey chains.
Definition qgis.h:5030
@ FeetClarkes
Clarke's feet.
Definition qgis.h:5037
@ Unknown
Unknown distance unit.
Definition qgis.h:5063
@ Yards
Imperial yards.
Definition qgis.h:5018
@ FeetBritish1936
British feet (1936).
Definition qgis.h:5032
@ FeetIndian1962
Indian feet (1962).
Definition qgis.h:5041
@ YardsBritishSears1922
British yards (Sears 1922).
Definition qgis.h:5054
@ FeetIndian1937
Indian feet (1937).
Definition qgis.h:5040
@ YardsIndian1937
Indian yards (1937).
Definition qgis.h:5057
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5020
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B).
Definition qgis.h:5026
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated).
Definition qgis.h:5047
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A).
Definition qgis.h:5025
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B).
Definition qgis.h:5052
@ FeetBritish1865
British feet (1865).
Definition qgis.h:5031
@ YardsIndian1962
Indian yards (1962).
Definition qgis.h:5058
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated).
Definition qgis.h:5035
@ MetersGermanLegal
German legal meter.
Definition qgis.h:5062
@ LinksBritishBenoit1895B
British links (Benoit 1895 B).
Definition qgis.h:5046
@ ChainsInternational
International chains.
Definition qgis.h:5024
@ Inches
Inches.
Definition qgis.h:5023
@ Fathoms
Fathoms.
Definition qgis.h:5061
@ LinksInternational
International links.
Definition qgis.h:5044
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated).
Definition qgis.h:5027
@ FeetIndian
Indian (geodetic) feet.
Definition qgis.h:5039
@ NauticalMiles
Nautical miles.
Definition qgis.h:5017
@ ChainsClarkes
Clarke's chains.
Definition qgis.h:5029
@ LinksClarkes
Clarke's links.
Definition qgis.h:5049
@ ChainsBritishSears1922
British chains (Sears 1922).
Definition qgis.h:5028
@ Kilometers
Kilometers.
Definition qgis.h:5015
@ FeetIndian1975
Indian feet (1975).
Definition qgis.h:5042
@ FeetGoldCoast
Gold Coast feet.
Definition qgis.h:5038
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A).
Definition qgis.h:5033
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
Definition qgis.h:5247
virtual void renderContent(QgsRenderContext &context, QgsPlotRenderContext &plotContext, const QRectF &plotArea, const QgsPlotData &plotData=QgsPlotData())
Renders the plot content.
Definition qgsplot.cpp:263
Base class for 2-dimensional plot/chart/graphs with an X and Y axes.
Definition qgsplot.h:659
double yMaximum() const
Returns the maximum value of the y axis.
Definition qgsplot.h:742
double xMinimum() const
Returns the minimum value of the x axis.
Definition qgsplot.h:700
double yMinimum() const
Returns the minimum value of the y axis.
Definition qgsplot.h:714
double xMaximum() const
Returns the maximum value of the x axis.
Definition qgsplot.h:728
Abstract base class for all geometries.
Interface for classes which can generate elevation profiles.
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.
static QgsProfileSourceRegistry * profileSourceRegistry()
Returns registry of available profile source implementations.
Represents a coordinate reference system (CRS).
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static Q_INVOKABLE QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QgsLayoutItemElevationProfile * create(QgsLayout *layout)
Returns a new elevation profile item for the specified layout.
Qgs2DXyPlot * plot()
Returns a reference to the elevation plot object, which can be used to set plot appearance and proper...
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 refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties) override
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of map layers participating in the elevation profile.
void setSubsectionsSymbol(QgsLineSymbol *symbol)
Sets the symbol used to draw the subsections.
QList< QgsMapLayer * > layers() const
Returns the list of map layers participating in the elevation profile.
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.
QList< QgsAbstractProfileSource * > sources() const
Returns the list of sources participating in the elevation profile.
void setDistanceUnit(Qgis::DistanceUnit unit)
Sets the unit for the distance axis.
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).
QgsLineSymbol * subsectionsSymbol()
Returns the symbol used to draw the subsections.
Qgis::DistanceUnit distanceUnit() const
Returns the units for the distance axis.
bool requiresRasterization() const override
Returns true if the item is drawn in such a way that forces the whole layout to be rasterized when ex...
void setSources(const QList< QgsAbstractProfileSource * > &sources)
Sets the list of sources participating in the elevation profile.
bool containsAdvancedEffects() const override
Returns true if the item contains contents with blend modes or transparency effects which can only be...
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
QIcon icon() const override
Returns the item's icon.
void previewRefreshed()
Emitted whenever the item's preview has been refreshed.
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.
Contains settings and helpers relating to a render of a QgsLayoutItem.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
friend class QgsLayout
QColor backgroundColor(bool useDataDefined=true) const
Returns the background color for this item.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
QgsLayoutItem(QgsLayout *layout, bool manageZValue=true)
Constructor for QgsLayoutItem, with the specified parent layout.
void refreshItemSize()
Refreshes an item's size by rechecking it against any possible item fixed or minimum sizes.
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.
@ FlagOverridesPaint
Item overrides the default layout item painting method.
@ FlagDisableSceneCaching
Item should not have QGraphicsItem caching enabled.
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.
QFlags< Flag > Flags
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
friend class QgsLayoutItemElevationProfile
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
QPainter::CompositionMode blendMode() const
Returns the item's composition blending mode.
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.
@ ElevationProfileMaximumDistance
Maximum distance value for elevation profile.
@ ElevationProfileElevationMinorInterval
Minor grid line interval for elevation profile elevation axis.
@ ElevationProfileDistanceMinorInterval
Minor grid line interval for elevation profile distance axis.
@ ElevationProfileMinimumDistance
Minimum distance value for elevation profile.
@ ElevationProfileMaximumElevation
Maximum elevation value for elevation profile.
@ ElevationProfileDistanceLabelInterval
Label interval for elevation profile distance axis.
@ ElevationProfileTolerance
Tolerance distance for elevation profiles.
@ ElevationProfileMinimumElevation
Minimum elevation value for elevation profile.
@ ElevationProfileElevationLabelInterval
Label interval for elevation profile elevation axis.
@ ElevationProfileDistanceMajorInterval
Major grid line interval for elevation profile distance axis.
@ ElevationProfileElevationMajorInterval
Major grid line interval for elevation profile elevation axis.
@ AllProperties
All properties for item.
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.
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated.
A line symbol type, for rendering LineString and MultiLineString geometries.
Base class for all map layer types.
Definition qgsmaplayer.h:80
virtual QgsAbstractProfileSource * profileSource()
Returns the layer's profile source if it has profile capabilities.
Perform transforms between map coordinates and device coordinates.
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Encapsulates one or more plot series.
Definition qgsplot.h:300
Contains information about the context of a plot rendering operation.
Definition qgsplot.h:184
Generates and renders elevation profile plots.
void setSubsectionsSymbol(QgsLineSymbol *symbol)
Sets the symbol used to draw the subsections.
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.
void profileSourceUnregistered(const QString &sourceId)
Signal emitted once a profile source is unregistered.
QList< QgsAbstractProfileSource * > profileSources() const
Returns a list of registered profile sources.
void profileSourceRegistered(const QString &sourceId, const QString &sourceName)
Signal emitted once a profile source is registered.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
A container for the context for various read/write operations on 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.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
Represents a vector layer which manages a vector based dataset.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:6817
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
T qgsgeometry_cast(QgsAbstractGeometry *geom)
_LayerRef< QgsMapLayer > QgsMapLayerRef
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.
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the layer's properties from an XML element.