36#define CACHE_SIZE_LIMIT 5000
39class QgsLayoutItemElevationProfilePlot :
public Qgs2DPlot
43 QgsLayoutItemElevationProfilePlot()
56 rc.
painter()->translate( plotArea.left(), plotArea.top() );
58 rc.
painter()->translate( -plotArea.left(), -plotArea.top() );
71 , mPlot( std::make_unique< QgsLayoutItemElevationProfilePlot >() )
73 mBackgroundUpdateTimer =
new QTimer(
this );
74 mBackgroundUpdateTimer->setSingleShot(
true );
75 connect( mBackgroundUpdateTimer, &QTimer::timeout,
this, &QgsLayoutItemElevationProfile::recreateCachedImageInBackground );
77 setCacheMode( QGraphicsItem::NoCache );
99 mRenderJob->cancelGeneration();
123 bool forceUpdate =
false;
128 double value = mTolerance;
148 double value = mPlot->xMinimum();
159 mPlot->setXMinimum( value );
168 double value = mPlot->xMaximum();
179 mPlot->setXMaximum( value );
188 double value = mPlot->yMinimum();
199 mPlot->setYMinimum( value );
208 double value = mPlot->yMaximum();
219 mPlot->setYMaximum( value );
228 double value = mPlot->xAxis().gridIntervalMajor();
239 mPlot->xAxis().setGridIntervalMajor( value );
248 double value = mPlot->xAxis().gridIntervalMinor();
259 mPlot->xAxis().setGridIntervalMinor( value );
268 double value = mPlot->xAxis().labelInterval();
279 mPlot->xAxis().setLabelInterval( value );
288 double value = mPlot->yAxis().gridIntervalMajor();
299 mPlot->yAxis().setGridIntervalMajor( value );
308 double value = mPlot->yAxis().gridIntervalMinor();
319 mPlot->yAxis().setGridIntervalMinor( value );
328 double value = mPlot->yAxis().labelInterval();
339 mPlot->yAxis().setLabelInterval( value );
348 double value = mPlot->margins().left();
361 mPlot->setMargins( margins );
370 double value = mPlot->margins().right();
383 mPlot->setMargins( margins );
392 double value = mPlot->margins().top();
405 mPlot->setMargins( margins );
414 double value = mPlot->margins().bottom();
427 mPlot->setMargins( margins );
435 mCacheInvalidated =
true;
461 return _qgis_listRefToRaw( mLayers );
466 if (
layers == _qgis_listRefToRaw( mLayers ) )
469 mLayers = _qgis_listRawToRef(
layers );
475 mCurve.reset( curve );
514 mAtlasDriven = enabled;
540 if ( !
mLayout || !painter || !painter->device() || !mUpdatesEnabled )
549 QRectF thisPaintRect = rect();
553 if (
mLayout->renderContext().isPreviewRender() )
559 painter->setClipRect( thisPaintRect );
560 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
563 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
564 painter->drawRect( thisPaintRect );
565 painter->setBrush( Qt::NoBrush );
567 messageFont.setPointSize( 12 );
568 painter->setFont( messageFont );
569 painter->setPen( QColor( 255, 255, 255, 255 ) );
570 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Rendering profile" ) );
573 ( mRenderJob && mCacheInvalidated && !mDrawingPreview )
575 ( !mRenderJob && !mDrawingPreview )
580 mBackgroundUpdateTimer->start( 1 );
585 if ( mCacheInvalidated && !mDrawingPreview )
589 mBackgroundUpdateTimer->start( 1 );
594 double imagePixelWidth = mCacheFinalImage->width();
595 double scale = rect().width() / imagePixelWidth;
599 painter->scale( scale, scale );
600 painter->drawImage( 0, 0, *mCacheFinalImage );
603 painter->setClipRect( thisPaintRect, Qt::NoClip );
616 QPaintDevice *paintDevice = painter->device();
623 painter->setRenderHint( QPainter::LosslessImageRendering,
true );
639 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
640 layoutSize *= dotsPerMM;
641 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM );
643 QList< QgsAbstractProfileSource * > sources;
647 sources.append( source );
659 mPlot->setRenderer( &renderer );
662 mPlot->setSize( layoutSize );
666 mPlot->setRenderer(
nullptr );
668 painter->setClipRect( thisPaintRect, Qt::NoClip );
681 if ( mAtlasDriven &&
mLayout &&
mLayout->reportContext().layer() )
690 if (
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom->simplifiedTypeRef() ) )
692 mCurve.reset( curve->clone() );
705 mCacheInvalidated =
true;
716 QDomElement plotElement = doc.createElement( QStringLiteral(
"plot" ) );
717 mPlot->writeXml( plotElement, doc, rwContext );
718 layoutProfileElem.appendChild( plotElement );
721 layoutProfileElem.setAttribute( QStringLiteral(
"tolerance" ), mTolerance );
722 layoutProfileElem.setAttribute( QStringLiteral(
"atlasDriven" ), mAtlasDriven ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
725 QDomElement crsElem = doc.createElement( QStringLiteral(
"crs" ) );
727 layoutProfileElem.appendChild( crsElem );
731 QDomElement curveElem = doc.createElement( QStringLiteral(
"curve" ) );
732 curveElem.appendChild( doc.createTextNode( mCurve->asWkt( ) ) );
733 layoutProfileElem.appendChild( curveElem );
737 QDomElement layersElement = doc.createElement( QStringLiteral(
"layers" ) );
740 QDomElement layerElement = doc.createElement( QStringLiteral(
"layer" ) );
741 layer.writeXml( layerElement, rwContext );
742 layersElement.appendChild( layerElement );
744 layoutProfileElem.appendChild( layersElement );
752 const QDomElement plotElement = itemElem.firstChildElement( QStringLiteral(
"plot" ) );
753 if ( !plotElement.isNull() )
755 mPlot->readXml( plotElement, context );
758 const QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral(
"crs" ) );
760 if ( !crsNodeList.isEmpty() )
762 const QDomElement crsElem = crsNodeList.at( 0 ).toElement();
767 const QDomNodeList curveNodeList = itemElem.elementsByTagName( QStringLiteral(
"curve" ) );
768 if ( !curveNodeList.isEmpty() )
770 const QDomElement curveElem = curveNodeList.at( 0 ).toElement();
772 if (
const QgsCurve *curveGeom = qgsgeometry_cast< const QgsCurve * >( curve.
constGet() ) )
774 mCurve.reset( curveGeom->clone() );
782 mTolerance = itemElem.attribute( QStringLiteral(
"tolerance" ) ).toDouble();
783 mAtlasDriven =
static_cast< bool >( itemElem.attribute( QStringLiteral(
"atlasDriven" ), QStringLiteral(
"0" ) ).toInt() );
787 const QDomElement layersElement = itemElem.firstChildElement( QStringLiteral(
"layers" ) );
788 QDomElement layerElement = layersElement.firstChildElement( QStringLiteral(
"layer" ) );
789 while ( !layerElement.isNull() )
792 ref.
readXml( layerElement, context );
794 mLayers.append( ref );
796 layerElement = layerElement.nextSiblingElement( QStringLiteral(
"layer" ) );
803void QgsLayoutItemElevationProfile::recreateCachedImageInBackground()
809 QPainter *oldPainter = mPainter.release();
810 QImage *oldImage = mCacheRenderingImage.release();
813 oldJob->deleteLater();
821 mCacheRenderingImage.reset(
nullptr );
825 Q_ASSERT( !mRenderJob );
826 Q_ASSERT( !mPainter );
827 Q_ASSERT( !mCacheRenderingImage );
830 double widthLayoutUnits = layoutSize.width();
831 double heightLayoutUnits = layoutSize.height();
833 int w =
static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
834 int h =
static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
837 if ( w > 5000 || h > 5000 )
842 h =
static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
847 w =
static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
851 if ( w <= 0 || h <= 0 )
854 mCacheRenderingImage.reset(
new QImage( w, h, QImage::Format_ARGB32 ) );
857 mCacheRenderingImage->setDotsPerMeterX(
static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
858 mCacheRenderingImage->setDotsPerMeterY(
static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
861 mCacheRenderingImage->fill( Qt::transparent );
868 mCacheInvalidated =
false;
869 mPainter.reset(
new QPainter( mCacheRenderingImage.get() ) );
871 QList< QgsAbstractProfileSource * > sources;
875 sources.append( source );
878 mRenderJob = std::make_unique< QgsProfilePlotRenderer >( sources,
profileRequest() );
880 mRenderJob->startGeneration();
882 mDrawingPreview =
false;
885void QgsLayoutItemElevationProfile::profileGenerationFinished()
887 mPlot->setRenderer( mRenderJob.get() );
892 mPlot->setSize( mCacheRenderingImage->size() );
896 mPlot->setRenderer(
nullptr );
899 mRenderJob.reset(
nullptr );
900 mPainter.reset(
nullptr );
901 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.
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 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.