Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
First steps towards free-form graphics item layer
Based on a port from the downstream Kadas application's item layer type Kudos to @manisandro
- Loading branch information
1 parent
463e8ee
commit 9f943f7
Showing
3 changed files
with
405 additions
and
0 deletions.
There are no files selected for viewing
114 changes: 114 additions & 0 deletions
114
python/core/auto_generated/annotations/qgsannotationlayer.sip.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/core/annotations/qgsannotationlayer.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ | ||
|
||
|
||
|
||
|
||
|
||
class QgsAnnotationItem | ||
{ | ||
%Docstring | ||
************************************************************************* | ||
|
||
This program is free software; you can redistribute it and/or modify * | ||
it under the terms of the GNU General Public License as published by * | ||
the Free Software Foundation; either version 2 of the License, or * | ||
(at your option) any later version. * | ||
|
||
************************************************************************** | ||
%End | ||
|
||
%TypeHeaderCode | ||
#include "qgsannotationlayer.h" | ||
%End | ||
public: | ||
|
||
QgsAnnotationItem *clone(); | ||
|
||
QgsCoordinateReferenceSystem crs() const; | ||
|
||
void render( QgsRenderContext &context, QgsFeedback *feedback ); | ||
|
||
}; | ||
|
||
class QgsAnnotationLayer : QgsMapLayer | ||
{ | ||
|
||
%TypeHeaderCode | ||
#include "qgsannotationlayer.h" | ||
%End | ||
public: | ||
|
||
|
||
struct LayerOptions | ||
{ | ||
|
||
explicit LayerOptions( const QgsCoordinateTransformContext &transformContext ); | ||
%Docstring | ||
Constructor for LayerOptions. | ||
%End | ||
|
||
QgsCoordinateTransformContext transformContext; | ||
|
||
}; | ||
|
||
|
||
QgsAnnotationLayer( const QString &name, const QgsAnnotationLayer::LayerOptions &options ); | ||
|
||
void addItem( QgsAnnotationItem *item ); | ||
|
||
|
||
const QMap<QString, QgsAnnotationItem *> &items() const; | ||
|
||
void setOpacity( double opacity ); | ||
double opacity() const; | ||
|
||
|
||
virtual QgsAnnotationLayer *clone() const /Factory/; | ||
|
||
|
||
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) /Factory/; | ||
|
||
|
||
virtual QgsRectangle extent() const; | ||
|
||
|
||
virtual void setTransformContext( const QgsCoordinateTransformContext &ctx ); | ||
|
||
|
||
virtual bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, StyleCategories categories = AllStyleCategories ) const; | ||
virtual bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories = AllStyleCategories ); | ||
|
||
protected: | ||
|
||
}; | ||
|
||
class QgsAnnotationLayerRenderer : QgsMapLayerRenderer | ||
{ | ||
|
||
%TypeHeaderCode | ||
#include "qgsannotationlayer.h" | ||
%End | ||
public: | ||
|
||
QgsAnnotationLayerRenderer( QgsAnnotationLayer *layer, QgsRenderContext &context ); | ||
~QgsAnnotationLayerRenderer(); | ||
virtual QgsFeedback *feedback() const; | ||
|
||
virtual bool render(); | ||
|
||
|
||
}; | ||
|
||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/core/annotations/qgsannotationlayer.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/*************************************************************************** | ||
qgsannotationlayer.cpp | ||
------------------ | ||
copyright : (C) 2019 by Sandro Mani | ||
email : smani at sourcepole dot ch | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsannotationlayer.h" | ||
#include "qgsfeedback.h" | ||
#include <QUuid> | ||
|
||
QgsAnnotationLayer::QgsAnnotationLayer( const QString &name, const LayerOptions &options ) | ||
: QgsMapLayer( QgsMapLayerType::AnnotationLayer, name ) | ||
, mTransformContext( options.transformContext ) | ||
{ | ||
mValid = true; | ||
} | ||
|
||
void QgsAnnotationLayer::addItem( QgsAnnotationItem *item ) | ||
{ | ||
mItems.insert( QUuid::createUuid().toString(), item ); | ||
} | ||
|
||
#if 0 | ||
QgsAnnotationItem *QgsAnnotationItem::takeItem( const QString &itemId ) | ||
{ | ||
return mItems.take( itemId ); | ||
} | ||
#endif | ||
|
||
QgsAnnotationLayer *QgsAnnotationLayer::clone() const | ||
{ | ||
QgsAnnotationLayer::LayerOptions options( mTransformContext ); | ||
std::unique_ptr< QgsAnnotationLayer > layer = qgis::make_unique< QgsAnnotationLayer >( name(), options ); | ||
QgsMapLayer::clone( layer.get() ); | ||
|
||
layer->setOpacity( opacity() ); | ||
|
||
for ( auto it = mItems.constBegin(); it != mItems.constEnd(); ++it ) | ||
{ | ||
layer->mItems.insert( it.key(), ( *it )->clone() ); | ||
} | ||
|
||
return layer.release(); | ||
} | ||
|
||
QgsMapLayerRenderer *QgsAnnotationLayer::createMapRenderer( QgsRenderContext &rendererContext ) | ||
{ | ||
return new QgsAnnotationLayerRenderer( this, rendererContext ); | ||
} | ||
|
||
QgsRectangle QgsAnnotationLayer::extent() const | ||
{ | ||
QgsRectangle rect; | ||
for ( auto it = mItems.constBegin(); it != mItems.constEnd(); ++it ) | ||
{ | ||
#if 0 | ||
QgsCoordinateTransform trans( it->crs(), crs(), mTransformContext ); | ||
if ( rect.isNull() ) | ||
{ | ||
rect = trans.transform( item->boundingBox() ); | ||
} | ||
else | ||
{ | ||
rect.combineExtentWith( trans.transform( item->boundingBox() ) ); | ||
} | ||
#endif | ||
} | ||
return rect; | ||
} | ||
|
||
void QgsAnnotationLayer::setTransformContext( const QgsCoordinateTransformContext &ctx ) | ||
{ | ||
mTransformContext = ctx; | ||
} | ||
|
||
#if 0 | ||
QString QgsAnnotationLayer::pickItem( const QgsRectangle &pickRect, const QgsMapSettings &mapSettings ) const | ||
{ | ||
for ( auto it = mItems.begin(), itEnd = mItems.end(); it != itEnd; ++it ) | ||
{ | ||
QgsCoordinateTransform crst( mapSettings.destinationCrs(), it.value()->crs(), transformContext() ); | ||
if ( it.value()->intersects( crst.transform( pickRect ), mapSettings ) ) | ||
{ | ||
return it.key(); | ||
} | ||
} | ||
return QString(); | ||
} | ||
|
||
QString QgsAnnotationLayer::pickItem( const QgsPointXY &mapPos, const QgsMapSettings &mapSettings ) const | ||
{ | ||
QgsRenderContext renderContext = QgsRenderContext::fromMapSettings( mapSettings ); | ||
double radiusmm = QgsSettings().value( "/Map/searchRadiusMM", Qgis::DEFAULT_SEARCH_RADIUS_MM ).toDouble(); | ||
radiusmm = radiusmm > 0 ? radiusmm : Qgis::DEFAULT_SEARCH_RADIUS_MM; | ||
double radiusmu = radiusmm * renderContext.scaleFactor() * renderContext.mapToPixel().mapUnitsPerPixel(); | ||
QgsRectangle filterRect; | ||
filterRect.setXMinimum( mapPos.x() - radiusmu ); | ||
filterRect.setXMaximum( mapPos.x() + radiusmu ); | ||
filterRect.setYMinimum( mapPos.y() - radiusmu ); | ||
filterRect.setYMaximum( mapPos.y() + radiusmu ); | ||
return pickItem( filterRect, mapSettings ); | ||
} | ||
|
||
QRectF QgsAnnotationLayer::margin() const | ||
{ | ||
bool empty = true; | ||
QRectF rect; | ||
for ( const KadasMapItem *item : mItems ) | ||
{ | ||
if ( empty ) | ||
{ | ||
rect = item->margin(); | ||
} | ||
else | ||
{ | ||
rect = rect.united( item->margin() ); | ||
} | ||
} | ||
return rect; | ||
} | ||
#endif | ||
|
||
QgsAnnotationLayerRenderer::QgsAnnotationLayerRenderer( QgsAnnotationLayer *layer, QgsRenderContext &context ) | ||
: QgsMapLayerRenderer( layer->id(), &context ) | ||
, mFeedback( qgis::make_unique< QgsFeedback >() ) | ||
{ | ||
// clone items from layer | ||
const QMap< QString, QgsAnnotationItem * > items = layer->items(); | ||
mItems.reserve( items.size() ); | ||
for ( auto it = items.constBegin(); it != items.constEnd(); ++it ) | ||
{ | ||
if ( it.value() ) | ||
mItems << ( *it )->clone(); | ||
} | ||
|
||
// std::sort( mItems.begin(), mItems.end(), []( QgsAnnotationItem * a, QgsAnnotationItem * b ) { return a->zIndex() < b->zIndex(); } ); | ||
} | ||
|
||
QgsAnnotationLayerRenderer::~QgsAnnotationLayerRenderer() | ||
{ | ||
qDeleteAll( mItems ); | ||
} | ||
|
||
QgsFeedback *QgsAnnotationLayerRenderer::feedback() const | ||
{ | ||
return mFeedback.get(); | ||
} | ||
|
||
bool QgsAnnotationLayerRenderer::render() | ||
{ | ||
QgsRenderContext &context = *renderContext(); | ||
|
||
for ( QgsAnnotationItem *item : qgis::as_const( mItems ) ) | ||
{ | ||
if ( mFeedback->isCanceled() ) | ||
break; | ||
|
||
|
||
renderContext()->setCoordinateTransform( QgsCoordinateTransform( item->crs(), context.coordinateTransform().destinationCrs(), context.transformContext() ) ); | ||
item->render( context, mFeedback.get() ); | ||
} | ||
return true; | ||
} |
Oops, something went wrong.