Skip to content

Commit

Permalink
[api] Add framework for collecting rendered item details during map
Browse files Browse the repository at this point in the history
renderer operations

This follow a similar pattern as how labeling results could be collected
after a map render job, but generalises the API so that it can be
used for storing details of rendered items of any type.

It's currently used for storing details of rendered annotation items,
so that map tools can retrieve details of annotation items visible
in the canvas in an optimised way.
  • Loading branch information
nyalldawson committed Aug 31, 2021
1 parent b09994a commit 660433d
Show file tree
Hide file tree
Showing 25 changed files with 912 additions and 16 deletions.
@@ -0,0 +1,57 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/annotations/qgsrenderedannotationitemdetails.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsRenderedAnnotationItemDetails : QgsRenderedItemDetails
{
%Docstring(signature="appended")
Contains information about a rendered annotation item.

.. versionadded:: 3.22
%End

%TypeHeaderCode
#include "qgsrenderedannotationitemdetails.h"
%End
public:

QgsRenderedAnnotationItemDetails( const QString &layerId, const QString &itemId );
%Docstring
Constructor for QgsRenderedAnnotationItemDetails.
%End

SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsRenderedAnnotationItemDetails: %1 - %2>" ).arg( sipCpp->layerId(), sipCpp->itemId() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End

virtual QgsRenderedAnnotationItemDetails *clone() const /Factory/;


QString layerId() const;
%Docstring
Returns the layer ID of the associated map layer.
%End

QString itemId() const;
%Docstring
Returns the item ID of the associated annotation item.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/annotations/qgsrenderedannotationitemdetails.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
12 changes: 12 additions & 0 deletions python/core/auto_generated/maprenderer/qgsmaprendererjob.sip.in
Expand Up @@ -49,6 +49,8 @@ The following subclasses are available:

QgsMapRendererJob( const QgsMapSettings &settings );

~QgsMapRendererJob();

void start();
%Docstring
Start the rendering job and immediately return.
Expand Down Expand Up @@ -95,6 +97,15 @@ Gets pointer to internal labeling engine (in order to get access to the results)
This should not be used if cached labeling was redrawn - see :py:func:`~QgsMapRendererJob.usedCachedLabels`.

.. seealso:: :py:func:`usedCachedLabels`
%End

QgsRenderedItemResults *takeRenderedItemResults() /Transfer/;
%Docstring
Takes the rendered item results from the map render job and returns them.

Ownership is transferred to the caller.

.. versionadded:: 3.22
%End

void setFeatureFilterProvider( const QgsFeatureFilterProvider *f );
Expand Down Expand Up @@ -194,6 +205,7 @@ emitted when asynchronous rendering is finished (or canceled).





};

Expand Down
@@ -0,0 +1,53 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/maprenderer/qgsrendereditemresults.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/






class QgsRenderedItemResults
{
%Docstring(signature="appended")
Stores collated details of rendered items during a map rendering operation.

.. versionadded:: 3.22
%End

%TypeHeaderCode
#include "qgsrendereditemresults.h"
%End
public:
QgsRenderedItemResults();
~QgsRenderedItemResults();


QList< QgsRenderedItemDetails * > renderedItems() const;
%Docstring
Returns a list of all rendered items.
%End

QList<const QgsRenderedAnnotationItemDetails *> renderedAnnotationItemsInBounds( const QgsRectangle &bounds ) const;
%Docstring
Returns a list with details of the rendered annotation items within the specified ``bounds``.

.. versionadded:: 3.22
%End


private:
QgsRenderedItemResults( const QgsRenderedItemResults & );
};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/maprenderer/qgsrendereditemresults.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
24 changes: 24 additions & 0 deletions python/core/auto_generated/qgsmaplayerrenderer.sip.in
Expand Up @@ -110,11 +110,35 @@ least partially) some data
%End


QList< QgsRenderedItemDetails * > takeRenderedItemDetails() /TransferBack/;
%Docstring
Takes the list of rendered item details from the renderer.

Ownership of items is transferred to the caller.

.. seealso:: :py:func:`appendRenderedItemDetails`

.. versionadded:: 3.22
%End

protected:




void appendRenderedItemDetails( QgsRenderedItemDetails *details /Transfer/ );
%Docstring
Appends the ``details`` of a rendered item to the renderer.

Rendered item details can be retrieved by calling :py:func:`~QgsMapLayerRenderer.takeRenderedItemDetails`.

Ownership of ``details`` is transferred to the renderer.

.. seealso:: :py:func:`takeRenderedItemDetails`

.. versionadded:: 3.22
%End

};

