36#define CACHE_SIZE_LIMIT 5000
39class QgsLayoutItemElevationProfilePlot :
public Qgs2DPlot
43 QgsLayoutItemElevationProfilePlot()
57 rc.
painter()->translate( plotArea.left(), plotArea.top() );
59 rc.
painter()->translate( -plotArea.left(), -plotArea.top() );
72 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
74 mBackgroundUpdateTimer =
new QTimer(
this );
75 mBackgroundUpdateTimer->setSingleShot(
true );
76 connect( mBackgroundUpdateTimer, &QTimer::timeout,
this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
78 setCacheMode( QGraphicsItem::NoCache );
100 mRenderJob->cancelGeneration();
124 bool forceUpdate =
false;
129 double value = mTolerance;
149 double value = mPlot->xMinimum();
160 mPlot->setXMinimum( value );
169 double value = mPlot->xMaximum();
180 mPlot->setXMaximum( value );
189 double value = mPlot->yMinimum();
200 mPlot->setYMinimum( value );
209 double value = mPlot->yMaximum();
220 mPlot->setYMaximum( value );
229 double value = mPlot->xAxis().gridIntervalMajor();
240 mPlot->xAxis().setGridIntervalMajor( value );
249 double value = mPlot->xAxis().gridIntervalMinor();
260 mPlot->xAxis().setGridIntervalMinor( value );
269 double value = mPlot->xAxis().labelInterval();
280 mPlot->xAxis().setLabelInterval( value );
289 double value = mPlot->yAxis().gridIntervalMajor();
300 mPlot->yAxis().setGridIntervalMajor( value );
309 double value = mPlot->yAxis().gridIntervalMinor();
320 mPlot->yAxis().setGridIntervalMinor( value );
329 double value = mPlot->yAxis().labelInterval();
340 mPlot->yAxis().setLabelInterval( value );
349 double value = mPlot->margins().left();
362 mPlot->setMargins( margins );
371 double value = mPlot->margins().right();
384 mPlot->setMargins( margins );
393 double value = mPlot->margins().top();
406 mPlot->setMargins( margins );
415 double value = mPlot->margins().bottom();
428 mPlot->setMargins( margins );
436 mCacheInvalidated =
true;
462 return _qgis_listRefToRaw( mLayers );
467 if (
layers == _qgis_listRefToRaw( mLayers ) )
470 mLayers = _qgis_listRawToRef(
layers );
476 mCurve.reset( curve );
515 mAtlasDriven = enabled;
541 if ( !
mLayout || !painter || !painter->device() || !mUpdatesEnabled )
550 QRectF thisPaintRect = rect();
554 if (
mLayout->renderContext().isPreviewRender() )
560 painter->setClipRect( thisPaintRect );
561 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
564 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
565 painter->drawRect( thisPaintRect );
566 painter->setBrush( Qt::NoBrush );
568 messageFont.setPointSize( 12 );
569 painter->setFont( messageFont );
570 painter->setPen( QColor( 255, 255, 255, 255 ) );
571 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Rendering profile" ) );
574 ( mRenderJob && mCacheInvalidated && !mDrawingPreview )
576 ( !mRenderJob && !mDrawingPreview )
581 mBackgroundUpdateTimer->start( 1 );
586 if ( mCacheInvalidated && !mDrawingPreview )
590 mBackgroundUpdateTimer->start( 1 );
595 double imagePixelWidth = mCacheFinalImage->width();
596 double scale = rect().width() / imagePixelWidth;
600 painter->scale( scale, scale );
601 painter->drawImage( 0, 0, *mCacheFinalImage );
604 painter->setClipRect( thisPaintRect, Qt::NoClip );
617 QPaintDevice *paintDevice = painter->device();
624 painter->setRenderHint( QPainter::LosslessImageRendering,
true );
640 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
641 layoutSize *= dotsPerMM;
642 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM );
644 const double mapUnitsPerPixel =
static_cast<double>( mPlot->xMaximum() - mPlot->xMinimum() ) / layoutSize.width();
647 QList< QgsAbstractProfileSource * > sources;
651 sources.append( source );
663 mPlot->setRenderer( &renderer );
666 mPlot->setSize( layoutSize );
670 mPlot->setRenderer(
nullptr );
672 painter->setClipRect( thisPaintRect, Qt::NoClip );
685 if ( mAtlasDriven &&
mLayout &&
mLayout->reportContext().layer() )
694 if (
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
696 mCurve.reset( curve->clone() );
709 mCacheInvalidated =
true;
720 QDomElement plotElement = doc.createElement( QStringLiteral(
"plot" ) );
721 mPlot->writeXml( plotElement, doc, rwContext );
722 layoutProfileElem.appendChild( plotElement );
725 layoutProfileElem.setAttribute( QStringLiteral(
"tolerance" ), mTolerance );
726 layoutProfileElem.setAttribute( QStringLiteral(
"atlasDriven" ), mAtlasDriven ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
729 QDomElement crsElem = doc.createElement( QStringLiteral(
"crs" ) );
731 layoutProfileElem.appendChild( crsElem );
735 QDomElement curveElem = doc.createElement( QStringLiteral(
"curve" ) );
736 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
737 layoutProfileElem.appendChild( curveElem );
741 QDomElement layersElement = doc.createElement( QStringLiteral(
"layers" ) );
744 QDomElement layerElement = doc.createElement( QStringLiteral(
"layer" ) );
745 layer.writeXml( layerElement, rwContext );
746 layersElement.appendChild( layerElement );
748 layoutProfileElem.appendChild( layersElement );
756 const QDomElement plotElement = itemElem.firstChildElement( QStringLiteral(
"plot" ) );
757 if ( !plotElement.isNull() )
759 mPlot->readXml( plotElement, context );
762 const QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral(
"crs" ) );
764 if ( !crsNodeList.isEmpty() )
766 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
771 const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral(
"curve" ) );
772 if ( !curveNodeList.isEmpty() )
774 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
776 if (
const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.
constGet() ) )
778 mCurve.reset( curveGeom->clone() );
786 mTolerance = itemElem.attribute( QStringLiteral(
"tolerance" ) ).toDouble();
787 mAtlasDriven =
static_cast< bool >( itemElem.attribute( QStringLiteral(
"atlasDriven" ), QStringLiteral(
"0" ) ).toInt() );
791 const QDomElement layersElement = itemElem.firstChildElement( QStringLiteral(
"layers" ) );
792 QDomElement layerElement = layersElement.firstChildElement( QStringLiteral(
"layer" ) );
793 while ( !layerElement.isNull() )
796 ref.
readXml( layerElement, context );
798 mLayers.append( ref );
800 layerElement = layerElement.nextSiblingElement( QStringLiteral(
"layer" ) );
807void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
813 QPainter *oldPainter = mPainter.release();
814 QImage *oldImage = mCacheRenderingImage.release();
817 oldJob->deleteLater();
825 mCacheRenderingImage.reset(
nullptr );
829 Q_ASSERT( !mRenderJob );
830 Q_ASSERT( !mPainter );
831 Q_ASSERT( !mCacheRenderingImage );
834 double widthLayoutUnits = layoutSize.width();
835 double heightLayoutUnits = layoutSize.height();
837 int w =
static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
838 int h =
static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
841 if ( w > 5000 || h > 5000 )
846 h =
static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
851 w =
static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
855 if ( w <= 0 || h <= 0 )
858 mCacheRenderingImage.reset(
new QImage( w, h, QImage::Format_ARGB32 ) );
861 mCacheRenderingImage->setDotsPerMeterX(
static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
862 mCacheRenderingImage->setDotsPerMeterY(
static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
865 mCacheRenderingImage->fill( Qt::transparent );
872 mCacheInvalidated =
false;
873 mPainter.reset(
new QPainter( mCacheRenderingImage.get() ) );
875 QList< QgsAbstractProfileSource * > sources;
879 sources.append( source );
882 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sources,
profileRequest() );
884 mRenderJob->startGeneration();
886 mDrawingPreview =
false;
889void QgsLayoutItemElevationProfile::profileGenerationFinished()
891 mPlot->setRenderer( mRenderJob.get() );
895 const double mapUnitsPerPixel =
static_cast< double >( mPlot->xMaximum() - mPlot->xMinimum() ) /
896 mCacheRenderingImage->size().width();
900 mPlot->setSize( mCacheRenderingImage->size() );
904 mPlot->setRenderer(
nullptr );
907 mRenderJob.reset(
nullptr );
908 mPainter.reset(
nullptr );
909 mCacheFinalImage = std::move( mCacheRenderingImage );
Base class for 2-dimensional plot/chart/graphs.
double yMaximum() const
Returns the maximum value of the y axis.
double xMaximum() const
Returns the maximum value of the x axis.
double yMinimum() const
Returns the minimum value of the y axis.
virtual void renderContent(QgsRenderContext &context, const QRectF &plotArea)
Renders the plot content.
Abstract base class for all geometries.
Interface for classes which can generate elevation profiles.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Abstract base class for terrain providers.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Abstract base class for curved geometry type.
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 SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
A layout item subclass for elevation profile plots.
static QgsLayoutItemElevationProfile * create(QgsLayout *layout)
Returns a new elevation profile item for the specified layout.
QgsLayoutItemElevationProfile(QgsLayout *layout)
Constructor for QgsLayoutItemElevationProfile, with the specified parent layout.
~QgsLayoutItemElevationProfile() override
QgsCurve * profileCurve() const
Returns the cross section profile curve, which represents the line along which the profile should be ...
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of map layers participating in the elevation profile.
QList< QgsMapLayer * > layers() const
Returns the list of map layers participating in the elevation profile.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
void invalidateCache() override
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the desired Coordinate Reference System (crs) for the profile.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
QgsLayoutItem::Flags itemFlags() const override
Returns the item's flags, which indicate how the item behaves.
Qgs2DPlot * plot()
Returns a reference to the elevation plot object, which can be used to set plot appearance and proper...
void setTolerance(double tolerance)
Sets the tolerance of the request (in crs() units).
QgsCoordinateReferenceSystem crs() const
Returns the desired Coordinate Reference System for the profile.
void setAtlasDriven(bool enabled)
Sets whether the profile curve will follow the current atlas feature.
double tolerance() const
Returns the tolerance of the request (in crs() units).
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
QIcon icon() const override
Returns the item's icon.
void setProfileCurve(QgsCurve *curve)
Sets the cross section profile curve, which represents the line along which the profile should be gen...
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
QgsProfileRequest profileRequest() const
Returns the profile request used to generate the elevation profile.
int type() const override
@ LayoutElevationProfile
Elevation profile item (since QGIS 3.30)
Contains settings and helpers relating to a render of a QgsLayoutItem.
Base class for graphical items within a QgsLayout.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
void refreshItemSize()
Refreshes an item's size by rechecking it against any possible item fixed or minimum sizes.
QColor backgroundColor() const
Returns the background color for this item.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual void drawBackground(QgsRenderContext &context)
Draws the background for the item.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
@ FlagOverridesPaint
Item overrides the default layout item painting method.
void sizePositionChanged()
Emitted when the item's size or position changes.
bool frameEnabled() const
Returns true if the item includes a frame.
bool hasBackground() const
Returns true if the item has a background.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
void backgroundTaskCountChanged(int count)
Emitted whenever the number of background tasks an item is executing changes.
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
QPointer< QgsLayout > mLayout
DataDefinedProperty
Data defined properties for different item types.
@ ElevationProfileTolerance
Tolerance distance for elevation profiles (since QGIS 3.30)
@ ElevationProfileElevationLabelInterval
Label interval for elevation profile elevation axis (since QGIS 3.30)
@ ElevationProfileDistanceMajorInterval
Major grid line interval for elevation profile distance axis (since QGIS 3.30)
@ MarginTop
Top margin (since QGIS 3.30)
@ ElevationProfileDistanceLabelInterval
Label interval for elevation profile distance axis (since QGIS 3.30)
@ ElevationProfileElevationMinorInterval
Minor grid line interval for elevation profile elevation axis (since QGIS 3.30)
@ AllProperties
All properties for item.
@ MarginLeft
Left margin (since QGIS 3.30)
@ ElevationProfileMaximumDistance
Maximum distance value for elevation profile (since QGIS 3.30)
@ MarginRight
Right margin (since QGIS 3.30)
@ ElevationProfileMinimumElevation
Minimum elevation value for elevation profile (since QGIS 3.30)
@ ElevationProfileElevationMajorInterval
Major grid line interval for elevation profile elevation axis (since QGIS 3.30)
@ ElevationProfileMinimumDistance
Minimum distance value for elevation profile (since QGIS 3.30)
@ MarginBottom
Bottom margin (since QGIS 3.30)
@ ElevationProfileDistanceMinorInterval
Minor grid line interval for elevation profile distance axis (since QGIS 3.30)
@ ElevationProfileMaximumElevation
Maximum elevation value for elevation profile (since QGIS 3.30)
@ FlagLosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static Q_DECL_DEPRECATED double scaleFactorFromItemStyle(const QStyleOptionGraphicsItem *style)
Extracts the scale factor from an item style.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated.
Perform transforms between map coordinates and device coordinates.
The QgsMargins class defines the four margins of a rectangle.
void setBottom(double bottom)
Sets the bottom margin to bottom.
void setLeft(double left)
Sets the left margin to left.
void setRight(double right)
Sets the right margin to right.
void setTop(double top)
Sets the top margin to top.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Generates and renders elevation profile plots.
void cancelGenerationWithoutBlocking()
Triggers cancellation of the generation job without blocking.
void generateSynchronously()
Generate the profile results synchronously in this thread.
void generationFinished()
Emitted when the profile generation is finished (or canceled).
Encapsulates properties and constraints relating to fetching elevation profiles from different source...
QgsProfileRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate expressions.
QgsProfileRequest & setTransformContext(const QgsCoordinateTransformContext &context)
Sets the transform context, for use when transforming coordinates from a source to the request's crs(...
QgsProfileRequest & setTerrainProvider(QgsAbstractTerrainProvider *provider)
Sets the terrain provider.
QgsProfileRequest & setTolerance(double tolerance)
Sets the tolerance of the request (in crs() units).
QgsProfileRequest & setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the desired Coordinate Reference System (crs) for the profile.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
void 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.
Represents a vector layer which manages a vector based data sets.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
const QgsCoordinateReferenceSystem & crs
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the layer's properties from an XML element.