mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-16 00:05:45 -04:00
[api] Add text-along-line annotation item type
This annotation item renders curved text along a linestring
This commit is contained in:
parent
b9c0fc46b5
commit
cd3a1bf237
@ -38,6 +38,10 @@ Abstract base class for annotation items which are drawn with :py:class:`QgsAnno
|
|||||||
{
|
{
|
||||||
sipType = sipType_QgsAnnotationPointTextItem;
|
sipType = sipType_QgsAnnotationPointTextItem;
|
||||||
}
|
}
|
||||||
|
else if ( sipCpp->type() == QLatin1String( "linetext" ) )
|
||||||
|
{
|
||||||
|
sipType = sipType_QgsAnnotationLineTextItem;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sipType = 0;
|
sipType = 0;
|
||||||
|
@ -25,7 +25,7 @@ An annotation item which renders a line symbol along a line geometry.
|
|||||||
|
|
||||||
QgsAnnotationLineItem( QgsCurve *curve /Transfer/ );
|
QgsAnnotationLineItem( QgsCurve *curve /Transfer/ );
|
||||||
%Docstring
|
%Docstring
|
||||||
Constructor for QgsAnnotationLineItem, with the specified ``linestring``.
|
Constructor for QgsAnnotationLineItem, with the specified ``curve``.
|
||||||
%End
|
%End
|
||||||
~QgsAnnotationLineItem();
|
~QgsAnnotationLineItem();
|
||||||
|
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/annotations/qgsannotationlinetextitem.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QgsAnnotationLineTextItem : QgsAnnotationItem
|
||||||
|
{
|
||||||
|
%Docstring(signature="appended")
|
||||||
|
An annotation item which renders text along a line geometry.
|
||||||
|
|
||||||
|
.. versionadded:: 3.32
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgsannotationlinetextitem.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem( const QString &text, QgsCurve *curve /Transfer/ );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsAnnotationLineTextItem, with the specified ``curve`` and ``text``.
|
||||||
|
%End
|
||||||
|
~QgsAnnotationLineTextItem();
|
||||||
|
|
||||||
|
virtual Qgis::AnnotationItemFlags flags() const;
|
||||||
|
|
||||||
|
virtual QString type() const;
|
||||||
|
|
||||||
|
virtual void render( QgsRenderContext &context, QgsFeedback *feedback );
|
||||||
|
|
||||||
|
virtual bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
|
||||||
|
|
||||||
|
virtual QList< QgsAnnotationItemNode > nodes() const;
|
||||||
|
|
||||||
|
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
|
||||||
|
|
||||||
|
virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;
|
||||||
|
|
||||||
|
|
||||||
|
static QgsAnnotationLineTextItem *create() /Factory/;
|
||||||
|
%Docstring
|
||||||
|
Creates a new linestring annotation item.
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual bool readXml( const QDomElement &element, const QgsReadWriteContext &context );
|
||||||
|
|
||||||
|
virtual QgsRectangle boundingBox() const;
|
||||||
|
|
||||||
|
virtual QgsRectangle boundingBox( QgsRenderContext &context ) const;
|
||||||
|
|
||||||
|
|
||||||
|
virtual QgsAnnotationLineTextItem *clone() /Factory/;
|
||||||
|
|
||||||
|
|
||||||
|
const QgsCurve *geometry() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the geometry of the item.
|
||||||
|
|
||||||
|
The coordinate reference system for the line will be the parent layer's :py:func:`QgsAnnotationLayer.crs()`.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setGeometry`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setGeometry( QgsCurve *geometry /Transfer/ );
|
||||||
|
%Docstring
|
||||||
|
Sets the ``geometry`` of the item. Ownership of ``geometry`` is transferred.
|
||||||
|
|
||||||
|
The coordinate reference system for the line will be the parent layer's :py:func:`QgsAnnotationLayer.crs()`.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`geometry`
|
||||||
|
%End
|
||||||
|
|
||||||
|
QString text() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the text rendered by the item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setText`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setText( const QString &text );
|
||||||
|
%Docstring
|
||||||
|
Sets the ``text`` rendered by the item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`text`
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsTextFormat format() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the text format used to render the text.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setFormat`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setFormat( const QgsTextFormat &format );
|
||||||
|
%Docstring
|
||||||
|
Sets the text ``format`` used to render the text.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`format`
|
||||||
|
%End
|
||||||
|
|
||||||
|
private:
|
||||||
|
QgsAnnotationLineTextItem( const QgsAnnotationLineTextItem &other );
|
||||||
|
};
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* This file has been generated automatically from *
|
||||||
|
* *
|
||||||
|
* src/core/annotations/qgsannotationlinetextitem.h *
|
||||||
|
* *
|
||||||
|
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||||
|
************************************************************************/
|
@ -227,6 +227,7 @@
|
|||||||
%Include auto_generated/annotations/qgsannotationitemregistry.sip
|
%Include auto_generated/annotations/qgsannotationitemregistry.sip
|
||||||
%Include auto_generated/annotations/qgsannotationlayer.sip
|
%Include auto_generated/annotations/qgsannotationlayer.sip
|
||||||
%Include auto_generated/annotations/qgsannotationlineitem.sip
|
%Include auto_generated/annotations/qgsannotationlineitem.sip
|
||||||
|
%Include auto_generated/annotations/qgsannotationlinetextitem.sip
|
||||||
%Include auto_generated/annotations/qgsannotationmarkeritem.sip
|
%Include auto_generated/annotations/qgsannotationmarkeritem.sip
|
||||||
%Include auto_generated/annotations/qgsannotationmanager.sip
|
%Include auto_generated/annotations/qgsannotationmanager.sip
|
||||||
%Include auto_generated/annotations/qgsannotationpointtextitem.sip
|
%Include auto_generated/annotations/qgsannotationpointtextitem.sip
|
||||||
|
@ -207,6 +207,7 @@ set(QGIS_CORE_SRCS
|
|||||||
annotations/qgsannotationlayer.cpp
|
annotations/qgsannotationlayer.cpp
|
||||||
annotations/qgsannotationlayerrenderer.cpp
|
annotations/qgsannotationlayerrenderer.cpp
|
||||||
annotations/qgsannotationlineitem.cpp
|
annotations/qgsannotationlineitem.cpp
|
||||||
|
annotations/qgsannotationlinetextitem.cpp
|
||||||
annotations/qgsannotationmarkeritem.cpp
|
annotations/qgsannotationmarkeritem.cpp
|
||||||
annotations/qgsannotationmanager.cpp
|
annotations/qgsannotationmanager.cpp
|
||||||
annotations/qgsannotationpointtextitem.cpp
|
annotations/qgsannotationpointtextitem.cpp
|
||||||
@ -1269,6 +1270,7 @@ set(QGIS_CORE_HDRS
|
|||||||
annotations/qgsannotationlayer.h
|
annotations/qgsannotationlayer.h
|
||||||
annotations/qgsannotationlayerrenderer.h
|
annotations/qgsannotationlayerrenderer.h
|
||||||
annotations/qgsannotationlineitem.h
|
annotations/qgsannotationlineitem.h
|
||||||
|
annotations/qgsannotationlinetextitem.h
|
||||||
annotations/qgsannotationmarkeritem.h
|
annotations/qgsannotationmarkeritem.h
|
||||||
annotations/qgsannotationmanager.h
|
annotations/qgsannotationmanager.h
|
||||||
annotations/qgsannotationpointtextitem.h
|
annotations/qgsannotationpointtextitem.h
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
#include "qgis_core.h"
|
#include "qgis_core.h"
|
||||||
#include "qgis_sip.h"
|
#include "qgis_sip.h"
|
||||||
#include "qgscoordinatereferencesystem.h"
|
#include "qgscoordinatereferencesystem.h"
|
||||||
#include "qgslinestring.h"
|
|
||||||
#include "qgspolygon.h"
|
|
||||||
|
|
||||||
class QgsFeedback;
|
class QgsFeedback;
|
||||||
class QgsMarkerSymbol;
|
class QgsMarkerSymbol;
|
||||||
@ -60,6 +58,10 @@ class CORE_EXPORT QgsAnnotationItem
|
|||||||
{
|
{
|
||||||
sipType = sipType_QgsAnnotationPointTextItem;
|
sipType = sipType_QgsAnnotationPointTextItem;
|
||||||
}
|
}
|
||||||
|
else if ( sipCpp->type() == QLatin1String( "linetext" ) )
|
||||||
|
{
|
||||||
|
sipType = sipType_QgsAnnotationLineTextItem;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sipType = 0;
|
sipType = 0;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "qgsannotationlineitem.h"
|
#include "qgsannotationlineitem.h"
|
||||||
#include "qgsannotationpolygonitem.h"
|
#include "qgsannotationpolygonitem.h"
|
||||||
#include "qgsannotationpointtextitem.h"
|
#include "qgsannotationpointtextitem.h"
|
||||||
|
#include "qgsannotationlinetextitem.h"
|
||||||
#include <QDomElement>
|
#include <QDomElement>
|
||||||
|
|
||||||
QgsAnnotationItemRegistry::QgsAnnotationItemRegistry( QObject *parent )
|
QgsAnnotationItemRegistry::QgsAnnotationItemRegistry( QObject *parent )
|
||||||
@ -45,6 +46,8 @@ bool QgsAnnotationItemRegistry::populate()
|
|||||||
QgsAnnotationPolygonItem::create ) );
|
QgsAnnotationPolygonItem::create ) );
|
||||||
mMetadata.insert( QStringLiteral( "pointtext" ), new QgsAnnotationItemMetadata( QStringLiteral( "pointtext" ), QObject::tr( "Text at point" ), QObject::tr( "Text at points" ),
|
mMetadata.insert( QStringLiteral( "pointtext" ), new QgsAnnotationItemMetadata( QStringLiteral( "pointtext" ), QObject::tr( "Text at point" ), QObject::tr( "Text at points" ),
|
||||||
QgsAnnotationPointTextItem::create ) );
|
QgsAnnotationPointTextItem::create ) );
|
||||||
|
mMetadata.insert( QStringLiteral( "linetext" ), new QgsAnnotationItemMetadata( QStringLiteral( "linetext" ), QObject::tr( "Text along line" ), QObject::tr( "Text along lines" ),
|
||||||
|
QgsAnnotationLineTextItem::create ) );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "qgslinesymbol.h"
|
#include "qgslinesymbol.h"
|
||||||
#include "qgsannotationitemnode.h"
|
#include "qgsannotationitemnode.h"
|
||||||
#include "qgsannotationitemeditoperation.h"
|
#include "qgsannotationitemeditoperation.h"
|
||||||
|
#include "qgscurve.h"
|
||||||
|
#include "qgslinestring.h"
|
||||||
|
|
||||||
QgsAnnotationLineItem::QgsAnnotationLineItem( QgsCurve *curve )
|
QgsAnnotationLineItem::QgsAnnotationLineItem( QgsCurve *curve )
|
||||||
: QgsAnnotationItem()
|
: QgsAnnotationItem()
|
||||||
@ -201,6 +203,8 @@ QgsAnnotationLineItem *QgsAnnotationLineItem::clone()
|
|||||||
return item.release();
|
return item.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsAnnotationLineItem::setGeometry( QgsCurve *geometry ) { mCurve.reset( geometry ); }
|
||||||
|
|
||||||
const QgsLineSymbol *QgsAnnotationLineItem::symbol() const
|
const QgsLineSymbol *QgsAnnotationLineItem::symbol() const
|
||||||
{
|
{
|
||||||
return mSymbol.get();
|
return mSymbol.get();
|
||||||
|
@ -35,7 +35,7 @@ class CORE_EXPORT QgsAnnotationLineItem : public QgsAnnotationItem
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for QgsAnnotationLineItem, with the specified \a linestring.
|
* Constructor for QgsAnnotationLineItem, with the specified \a curve.
|
||||||
*/
|
*/
|
||||||
QgsAnnotationLineItem( QgsCurve *curve SIP_TRANSFER );
|
QgsAnnotationLineItem( QgsCurve *curve SIP_TRANSFER );
|
||||||
~QgsAnnotationLineItem() override;
|
~QgsAnnotationLineItem() override;
|
||||||
@ -73,7 +73,7 @@ class CORE_EXPORT QgsAnnotationLineItem : public QgsAnnotationItem
|
|||||||
*
|
*
|
||||||
* \see geometry()
|
* \see geometry()
|
||||||
*/
|
*/
|
||||||
void setGeometry( QgsCurve *geometry SIP_TRANSFER ) { mCurve.reset( geometry ); }
|
void setGeometry( QgsCurve *geometry SIP_TRANSFER );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the symbol used to render the item.
|
* Returns the symbol used to render the item.
|
||||||
|
250
src/core/annotations/qgsannotationlinetextitem.cpp
Normal file
250
src/core/annotations/qgsannotationlinetextitem.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgsannotationlinetextitem.cpp
|
||||||
|
----------------
|
||||||
|
begin : March 2023
|
||||||
|
copyright : (C) 2023 by Nyall Dawson
|
||||||
|
email : nyall dot dawson at gmail dot com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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 "qgsannotationlinetextitem.h"
|
||||||
|
#include "qgsannotationitemnode.h"
|
||||||
|
#include "qgsannotationitemeditoperation.h"
|
||||||
|
#include "qgsrendercontext.h"
|
||||||
|
#include "qgscurve.h"
|
||||||
|
#include "qgslinestring.h"
|
||||||
|
#include "qgstextrenderer.h"
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem::QgsAnnotationLineTextItem( const QString &text, QgsCurve *curve )
|
||||||
|
: QgsAnnotationItem()
|
||||||
|
, mText( text )
|
||||||
|
, mCurve( curve )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Qgis::AnnotationItemFlags QgsAnnotationLineTextItem::flags() const
|
||||||
|
{
|
||||||
|
// in truth this should depend on whether the text format is scale dependent or not!
|
||||||
|
return Qgis::AnnotationItemFlag::ScaleDependentBoundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem::~QgsAnnotationLineTextItem() = default;
|
||||||
|
|
||||||
|
QString QgsAnnotationLineTextItem::type() const
|
||||||
|
{
|
||||||
|
return QStringLiteral( "linetext" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsAnnotationLineTextItem::render( QgsRenderContext &context, QgsFeedback * )
|
||||||
|
{
|
||||||
|
// TODO -- expose as an option!
|
||||||
|
QgsGeometry smoothed( mCurve->clone() );
|
||||||
|
smoothed = smoothed.smooth( );
|
||||||
|
|
||||||
|
QPolygonF pts = smoothed.asQPolygonF();
|
||||||
|
|
||||||
|
//transform the QPolygonF to screen coordinates
|
||||||
|
if ( context.coordinateTransform().isValid() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context.coordinateTransform().transformPolygon( pts );
|
||||||
|
}
|
||||||
|
catch ( QgsCsException & )
|
||||||
|
{
|
||||||
|
// we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
|
||||||
|
pts.erase( std::remove_if( pts.begin(), pts.end(),
|
||||||
|
[]( const QPointF point )
|
||||||
|
{
|
||||||
|
return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
|
||||||
|
} ), pts.end() );
|
||||||
|
|
||||||
|
QPointF *ptr = pts.data();
|
||||||
|
for ( int i = 0; i < pts.size(); ++i, ++ptr )
|
||||||
|
{
|
||||||
|
context.mapToPixel().transformInPlace( ptr->rx(), ptr->ry() );
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString displayText = QgsExpression::replaceExpressionText( mText, &context.expressionContext(), &context.distanceArea() );
|
||||||
|
QgsTextRenderer::drawTextOnLine( pts, displayText, context, mTextFormat );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsAnnotationLineTextItem::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
|
||||||
|
{
|
||||||
|
element.setAttribute( QStringLiteral( "wkt" ), mCurve->asWkt() );
|
||||||
|
element.setAttribute( QStringLiteral( "text" ), mText );
|
||||||
|
QDomElement textFormatElem = document.createElement( QStringLiteral( "lineTextFormat" ) );
|
||||||
|
textFormatElem.appendChild( mTextFormat.writeXml( document, context ) );
|
||||||
|
element.appendChild( textFormatElem );
|
||||||
|
|
||||||
|
writeCommonProperties( element, document, context );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QgsAnnotationItemNode> QgsAnnotationLineTextItem::nodes() const
|
||||||
|
{
|
||||||
|
QList< QgsAnnotationItemNode > res;
|
||||||
|
int i = 0;
|
||||||
|
for ( auto it = mCurve->vertices_begin(); it != mCurve->vertices_end(); ++it, ++i )
|
||||||
|
{
|
||||||
|
res.append( QgsAnnotationItemNode( it.vertexId(), QgsPointXY( ( *it ).x(), ( *it ).y() ), Qgis::AnnotationItemNodeType::VertexHandle ) );
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qgis::AnnotationItemEditOperationResult QgsAnnotationLineTextItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
|
||||||
|
{
|
||||||
|
switch ( operation->type() )
|
||||||
|
{
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationMoveNode *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
|
||||||
|
if ( mCurve->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) ) )
|
||||||
|
return Qgis::AnnotationItemEditOperationResult::Success;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationDeleteNode *deleteOperation = qgis::down_cast< QgsAnnotationItemEditOperationDeleteNode * >( operation );
|
||||||
|
if ( mCurve->deleteVertex( deleteOperation->nodeId() ) )
|
||||||
|
return mCurve->isEmpty() ? Qgis::AnnotationItemEditOperationResult::ItemCleared : Qgis::AnnotationItemEditOperationResult::Success;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::AddNode:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationAddNode *addOperation = qgis::down_cast< QgsAnnotationItemEditOperationAddNode * >( operation );
|
||||||
|
|
||||||
|
QgsPoint segmentPoint;
|
||||||
|
QgsVertexId endOfSegmentVertex;
|
||||||
|
mCurve->closestSegment( addOperation->point(), segmentPoint, endOfSegmentVertex );
|
||||||
|
if ( mCurve->insertVertex( endOfSegmentVertex, segmentPoint ) )
|
||||||
|
return Qgis::AnnotationItemEditOperationResult::Success;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
|
||||||
|
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
|
||||||
|
mCurve->transform( transform );
|
||||||
|
return Qgis::AnnotationItemEditOperationResult::Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Qgis::AnnotationItemEditOperationResult::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsAnnotationItemEditOperationTransientResults *QgsAnnotationLineTextItem::transientEditResults( QgsAbstractAnnotationItemEditOperation *operation )
|
||||||
|
{
|
||||||
|
switch ( operation->type() )
|
||||||
|
{
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationMoveNode *moveOperation = dynamic_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
|
||||||
|
std::unique_ptr< QgsCurve > modifiedCurve( mCurve->clone() );
|
||||||
|
if ( modifiedCurve->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) ) )
|
||||||
|
{
|
||||||
|
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( std::move( modifiedCurve ) ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
|
||||||
|
{
|
||||||
|
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
|
||||||
|
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
|
||||||
|
std::unique_ptr< QgsCurve > modifiedCurve( mCurve->clone() );
|
||||||
|
modifiedCurve->transform( transform );
|
||||||
|
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( std::move( modifiedCurve ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
|
||||||
|
case QgsAbstractAnnotationItemEditOperation::Type::AddNode:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem *QgsAnnotationLineTextItem::create()
|
||||||
|
{
|
||||||
|
return new QgsAnnotationLineTextItem( QString(), new QgsLineString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsAnnotationLineTextItem::readXml( const QDomElement &element, const QgsReadWriteContext &context )
|
||||||
|
{
|
||||||
|
const QString wkt = element.attribute( QStringLiteral( "wkt" ) );
|
||||||
|
const QgsGeometry geometry = QgsGeometry::fromWkt( wkt );
|
||||||
|
if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geometry.constGet() ) )
|
||||||
|
mCurve.reset( curve->clone() );
|
||||||
|
|
||||||
|
mText = element.attribute( QStringLiteral( "text" ) );
|
||||||
|
const QDomElement textFormatElem = element.firstChildElement( QStringLiteral( "lineTextFormat" ) );
|
||||||
|
if ( !textFormatElem.isNull() )
|
||||||
|
{
|
||||||
|
const QDomNodeList textFormatNodeList = textFormatElem.elementsByTagName( QStringLiteral( "text-style" ) );
|
||||||
|
const QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
|
||||||
|
mTextFormat.readXml( textFormatElem, context );
|
||||||
|
}
|
||||||
|
|
||||||
|
readCommonProperties( element, context );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRectangle QgsAnnotationLineTextItem::boundingBox() const
|
||||||
|
{
|
||||||
|
return mCurve->boundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRectangle QgsAnnotationLineTextItem::boundingBox( QgsRenderContext &context ) const
|
||||||
|
{
|
||||||
|
const QString displayText = QgsExpression::replaceExpressionText( mText, &context.expressionContext(), &context.distanceArea() );
|
||||||
|
|
||||||
|
const double heightInPixels = QgsTextRenderer::textHeight( context, mTextFormat, { displayText} );
|
||||||
|
|
||||||
|
// text size has already been calculated using any symbology reference scale factor above -- we need
|
||||||
|
// to temporarily remove the reference scale here or we'll be undoing the scaling
|
||||||
|
QgsScopedRenderContextReferenceScaleOverride resetScaleFactor( context, -1.0 );
|
||||||
|
const double heightInMapUnits = context.convertToMapUnits( heightInPixels, Qgis::RenderUnit::Pixels );
|
||||||
|
|
||||||
|
return mCurve->boundingBox().buffered( heightInMapUnits );
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem *QgsAnnotationLineTextItem::clone()
|
||||||
|
{
|
||||||
|
std::unique_ptr< QgsAnnotationLineTextItem > item = std::make_unique< QgsAnnotationLineTextItem >( mText, mCurve->clone() );
|
||||||
|
item->setFormat( mTextFormat );
|
||||||
|
item->copyCommonProperties( this );
|
||||||
|
return item.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsAnnotationLineTextItem::setGeometry( QgsCurve *geometry )
|
||||||
|
{
|
||||||
|
mCurve.reset( geometry );
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsTextFormat QgsAnnotationLineTextItem::format() const
|
||||||
|
{
|
||||||
|
return mTextFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsAnnotationLineTextItem::setFormat( const QgsTextFormat &format )
|
||||||
|
{
|
||||||
|
mTextFormat = format;
|
||||||
|
}
|
121
src/core/annotations/qgsannotationlinetextitem.h
Normal file
121
src/core/annotations/qgsannotationlinetextitem.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
qgsannotationlinetextitem.h
|
||||||
|
----------------
|
||||||
|
begin : March 2023
|
||||||
|
copyright : (C) 2023 by Nyall Dawson
|
||||||
|
email : nyall dot dawson at gmail dot com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QGSANNOTATIONLINETEXTITEM_H
|
||||||
|
#define QGSANNOTATIONLINETEXTITEM_H
|
||||||
|
|
||||||
|
#include "qgis_core.h"
|
||||||
|
#include "qgis_sip.h"
|
||||||
|
#include "qgsannotationitem.h"
|
||||||
|
#include "qgstextformat.h"
|
||||||
|
|
||||||
|
class QgsCurve;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup core
|
||||||
|
* \brief An annotation item which renders text along a line geometry.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.32
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsAnnotationLineTextItem : public QgsAnnotationItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsAnnotationLineTextItem, with the specified \a curve and \a text.
|
||||||
|
*/
|
||||||
|
QgsAnnotationLineTextItem( const QString &text, QgsCurve *curve SIP_TRANSFER );
|
||||||
|
~QgsAnnotationLineTextItem() override;
|
||||||
|
|
||||||
|
Qgis::AnnotationItemFlags flags() const override;
|
||||||
|
QString type() const override;
|
||||||
|
void render( QgsRenderContext &context, QgsFeedback *feedback ) override;
|
||||||
|
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
|
||||||
|
QList< QgsAnnotationItemNode > nodes() const override;
|
||||||
|
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
|
||||||
|
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new linestring annotation item.
|
||||||
|
*/
|
||||||
|
static QgsAnnotationLineTextItem *create() SIP_FACTORY;
|
||||||
|
|
||||||
|
bool readXml( const QDomElement &element, const QgsReadWriteContext &context ) override;
|
||||||
|
QgsRectangle boundingBox() const override;
|
||||||
|
QgsRectangle boundingBox( QgsRenderContext &context ) const override;
|
||||||
|
|
||||||
|
QgsAnnotationLineTextItem *clone() override SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the geometry of the item.
|
||||||
|
*
|
||||||
|
* The coordinate reference system for the line will be the parent layer's QgsAnnotationLayer::crs().
|
||||||
|
*
|
||||||
|
* \see setGeometry()
|
||||||
|
*/
|
||||||
|
const QgsCurve *geometry() const { return mCurve.get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the \a geometry of the item. Ownership of \a geometry is transferred.
|
||||||
|
*
|
||||||
|
* The coordinate reference system for the line will be the parent layer's QgsAnnotationLayer::crs().
|
||||||
|
*
|
||||||
|
* \see geometry()
|
||||||
|
*/
|
||||||
|
void setGeometry( QgsCurve *geometry SIP_TRANSFER );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text rendered by the item.
|
||||||
|
*
|
||||||
|
* \see setText()
|
||||||
|
*/
|
||||||
|
QString text() const { return mText; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the \a text rendered by the item.
|
||||||
|
*
|
||||||
|
* \see text()
|
||||||
|
*/
|
||||||
|
void setText( const QString &text ) { mText = text; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text format used to render the text.
|
||||||
|
*
|
||||||
|
* \see setFormat()
|
||||||
|
*/
|
||||||
|
QgsTextFormat format() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text \a format used to render the text.
|
||||||
|
*
|
||||||
|
* \see format()
|
||||||
|
*/
|
||||||
|
void setFormat( const QgsTextFormat &format );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QString mText;
|
||||||
|
std::unique_ptr< QgsCurve > mCurve;
|
||||||
|
QgsTextFormat mTextFormat;
|
||||||
|
|
||||||
|
#ifdef SIP_RUN
|
||||||
|
QgsAnnotationLineTextItem( const QgsAnnotationLineTextItem &other );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QGSANNOTATIONLINETEXTITEM_H
|
@ -18,7 +18,9 @@
|
|||||||
#include "qgsannotationpolygonitem.h"
|
#include "qgsannotationpolygonitem.h"
|
||||||
#include "qgssymbol.h"
|
#include "qgssymbol.h"
|
||||||
#include "qgssymbollayerutils.h"
|
#include "qgssymbollayerutils.h"
|
||||||
#include "qgssurface.h"
|
#include "qgscurvepolygon.h"
|
||||||
|
#include "qgscurve.h"
|
||||||
|
#include "qgspolygon.h"
|
||||||
#include "qgsfillsymbol.h"
|
#include "qgsfillsymbol.h"
|
||||||
#include "qgsannotationitemnode.h"
|
#include "qgsannotationitemnode.h"
|
||||||
#include "qgsannotationitemeditoperation.h"
|
#include "qgsannotationitemeditoperation.h"
|
||||||
@ -230,6 +232,11 @@ QgsRectangle QgsAnnotationPolygonItem::boundingBox() const
|
|||||||
return mPolygon->boundingBox();
|
return mPolygon->boundingBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsAnnotationPolygonItem::setGeometry( QgsCurvePolygon *geometry )
|
||||||
|
{
|
||||||
|
mPolygon.reset( geometry );
|
||||||
|
}
|
||||||
|
|
||||||
const QgsFillSymbol *QgsAnnotationPolygonItem::symbol() const
|
const QgsFillSymbol *QgsAnnotationPolygonItem::symbol() const
|
||||||
{
|
{
|
||||||
return mSymbol.get();
|
return mSymbol.get();
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "qgis_sip.h"
|
#include "qgis_sip.h"
|
||||||
#include "qgsannotationitem.h"
|
#include "qgsannotationitem.h"
|
||||||
|
|
||||||
|
class QgsCurvePolygon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
@ -71,7 +72,7 @@ class CORE_EXPORT QgsAnnotationPolygonItem : public QgsAnnotationItem
|
|||||||
*
|
*
|
||||||
* \see geometry()
|
* \see geometry()
|
||||||
*/
|
*/
|
||||||
void setGeometry( QgsCurvePolygon *geometry SIP_TRANSFER ) { mPolygon.reset( geometry ); }
|
void setGeometry( QgsCurvePolygon *geometry SIP_TRANSFER );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the symbol used to render the item.
|
* Returns the symbol used to render the item.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "qgsadvanceddigitizingdockwidget.h"
|
#include "qgsadvanceddigitizingdockwidget.h"
|
||||||
#include "qgsapplication.h"
|
#include "qgsapplication.h"
|
||||||
#include "qgsrecentstylehandler.h"
|
#include "qgsrecentstylehandler.h"
|
||||||
|
#include "qgscurvepolygon.h"
|
||||||
|
|
||||||
///@cond PRIVATE
|
///@cond PRIVATE
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ ADD_PYTHON_TEST(PyQgsAnnotationItemEditOperation test_qgsannotationitemeditopera
|
|||||||
ADD_PYTHON_TEST(PyQgsAnnotationItemNode test_qgsannotationitemnode.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationItemNode test_qgsannotationitemnode.py)
|
||||||
ADD_PYTHON_TEST(PyQgsAnnotationLayer test_qgsannotationlayer.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationLayer test_qgsannotationlayer.py)
|
||||||
ADD_PYTHON_TEST(PyQgsAnnotationLineItem test_qgsannotationlineitem.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationLineItem test_qgsannotationlineitem.py)
|
||||||
|
ADD_PYTHON_TEST(PyQgsAnnotationLineTextItem test_qgsannotationlinetextitem.py)
|
||||||
ADD_PYTHON_TEST(PyQgsAnnotationMarkerItem test_qgsannotationmarkeritem.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationMarkerItem test_qgsannotationmarkeritem.py)
|
||||||
ADD_PYTHON_TEST(PyQgsAnnotationPointTextItem test_qgsannotationpointtextitem.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationPointTextItem test_qgsannotationpointtextitem.py)
|
||||||
ADD_PYTHON_TEST(PyQgsAnnotationPolygonItem test_qgsannotationpolygonitem.py)
|
ADD_PYTHON_TEST(PyQgsAnnotationPolygonItem test_qgsannotationpolygonitem.py)
|
||||||
|
288
tests/src/python/test_qgsannotationlinetextitem.py
Normal file
288
tests/src/python/test_qgsannotationlinetextitem.py
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
"""QGIS Unit tests for QgsAnnotationLineTextItem.
|
||||||
|
|
||||||
|
From build dir, run: ctest -R PyQgsAnnotationlINETextItem -V
|
||||||
|
|
||||||
|
.. note:: 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.
|
||||||
|
"""
|
||||||
|
__author__ = '(C) 2020 by Nyall Dawson'
|
||||||
|
__date__ = '10/08/2020'
|
||||||
|
__copyright__ = 'Copyright 2020, The QGIS Project'
|
||||||
|
|
||||||
|
import qgis # NOQA
|
||||||
|
from qgis.PyQt.QtCore import QDir, QSize, Qt
|
||||||
|
from qgis.PyQt.QtGui import QColor, QImage, QPainter
|
||||||
|
from qgis.PyQt.QtXml import QDomDocument
|
||||||
|
from qgis.core import (
|
||||||
|
Qgis,
|
||||||
|
QgsAnnotationItemEditOperationAddNode,
|
||||||
|
QgsAnnotationItemEditOperationDeleteNode,
|
||||||
|
QgsAnnotationItemEditOperationMoveNode,
|
||||||
|
QgsAnnotationItemEditOperationTranslateItem,
|
||||||
|
QgsAnnotationItemNode,
|
||||||
|
QgsAnnotationLineTextItem,
|
||||||
|
QgsCoordinateReferenceSystem,
|
||||||
|
QgsCoordinateTransform,
|
||||||
|
QgsMapSettings,
|
||||||
|
QgsPoint,
|
||||||
|
QgsPointXY,
|
||||||
|
QgsProject,
|
||||||
|
QgsReadWriteContext,
|
||||||
|
QgsRectangle,
|
||||||
|
QgsRenderChecker,
|
||||||
|
QgsRenderContext,
|
||||||
|
QgsTextFormat,
|
||||||
|
QgsVertexId,
|
||||||
|
QgsLineString,
|
||||||
|
)
|
||||||
|
from qgis.testing import start_app, unittest
|
||||||
|
|
||||||
|
from utilities import getTestFont, unitTestDataPath
|
||||||
|
|
||||||
|
start_app()
|
||||||
|
TEST_DATA_DIR = unitTestDataPath()
|
||||||
|
|
||||||
|
|
||||||
|
class TestQgsAnnotationLineTextItem(unittest.TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.report = "<h1>Python QgsAnnotationLineTextItem Tests</h1>\n"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
report_file_path = f"{QDir.tempPath()}/qgistest.html"
|
||||||
|
with open(report_file_path, 'a') as report_file:
|
||||||
|
report_file.write(cls.report)
|
||||||
|
|
||||||
|
def testBasic(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
|
||||||
|
self.assertEqual(item.text(), 'my text')
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
item.setText('tttttt')
|
||||||
|
item.setGeometry(QgsLineString(((12, 13), (13, 13.1))))
|
||||||
|
item.setZIndex(11)
|
||||||
|
|
||||||
|
format = QgsTextFormat()
|
||||||
|
format.setSize(37)
|
||||||
|
item.setFormat(format)
|
||||||
|
|
||||||
|
self.assertEqual(item.text(), 'tttttt')
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1)')
|
||||||
|
self.assertEqual(item.zIndex(), 11)
|
||||||
|
self.assertEqual(item.format().size(), 37)
|
||||||
|
|
||||||
|
def test_nodes(self):
|
||||||
|
"""
|
||||||
|
Test nodes for item
|
||||||
|
"""
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.nodes(), [
|
||||||
|
QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13),
|
||||||
|
Qgis.AnnotationItemNodeType.VertexHandle),
|
||||||
|
QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(13, 13.1),
|
||||||
|
Qgis.AnnotationItemNodeType.VertexHandle),
|
||||||
|
QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(14, 13),
|
||||||
|
Qgis.AnnotationItemNodeType.VertexHandle)
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_transform(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationTranslateItem('', 100, 200)), Qgis.AnnotationItemEditOperationResult.Success)
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (112 213, 113 213.1, 114 213)')
|
||||||
|
|
||||||
|
def test_apply_move_node_edit(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18))), Qgis.AnnotationItemEditOperationResult.Success)
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 17 18, 14 13)')
|
||||||
|
|
||||||
|
def test_transient_move_operation(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
res = item.transientEditResults(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18)))
|
||||||
|
self.assertEqual(res.representativeGeometry().asWkt(1), 'LineString (12 13, 17 18, 14 13)')
|
||||||
|
|
||||||
|
def test_transient_translate_operation(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
res = item.transientEditResults(QgsAnnotationItemEditOperationTranslateItem('', 100, 200))
|
||||||
|
self.assertEqual(res.representativeGeometry().asWkt(1), 'LineString (112 213, 113 213.1, 114 213)')
|
||||||
|
|
||||||
|
def test_apply_delete_node_edit(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1))), Qgis.AnnotationItemEditOperationResult.Success)
|
||||||
|
self.assertEqual(item.geometry().asWkt(1),
|
||||||
|
'LineString (12 13, 14 13)')
|
||||||
|
|
||||||
|
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13))), Qgis.AnnotationItemEditOperationResult.ItemCleared)
|
||||||
|
|
||||||
|
def test_apply_add_node_edit(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationAddNode('', QgsPoint(12.5, 12.8))), Qgis.AnnotationItemEditOperationResult.Success)
|
||||||
|
self.assertEqual(item.geometry().asWkt(1),
|
||||||
|
'LineString (12 13, 12.5 13, 13 13.1, 14 13)')
|
||||||
|
|
||||||
|
def testReadWriteXml(self):
|
||||||
|
doc = QDomDocument("testdoc")
|
||||||
|
elem = doc.createElement('test')
|
||||||
|
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
item.setZIndex(11)
|
||||||
|
format = QgsTextFormat()
|
||||||
|
format.setSize(37)
|
||||||
|
item.setFormat(format)
|
||||||
|
item.setUseSymbologyReferenceScale(True)
|
||||||
|
item.setSymbologyReferenceScale(5000)
|
||||||
|
|
||||||
|
self.assertTrue(item.writeXml(elem, doc, QgsReadWriteContext()))
|
||||||
|
|
||||||
|
s2 = QgsAnnotationLineTextItem.create()
|
||||||
|
self.assertTrue(s2.readXml(elem, QgsReadWriteContext()))
|
||||||
|
self.assertEqual(s2.text(), 'my text')
|
||||||
|
self.assertEqual(s2.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
self.assertEqual(s2.zIndex(), 11)
|
||||||
|
self.assertEqual(s2.format().size(), 37)
|
||||||
|
self.assertTrue(s2.useSymbologyReferenceScale())
|
||||||
|
self.assertEqual(s2.symbologyReferenceScale(), 5000)
|
||||||
|
|
||||||
|
def testClone(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13))))
|
||||||
|
item.setZIndex(11)
|
||||||
|
format = QgsTextFormat()
|
||||||
|
format.setSize(37)
|
||||||
|
item.setFormat(format)
|
||||||
|
item.setUseSymbologyReferenceScale(True)
|
||||||
|
item.setSymbologyReferenceScale(5000)
|
||||||
|
|
||||||
|
item2 = item.clone()
|
||||||
|
self.assertEqual(item2.text(), 'my text')
|
||||||
|
self.assertEqual(item2.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)')
|
||||||
|
self.assertEqual(item2.zIndex(), 11)
|
||||||
|
self.assertEqual(item2.format().size(), 37)
|
||||||
|
self.assertTrue(item2.useSymbologyReferenceScale())
|
||||||
|
self.assertEqual(item2.symbologyReferenceScale(), 5000)
|
||||||
|
|
||||||
|
def testRenderLine(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 12))))
|
||||||
|
|
||||||
|
format = QgsTextFormat.fromQFont(getTestFont('Bold'))
|
||||||
|
format.setColor(QColor(255, 0, 0))
|
||||||
|
format.setOpacity(150 / 255)
|
||||||
|
format.setSize(55)
|
||||||
|
item.setFormat(format)
|
||||||
|
|
||||||
|
settings = QgsMapSettings()
|
||||||
|
settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
|
||||||
|
settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14))
|
||||||
|
settings.setOutputSize(QSize(600, 300))
|
||||||
|
|
||||||
|
settings.setFlag(QgsMapSettings.Antialiasing, False)
|
||||||
|
|
||||||
|
rc = QgsRenderContext.fromMapSettings(settings)
|
||||||
|
image = QImage(600, 300, QImage.Format_ARGB32)
|
||||||
|
image.setDotsPerMeterX(int(96 / 25.4 * 1000))
|
||||||
|
image.setDotsPerMeterY(int(96 / 25.4 * 1000))
|
||||||
|
image.fill(QColor(255, 255, 255))
|
||||||
|
painter = QPainter(image)
|
||||||
|
rc.setPainter(painter)
|
||||||
|
|
||||||
|
try:
|
||||||
|
item.render(rc, None)
|
||||||
|
finally:
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
self.assertTrue(self.imageCheck('linetext_item', 'linetext_item', image))
|
||||||
|
|
||||||
|
def testRenderLineTextExpression(self):
|
||||||
|
item = QgsAnnotationLineTextItem('[% 1 + 1.5 %]', QgsLineString(((12, 13), (13, 13.1), (14, 12))))
|
||||||
|
|
||||||
|
format = QgsTextFormat.fromQFont(getTestFont('Bold'))
|
||||||
|
format.setColor(QColor(255, 0, 0))
|
||||||
|
format.setOpacity(150 / 255)
|
||||||
|
format.setSize(55)
|
||||||
|
item.setFormat(format)
|
||||||
|
|
||||||
|
settings = QgsMapSettings()
|
||||||
|
settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
|
||||||
|
settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14))
|
||||||
|
settings.setOutputSize(QSize(600, 300))
|
||||||
|
|
||||||
|
settings.setFlag(QgsMapSettings.Antialiasing, False)
|
||||||
|
|
||||||
|
rc = QgsRenderContext.fromMapSettings(settings)
|
||||||
|
image = QImage(600, 300, QImage.Format_ARGB32)
|
||||||
|
image.setDotsPerMeterX(int(96 / 25.4 * 1000))
|
||||||
|
image.setDotsPerMeterY(int(96 / 25.4 * 1000))
|
||||||
|
image.fill(QColor(255, 255, 255))
|
||||||
|
painter = QPainter(image)
|
||||||
|
rc.setPainter(painter)
|
||||||
|
|
||||||
|
try:
|
||||||
|
item.render(rc, None)
|
||||||
|
finally:
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
self.assertTrue(self.imageCheck('linetext_item_expression', 'linetext_item_expression', image))
|
||||||
|
|
||||||
|
def testRenderWithTransform(self):
|
||||||
|
item = QgsAnnotationLineTextItem('my text', QgsLineString(
|
||||||
|
((12, 13), (13, 13.1), (14, 12))))
|
||||||
|
|
||||||
|
format = QgsTextFormat.fromQFont(getTestFont('Bold'))
|
||||||
|
format.setColor(QColor(255, 0, 0))
|
||||||
|
format.setOpacity(150 / 255)
|
||||||
|
format.setSize(55)
|
||||||
|
item.setFormat(format)
|
||||||
|
|
||||||
|
settings = QgsMapSettings()
|
||||||
|
settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
|
||||||
|
settings.setExtent(QgsRectangle(1291958, 1386945, 1420709, 1532518))
|
||||||
|
settings.setOutputSize(QSize(600, 300))
|
||||||
|
|
||||||
|
settings.setFlag(QgsMapSettings.Antialiasing, False)
|
||||||
|
|
||||||
|
rc = QgsRenderContext.fromMapSettings(settings)
|
||||||
|
rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance()))
|
||||||
|
image = QImage(600, 300, QImage.Format_ARGB32)
|
||||||
|
image.setDotsPerMeterX(int(96 / 25.4 * 1000))
|
||||||
|
image.setDotsPerMeterY(int(96 / 25.4 * 1000))
|
||||||
|
image.fill(QColor(255, 255, 255))
|
||||||
|
painter = QPainter(image)
|
||||||
|
rc.setPainter(painter)
|
||||||
|
|
||||||
|
try:
|
||||||
|
item.render(rc, None)
|
||||||
|
finally:
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
self.assertTrue(self.imageCheck('linetext_item_transform', 'linetext_item_transform', image))
|
||||||
|
|
||||||
|
def imageCheck(self, name, reference_image, image):
|
||||||
|
TestQgsAnnotationLineTextItem.report += f"<h2>Render {name}</h2>\n"
|
||||||
|
temp_dir = QDir.tempPath() + '/'
|
||||||
|
file_name = temp_dir + 'patch_' + name + ".png"
|
||||||
|
image.save(file_name, "PNG")
|
||||||
|
checker = QgsRenderChecker()
|
||||||
|
checker.setControlPathPrefix("annotation_layer")
|
||||||
|
checker.setControlName("expected_" + reference_image)
|
||||||
|
checker.setRenderedImage(file_name)
|
||||||
|
checker.setColorTolerance(2)
|
||||||
|
result = checker.compareImages(name, 20)
|
||||||
|
TestQgsAnnotationLineTextItem.report += checker.report()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
BIN
tests/testdata/control_images/annotation_layer/expected_linetext_item/expected_linetext_item.png
vendored
Normal file
BIN
tests/testdata/control_images/annotation_layer/expected_linetext_item/expected_linetext_item.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Loading…
x
Reference in New Issue
Block a user