QGIS API Documentation 3.99.0-Master (7d2ca374f2d)
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 this if block in QGIS 5.0 along with setLayers/layers methods.
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 QList< QgsAbstractProfileSource * > sources;
533 sources.reserve( mSources.count() );
534 for ( const auto &source : mSources )
535 {
536 if ( const QgsMapLayerRef *layerRef = std::get_if< QgsMapLayerRef >( &source ) )
537 {
538 if ( QgsMapLayer *layer = layerRef->get() )
539 {
540 sources << layer->profileSource();
541 }
542 }
543 else if ( auto profileSource = std::get_if< QgsAbstractProfileSource * >( &source ) )
544 {
545 if ( QgsApplication::profileSourceRegistry()->findSourceById( ( *profileSource )->profileSourceId() ) )
546 {
547 sources << *profileSource;
548 }
549 }
550 }
551
552 return sources;
553}
554
555void QgsLayoutItemElevationProfile::setSources( const QList<QgsAbstractProfileSource *> &sources )
556{
557 mSources.clear();
558 mSources.reserve( sources.count() );
559 for ( QgsAbstractProfileSource *profileSource : sources )
560 {
561 if ( auto layer = dynamic_cast<QgsMapLayer *>( profileSource ) )
562 {
563 mSources << QgsMapLayerRef( layer );
564 }
565 else if ( QgsApplication::profileSourceRegistry()->findSourceById( profileSource->profileSourceId() ) )
566 {
567 mSources << profileSource;
568 }
569 }
570
572}
573
575{
576 mCurve.reset( curve );
578}
579
581{
582 return mCurve.get();
583}
584
586{
587 if ( mCrs == crs )
588 return;
589
590 mCrs = crs;
592}
593
598
600{
601 if ( mTolerance == tolerance )
602 return;
603
604 mTolerance = tolerance;
606}
607
609{
610 return mTolerance;
611}
612
614{
615 mAtlasDriven = enabled;
616}
617
619{
620 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
621
622 req.setCrs( mCrs );
623 req.setTolerance( mTolerance );
625 if ( mLayout )
626 {
627 if ( QgsProject *project = mLayout->project() )
628 {
629 req.setTransformContext( project->transformContext() );
630 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
631 {
632 req.setTerrainProvider( provider->clone() );
633 }
634 }
635 }
636 return req;
637}
638
639void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
640{
641 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
642 {
643 return;
644 }
645 if ( !shouldDrawItem() )
646 {
647 return;
648 }
649
650 QRectF thisPaintRect = rect();
651 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
652 return;
653
654 if ( mLayout->renderContext().isPreviewRender() )
655 {
658
659 QgsScopedQPainterState painterState( painter );
660 painter->setClipRect( thisPaintRect );
661 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
662 {
663 // No initial render available - so draw some preview text alerting user
664 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
665 painter->drawRect( thisPaintRect );
666 painter->setBrush( Qt::NoBrush );
667 QFont messageFont;
668 messageFont.setPointSize( 12 );
669 painter->setFont( messageFont );
670 painter->setPen( QColor( 255, 255, 255, 255 ) );
671 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
672
673 if (
674 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
675 ||
676 ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
677 )
678 {
679
680 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
681 mBackgroundUpdateTimer->start( 1 );
682 }
683 }
684 else
685 {
686 if ( mCacheInvalidated && !mDrawingPreview )
687 {
688 // cache was invalidated - trigger a background update
689 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
690 mBackgroundUpdateTimer->start( 1 );
691 }
692
693 //Background color is already included in cached image, so no need to draw
694
695 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
696 double scale = rect().width() / imagePixelWidth;
697
698 QgsScopedQPainterState rotatedPainterState( painter );
699
700 painter->scale( scale, scale );
701 painter->setCompositionMode( blendModeForRender() );
702 painter->drawImage( 0, 0, *mCacheFinalImage );
703 }
704
705 painter->setClipRect( thisPaintRect, Qt::NoClip );
706
707 if ( frameEnabled() )
708 {
710 }
711 }
712 else
713 {
714 if ( mDrawing )
715 return;
716
717 mDrawing = true;
718 QPaintDevice *paintDevice = painter->device();
719 if ( !paintDevice )
720 return;
721
722 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
723
724 if ( mLayout->renderContext().flags() & Qgis::LayoutRenderFlag::LosslessImageRendering )
725 painter->setRenderHint( QPainter::LosslessImageRendering, true );
726
727 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
728
729 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
730 {
731 const bool forceVector = mLayout && mLayout->renderContext().rasterizedRenderingPolicy() == Qgis::RasterizedRenderingPolicy::ForceVector;
732 if ( ( containsAdvancedEffects() || ( blendModeForRender() != QPainter::CompositionMode_SourceOver ) )
733 && !forceVector )
734 {
735 // rasterize
736 double destinationDpi = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter ) * 25.4;
737 double layoutUnitsInInches = mLayout ? mLayout->convertFromLayoutUnits( 1, Qgis::LayoutUnit::Inches ).length() : 1;
738 int widthInPixels = static_cast< int >( std::round( boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
739 int heightInPixels = static_cast< int >( std::round( boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
740 QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
741
742 image.fill( Qt::transparent );
743 image.setDotsPerMeterX( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
744 image.setDotsPerMeterY( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
745 double dotsPerMM = destinationDpi / 25.4;
746 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
747 QPainter p( &image );
748 preparePainter( &p );
749
752
753 p.scale( dotsPerMM, dotsPerMM );
754 if ( hasBackground() )
755 {
757 }
758
759 p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
760
761 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
762 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
763
764 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
765 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
766
767 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
768 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
769 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
770
771 renderer.generateSynchronously();
772 mPlot->setRenderer( &renderer );
773
774 // size must be in pixels, not layout units
775 mPlot->setSize( layoutSize );
776
777 QgsPlotRenderContext plotContext;
778 mPlot->render( rc, plotContext );
779
780 mPlot->setRenderer( nullptr );
781
782 p.scale( dotsPerMM, dotsPerMM );
783
784 if ( frameEnabled() )
785 {
787 }
788
789 QgsScopedQPainterState painterState( painter );
790 painter->setCompositionMode( blendModeForRender() );
791 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
792 painter->drawImage( 0, 0, image );
793 painter->scale( dotsPerMM, dotsPerMM );
794 }
795 else
796 {
799
800 // Fill with background color
801 if ( hasBackground() )
802 {
804 }
805
806 QgsScopedQPainterState painterState( painter );
807 QgsScopedQPainterState stagedPainterState( painter );
808 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
809 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
810 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
811
812 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
813 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
814
815 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
816 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
817
818 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
819 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
820 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
821
822 // TODO
823 // we should be able to call renderer.start()/renderer.waitForFinished() here and
824 // benefit from parallel source generation. BUT
825 // for some reason the QtConcurrent::map call in start() never triggers
826 // the actual background thread execution.
827 // So for now just generate the results one by one
828 renderer.generateSynchronously();
829 mPlot->setRenderer( &renderer );
830
831 // size must be in pixels, not layout units
832 mPlot->setSize( layoutSize );
833
834 QgsPlotRenderContext plotContext;
835 mPlot->render( rc, plotContext );
836
837 mPlot->setRenderer( nullptr );
838
839 painter->setClipRect( thisPaintRect, Qt::NoClip );
840
841 if ( frameEnabled() )
842 {
844 }
845 }
846 }
847
848 mDrawing = false;
849 }
850}
851
853{
854 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
855 {
856 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
857 {
858 mCrs = layer->crs();
859 }
860 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
861 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
862 {
863 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
864 {
865 mCurve.reset( curve->clone() );
866 }
867 }
868 }
871}
872
874{
875 if ( mDrawing )
876 return;
877
878 mCacheInvalidated = true;
879 update();
880}
881
885
886bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
887{
888 {
889 QDomElement plotElement = doc.createElement( u"plot"_s );
890 mPlot->writeXml( plotElement, doc, rwContext );
891 layoutProfileElem.appendChild( plotElement );
892 }
893
894 layoutProfileElem.setAttribute( u"distanceUnit"_s, qgsEnumValueToKey( mDistanceUnit ) );
895
896 layoutProfileElem.setAttribute( u"tolerance"_s, mTolerance );
897 layoutProfileElem.setAttribute( u"atlasDriven"_s, mAtlasDriven ? u"1"_s : u"0"_s );
898 if ( mCrs.isValid() )
899 {
900 QDomElement crsElem = doc.createElement( u"crs"_s );
901 mCrs.writeXml( crsElem, doc );
902 layoutProfileElem.appendChild( crsElem );
903 }
904 if ( mCurve )
905 {
906 QDomElement curveElem = doc.createElement( u"curve"_s );
907 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
908 layoutProfileElem.appendChild( curveElem );
909 }
910
911 {
912 QDomElement layersElement = doc.createElement( u"layers"_s );
913 for ( const QgsMapLayerRef &layer : mLayers )
914 {
915 QDomElement layerElement = doc.createElement( u"layer"_s );
916 layer.writeXml( layerElement, rwContext );
917 layersElement.appendChild( layerElement );
918 }
919 layoutProfileElem.appendChild( layersElement );
920 }
921
922 {
923 QDomElement sourcesElement = doc.createElement( u"profileSources"_s );
924 for ( const auto &source : mSources )
925 {
926 if ( const QgsMapLayerRef *layerRef = std::get_if< QgsMapLayerRef >( &source ) )
927 {
928 if ( layerRef->get() )
929 {
930 QDomElement sourceElement = doc.createElement( u"profileLayerSource"_s );
931 layerRef->writeXml( sourceElement, rwContext );
932 sourcesElement.appendChild( sourceElement );
933 }
934 }
935 else if ( auto profileSource = std::get_if< QgsAbstractProfileSource * >( &source ) )
936 {
937 if ( QgsApplication::profileSourceRegistry()->findSourceById( ( *profileSource )->profileSourceId() ) )
938 {
939 QDomElement sourceElement = doc.createElement( u"profileCustomSource"_s );
940 sourceElement.setAttribute( u"id"_s, ( *profileSource )->profileSourceId() );
941 sourcesElement.appendChild( sourceElement );
942 }
943 }
944 }
945
946 layoutProfileElem.appendChild( sourcesElement );
947 }
948
949 if ( mSubsectionsSymbol )
950 {
951 QDomElement subsectionsElement = doc.createElement( u"subsections"_s );
952 const QDomElement symbolElement = QgsSymbolLayerUtils::saveSymbol( u"subsections"_s, mSubsectionsSymbol.get(), doc, rwContext );
953 subsectionsElement.appendChild( symbolElement );
954 layoutProfileElem.appendChild( subsectionsElement );
955 }
956
957 return true;
958}
959
960bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
961{
962 const QDomElement plotElement = itemElem.firstChildElement( u"plot"_s );
963 if ( !plotElement.isNull() )
964 {
965 mPlot->readXml( plotElement, context );
966 }
967
968 const QDomNodeList crsNodeList = itemElem.elementsByTagName( u"crs"_s );
970 if ( !crsNodeList.isEmpty() )
971 {
972 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
973 crs.readXml( crsElem );
974 }
975 mCrs = crs;
976
977 setDistanceUnit( qgsEnumKeyToValue( itemElem.attribute( u"distanceUnit"_s ), mCrs.mapUnits() ) );
978
979 const QDomNodeList curveNodeList = itemElem.elementsByTagName( u"curve"_s );
980 if ( !curveNodeList.isEmpty() )
981 {
982 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
983 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
984 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
985 {
986 mCurve.reset( curveGeom->clone() );
987 }
988 else
989 {
990 mCurve.reset();
991 }
992 }
993
994 mTolerance = itemElem.attribute( u"tolerance"_s ).toDouble();
995 mAtlasDriven = static_cast< bool >( itemElem.attribute( u"atlasDriven"_s, u"0"_s ).toInt() );
996
997 {
998 mLayers.clear();
999 const QDomElement layersElement = itemElem.firstChildElement( u"layers"_s );
1000 QDomElement layerElement = layersElement.firstChildElement( u"layer"_s );
1001 while ( !layerElement.isNull() )
1002 {
1003 QgsMapLayerRef ref;
1004 ref.readXml( layerElement, context );
1005 ref.resolveWeakly( mLayout->project() );
1006 mLayers.append( ref );
1007
1008 layerElement = layerElement.nextSiblingElement( u"layer"_s );
1009 }
1010 }
1011
1012 {
1013 mSources.clear();
1014 mSources.reserve( itemElem.elementsByTagName( u"profileSources"_s ).count() );
1015 const QDomElement sourcesElement = itemElem.firstChildElement( u"profileSources"_s );
1016 QDomElement sourceElement = sourcesElement.firstChildElement();
1017 while ( !sourceElement.isNull() )
1018 {
1019 if ( sourceElement.tagName() == "profileCustomSource"_L1 )
1020 {
1021 const QString sourceId = sourceElement.attribute( u"id"_s );
1022 if ( QgsAbstractProfileSource *profileSource = QgsApplication::profileSourceRegistry()->findSourceById( sourceId ) )
1023 {
1024 mSources << profileSource ;
1025 }
1026 }
1027 else if ( sourceElement.tagName() == "profileLayerSource"_L1 )
1028 {
1029 QgsMapLayerRef ref;
1030 ref.readXml( sourceElement, context );
1031 ref.resolveWeakly( mLayout->project() );
1032 if ( ref.get() )
1033 {
1034 mSources << ref;
1035 }
1036 }
1037
1038 sourceElement = sourceElement.nextSiblingElement();
1039 }
1040 }
1041
1042 const QDomElement subsectionsElement = itemElem.firstChildElement( u"subsections"_s );
1043 const QDomElement symbolsElement = subsectionsElement.firstChildElement( u"symbol"_s );
1044 if ( !symbolsElement.isNull() )
1045 {
1046 std::unique_ptr< QgsLineSymbol > subSectionsSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol >( symbolsElement, context );
1047 if ( subSectionsSymbol )
1048 {
1049 setSubsectionsSymbol( subSectionsSymbol.release() );
1050 }
1051 }
1052
1053 return true;
1054}
1055
1056void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
1057{
1058 if ( mRenderJob )
1059 {
1060 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1061 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
1062 QPainter *oldPainter = mPainter.release();
1063 QImage *oldImage = mCacheRenderingImage.release();
1064 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage]
1065 {
1066 oldJob->deleteLater();
1067 delete oldPainter;
1068 delete oldImage;
1069 } );
1071 }
1072 else
1073 {
1074 mCacheRenderingImage.reset( nullptr );
1076 }
1077
1078 Q_ASSERT( !mRenderJob );
1079 Q_ASSERT( !mPainter );
1080 Q_ASSERT( !mCacheRenderingImage );
1081
1082 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
1083 double widthLayoutUnits = layoutSize.width();
1084 double heightLayoutUnits = layoutSize.height();
1085
1086 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1087 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1088
1089 // limit size of image for better performance
1090 if ( w > 5000 || h > 5000 )
1091 {
1092 if ( w > h )
1093 {
1094 w = 5000;
1095 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1096 }
1097 else
1098 {
1099 h = 5000;
1100 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1101 }
1102 }
1103
1104 if ( w <= 0 || h <= 0 )
1105 return;
1106
1107 mCacheRenderingImage = std::make_unique<QImage>( w, h, QImage::Format_ARGB32 );
1108
1109 // set DPI of the image
1110 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1111 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1112
1113 //start with empty fill to avoid artifacts
1114 mCacheRenderingImage->fill( Qt::transparent );
1115 if ( hasBackground() )
1116 {
1117 //Initially fill image with specified background color
1118 mCacheRenderingImage->fill( backgroundColor().rgba() );
1119 }
1120
1121 mCacheInvalidated = false;
1122 mPainter = std::make_unique<QPainter>( mCacheRenderingImage.get() );
1123
1124 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
1125 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
1126
1127 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sourcesToRender, profileRequest() );
1128 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
1129 mRenderJob->setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
1130 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1131 mRenderJob->startGeneration();
1132
1133 mDrawingPreview = false;
1134}
1135
1136void QgsLayoutItemElevationProfile::profileGenerationFinished()
1137{
1138 mPlot->setRenderer( mRenderJob.get() );
1139
1140 QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( mLayout, mPainter.get() );
1141
1142 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
1143
1144 const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale /
1145 mCacheRenderingImage->size().width();
1146 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
1147
1148 // size must be in pixels, not layout units
1149 mPlot->setSize( mCacheRenderingImage->size() );
1150
1151 QgsPlotRenderContext plotContext;
1152 mPlot->render( rc, plotContext );
1153
1154 mPlot->setRenderer( nullptr );
1155
1156 mPainter->end();
1157 mRenderJob.reset( nullptr );
1158 mPainter.reset( nullptr );
1159 mCacheFinalImage = std::move( mCacheRenderingImage );
1161 update();
1162 emit previewRefreshed();
1163}
1164
1166{
1167 return mDistanceUnit;
1168}
1169
1171{
1172 mDistanceUnit = unit;
1173
1174 switch ( mDistanceUnit )
1175 {
1224 mPlot->xAxis().setLabelSuffix( u" %1"_s.arg( QgsUnitTypes::toAbbreviatedString( mDistanceUnit ) ) );
1225 break;
1226
1228 mPlot->xAxis().setLabelSuffix( QObject::tr( "°" ) );
1229 break;
1230
1232 mPlot->xAxis().setLabelSuffix( QString() );
1233 break;
1234 }
1235}
1236
1238{
1239 mSubsectionsSymbol.reset( symbol );
1240}
1241
1242void QgsLayoutItemElevationProfile::setSourcesPrivate()
1243{
1244 mSources.clear();
1245 mSources.reserve( QgsApplication::profileSourceRegistry()->profileSources().count() );
1246 for ( QgsAbstractProfileSource *source : QgsApplication::profileSourceRegistry()->profileSources() )
1247 mSources << source;
1248}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2779
@ Inches
Inches.
Definition qgis.h:5329
DistanceUnit
Units of distance.
Definition qgis.h:5135
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated).
Definition qgis.h:5175
@ Feet
Imperial feet.
Definition qgis.h:5138
@ MilesUSSurvey
US Survey miles.
Definition qgis.h:5182
@ LinksBritishSears1922
British links (Sears 1922).
Definition qgis.h:5170
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A).
Definition qgis.h:5173
@ LinksBritishBenoit1895A
British links (Benoit 1895 A).
Definition qgis.h:5167
@ Centimeters
Centimeters.
Definition qgis.h:5143
@ YardsIndian1975
Indian yards (1975).
Definition qgis.h:5181
@ FeetUSSurvey
US Survey feet.
Definition qgis.h:5165
@ Millimeters
Millimeters.
Definition qgis.h:5144
@ FeetBritishSears1922
British feet (Sears 1922).
Definition qgis.h:5158
@ YardsClarkes
Clarke's yards.
Definition qgis.h:5177
@ YardsIndian
Indian yards.
Definition qgis.h:5178
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B).
Definition qgis.h:5156
@ Miles
Terrestrial miles.
Definition qgis.h:5141
@ LinksUSSurvey
US Survey links.
Definition qgis.h:5172
@ Meters
Meters.
Definition qgis.h:5136
@ ChainsUSSurvey
US Survey chains.
Definition qgis.h:5152
@ FeetClarkes
Clarke's feet.
Definition qgis.h:5159
@ Unknown
Unknown distance unit.
Definition qgis.h:5185
@ Yards
Imperial yards.
Definition qgis.h:5140
@ FeetBritish1936
British feet (1936).
Definition qgis.h:5154
@ FeetIndian1962
Indian feet (1962).
Definition qgis.h:5163
@ YardsBritishSears1922
British yards (Sears 1922).
Definition qgis.h:5176
@ FeetIndian1937
Indian feet (1937).
Definition qgis.h:5162
@ YardsIndian1937
Indian yards (1937).
Definition qgis.h:5179
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5142
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B).
Definition qgis.h:5148
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated).
Definition qgis.h:5169
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A).
Definition qgis.h:5147
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B).
Definition qgis.h:5174
@ FeetBritish1865
British feet (1865).
Definition qgis.h:5153
@ YardsIndian1962
Indian yards (1962).
Definition qgis.h:5180
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated).
Definition qgis.h:5157
@ MetersGermanLegal
German legal meter.
Definition qgis.h:5184
@ LinksBritishBenoit1895B
British links (Benoit 1895 B).
Definition qgis.h:5168
@ ChainsInternational
International chains.
Definition qgis.h:5146
@ Inches
Inches.
Definition qgis.h:5145
@ Fathoms
Fathoms.
Definition qgis.h:5183
@ LinksInternational
International links.
Definition qgis.h:5166
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated).
Definition qgis.h:5149
@ FeetIndian
Indian (geodetic) feet.
Definition qgis.h:5161
@ NauticalMiles
Nautical miles.
Definition qgis.h:5139
@ ChainsClarkes
Clarke's chains.
Definition qgis.h:5151
@ LinksClarkes
Clarke's links.
Definition qgis.h:5171
@ ChainsBritishSears1922
British chains (Sears 1922).
Definition qgis.h:5150
@ Kilometers
Kilometers.
Definition qgis.h:5137
@ FeetIndian1975
Indian feet (1975).
Definition qgis.h:5164
@ FeetGoldCoast
Gold Coast feet.
Definition qgis.h:5160
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A).
Definition qgis.h:5155
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
Definition qgis.h:5369
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:661
double yMaximum() const
Returns the maximum value of the y axis.
Definition qgsplot.h:744
double xMinimum() const
Returns the minimum value of the x axis.
Definition qgsplot.h:702
double yMinimum() const
Returns the minimum value of the y axis.
Definition qgsplot.h:716
double xMaximum() const
Returns the maximum value of the x axis.
Definition qgsplot.h:730
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
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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.
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:113
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:7160
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7141
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6950
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.