QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <QString>
41#include <QTimer>
42
43#include "moc_qgslayoutitemelevationprofile.cpp"
44
45using namespace Qt::StringLiterals;
46
47#define CACHE_SIZE_LIMIT 5000
48
50class QgsLayoutItemElevationProfilePlot : public Qgs2DXyPlot
51{
52 public:
53
54 QgsLayoutItemElevationProfilePlot()
55 {
56 }
57
58 void setRenderer( QgsProfilePlotRenderer *renderer )
59 {
60 // cppcheck-suppress danglingLifetime
61 mRenderer = renderer;
62 }
63
64 void renderContent( QgsRenderContext &rc, QgsPlotRenderContext &, const QRectF &plotArea, const QgsPlotData & ) override
65 {
66 if ( mRenderer )
67 {
68 const double distanceMin = xMinimum() * xScale;
69 const double distanceMax = xMaximum() * xScale;
70 rc.painter()->translate( plotArea.left(), plotArea.top() );
71 mRenderer->render( rc, plotArea.width(), plotArea.height(), distanceMin, distanceMax, yMinimum(), yMaximum() );
72 rc.painter()->translate( -plotArea.left(), -plotArea.top() );
73 mRenderer->renderSubsectionsIndicator( rc, plotArea, distanceMin, distanceMax, yMinimum(), yMaximum() );
74 }
75 }
76
77 double xScale = 1;
78
79 private:
80
81 QgsProfilePlotRenderer *mRenderer = nullptr;
82
83};
85
88 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
89{
90 mBackgroundUpdateTimer = new QTimer( this );
91 mBackgroundUpdateTimer->setSingleShot( true );
92 connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
93
94 setCacheMode( QGraphicsItem::NoCache );
95
96 if ( mLayout )
97 {
99 }
100
101 connect( this, &QgsLayoutItem::sizePositionChanged, this, [this]
102 {
104 } );
105
106 //default to no background
107 setBackgroundEnabled( false );
108
109 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceRegistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
110 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceUnregistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
111
112 setSourcesPrivate(); // Initialize with registered sources
113}
114
116{
117 if ( mRenderJob )
118 {
119 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
121 mRenderJob->cancelGeneration(); // blocks
122 mPainter->end();
123 }
124}
125
130
135
137{
138 return QgsApplication::getThemeIcon( u"mLayoutItemElevationProfile.svg"_s );
139}
140
142{
144
145 bool forceUpdate = false;
146
149 {
150 double value = mTolerance;
151
152 bool ok = false;
154
155 if ( !ok )
156 {
157 QgsMessageLog::logMessage( tr( "Elevation profile tolerance expression eval error" ) );
158 }
159 else
160 {
161 mTolerance = value;
162 }
163
164 forceUpdate = true;
165 }
166
169 {
170 double value = mPlot->xMinimum();
171
172 bool ok = false;
174
175 if ( !ok )
176 {
177 QgsMessageLog::logMessage( tr( "Elevation profile minimum distance expression eval error" ) );
178 }
179 else
180 {
181 mPlot->setXMinimum( value );
182 }
183
184 forceUpdate = true;
185 }
186
189 {
190 double value = mPlot->xMaximum();
191
192 bool ok = false;
194
195 if ( !ok )
196 {
197 QgsMessageLog::logMessage( tr( "Elevation profile maximum distance expression eval error" ) );
198 }
199 else
200 {
201 mPlot->setXMaximum( value );
202 }
203
204 forceUpdate = true;
205 }
206
209 {
210 double value = mPlot->yMinimum();
211
212 bool ok = false;
214
215 if ( !ok )
216 {
217 QgsMessageLog::logMessage( tr( "Elevation profile minimum elevation expression eval error" ) );
218 }
219 else
220 {
221 mPlot->setYMinimum( value );
222 }
223
224 forceUpdate = true;
225 }
226
229 {
230 double value = mPlot->yMaximum();
231
232 bool ok = false;
234
235 if ( !ok )
236 {
237 QgsMessageLog::logMessage( tr( "Elevation profile maximum elevation expression eval error" ) );
238 }
239 else
240 {
241 mPlot->setYMaximum( value );
242 }
243
244 forceUpdate = true;
245 }
246
249 {
250 double value = mPlot->xAxis().gridIntervalMajor();
251
252 bool ok = false;
254
255 if ( !ok )
256 {
257 QgsMessageLog::logMessage( tr( "Elevation profile distance axis major interval expression eval error" ) );
258 }
259 else
260 {
261 mPlot->xAxis().setGridIntervalMajor( value );
262 }
263
264 forceUpdate = true;
265 }
266
269 {
270 double value = mPlot->xAxis().gridIntervalMinor();
271
272 bool ok = false;
274
275 if ( !ok )
276 {
277 QgsMessageLog::logMessage( tr( "Elevation profile distance axis minor interval expression eval error" ) );
278 }
279 else
280 {
281 mPlot->xAxis().setGridIntervalMinor( value );
282 }
283
284 forceUpdate = true;
285 }
286
289 {
290 double value = mPlot->xAxis().labelInterval();
291
292 bool ok = false;
294
295 if ( !ok )
296 {
297 QgsMessageLog::logMessage( tr( "Elevation profile distance axis label interval expression eval error" ) );
298 }
299 else
300 {
301 mPlot->xAxis().setLabelInterval( value );
302 }
303
304 forceUpdate = true;
305 }
306
309 {
310 double value = mPlot->yAxis().gridIntervalMajor();
311
312 bool ok = false;
314
315 if ( !ok )
316 {
317 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis major interval expression eval error" ) );
318 }
319 else
320 {
321 mPlot->yAxis().setGridIntervalMajor( value );
322 }
323
324 forceUpdate = true;
325 }
326
329 {
330 double value = mPlot->yAxis().gridIntervalMinor();
331
332 bool ok = false;
334
335 if ( !ok )
336 {
337 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis minor interval expression eval error" ) );
338 }
339 else
340 {
341 mPlot->yAxis().setGridIntervalMinor( value );
342 }
343
344 forceUpdate = true;
345 }
346
349 {
350 double value = mPlot->yAxis().labelInterval();
351
352 bool ok = false;
354
355 if ( !ok )
356 {
357 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis label interval expression eval error" ) );
358 }
359 else
360 {
361 mPlot->yAxis().setLabelInterval( value );
362 }
363
364 forceUpdate = true;
365 }
366
369 {
370 double value = mPlot->margins().left();
371
372 bool ok = false;
373 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginLeft, context, value, &ok );
374
375 if ( !ok )
376 {
377 QgsMessageLog::logMessage( tr( "Elevation profile left margin expression eval error" ) );
378 }
379 else
380 {
381 QgsMargins margins = mPlot->margins();
382 margins.setLeft( value );
383 mPlot->setMargins( margins );
384 }
385
386 forceUpdate = true;
387 }
388
391 {
392 double value = mPlot->margins().right();
393
394 bool ok = false;
395 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginRight, context, value, &ok );
396
397 if ( !ok )
398 {
399 QgsMessageLog::logMessage( tr( "Elevation profile right margin expression eval error" ) );
400 }
401 else
402 {
403 QgsMargins margins = mPlot->margins();
404 margins.setRight( value );
405 mPlot->setMargins( margins );
406 }
407
408 forceUpdate = true;
409 }
410
413 {
414 double value = mPlot->margins().top();
415
416 bool ok = false;
417 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginTop, context, value, &ok );
418
419 if ( !ok )
420 {
421 QgsMessageLog::logMessage( tr( "Elevation profile top margin expression eval error" ) );
422 }
423 else
424 {
425 QgsMargins margins = mPlot->margins();
426 margins.setTop( value );
427 mPlot->setMargins( margins );
428 }
429
430 forceUpdate = true;
431 }
432
435 {
436 double value = mPlot->margins().bottom();
437
438 bool ok = false;
439 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginBottom, context, value, &ok );
440
441 if ( !ok )
442 {
443 QgsMessageLog::logMessage( tr( "Elevation profile bottom margin expression eval error" ) );
444 }
445 else
446 {
447 QgsMargins margins = mPlot->margins();
448 margins.setBottom( value );
449 mPlot->setMargins( margins );
450 }
451
452 forceUpdate = true;
453 }
454
455 if ( forceUpdate )
456 {
457 mCacheInvalidated = true;
458
460 update();
461 }
462
464}
465
470
472{
473 return blendMode() != QPainter::CompositionMode_SourceOver;
474}
475
477{
478 return mEvaluatedOpacity < 1.0;
479}
480
482{
483 return mPlot.get();
484}
485
487{
488 return mPlot.get();
489}
490
491QList<QgsMapLayer *> QgsLayoutItemElevationProfile::layers() const
492{
493 return _qgis_listRefToRaw( mLayers );
494}
495
496void QgsLayoutItemElevationProfile::setLayers( const QList<QgsMapLayer *> &layers )
497{
498 if ( layers == _qgis_listRefToRaw( mLayers ) )
499 return;
500
501 mLayers = _qgis_listRawToRef( layers );
503}
504
505QList<QgsAbstractProfileSource *> QgsLayoutItemElevationProfile::sources() const
506{
507 if ( mSources.isEmpty() && !mLayers.isEmpty() )
508 {
509 // Legacy: If we have layers, extract their sources and return them.
510 // We don't set mSources here, because we want the previous check to
511 // continue failing if only layers are set.
512 // TODO: Remove in QGIS 5.0.
513 QList< QgsAbstractProfileSource * > sources;
514 const QList<QgsMapLayer *> layersToGenerate = layers();
515 sources.reserve( layersToGenerate.size() );
516
517 for ( QgsMapLayer *layer : layersToGenerate )
518 {
519 if ( QgsAbstractProfileSource *source = layer->profileSource() )
520 sources << source;
521 }
522
523 // More legacy: elevation profile layers are in opposite direction
524 // to what the layer tree requires, and are in the same direction as
525 // the renderer expects, but since we reverse sources() (i.e., layers)
526 // before passing them to the renderer, then we need to reverse here first.
527 std::reverse( sources.begin(), sources.end() );
528
529 return sources;
530 }
531
532 return mSources;
533}
534
535void QgsLayoutItemElevationProfile::setSources( const QList<QgsAbstractProfileSource *> &sources )
536{
537 mSources = sources;
539}
540
542{
543 mCurve.reset( curve );
545}
546
548{
549 return mCurve.get();
550}
551
553{
554 if ( mCrs == crs )
555 return;
556
557 mCrs = crs;
559}
560
565
567{
568 if ( mTolerance == tolerance )
569 return;
570
571 mTolerance = tolerance;
573}
574
576{
577 return mTolerance;
578}
579
581{
582 mAtlasDriven = enabled;
583}
584
586{
587 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
588
589 req.setCrs( mCrs );
590 req.setTolerance( mTolerance );
592 if ( mLayout )
593 {
594 if ( QgsProject *project = mLayout->project() )
595 {
596 req.setTransformContext( project->transformContext() );
597 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
598 {
599 req.setTerrainProvider( provider->clone() );
600 }
601 }
602 }
603 return req;
604}
605
606void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
607{
608 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
609 {
610 return;
611 }
612 if ( !shouldDrawItem() )
613 {
614 return;
615 }
616
617 QRectF thisPaintRect = rect();
618 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
619 return;
620
621 if ( mLayout->renderContext().isPreviewRender() )
622 {
625
626 QgsScopedQPainterState painterState( painter );
627 painter->setClipRect( thisPaintRect );
628 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
629 {
630 // No initial render available - so draw some preview text alerting user
631 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
632 painter->drawRect( thisPaintRect );
633 painter->setBrush( Qt::NoBrush );
634 QFont messageFont;
635 messageFont.setPointSize( 12 );
636 painter->setFont( messageFont );
637 painter->setPen( QColor( 255, 255, 255, 255 ) );
638 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
639
640 if (
641 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
642 ||
643 ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
644 )
645 {
646
647 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
648 mBackgroundUpdateTimer->start( 1 );
649 }
650 }
651 else
652 {
653 if ( mCacheInvalidated && !mDrawingPreview )
654 {
655 // cache was invalidated - trigger a background update
656 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
657 mBackgroundUpdateTimer->start( 1 );
658 }
659
660 //Background color is already included in cached image, so no need to draw
661
662 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
663 double scale = rect().width() / imagePixelWidth;
664
665 QgsScopedQPainterState rotatedPainterState( painter );
666
667 painter->scale( scale, scale );
668 painter->setCompositionMode( blendModeForRender() );
669 painter->drawImage( 0, 0, *mCacheFinalImage );
670 }
671
672 painter->setClipRect( thisPaintRect, Qt::NoClip );
673
674 if ( frameEnabled() )
675 {
677 }
678 }
679 else
680 {
681 if ( mDrawing )
682 return;
683
684 mDrawing = true;
685 QPaintDevice *paintDevice = painter->device();
686 if ( !paintDevice )
687 return;
688
689 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
690
691 if ( mLayout->renderContext().flags() & Qgis::LayoutRenderFlag::LosslessImageRendering )
692 painter->setRenderHint( QPainter::LosslessImageRendering, true );
693
694 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
695
696 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
697 {
698 const bool forceVector = mLayout && mLayout->renderContext().rasterizedRenderingPolicy() == Qgis::RasterizedRenderingPolicy::ForceVector;
699 if ( ( containsAdvancedEffects() || ( blendModeForRender() != QPainter::CompositionMode_SourceOver ) )
700 && !forceVector )
701 {
702 // rasterize
703 double destinationDpi = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter ) * 25.4;
704 double layoutUnitsInInches = mLayout ? mLayout->convertFromLayoutUnits( 1, Qgis::LayoutUnit::Inches ).length() : 1;
705 int widthInPixels = static_cast< int >( std::round( boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
706 int heightInPixels = static_cast< int >( std::round( boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
707 QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
708
709 image.fill( Qt::transparent );
710 image.setDotsPerMeterX( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
711 image.setDotsPerMeterY( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
712 double dotsPerMM = destinationDpi / 25.4;
713 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
714 QPainter p( &image );
715 preparePainter( &p );
716
719
720 p.scale( dotsPerMM, dotsPerMM );
721 if ( hasBackground() )
722 {
724 }
725
726 p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
727
728 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
729 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
730
731 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
732 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
733
734 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
735 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
736 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
737
738 renderer.generateSynchronously();
739 mPlot->setRenderer( &renderer );
740
741 // size must be in pixels, not layout units
742 mPlot->setSize( layoutSize );
743
744 QgsPlotRenderContext plotContext;
745 mPlot->render( rc, plotContext );
746
747 mPlot->setRenderer( nullptr );
748
749 p.scale( dotsPerMM, dotsPerMM );
750
751 if ( frameEnabled() )
752 {
754 }
755
756 QgsScopedQPainterState painterState( painter );
757 painter->setCompositionMode( blendModeForRender() );
758 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
759 painter->drawImage( 0, 0, image );
760 painter->scale( dotsPerMM, dotsPerMM );
761 }
762 else
763 {
766
767 // Fill with background color
768 if ( hasBackground() )
769 {
771 }
772
773 QgsScopedQPainterState painterState( painter );
774 QgsScopedQPainterState stagedPainterState( painter );
775 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
776 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
777 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
778
779 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
780 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
781
782 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
783 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
784
785 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
786 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
787 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
788
789 // TODO
790 // we should be able to call renderer.start()/renderer.waitForFinished() here and
791 // benefit from parallel source generation. BUT
792 // for some reason the QtConcurrent::map call in start() never triggers
793 // the actual background thread execution.
794 // So for now just generate the results one by one
795 renderer.generateSynchronously();
796 mPlot->setRenderer( &renderer );
797
798 // size must be in pixels, not layout units
799 mPlot->setSize( layoutSize );
800
801 QgsPlotRenderContext plotContext;
802 mPlot->render( rc, plotContext );
803
804 mPlot->setRenderer( nullptr );
805
806 painter->setClipRect( thisPaintRect, Qt::NoClip );
807
808 if ( frameEnabled() )
809 {
811 }
812 }
813 }
814
815 mDrawing = false;
816 }
817}
818
820{
821 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
822 {
823 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
824 {
825 mCrs = layer->crs();
826 }
827 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
828 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
829 {
830 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
831 {
832 mCurve.reset( curve->clone() );
833 }
834 }
835 }
838}
839
841{
842 if ( mDrawing )
843 return;
844
845 mCacheInvalidated = true;
846 update();
847}
848
852
853bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
854{
855 {
856 QDomElement plotElement = doc.createElement( u"plot"_s );
857 mPlot->writeXml( plotElement, doc, rwContext );
858 layoutProfileElem.appendChild( plotElement );
859 }
860
861 layoutProfileElem.setAttribute( u"distanceUnit"_s, qgsEnumValueToKey( mDistanceUnit ) );
862
863 layoutProfileElem.setAttribute( u"tolerance"_s, mTolerance );
864 layoutProfileElem.setAttribute( u"atlasDriven"_s, mAtlasDriven ? u"1"_s : u"0"_s );
865 if ( mCrs.isValid() )
866 {
867 QDomElement crsElem = doc.createElement( u"crs"_s );
868 mCrs.writeXml( crsElem, doc );
869 layoutProfileElem.appendChild( crsElem );
870 }
871 if ( mCurve )
872 {
873 QDomElement curveElem = doc.createElement( u"curve"_s );
874 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
875 layoutProfileElem.appendChild( curveElem );
876 }
877
878 {
879 QDomElement layersElement = doc.createElement( u"layers"_s );
880 for ( const QgsMapLayerRef &layer : mLayers )
881 {
882 QDomElement layerElement = doc.createElement( u"layer"_s );
883 layer.writeXml( layerElement, rwContext );
884 layersElement.appendChild( layerElement );
885 }
886 layoutProfileElem.appendChild( layersElement );
887 }
888
889 {
890 QDomElement sourcesElement = doc.createElement( u"profileSources"_s );
891 for ( QgsAbstractProfileSource *source : mSources )
892 {
893 if ( source )
894 {
895 if ( QgsApplication::profileSourceRegistry()->findSourceById( source->profileSourceId() ) )
896 {
897 QDomElement sourceElement = doc.createElement( u"profileCustomSource"_s );
898 sourceElement.setAttribute( u"id"_s, source->profileSourceId() );
899 sourcesElement.appendChild( sourceElement );
900 }
901 else if ( auto layer = QgsMapLayerRef( dynamic_cast<QgsMapLayer *>( source ) ) )
902 {
903 QDomElement sourceElement = doc.createElement( u"profileLayerSource"_s );
904 layer.writeXml( sourceElement, rwContext );
905 sourcesElement.appendChild( sourceElement );
906 }
907 }
908 }
909 layoutProfileElem.appendChild( sourcesElement );
910 }
911
912 if ( mSubsectionsSymbol )
913 {
914 QDomElement subsectionsElement = doc.createElement( u"subsections"_s );
915 const QDomElement symbolElement = QgsSymbolLayerUtils::saveSymbol( u"subsections"_s, mSubsectionsSymbol.get(), doc, rwContext );
916 subsectionsElement.appendChild( symbolElement );
917 layoutProfileElem.appendChild( subsectionsElement );
918 }
919
920 return true;
921}
922
923bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
924{
925 const QDomElement plotElement = itemElem.firstChildElement( u"plot"_s );
926 if ( !plotElement.isNull() )
927 {
928 mPlot->readXml( plotElement, context );
929 }
930
931 const QDomNodeList crsNodeList = itemElem.elementsByTagName( u"crs"_s );
933 if ( !crsNodeList.isEmpty() )
934 {
935 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
936 crs.readXml( crsElem );
937 }
938 mCrs = crs;
939
940 setDistanceUnit( qgsEnumKeyToValue( itemElem.attribute( u"distanceUnit"_s ), mCrs.mapUnits() ) );
941
942 const QDomNodeList curveNodeList = itemElem.elementsByTagName( u"curve"_s );
943 if ( !curveNodeList.isEmpty() )
944 {
945 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
946 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
947 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
948 {
949 mCurve.reset( curveGeom->clone() );
950 }
951 else
952 {
953 mCurve.reset();
954 }
955 }
956
957 mTolerance = itemElem.attribute( u"tolerance"_s ).toDouble();
958 mAtlasDriven = static_cast< bool >( itemElem.attribute( u"atlasDriven"_s, u"0"_s ).toInt() );
959
960 {
961 mLayers.clear();
962 const QDomElement layersElement = itemElem.firstChildElement( u"layers"_s );
963 QDomElement layerElement = layersElement.firstChildElement( u"layer"_s );
964 while ( !layerElement.isNull() )
965 {
966 QgsMapLayerRef ref;
967 ref.readXml( layerElement, context );
968 ref.resolveWeakly( mLayout->project() );
969 mLayers.append( ref );
970
971 layerElement = layerElement.nextSiblingElement( u"layer"_s );
972 }
973 }
974
975 {
976 mSources.clear();
977 const QDomElement sourcesElement = itemElem.firstChildElement( u"profileSources"_s );
978 QDomElement sourceElement = sourcesElement.firstChildElement();
979 while ( !sourceElement.isNull() )
980 {
981 if ( sourceElement.tagName() == "profileCustomSource"_L1 )
982 {
983 const QString sourceId = sourceElement.attribute( u"id"_s );
984 if ( QgsAbstractProfileSource *profileSource = QgsApplication::profileSourceRegistry()->findSourceById( sourceId ) )
985 {
986 mSources.append( profileSource );
987 }
988 }
989 else if ( sourceElement.tagName() == "profileLayerSource"_L1 )
990 {
991 QgsMapLayerRef ref;
992 ref.readXml( sourceElement, context );
993 ref.resolveWeakly( mLayout->project() );
994 if ( ref.get() )
995 {
996 mSources.append( ref.get()->profileSource() );
997 }
998 }
999
1000 sourceElement = sourceElement.nextSiblingElement();
1001 }
1002 }
1003
1004 const QDomElement subsectionsElement = itemElem.firstChildElement( u"subsections"_s );
1005 const QDomElement symbolsElement = subsectionsElement.firstChildElement( u"symbol"_s );
1006 if ( !symbolsElement.isNull() )
1007 {
1008 std::unique_ptr< QgsLineSymbol > subSectionsSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol >( symbolsElement, context );
1009 if ( subSectionsSymbol )
1010 {
1011 setSubsectionsSymbol( subSectionsSymbol.release() );
1012 }
1013 }
1014
1015
1016 return true;
1017}
1018
1019void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
1020{
1021 if ( mRenderJob )
1022 {
1023 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1024 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
1025 QPainter *oldPainter = mPainter.release();
1026 QImage *oldImage = mCacheRenderingImage.release();
1027 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage]
1028 {
1029 oldJob->deleteLater();
1030 delete oldPainter;
1031 delete oldImage;
1032 } );
1034 }
1035 else
1036 {
1037 mCacheRenderingImage.reset( nullptr );
1039 }
1040
1041 Q_ASSERT( !mRenderJob );
1042 Q_ASSERT( !mPainter );
1043 Q_ASSERT( !mCacheRenderingImage );
1044
1045 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
1046 double widthLayoutUnits = layoutSize.width();
1047 double heightLayoutUnits = layoutSize.height();
1048
1049 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1050 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1051
1052 // limit size of image for better performance
1053 if ( w > 5000 || h > 5000 )
1054 {
1055 if ( w > h )
1056 {
1057 w = 5000;
1058 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1059 }
1060 else
1061 {
1062 h = 5000;
1063 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1064 }
1065 }
1066
1067 if ( w <= 0 || h <= 0 )
1068 return;
1069
1070 mCacheRenderingImage = std::make_unique<QImage>( w, h, QImage::Format_ARGB32 );
1071
1072 // set DPI of the image
1073 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1074 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1075
1076 //start with empty fill to avoid artifacts
1077 mCacheRenderingImage->fill( Qt::transparent );
1078 if ( hasBackground() )
1079 {
1080 //Initially fill image with specified background color
1081 mCacheRenderingImage->fill( backgroundColor().rgba() );
1082 }
1083
1084 mCacheInvalidated = false;
1085 mPainter = std::make_unique<QPainter>( mCacheRenderingImage.get() );
1086
1087 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
1088 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
1089
1090 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sourcesToRender, profileRequest() );
1091 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
1092 mRenderJob->setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
1093 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1094 mRenderJob->startGeneration();
1095
1096 mDrawingPreview = false;
1097}
1098
1099void QgsLayoutItemElevationProfile::profileGenerationFinished()
1100{
1101 mPlot->setRenderer( mRenderJob.get() );
1102
1103 QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( mLayout, mPainter.get() );
1104
1105 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
1106
1107 const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale /
1108 mCacheRenderingImage->size().width();
1109 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
1110
1111 // size must be in pixels, not layout units
1112 mPlot->setSize( mCacheRenderingImage->size() );
1113
1114 QgsPlotRenderContext plotContext;
1115 mPlot->render( rc, plotContext );
1116
1117 mPlot->setRenderer( nullptr );
1118
1119 mPainter->end();
1120 mRenderJob.reset( nullptr );
1121 mPainter.reset( nullptr );
1122 mCacheFinalImage = std::move( mCacheRenderingImage );
1124 update();
1125 emit previewRefreshed();
1126}
1127
1129{
1130 return mDistanceUnit;
1131}
1132
1134{
1135 mDistanceUnit = unit;
1136
1137 switch ( mDistanceUnit )
1138 {
1187 mPlot->xAxis().setLabelSuffix( u" %1"_s.arg( QgsUnitTypes::toAbbreviatedString( mDistanceUnit ) ) );
1188 break;
1189
1191 mPlot->xAxis().setLabelSuffix( QObject::tr( "°" ) );
1192 break;
1193
1195 mPlot->xAxis().setLabelSuffix( QString() );
1196 break;
1197 }
1198}
1199
1201{
1202 mSubsectionsSymbol.reset( symbol );
1203}
1204
1205void QgsLayoutItemElevationProfile::setSourcesPrivate()
1206{
1208}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2764
@ Inches
Inches.
Definition qgis.h:5279
DistanceUnit
Units of distance.
Definition qgis.h:5085
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated).
Definition qgis.h:5125
@ Feet
Imperial feet.
Definition qgis.h:5088
@ MilesUSSurvey
US Survey miles.
Definition qgis.h:5132
@ LinksBritishSears1922
British links (Sears 1922).
Definition qgis.h:5120
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A).
Definition qgis.h:5123
@ LinksBritishBenoit1895A
British links (Benoit 1895 A).
Definition qgis.h:5117
@ Centimeters
Centimeters.
Definition qgis.h:5093
@ YardsIndian1975
Indian yards (1975).
Definition qgis.h:5131
@ FeetUSSurvey
US Survey feet.
Definition qgis.h:5115
@ Millimeters
Millimeters.
Definition qgis.h:5094
@ FeetBritishSears1922
British feet (Sears 1922).
Definition qgis.h:5108
@ YardsClarkes
Clarke's yards.
Definition qgis.h:5127
@ YardsIndian
Indian yards.
Definition qgis.h:5128
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B).
Definition qgis.h:5106
@ Miles
Terrestrial miles.
Definition qgis.h:5091
@ LinksUSSurvey
US Survey links.
Definition qgis.h:5122
@ Meters
Meters.
Definition qgis.h:5086
@ ChainsUSSurvey
US Survey chains.
Definition qgis.h:5102
@ FeetClarkes
Clarke's feet.
Definition qgis.h:5109
@ Unknown
Unknown distance unit.
Definition qgis.h:5135
@ Yards
Imperial yards.
Definition qgis.h:5090
@ FeetBritish1936
British feet (1936).
Definition qgis.h:5104
@ FeetIndian1962
Indian feet (1962).
Definition qgis.h:5113
@ YardsBritishSears1922
British yards (Sears 1922).
Definition qgis.h:5126
@ FeetIndian1937
Indian feet (1937).
Definition qgis.h:5112
@ YardsIndian1937
Indian yards (1937).
Definition qgis.h:5129
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5092
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B).
Definition qgis.h:5098
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated).
Definition qgis.h:5119
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A).
Definition qgis.h:5097
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B).
Definition qgis.h:5124
@ FeetBritish1865
British feet (1865).
Definition qgis.h:5103
@ YardsIndian1962
Indian yards (1962).
Definition qgis.h:5130
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated).
Definition qgis.h:5107
@ MetersGermanLegal
German legal meter.
Definition qgis.h:5134
@ LinksBritishBenoit1895B
British links (Benoit 1895 B).
Definition qgis.h:5118
@ ChainsInternational
International chains.
Definition qgis.h:5096
@ Inches
Inches.
Definition qgis.h:5095
@ Fathoms
Fathoms.
Definition qgis.h:5133
@ LinksInternational
International links.
Definition qgis.h:5116
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated).
Definition qgis.h:5099
@ FeetIndian
Indian (geodetic) feet.
Definition qgis.h:5111
@ NauticalMiles
Nautical miles.
Definition qgis.h:5089
@ ChainsClarkes
Clarke's chains.
Definition qgis.h:5101
@ LinksClarkes
Clarke's links.
Definition qgis.h:5121
@ ChainsBritishSears1922
British chains (Sears 1922).
Definition qgis.h:5100
@ Kilometers
Kilometers.
Definition qgis.h:5087
@ FeetIndian1975
Indian feet (1975).
Definition qgis.h:5114
@ FeetGoldCoast
Gold Coast feet.
Definition qgis.h:5110
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A).
Definition qgis.h:5105
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
Definition qgis.h:5319
virtual void renderContent(QgsRenderContext &context, QgsPlotRenderContext &plotContext, const QRectF &plotArea, const QgsPlotData &plotData=QgsPlotData())
Renders the plot content.
Definition qgsplot.cpp:267
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:83
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:40
void setBottom(double bottom)
Sets the bottom margin to bottom.
Definition qgsmargins.h:116
void setLeft(double left)
Sets the left margin to left.
Definition qgsmargins.h:98
void setRight(double right)
Sets the right margin to right.
Definition qgsmargins.h:110
void setTop(double top)
Sets the top margin to top.
Definition qgsmargins.h:104
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:112
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:7110
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7091
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6900
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.