QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 QgsLayoutItemElevationProfilePlot() {}
54
55 void setRenderer( QgsProfilePlotRenderer *renderer )
56 {
57 // cppcheck-suppress danglingLifetime
58 mRenderer = renderer;
59 }
60
61 void renderContent( QgsRenderContext &rc, QgsPlotRenderContext &, const QRectF &plotArea, const QgsPlotData & ) override
62 {
63 if ( mRenderer )
64 {
65 const double distanceMin = xMinimum() * xScale;
66 const double distanceMax = xMaximum() * xScale;
67 rc.painter()->translate( plotArea.left(), plotArea.top() );
68 mRenderer->render( rc, plotArea.width(), plotArea.height(), distanceMin, distanceMax, yMinimum(), yMaximum() );
69 rc.painter()->translate( -plotArea.left(), -plotArea.top() );
70 mRenderer->renderSubsectionsIndicator( rc, plotArea, distanceMin, distanceMax, yMinimum(), yMaximum() );
71 }
72 }
73
74 double xScale = 1;
75
76 private:
77 QgsProfilePlotRenderer *mRenderer = nullptr;
78};
80
83 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
84{
85 mBackgroundUpdateTimer = new QTimer( this );
86 mBackgroundUpdateTimer->setSingleShot( true );
87 connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
88
89 setCacheMode( QGraphicsItem::NoCache );
90
91 if ( mLayout )
92 {
94 }
95
96 connect( this, &QgsLayoutItem::sizePositionChanged, this, [this] { invalidateCache(); } );
97
98 //default to no background
99 setBackgroundEnabled( false );
100
101 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceRegistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
102 connect( QgsApplication::profileSourceRegistry(), &QgsProfileSourceRegistry::profileSourceUnregistered, this, &QgsLayoutItemElevationProfile::setSourcesPrivate );
103
104 setSourcesPrivate(); // Initialize with registered sources
105}
106
108{
109 if ( mRenderJob )
110 {
111 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
113 mRenderJob->cancelGeneration(); // blocks
114 mPainter->end();
115 }
116}
117
122
127
129{
130 return QgsApplication::getThemeIcon( u"mLayoutItemElevationProfile.svg"_s );
131}
132
134{
136
137 bool forceUpdate = false;
138
141 {
142 double value = mTolerance;
143
144 bool ok = false;
146
147 if ( !ok )
148 {
149 QgsMessageLog::logMessage( tr( "Elevation profile tolerance expression eval error" ) );
150 }
151 else
152 {
153 mTolerance = value;
154 }
155
156 forceUpdate = true;
157 }
158
161 {
162 double value = mPlot->xMinimum();
163
164 bool ok = false;
166
167 if ( !ok )
168 {
169 QgsMessageLog::logMessage( tr( "Elevation profile minimum distance expression eval error" ) );
170 }
171 else
172 {
173 mPlot->setXMinimum( value );
174 }
175
176 forceUpdate = true;
177 }
178
181 {
182 double value = mPlot->xMaximum();
183
184 bool ok = false;
186
187 if ( !ok )
188 {
189 QgsMessageLog::logMessage( tr( "Elevation profile maximum distance expression eval error" ) );
190 }
191 else
192 {
193 mPlot->setXMaximum( value );
194 }
195
196 forceUpdate = true;
197 }
198
201 {
202 double value = mPlot->yMinimum();
203
204 bool ok = false;
206
207 if ( !ok )
208 {
209 QgsMessageLog::logMessage( tr( "Elevation profile minimum elevation expression eval error" ) );
210 }
211 else
212 {
213 mPlot->setYMinimum( value );
214 }
215
216 forceUpdate = true;
217 }
218
221 {
222 double value = mPlot->yMaximum();
223
224 bool ok = false;
226
227 if ( !ok )
228 {
229 QgsMessageLog::logMessage( tr( "Elevation profile maximum elevation expression eval error" ) );
230 }
231 else
232 {
233 mPlot->setYMaximum( value );
234 }
235
236 forceUpdate = true;
237 }
238
241 {
242 double value = mPlot->xAxis().gridIntervalMajor();
243
244 bool ok = false;
246
247 if ( !ok )
248 {
249 QgsMessageLog::logMessage( tr( "Elevation profile distance axis major interval expression eval error" ) );
250 }
251 else
252 {
253 mPlot->xAxis().setGridIntervalMajor( value );
254 }
255
256 forceUpdate = true;
257 }
258
261 {
262 double value = mPlot->xAxis().gridIntervalMinor();
263
264 bool ok = false;
266
267 if ( !ok )
268 {
269 QgsMessageLog::logMessage( tr( "Elevation profile distance axis minor interval expression eval error" ) );
270 }
271 else
272 {
273 mPlot->xAxis().setGridIntervalMinor( value );
274 }
275
276 forceUpdate = true;
277 }
278
281 {
282 double value = mPlot->xAxis().labelInterval();
283
284 bool ok = false;
286
287 if ( !ok )
288 {
289 QgsMessageLog::logMessage( tr( "Elevation profile distance axis label interval expression eval error" ) );
290 }
291 else
292 {
293 mPlot->xAxis().setLabelInterval( value );
294 }
295
296 forceUpdate = true;
297 }
298
301 {
302 double value = mPlot->yAxis().gridIntervalMajor();
303
304 bool ok = false;
306
307 if ( !ok )
308 {
309 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis major interval expression eval error" ) );
310 }
311 else
312 {
313 mPlot->yAxis().setGridIntervalMajor( value );
314 }
315
316 forceUpdate = true;
317 }
318
321 {
322 double value = mPlot->yAxis().gridIntervalMinor();
323
324 bool ok = false;
326
327 if ( !ok )
328 {
329 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis minor interval expression eval error" ) );
330 }
331 else
332 {
333 mPlot->yAxis().setGridIntervalMinor( value );
334 }
335
336 forceUpdate = true;
337 }
338
341 {
342 double value = mPlot->yAxis().labelInterval();
343
344 bool ok = false;
346
347 if ( !ok )
348 {
349 QgsMessageLog::logMessage( tr( "Elevation profile elevation axis label interval expression eval error" ) );
350 }
351 else
352 {
353 mPlot->yAxis().setLabelInterval( value );
354 }
355
356 forceUpdate = true;
357 }
358
361 {
362 double value = mPlot->margins().left();
363
364 bool ok = false;
365 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginLeft, context, value, &ok );
366
367 if ( !ok )
368 {
369 QgsMessageLog::logMessage( tr( "Elevation profile left margin expression eval error" ) );
370 }
371 else
372 {
373 QgsMargins margins = mPlot->margins();
374 margins.setLeft( value );
375 mPlot->setMargins( margins );
376 }
377
378 forceUpdate = true;
379 }
380
383 {
384 double value = mPlot->margins().right();
385
386 bool ok = false;
387 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginRight, context, value, &ok );
388
389 if ( !ok )
390 {
391 QgsMessageLog::logMessage( tr( "Elevation profile right margin expression eval error" ) );
392 }
393 else
394 {
395 QgsMargins margins = mPlot->margins();
396 margins.setRight( value );
397 mPlot->setMargins( margins );
398 }
399
400 forceUpdate = true;
401 }
402
405 {
406 double value = mPlot->margins().top();
407
408 bool ok = false;
409 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginTop, context, value, &ok );
410
411 if ( !ok )
412 {
413 QgsMessageLog::logMessage( tr( "Elevation profile top margin expression eval error" ) );
414 }
415 else
416 {
417 QgsMargins margins = mPlot->margins();
418 margins.setTop( value );
419 mPlot->setMargins( margins );
420 }
421
422 forceUpdate = true;
423 }
424
427 {
428 double value = mPlot->margins().bottom();
429
430 bool ok = false;
431 value = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::MarginBottom, context, value, &ok );
432
433 if ( !ok )
434 {
435 QgsMessageLog::logMessage( tr( "Elevation profile bottom margin expression eval error" ) );
436 }
437 else
438 {
439 QgsMargins margins = mPlot->margins();
440 margins.setBottom( value );
441 mPlot->setMargins( margins );
442 }
443
444 forceUpdate = true;
445 }
446
447 if ( forceUpdate )
448 {
449 mCacheInvalidated = true;
450
452 update();
453 }
454
456}
457
462
464{
465 return blendMode() != QPainter::CompositionMode_SourceOver;
466}
467
469{
470 return mEvaluatedOpacity < 1.0;
471}
472
474{
475 return mPlot.get();
476}
477
479{
480 return mPlot.get();
481}
482
483QList<QgsMapLayer *> QgsLayoutItemElevationProfile::layers() const
484{
485 return _qgis_listRefToRaw( mLayers );
486}
487
488void QgsLayoutItemElevationProfile::setLayers( const QList<QgsMapLayer *> &layers )
489{
490 if ( layers == _qgis_listRefToRaw( mLayers ) )
491 return;
492
493 mLayers = _qgis_listRawToRef( layers );
495}
496
497QList<QgsAbstractProfileSource *> QgsLayoutItemElevationProfile::sources() const
498{
499 if ( mSources.isEmpty() && !mLayers.isEmpty() )
500 {
501 // Legacy: If we have layers, extract their sources and return them.
502 // We don't set mSources here, because we want the previous check to
503 // continue failing if only layers are set.
504 // TODO: Remove this if block in QGIS 5.0 along with setLayers/layers methods.
505 QList< QgsAbstractProfileSource * > sources;
506 const QList<QgsMapLayer *> layersToGenerate = layers();
507 sources.reserve( layersToGenerate.size() );
508
509 for ( QgsMapLayer *layer : layersToGenerate )
510 {
511 if ( QgsAbstractProfileSource *source = layer->profileSource() )
512 sources << source;
513 }
514
515 // More legacy: elevation profile layers are in opposite direction
516 // to what the layer tree requires, and are in the same direction as
517 // the renderer expects, but since we reverse sources() (i.e., layers)
518 // before passing them to the renderer, then we need to reverse here first.
519 std::reverse( sources.begin(), sources.end() );
520
521 return sources;
522 }
523
524 QList< QgsAbstractProfileSource * > sources;
525 sources.reserve( mSources.count() );
526 for ( const auto &source : mSources )
527 {
528 if ( const QgsMapLayerRef *layerRef = std::get_if< QgsMapLayerRef >( &source ) )
529 {
530 if ( QgsMapLayer *layer = layerRef->get() )
531 {
532 sources << layer->profileSource();
533 }
534 }
535 else if ( auto profileSource = std::get_if< QgsAbstractProfileSource * >( &source ) )
536 {
537 if ( QgsApplication::profileSourceRegistry()->findSourceById( ( *profileSource )->profileSourceId() ) )
538 {
539 sources << *profileSource;
540 }
541 }
542 }
543
544 return sources;
545}
546
547void QgsLayoutItemElevationProfile::setSources( const QList<QgsAbstractProfileSource *> &sources )
548{
549 mSources.clear();
550 mSources.reserve( sources.count() );
551 for ( QgsAbstractProfileSource *profileSource : sources )
552 {
553 if ( auto layer = dynamic_cast<QgsMapLayer *>( profileSource ) )
554 {
555 mSources << QgsMapLayerRef( layer );
556 }
557 else if ( QgsApplication::profileSourceRegistry()->findSourceById( profileSource->profileSourceId() ) )
558 {
559 mSources << profileSource;
560 }
561 }
562
564}
565
567{
568 mCurve.reset( curve );
570}
571
573{
574 return mCurve.get();
575}
576
578{
579 if ( mCrs == crs )
580 return;
581
582 mCrs = crs;
584}
585
590
592{
593 if ( mTolerance == tolerance )
594 return;
595
596 mTolerance = tolerance;
598}
599
601{
602 return mTolerance;
603}
604
606{
607 mAtlasDriven = enabled;
608}
609
611{
612 QgsProfileRequest req( mCurve ? mCurve.get()->clone() : nullptr );
613
614 req.setCrs( mCrs );
615 req.setTolerance( mTolerance );
617 if ( mLayout )
618 {
619 if ( QgsProject *project = mLayout->project() )
620 {
621 req.setTransformContext( project->transformContext() );
622 if ( QgsAbstractTerrainProvider *provider = project->elevationProperties()->terrainProvider() )
623 {
624 req.setTerrainProvider( provider->clone() );
625 }
626 }
627 }
628 return req;
629}
630
631void QgsLayoutItemElevationProfile::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
632{
633 if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
634 {
635 return;
636 }
637 if ( !shouldDrawItem() )
638 {
639 return;
640 }
641
642 QRectF thisPaintRect = rect();
643 if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
644 return;
645
646 if ( mLayout->renderContext().isPreviewRender() )
647 {
650
651 QgsScopedQPainterState painterState( painter );
652 painter->setClipRect( thisPaintRect );
653 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
654 {
655 // No initial render available - so draw some preview text alerting user
656 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
657 painter->drawRect( thisPaintRect );
658 painter->setBrush( Qt::NoBrush );
659 QFont messageFont;
660 messageFont.setPointSize( 12 );
661 painter->setFont( messageFont );
662 painter->setPen( QColor( 255, 255, 255, 255 ) );
663 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering profile" ) );
664
665 if (
666 ( mRenderJob && mCacheInvalidated && !mDrawingPreview ) // current job was invalidated - start a new one
667 || ( !mRenderJob && !mDrawingPreview ) // this is the profiles's very first paint - trigger a cache update
668 )
669 {
670 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
671 mBackgroundUpdateTimer->start( 1 );
672 }
673 }
674 else
675 {
676 if ( mCacheInvalidated && !mDrawingPreview )
677 {
678 // cache was invalidated - trigger a background update
679 mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
680 mBackgroundUpdateTimer->start( 1 );
681 }
682
683 //Background color is already included in cached image, so no need to draw
684
685 double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
686 double scale = rect().width() / imagePixelWidth;
687
688 QgsScopedQPainterState rotatedPainterState( painter );
689
690 painter->scale( scale, scale );
691 painter->setCompositionMode( blendModeForRender() );
692 painter->drawImage( 0, 0, *mCacheFinalImage );
693 }
694
695 painter->setClipRect( thisPaintRect, Qt::NoClip );
696
697 if ( frameEnabled() )
698 {
700 }
701 }
702 else
703 {
704 if ( mDrawing )
705 return;
706
707 mDrawing = true;
708 QPaintDevice *paintDevice = painter->device();
709 if ( !paintDevice )
710 return;
711
712 QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
713
714 if ( mLayout->renderContext().flags() & Qgis::LayoutRenderFlag::LosslessImageRendering )
715 painter->setRenderHint( QPainter::LosslessImageRendering, true );
716
717 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
718
719 if ( !qgsDoubleNear( layoutSize.width(), 0.0 ) && !qgsDoubleNear( layoutSize.height(), 0.0 ) )
720 {
721 const bool forceVector = mLayout && mLayout->renderContext().rasterizedRenderingPolicy() == Qgis::RasterizedRenderingPolicy::ForceVector;
722 if ( ( containsAdvancedEffects() || ( blendModeForRender() != QPainter::CompositionMode_SourceOver ) ) && !forceVector )
723 {
724 // rasterize
725 double destinationDpi = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter ) * 25.4;
726 double layoutUnitsInInches = mLayout ? mLayout->convertFromLayoutUnits( 1, Qgis::LayoutUnit::Inches ).length() : 1;
727 int widthInPixels = static_cast< int >( std::round( boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
728 int heightInPixels = static_cast< int >( std::round( boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
729 QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
730
731 image.fill( Qt::transparent );
732 image.setDotsPerMeterX( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
733 image.setDotsPerMeterY( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
734 double dotsPerMM = destinationDpi / 25.4;
735 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
736 QPainter p( &image );
737 preparePainter( &p );
738
741
742 p.scale( dotsPerMM, dotsPerMM );
743 if ( hasBackground() )
744 {
746 }
747
748 p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
749
750 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
751 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
752
753 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
754 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
755
756 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
757 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
758 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
759
760 renderer.generateSynchronously();
761 mPlot->setRenderer( &renderer );
762
763 // size must be in pixels, not layout units
764 mPlot->setSize( layoutSize );
765
766 QgsPlotRenderContext plotContext;
767 mPlot->render( rc, plotContext );
768
769 mPlot->setRenderer( nullptr );
770
771 p.scale( dotsPerMM, dotsPerMM );
772
773 if ( frameEnabled() )
774 {
776 }
777
778 QgsScopedQPainterState painterState( painter );
779 painter->setCompositionMode( blendModeForRender() );
780 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
781 painter->drawImage( 0, 0, image );
782 painter->scale( dotsPerMM, dotsPerMM );
783 }
784 else
785 {
788
789 // Fill with background color
790 if ( hasBackground() )
791 {
793 }
794
795 QgsScopedQPainterState painterState( painter );
796 QgsScopedQPainterState stagedPainterState( painter );
797 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
798 layoutSize *= dotsPerMM; // output size will be in dots (pixels)
799 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
800
801 const double mapUnitsPerPixel = static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / layoutSize.width();
802 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
803
804 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
805 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
806
807 QgsProfilePlotRenderer renderer( sourcesToRender, profileRequest() );
808 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
809 renderer.setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
810
811 // TODO
812 // we should be able to call renderer.start()/renderer.waitForFinished() here and
813 // benefit from parallel source generation. BUT
814 // for some reason the QtConcurrent::map call in start() never triggers
815 // the actual background thread execution.
816 // So for now just generate the results one by one
817 renderer.generateSynchronously();
818 mPlot->setRenderer( &renderer );
819
820 // size must be in pixels, not layout units
821 mPlot->setSize( layoutSize );
822
823 QgsPlotRenderContext plotContext;
824 mPlot->render( rc, plotContext );
825
826 mPlot->setRenderer( nullptr );
827
828 painter->setClipRect( thisPaintRect, Qt::NoClip );
829
830 if ( frameEnabled() )
831 {
833 }
834 }
835 }
836
837 mDrawing = false;
838 }
839}
840
842{
843 if ( mAtlasDriven && mLayout && mLayout->reportContext().layer() )
844 {
845 if ( QgsVectorLayer *layer = mLayout->reportContext().layer() )
846 {
847 mCrs = layer->crs();
848 }
849 const QgsGeometry curveGeom( mLayout->reportContext().currentGeometry( mCrs ) );
850 if ( const QgsAbstractGeometry *geom = curveGeom.constGet() )
851 {
852 if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
853 {
854 mCurve.reset( curve->clone() );
855 }
856 }
857 }
860}
861
863{
864 if ( mDrawing )
865 return;
866
867 mCacheInvalidated = true;
868 update();
869}
870
873
874bool QgsLayoutItemElevationProfile::writePropertiesToElement( QDomElement &layoutProfileElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
875{
876 {
877 QDomElement plotElement = doc.createElement( u"plot"_s );
878 mPlot->writeXml( plotElement, doc, rwContext );
879 layoutProfileElem.appendChild( plotElement );
880 }
881
882 layoutProfileElem.setAttribute( u"distanceUnit"_s, qgsEnumValueToKey( mDistanceUnit ) );
883
884 layoutProfileElem.setAttribute( u"tolerance"_s, mTolerance );
885 layoutProfileElem.setAttribute( u"atlasDriven"_s, mAtlasDriven ? u"1"_s : u"0"_s );
886 if ( mCrs.isValid() )
887 {
888 QDomElement crsElem = doc.createElement( u"crs"_s );
889 mCrs.writeXml( crsElem, doc );
890 layoutProfileElem.appendChild( crsElem );
891 }
892 if ( mCurve )
893 {
894 QDomElement curveElem = doc.createElement( u"curve"_s );
895 curveElem.appendChild( doc.createTextNode( mCurve->asWkt() ) );
896 layoutProfileElem.appendChild( curveElem );
897 }
898
899 {
900 QDomElement layersElement = doc.createElement( u"layers"_s );
901 for ( const QgsMapLayerRef &layer : mLayers )
902 {
903 QDomElement layerElement = doc.createElement( u"layer"_s );
904 layer.writeXml( layerElement, rwContext );
905 layersElement.appendChild( layerElement );
906 }
907 layoutProfileElem.appendChild( layersElement );
908 }
909
910 {
911 QDomElement sourcesElement = doc.createElement( u"profileSources"_s );
912 for ( const auto &source : mSources )
913 {
914 if ( const QgsMapLayerRef *layerRef = std::get_if< QgsMapLayerRef >( &source ) )
915 {
916 if ( layerRef->get() )
917 {
918 QDomElement sourceElement = doc.createElement( u"profileLayerSource"_s );
919 layerRef->writeXml( sourceElement, rwContext );
920 sourcesElement.appendChild( sourceElement );
921 }
922 }
923 else if ( auto profileSource = std::get_if< QgsAbstractProfileSource * >( &source ) )
924 {
925 if ( QgsApplication::profileSourceRegistry()->findSourceById( ( *profileSource )->profileSourceId() ) )
926 {
927 QDomElement sourceElement = doc.createElement( u"profileCustomSource"_s );
928 sourceElement.setAttribute( u"id"_s, ( *profileSource )->profileSourceId() );
929 sourcesElement.appendChild( sourceElement );
930 }
931 }
932 }
933
934 layoutProfileElem.appendChild( sourcesElement );
935 }
936
937 if ( mSubsectionsSymbol )
938 {
939 QDomElement subsectionsElement = doc.createElement( u"subsections"_s );
940 const QDomElement symbolElement = QgsSymbolLayerUtils::saveSymbol( u"subsections"_s, mSubsectionsSymbol.get(), doc, rwContext );
941 subsectionsElement.appendChild( symbolElement );
942 layoutProfileElem.appendChild( subsectionsElement );
943 }
944
945 return true;
946}
947
948bool QgsLayoutItemElevationProfile::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
949{
950 const QDomElement plotElement = itemElem.firstChildElement( u"plot"_s );
951 if ( !plotElement.isNull() )
952 {
953 mPlot->readXml( plotElement, context );
954 }
955
956 const QDomNodeList crsNodeList = itemElem.elementsByTagName( u"crs"_s );
958 if ( !crsNodeList.isEmpty() )
959 {
960 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
961 crs.readXml( crsElem );
962 }
963 mCrs = crs;
964
965 setDistanceUnit( qgsEnumKeyToValue( itemElem.attribute( u"distanceUnit"_s ), mCrs.mapUnits() ) );
966
967 const QDomNodeList curveNodeList = itemElem.elementsByTagName( u"curve"_s );
968 if ( !curveNodeList.isEmpty() )
969 {
970 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
971 const QgsGeometry curve = QgsGeometry::fromWkt( curveElem.text() );
972 if ( const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.constGet() ) )
973 {
974 mCurve.reset( curveGeom->clone() );
975 }
976 else
977 {
978 mCurve.reset();
979 }
980 }
981
982 mTolerance = itemElem.attribute( u"tolerance"_s ).toDouble();
983 mAtlasDriven = static_cast< bool >( itemElem.attribute( u"atlasDriven"_s, u"0"_s ).toInt() );
984
985 {
986 mLayers.clear();
987 const QDomElement layersElement = itemElem.firstChildElement( u"layers"_s );
988 QDomElement layerElement = layersElement.firstChildElement( u"layer"_s );
989 while ( !layerElement.isNull() )
990 {
991 QgsMapLayerRef ref;
992 ref.readXml( layerElement, context );
993 ref.resolveWeakly( mLayout->project() );
994 mLayers.append( ref );
995
996 layerElement = layerElement.nextSiblingElement( u"layer"_s );
997 }
998 }
999
1000 {
1001 mSources.clear();
1002 mSources.reserve( itemElem.elementsByTagName( u"profileSources"_s ).count() );
1003 const QDomElement sourcesElement = itemElem.firstChildElement( u"profileSources"_s );
1004 QDomElement sourceElement = sourcesElement.firstChildElement();
1005 while ( !sourceElement.isNull() )
1006 {
1007 if ( sourceElement.tagName() == "profileCustomSource"_L1 )
1008 {
1009 const QString sourceId = sourceElement.attribute( u"id"_s );
1010 if ( QgsAbstractProfileSource *profileSource = QgsApplication::profileSourceRegistry()->findSourceById( sourceId ) )
1011 {
1012 mSources << profileSource;
1013 }
1014 }
1015 else if ( sourceElement.tagName() == "profileLayerSource"_L1 )
1016 {
1017 QgsMapLayerRef ref;
1018 ref.readXml( sourceElement, context );
1019 ref.resolveWeakly( mLayout->project() );
1020 if ( ref.get() )
1021 {
1022 mSources << ref;
1023 }
1024 }
1025
1026 sourceElement = sourceElement.nextSiblingElement();
1027 }
1028 }
1029
1030 const QDomElement subsectionsElement = itemElem.firstChildElement( u"subsections"_s );
1031 const QDomElement symbolsElement = subsectionsElement.firstChildElement( u"symbol"_s );
1032 if ( !symbolsElement.isNull() )
1033 {
1034 std::unique_ptr< QgsLineSymbol > subSectionsSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol >( symbolsElement, context );
1035 if ( subSectionsSymbol )
1036 {
1037 setSubsectionsSymbol( subSectionsSymbol.release() );
1038 }
1039 }
1040
1041 return true;
1042}
1043
1044void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
1045{
1046 if ( mRenderJob )
1047 {
1048 disconnect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1049 QgsProfilePlotRenderer *oldJob = mRenderJob.release();
1050 QPainter *oldPainter = mPainter.release();
1051 QImage *oldImage = mCacheRenderingImage.release();
1052 connect( oldJob, &QgsProfilePlotRenderer::generationFinished, this, [oldPainter, oldJob, oldImage] {
1053 oldJob->deleteLater();
1054 delete oldPainter;
1055 delete oldImage;
1056 } );
1058 }
1059 else
1060 {
1061 mCacheRenderingImage.reset( nullptr );
1063 }
1064
1065 Q_ASSERT( !mRenderJob );
1066 Q_ASSERT( !mPainter );
1067 Q_ASSERT( !mCacheRenderingImage );
1068
1069 const QSizeF layoutSize = mLayout->convertToLayoutUnits( sizeWithUnits() );
1070 double widthLayoutUnits = layoutSize.width();
1071 double heightLayoutUnits = layoutSize.height();
1072
1073 int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1074 int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1075
1076 // limit size of image for better performance
1077 if ( w > 5000 || h > 5000 )
1078 {
1079 if ( w > h )
1080 {
1081 w = 5000;
1082 h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1083 }
1084 else
1085 {
1086 h = 5000;
1087 w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1088 }
1089 }
1090
1091 if ( w <= 0 || h <= 0 )
1092 return;
1093
1094 mCacheRenderingImage = std::make_unique<QImage>( w, h, QImage::Format_ARGB32 );
1095
1096 // set DPI of the image
1097 mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1098 mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1099
1100 //start with empty fill to avoid artifacts
1101 mCacheRenderingImage->fill( Qt::transparent );
1102 if ( hasBackground() )
1103 {
1104 //Initially fill image with specified background color
1105 mCacheRenderingImage->fill( backgroundColor().rgba() );
1106 }
1107
1108 mCacheInvalidated = false;
1109 mPainter = std::make_unique<QPainter>( mCacheRenderingImage.get() );
1110
1111 QList< QgsAbstractProfileSource *> sourcesToRender = sources();
1112 std::reverse( sourcesToRender.begin(), sourcesToRender.end() ); // sources are rendered from bottom to top
1113
1114 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sourcesToRender, profileRequest() );
1115 std::unique_ptr<QgsLineSymbol> rendererSubSectionsSymbol( subsectionsSymbol() ? subsectionsSymbol()->clone() : nullptr );
1116 mRenderJob->setSubsectionsSymbol( rendererSubSectionsSymbol.release() );
1117 connect( mRenderJob.get(), &QgsProfilePlotRenderer::generationFinished, this, &QgsLayoutItemElevationProfile::profileGenerationFinished );
1118 mRenderJob->startGeneration();
1119
1120 mDrawingPreview = false;
1121}
1122
1123void QgsLayoutItemElevationProfile::profileGenerationFinished()
1124{
1125 mPlot->setRenderer( mRenderJob.get() );
1126
1127 QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( mLayout, mPainter.get() );
1128
1129 mPlot->xScale = QgsUnitTypes::fromUnitToUnitFactor( mDistanceUnit, mCrs.mapUnits() );
1130
1131 const double mapUnitsPerPixel = static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) * mPlot->xScale / mCacheRenderingImage->size().width();
1132 rc.setMapToPixel( QgsMapToPixel( mapUnitsPerPixel ) );
1133
1134 // size must be in pixels, not layout units
1135 mPlot->setSize( mCacheRenderingImage->size() );
1136
1137 QgsPlotRenderContext plotContext;
1138 mPlot->render( rc, plotContext );
1139
1140 mPlot->setRenderer( nullptr );
1141
1142 mPainter->end();
1143 mRenderJob.reset( nullptr );
1144 mPainter.reset( nullptr );
1145 mCacheFinalImage = std::move( mCacheRenderingImage );
1147 update();
1148 emit previewRefreshed();
1149}
1150
1152{
1153 return mDistanceUnit;
1154}
1155
1157{
1158 mDistanceUnit = unit;
1159
1160 switch ( mDistanceUnit )
1161 {
1210 mPlot->xAxis().setLabelSuffix( u" %1"_s.arg( QgsUnitTypes::toAbbreviatedString( mDistanceUnit ) ) );
1211 break;
1212
1214 mPlot->xAxis().setLabelSuffix( QObject::tr( "°" ) );
1215 break;
1216
1218 mPlot->xAxis().setLabelSuffix( QString() );
1219 break;
1220 }
1221}
1222
1224{
1225 mSubsectionsSymbol.reset( symbol );
1226}
1227
1228void QgsLayoutItemElevationProfile::setSourcesPrivate()
1229{
1230 mSources.clear();
1231 mSources.reserve( QgsApplication::profileSourceRegistry()->profileSources().count() );
1232 for ( QgsAbstractProfileSource *source : QgsApplication::profileSourceRegistry()->profileSources() )
1233 mSources << source;
1234}
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2801
@ Inches
Inches.
Definition qgis.h:5364
DistanceUnit
Units of distance.
Definition qgis.h:5170
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated).
Definition qgis.h:5210
@ Feet
Imperial feet.
Definition qgis.h:5173
@ MilesUSSurvey
US Survey miles.
Definition qgis.h:5217
@ LinksBritishSears1922
British links (Sears 1922).
Definition qgis.h:5205
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A).
Definition qgis.h:5208
@ LinksBritishBenoit1895A
British links (Benoit 1895 A).
Definition qgis.h:5202
@ Centimeters
Centimeters.
Definition qgis.h:5178
@ YardsIndian1975
Indian yards (1975).
Definition qgis.h:5216
@ FeetUSSurvey
US Survey feet.
Definition qgis.h:5200
@ Millimeters
Millimeters.
Definition qgis.h:5179
@ FeetBritishSears1922
British feet (Sears 1922).
Definition qgis.h:5193
@ YardsClarkes
Clarke's yards.
Definition qgis.h:5212
@ YardsIndian
Indian yards.
Definition qgis.h:5213
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B).
Definition qgis.h:5191
@ Miles
Terrestrial miles.
Definition qgis.h:5176
@ LinksUSSurvey
US Survey links.
Definition qgis.h:5207
@ Meters
Meters.
Definition qgis.h:5171
@ ChainsUSSurvey
US Survey chains.
Definition qgis.h:5187
@ FeetClarkes
Clarke's feet.
Definition qgis.h:5194
@ Unknown
Unknown distance unit.
Definition qgis.h:5220
@ Yards
Imperial yards.
Definition qgis.h:5175
@ FeetBritish1936
British feet (1936).
Definition qgis.h:5189
@ FeetIndian1962
Indian feet (1962).
Definition qgis.h:5198
@ YardsBritishSears1922
British yards (Sears 1922).
Definition qgis.h:5211
@ FeetIndian1937
Indian feet (1937).
Definition qgis.h:5197
@ YardsIndian1937
Indian yards (1937).
Definition qgis.h:5214
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5177
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B).
Definition qgis.h:5183
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated).
Definition qgis.h:5204
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A).
Definition qgis.h:5182
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B).
Definition qgis.h:5209
@ FeetBritish1865
British feet (1865).
Definition qgis.h:5188
@ YardsIndian1962
Indian yards (1962).
Definition qgis.h:5215
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated).
Definition qgis.h:5192
@ MetersGermanLegal
German legal meter.
Definition qgis.h:5219
@ LinksBritishBenoit1895B
British links (Benoit 1895 B).
Definition qgis.h:5203
@ ChainsInternational
International chains.
Definition qgis.h:5181
@ Inches
Inches.
Definition qgis.h:5180
@ Fathoms
Fathoms.
Definition qgis.h:5218
@ LinksInternational
International links.
Definition qgis.h:5201
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated).
Definition qgis.h:5184
@ FeetIndian
Indian (geodetic) feet.
Definition qgis.h:5196
@ NauticalMiles
Nautical miles.
Definition qgis.h:5174
@ ChainsClarkes
Clarke's chains.
Definition qgis.h:5186
@ LinksClarkes
Clarke's links.
Definition qgis.h:5206
@ ChainsBritishSears1922
British chains (Sears 1922).
Definition qgis.h:5185
@ Kilometers
Kilometers.
Definition qgis.h:5172
@ FeetIndian1975
Indian feet (1975).
Definition qgis.h:5199
@ FeetGoldCoast
Gold Coast feet.
Definition qgis.h:5195
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A).
Definition qgis.h:5190
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
Definition qgis.h:5407
virtual void renderContent(QgsRenderContext &context, QgsPlotRenderContext &plotContext, const QRectF &plotArea, const QgsPlotData &plotData=QgsPlotData())
Renders the plot content.
Definition qgsplot.cpp:310
Base class for 2-dimensional plot/chart/graphs with an X and Y axes.
Definition qgsplot.h:687
double yMaximum() const
Returns the maximum value of the y axis.
Definition qgsplot.h:769
double xMinimum() const
Returns the minimum value of the x axis.
Definition qgsplot.h:727
double yMinimum() const
Returns the minimum value of the y axis.
Definition qgsplot.h:741
double xMaximum() const
Returns the maximum value of the x axis.
Definition qgsplot.h:755
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:112
void setLeft(double left)
Sets the left margin to left.
Definition qgsmargins.h:94
void setRight(double right)
Sets the right margin to right.
Definition qgsmargins.h:106
void setTop(double top)
Sets the top margin to top.
Definition qgsmargins.h:100
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:303
Contains information about the context of a plot rendering operation.
Definition qgsplot.h:191
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:7176
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7157
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
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.