/************************************************************************
Expand Down
61 changes: 61 additions & 0 deletions python/core/auto_generated/qgsrendereditemdetails.sip.in
@@ -0,0 +1,61 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsrendereditemdetails.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsRenderedItemDetails
{
%Docstring(signature="appended")
Base class for detailed information about a rendered item.

.. versionadded:: 3.22
%End

%TypeHeaderCode
#include "qgsrendereditemdetails.h"
%End
public:

%ConvertToSubClassCode
if ( dynamic_cast<QgsRenderedAnnotationItemDetails *>( sipCpp ) )
sipType = sipType_QgsRenderedAnnotationItemDetails;
else
sipType = 0;
%End

virtual ~QgsRenderedItemDetails();

virtual QgsRenderedItemDetails *clone() const = 0 /Factory/;
%Docstring
Clones the details.
%End

QgsRectangle boundingBox() const;
%Docstring
Returns the bounding box of the item (in map units).

.. seealso:: :py:func:`setBoundingBox`
%End

void setBoundingBox( const QgsRectangle &bounds );
%Docstring
Sets the bounding box of the item (in map units).

.. seealso:: :py:func:`boundingBox`
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsrendereditemdetails.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
3 changes: 3 additions & 0 deletions python/core/core_auto.sip
Expand Up @@ -152,6 +152,7 @@
%Include auto_generated/qgsrenderchecker.sip
%Include auto_generated/qgsrendercontext.sip
%Include auto_generated/qgsrenderedfeaturehandlerinterface.sip
%Include auto_generated/qgsrendereditemdetails.sip
%Include auto_generated/qgsrunprocess.sip
%Include auto_generated/qgsruntimeprofiler.sip
%Include auto_generated/qgsscalecalculator.sip
Expand Down Expand Up @@ -212,6 +213,7 @@
%Include auto_generated/annotations/qgsannotationpointtextitem.sip
%Include auto_generated/annotations/qgsannotationpolygonitem.sip
%Include auto_generated/annotations/qgshtmlannotation.sip
%Include auto_generated/annotations/qgsrenderedannotationitemdetails.sip
%Include auto_generated/annotations/qgssvgannotation.sip
%Include auto_generated/annotations/qgstextannotation.sip
%Include auto_generated/auth/qgsauthcertutils.sip
Expand Down Expand Up @@ -419,6 +421,7 @@
%Include auto_generated/maprenderer/qgsmaprendererparalleljob.sip
%Include auto_generated/maprenderer/qgsmaprenderersequentialjob.sip
%Include auto_generated/maprenderer/qgsmaprenderertask.sip
%Include auto_generated/maprenderer/qgsrendereditemresults.sip
%Include auto_generated/mesh/qgsmesh3daveraging.sip
%Include auto_generated/mesh/qgsmesheditor.sip
%Include auto_generated/mesh/qgsmeshdataprovider.sip
Expand Down
11 changes: 11 additions & 0 deletions python/gui/auto_generated/qgsmapcanvas.sip.in
Expand Up @@ -115,6 +115,17 @@ Since QGIS 3.20, if the ``allowOutdatedResults`` flag is ``False`` then outdated
as a result of an ongoing canvas render) will not be returned, and instead ``None`` will be returned.

.. versionadded:: 2.4
%End

const QgsRenderedItemResults *renderedItemResults( bool allowOutdatedResults = true ) const;
%Docstring
Gets access to the rendered item results (may be ``None``), which includes the results of rendering
annotation items in the canvas map.

If the ``allowOutdatedResults`` flag is ``False`` then outdated rendered item results (e.g.
as a result of an ongoing canvas render) will not be returned, and instead ``None`` will be returned.

.. versionadded:: 3.22
%End

void setCachingEnabled( bool enabled );
Expand Down
7 changes: 7 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -184,6 +184,7 @@ set(QGIS_CORE_SRCS
annotations/qgsannotationpointtextitem.cpp
annotations/qgsannotationpolygonitem.cpp
annotations/qgshtmlannotation.cpp
annotations/qgsrenderedannotationitemdetails.cpp
annotations/qgssvgannotation.cpp
annotations/qgstextannotation.cpp

Expand Down Expand Up @@ -397,6 +398,7 @@ set(QGIS_CORE_SRCS
qgsmaplayerlegend.cpp
qgsmaplayermodel.cpp
qgsmaplayerproxymodel.cpp
qgsmaplayerrenderer.cpp
qgsmaplayerstore.cpp
qgsmaplayerstyle.cpp
qgsmaplayerstylemanager.cpp
Expand Down Expand Up @@ -448,6 +450,7 @@ set(QGIS_CORE_SRCS
qgsremappingproxyfeaturesink.cpp
qgsrenderchecker.cpp
qgsrendercontext.cpp
qgsrendereditemdetails.cpp
qgsrunprocess.cpp
qgsruntimeprofiler.cpp
qgsscalecalculator.cpp
Expand Down Expand Up @@ -588,6 +591,7 @@ set(QGIS_CORE_SRCS
maprenderer/qgsmaprenderersequentialjob.cpp
maprenderer/qgsmaprendererstagedrenderjob.cpp
maprenderer/qgsmaprenderertask.cpp
maprenderer/qgsrendereditemresults.cpp

pal/costcalculator.cpp
pal/feature.cpp
Expand Down Expand Up @@ -1084,6 +1088,7 @@ set(QGIS_CORE_HDRS
qgsrenderchecker.h
qgsrendercontext.h
qgsrenderedfeaturehandlerinterface.h
qgsrendereditemdetails.h
qgsrunprocess.h
qgsruntimeprofiler.h
qgsscalecalculator.h
Expand Down Expand Up @@ -1158,6 +1163,7 @@ set(QGIS_CORE_HDRS
annotations/qgsannotationpolygonitem.h
annotations/qgsannotationregistry.h
annotations/qgshtmlannotation.h
annotations/qgsrenderedannotationitemdetails.h
annotations/qgssvgannotation.h
annotations/qgstextannotation.h

Expand Down Expand Up @@ -1404,6 +1410,7 @@ set(QGIS_CORE_HDRS
maprenderer/qgsmaprenderersequentialjob.h
maprenderer/qgsmaprendererstagedrenderjob.h
maprenderer/qgsmaprenderertask.h
maprenderer/qgsrendereditemresults.h

mesh/qgsmesh3daveraging.h
mesh/qgsmesheditor.h
Expand Down
27 changes: 19 additions & 8 deletions src/core/annotations/qgsannotationlayerrenderer.cpp
Expand Up @@ -17,6 +17,7 @@
#include "qgsannotationlayerrenderer.h"
#include "qgsannotationlayer.h"
#include "qgsfeedback.h"
#include "qgsrenderedannotationitemdetails.h"

QgsAnnotationLayerRenderer::QgsAnnotationLayerRenderer( QgsAnnotationLayer *layer, QgsRenderContext &context )
: QgsMapLayerRenderer( layer->id(), &context )
Expand All @@ -39,15 +40,18 @@ QgsAnnotationLayerRenderer::QgsAnnotationLayerRenderer( QgsAnnotationLayer *laye

mItems.reserve( items.size() );
std::transform( items.begin(), items.end(), std::back_inserter( mItems ),
[layer]( const QString & id ) -> QgsAnnotationItem* { return layer->item( id )->clone(); } );
[layer]( const QString & id ) ->std::pair< QString, std::unique_ptr< QgsAnnotationItem > >
{
return std::make_pair( id, std::unique_ptr< QgsAnnotationItem >( layer->item( id )->clone() ) );
} );

std::sort( mItems.begin(), mItems.end(), []( QgsAnnotationItem * a, QgsAnnotationItem * b ) { return a->zIndex() < b->zIndex(); } ); //clazy:exclude=detaching-member
std::sort( mItems.begin(), mItems.end(), [](
const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &a,
const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &b )
{ return a.second->zIndex() < b.second->zIndex(); } );
}

QgsAnnotationLayerRenderer::~QgsAnnotationLayerRenderer()
{
qDeleteAll( mItems );
}
QgsAnnotationLayerRenderer::~QgsAnnotationLayerRenderer() = default;

QgsFeedback *QgsAnnotationLayerRenderer::feedback() const
{
Expand All @@ -59,15 +63,22 @@ bool QgsAnnotationLayerRenderer::render()
QgsRenderContext &context = *renderContext();

bool canceled = false;
for ( QgsAnnotationItem *item : std::as_const( mItems ) )
for ( const std::pair< QString, std::unique_ptr< QgsAnnotationItem > > &item : std::as_const( mItems ) )
{
if ( mFeedback->isCanceled() )
{
canceled = true;
break;
}

item->render( context, mFeedback.get() );
const QgsRectangle bounds = item.second->boundingBox( context );
if ( bounds.intersects( context.extent() ) )
{
item.second->render( context, mFeedback.get() );
std::unique_ptr< QgsRenderedAnnotationItemDetails > details = std::make_unique< QgsRenderedAnnotationItemDetails >( mLayerID, item.first );
details->setBoundingBox( bounds );
appendRenderedItemDetails( details.release() );
}
}
return !canceled;
}
Expand Down

0 comments on commit 660433d

Please sign in to comment.