Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspointcloudextentrenderer.h 3 : : -------------------- 4 : : begin : December 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 "qgspointcloudextentrenderer.h" 19 : : #include "qgspointcloudblock.h" 20 : : #include "qgssymbollayerutils.h" 21 : : #include "qgssymbol.h" 22 : : #include "qgswkbtypes.h" 23 : : #include "qgspolygon.h" 24 : : #include "qgscurve.h" 25 : : #include "qgslinesymbollayer.h" 26 : : #include "qgslayertreemodellegendnode.h" 27 : : 28 : 0 : QgsPointCloudExtentRenderer::QgsPointCloudExtentRenderer( QgsFillSymbol *symbol ) 29 : 0 : : mFillSymbol( symbol ? symbol : defaultFillSymbol() ) 30 : 0 : { 31 : : 32 : 0 : } 33 : : 34 : 0 : QString QgsPointCloudExtentRenderer::type() const 35 : : { 36 : 0 : return QStringLiteral( "extent" ); 37 : : } 38 : : 39 : 0 : QgsPointCloudRenderer *QgsPointCloudExtentRenderer::clone() const 40 : : { 41 : 0 : std::unique_ptr< QgsPointCloudExtentRenderer > res = std::make_unique< QgsPointCloudExtentRenderer >( mFillSymbol ? mFillSymbol->clone() : nullptr ); 42 : 0 : copyCommonProperties( res.get() ); 43 : 0 : return res.release(); 44 : 0 : } 45 : : 46 : 0 : void QgsPointCloudExtentRenderer::renderBlock( const QgsPointCloudBlock *, QgsPointCloudRenderContext & ) 47 : : { 48 : : 49 : 0 : } 50 : : 51 : 0 : QgsPointCloudRenderer *QgsPointCloudExtentRenderer::create( QDomElement &element, const QgsReadWriteContext &context ) 52 : : { 53 : 0 : std::unique_ptr< QgsPointCloudExtentRenderer > r = std::make_unique< QgsPointCloudExtentRenderer >(); 54 : : 55 : 0 : QDomElement symbolElem = element.firstChildElement( QStringLiteral( "symbol" ) ); 56 : 0 : if ( !symbolElem.isNull() ) 57 : : { 58 : 0 : r->mFillSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) ); 59 : 0 : } 60 : : 61 : 0 : r->restoreCommonProperties( element, context ); 62 : 0 : return r.release(); 63 : 0 : } 64 : : 65 : 0 : void QgsPointCloudExtentRenderer::renderExtent( const QgsGeometry &extent, QgsPointCloudRenderContext &context ) 66 : : { 67 : 0 : auto transformRing = [&context]( QPolygonF & pts ) 68 : : { 69 : : //transform the QPolygonF to screen coordinates 70 : 0 : if ( context.renderContext().coordinateTransform().isValid() ) 71 : : { 72 : : try 73 : : { 74 : 0 : context.renderContext().coordinateTransform().transformPolygon( pts ); 75 : 0 : } 76 : : catch ( QgsCsException & ) 77 : : { 78 : : // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid 79 : 0 : } 80 : 0 : } 81 : : 82 : : // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors 83 : 0 : pts.erase( std::remove_if( pts.begin(), pts.end(), 84 : 0 : []( const QPointF point ) 85 : : { 86 : 0 : return !std::isfinite( point.x() ) || !std::isfinite( point.y() ); 87 : 0 : } ), pts.end() ); 88 : : 89 : 0 : QPointF *ptr = pts.data(); 90 : 0 : for ( int i = 0; i < pts.size(); ++i, ++ptr ) 91 : : { 92 : 0 : context.renderContext().mapToPixel().transformInPlace( ptr->rx(), ptr->ry() ); 93 : 0 : } 94 : 0 : }; 95 : : 96 : 0 : for ( auto it = extent.const_parts_begin(); it != extent.const_parts_end(); ++it ) 97 : : { 98 : 0 : if ( const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( *it ) ) 99 : : { 100 : 0 : QPolygonF exterior = polygon->exteriorRing()->asQPolygonF(); 101 : 0 : transformRing( exterior ); 102 : 0 : QVector<QPolygonF> rings; 103 : 0 : rings.reserve( polygon->numInteriorRings() ); 104 : 0 : for ( int i = 0; i < polygon->numInteriorRings(); ++i ) 105 : : { 106 : 0 : QPolygonF ring = polygon->interiorRing( i )->asQPolygonF(); 107 : 0 : transformRing( ring ); 108 : 0 : rings.append( ring ); 109 : 0 : } 110 : : 111 : 0 : mFillSymbol->renderPolygon( exterior, rings.empty() ? nullptr : &rings, nullptr, context.renderContext() ); 112 : 0 : } 113 : 0 : } 114 : 0 : } 115 : : 116 : 0 : QgsFillSymbol *QgsPointCloudExtentRenderer::defaultFillSymbol() 117 : : { 118 : 0 : std::unique_ptr< QgsSimpleLineSymbolLayer > layer = std::make_unique< QgsSimpleLineSymbolLayer >(); 119 : 0 : layer->setColor( QColor( 228, 26, 28 ) ); 120 : 0 : layer->setWidth( 0.960000 ); 121 : 0 : layer->setPenStyle( Qt::DotLine ); 122 : 0 : layer->setWidthUnit( QgsUnitTypes::RenderMillimeters ); 123 : 0 : return new QgsFillSymbol( QgsSymbolLayerList() << layer.release() ); 124 : 0 : } 125 : : 126 : 0 : QgsFillSymbol *QgsPointCloudExtentRenderer::fillSymbol() const 127 : : { 128 : 0 : return mFillSymbol.get(); 129 : : } 130 : : 131 : 0 : void QgsPointCloudExtentRenderer::setFillSymbol( QgsFillSymbol *symbol ) 132 : : { 133 : 0 : mFillSymbol.reset( symbol ); 134 : 0 : } 135 : : 136 : 0 : QDomElement QgsPointCloudExtentRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) const 137 : : { 138 : 0 : QDomElement rendererElem = doc.createElement( QStringLiteral( "renderer" ) ); 139 : : 140 : 0 : rendererElem.setAttribute( QStringLiteral( "type" ), type() ); 141 : : 142 : 0 : QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QString(), mFillSymbol.get(), doc, context ); 143 : 0 : rendererElem.appendChild( symbolElem ); 144 : : 145 : 0 : saveCommonProperties( rendererElem, context ); 146 : 0 : return rendererElem; 147 : 0 : } 148 : : 149 : 0 : void QgsPointCloudExtentRenderer::startRender( QgsPointCloudRenderContext &context ) 150 : : { 151 : 0 : QgsPointCloudRenderer::startRender( context ); 152 : 0 : mFillSymbol->startRender( context.renderContext() ); 153 : 0 : } 154 : : 155 : 0 : void QgsPointCloudExtentRenderer::stopRender( QgsPointCloudRenderContext &context ) 156 : : { 157 : 0 : QgsPointCloudRenderer::stopRender( context ); 158 : 0 : mFillSymbol->stopRender( context.renderContext() ); 159 : 0 : } 160 : : 161 : 0 : QList<QgsLayerTreeModelLegendNode *> QgsPointCloudExtentRenderer::createLegendNodes( QgsLayerTreeLayer *nodeLayer ) 162 : : { 163 : 0 : QList<QgsLayerTreeModelLegendNode *> nodes; 164 : : 165 : 0 : QgsLegendSymbolItem extentItem( mFillSymbol.get(), QStringLiteral( "extent" ), QStringLiteral( "extent" ) ); 166 : 0 : QgsSymbolLegendNode *node = new QgsSymbolLegendNode( nodeLayer, extentItem ); 167 : 0 : node->setEmbeddedInParent( true ); 168 : 0 : nodes << node; 169 : : 170 : 0 : return nodes; 171 : 0 : } 172 : :