Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsannotationpolygonitem.cpp 3 : : ---------------- 4 : : begin : July 2020 5 : : copyright : (C) 2020 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgsannotationpolygonitem.h" 19 : : #include "qgssymbol.h" 20 : : #include "qgssymbollayerutils.h" 21 : : #include "qgssurface.h" 22 : : 23 : 0 : QgsAnnotationPolygonItem::QgsAnnotationPolygonItem( QgsCurvePolygon *polygon ) 24 : 0 : : QgsAnnotationItem() 25 : 0 : , mPolygon( polygon ) 26 : 0 : , mSymbol( std::make_unique< QgsFillSymbol >() ) 27 : 0 : { 28 : : 29 : 0 : } 30 : : 31 : 0 : QgsAnnotationPolygonItem::~QgsAnnotationPolygonItem() = default; 32 : : 33 : 0 : QString QgsAnnotationPolygonItem::type() const 34 : : { 35 : 0 : return QStringLiteral( "polygon" ); 36 : : } 37 : : 38 : 0 : void QgsAnnotationPolygonItem::render( QgsRenderContext &context, QgsFeedback * ) 39 : : { 40 : : 41 : 0 : auto transformRing = [&context]( QPolygonF & pts ) 42 : : { 43 : : //transform the QPolygonF to screen coordinates 44 : 0 : if ( context.coordinateTransform().isValid() ) 45 : : { 46 : : try 47 : : { 48 : 0 : context.coordinateTransform().transformPolygon( pts ); 49 : 0 : } 50 : : catch ( QgsCsException & ) 51 : : { 52 : : // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid 53 : 0 : } 54 : 0 : } 55 : : 56 : : // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors 57 : 0 : pts.erase( std::remove_if( pts.begin(), pts.end(), 58 : 0 : []( const QPointF point ) 59 : : { 60 : 0 : return !std::isfinite( point.x() ) || !std::isfinite( point.y() ); 61 : 0 : } ), pts.end() ); 62 : : 63 : 0 : QPointF *ptr = pts.data(); 64 : 0 : for ( int i = 0; i < pts.size(); ++i, ++ptr ) 65 : : { 66 : 0 : context.mapToPixel().transformInPlace( ptr->rx(), ptr->ry() ); 67 : 0 : } 68 : 0 : }; 69 : : 70 : 0 : QPolygonF exterior = mPolygon->exteriorRing()->asQPolygonF(); 71 : 0 : transformRing( exterior ); 72 : 0 : QVector<QPolygonF> rings; 73 : 0 : rings.reserve( mPolygon->numInteriorRings() ); 74 : 0 : for ( int i = 0; i < mPolygon->numInteriorRings(); ++i ) 75 : : { 76 : 0 : QPolygonF ring = mPolygon->interiorRing( i )->asQPolygonF(); 77 : 0 : transformRing( ring ); 78 : 0 : rings.append( ring ); 79 : 0 : } 80 : : 81 : 0 : mSymbol->startRender( context ); 82 : 0 : mSymbol->renderPolygon( exterior, rings.empty() ? nullptr : &rings, nullptr, context ); 83 : 0 : mSymbol->stopRender( context ); 84 : 0 : } 85 : : 86 : 0 : bool QgsAnnotationPolygonItem::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const 87 : : { 88 : 0 : element.setAttribute( QStringLiteral( "wkt" ), mPolygon->asWkt() ); 89 : : 90 : 0 : element.setAttribute( QStringLiteral( "zIndex" ), zIndex() ); 91 : 0 : element.appendChild( QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "lineSymbol" ), mSymbol.get(), document, context ) ); 92 : : 93 : 0 : return true; 94 : 0 : } 95 : : 96 : 0 : QgsAnnotationPolygonItem *QgsAnnotationPolygonItem::create() 97 : : { 98 : 0 : return new QgsAnnotationPolygonItem( new QgsPolygon() ); 99 : 0 : } 100 : : 101 : 0 : bool QgsAnnotationPolygonItem::readXml( const QDomElement &element, const QgsReadWriteContext &context ) 102 : : { 103 : 0 : const QString wkt = element.attribute( QStringLiteral( "wkt" ) ); 104 : 0 : const QgsGeometry geometry = QgsGeometry::fromWkt( wkt ); 105 : 0 : if ( const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( geometry.constGet() ) ) 106 : 0 : mPolygon.reset( polygon->clone() ); 107 : : 108 : 0 : setZIndex( element.attribute( QStringLiteral( "zIndex" ) ).toInt() ); 109 : : 110 : 0 : const QDomElement symbolElem = element.firstChildElement( QStringLiteral( "symbol" ) ); 111 : 0 : if ( !symbolElem.isNull() ) 112 : 0 : setSymbol( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( symbolElem, context ) ); 113 : : 114 : : return true; 115 : 0 : } 116 : : 117 : 0 : QgsAnnotationPolygonItem *QgsAnnotationPolygonItem::clone() 118 : : { 119 : 0 : std::unique_ptr< QgsAnnotationPolygonItem > item = std::make_unique< QgsAnnotationPolygonItem >( mPolygon->clone() ); 120 : 0 : item->setSymbol( mSymbol->clone() ); 121 : 0 : item->setZIndex( zIndex() ); 122 : 0 : return item.release(); 123 : 0 : } 124 : : 125 : 0 : QgsRectangle QgsAnnotationPolygonItem::boundingBox() const 126 : : { 127 : 0 : return mPolygon->boundingBox(); 128 : : } 129 : : 130 : 0 : const QgsFillSymbol *QgsAnnotationPolygonItem::symbol() const 131 : : { 132 : 0 : return mSymbol.get(); 133 : : } 134 : : 135 : 0 : void QgsAnnotationPolygonItem::setSymbol( QgsFillSymbol *symbol ) 136 : : { 137 : 0 : mSymbol.reset( symbol ); 138 : 0 : }