Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgs25drenderer.cpp - qgs25drenderer 3 : : ----------------------------------- 4 : : 5 : : begin : 14.1.2016 6 : : Copyright : (C) 2016 Matthias Kuhn 7 : : Email : matthias at opengis dot ch 8 : : *************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : #include "qgs25drenderer.h" 17 : : #include "qgsgeometrygeneratorsymbollayer.h" 18 : : #include "qgsfillsymbollayer.h" 19 : : #include "qgspainteffect.h" 20 : : #include "qgseffectstack.h" 21 : : #include "qgsgloweffect.h" 22 : : #include "qgsproperty.h" 23 : : #include "qgssymbollayerutils.h" 24 : : #include "qgsdatadefinedsizelegend.h" 25 : : #include "qgsstyleentityvisitor.h" 26 : : 27 : : #define ROOF_EXPRESSION \ 28 : : "translate(" \ 29 : : " $geometry," \ 30 : : " cos( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )," \ 31 : : " sin( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )" \ 32 : : ")" 33 : : 34 : : #define WALL_EXPRESSION \ 35 : : "order_parts( "\ 36 : : " extrude(" \ 37 : : " segments_to_lines( $geometry )," \ 38 : : " cos( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )," \ 39 : : " sin( radians( eval( @qgis_25d_angle ) ) ) * eval( @qgis_25d_height )" \ 40 : : " )," \ 41 : : " 'distance( $geometry, translate( @map_extent_center, 1000 * @map_extent_width * cos( radians( @qgis_25d_angle + 180 ) ), 1000 * @map_extent_width * sin( radians( @qgis_25d_angle + 180 ) ) ))'," \ 42 : : " False" \ 43 : : ")" 44 : : 45 : : #define ORDER_BY_EXPRESSION \ 46 : : "distance(" \ 47 : : " $geometry," \ 48 : : " translate(" \ 49 : : " @map_extent_center," \ 50 : : " 1000 * @map_extent_width * cos( radians( @qgis_25d_angle + 180 ) )," \ 51 : : " 1000 * @map_extent_width * sin( radians( @qgis_25d_angle + 180 ) )" \ 52 : : " )" \ 53 : : ")" 54 : : 55 : : #define WALL_SHADING_EXPRESSION \ 56 : : "set_color_part( " \ 57 : : " @symbol_color," \ 58 : : " 'value'," \ 59 : : " 40 + 19 * abs( $pi - azimuth( " \ 60 : : " point_n( geometry_n($geometry, @geometry_part_num) , 1 ), " \ 61 : : " point_n( geometry_n($geometry, @geometry_part_num) , 2 )" \ 62 : : " ) ) " \ 63 : : ")" 64 : : 65 : 0 : Qgs25DRenderer::Qgs25DRenderer() 66 : 0 : : QgsFeatureRenderer( QStringLiteral( "25dRenderer" ) ) 67 : 0 : { 68 : 0 : mSymbol.reset( new QgsFillSymbol() ); 69 : : 70 : 0 : mSymbol->deleteSymbolLayer( 0 ); // We never asked for the default layer 71 : : 72 : 0 : QgsSymbolLayer *floor = QgsSimpleFillSymbolLayer::create(); 73 : : 74 : 0 : QVariantMap wallProperties; 75 : 0 : wallProperties.insert( QStringLiteral( "geometryModifier" ), WALL_EXPRESSION ); 76 : 0 : wallProperties.insert( QStringLiteral( "symbolType" ), QStringLiteral( "Fill" ) ); 77 : 0 : QgsSymbolLayer *walls = QgsGeometryGeneratorSymbolLayer::create( wallProperties ); 78 : : 79 : 0 : QVariantMap roofProperties; 80 : 0 : roofProperties.insert( QStringLiteral( "geometryModifier" ), ROOF_EXPRESSION ); 81 : 0 : roofProperties.insert( QStringLiteral( "symbolType" ), QStringLiteral( "Fill" ) ); 82 : 0 : QgsSymbolLayer *roof = QgsGeometryGeneratorSymbolLayer::create( roofProperties ); 83 : : 84 : 0 : floor->setLocked( true ); 85 : : 86 : 0 : mSymbol->appendSymbolLayer( floor ); 87 : 0 : mSymbol->appendSymbolLayer( walls ); 88 : 0 : mSymbol->appendSymbolLayer( roof ); 89 : : 90 : 0 : QgsEffectStack *effectStack = new QgsEffectStack(); 91 : 0 : QgsOuterGlowEffect *glowEffect = new QgsOuterGlowEffect(); 92 : 0 : glowEffect->setBlurLevel( 5 ); 93 : 0 : glowEffect->setSpreadUnit( QgsUnitTypes::RenderMapUnits ); 94 : 0 : effectStack->appendEffect( glowEffect ); 95 : 0 : floor->setPaintEffect( effectStack ); 96 : : 97 : : // These methods must only be used after the above initialization! 98 : : 99 : 0 : setRoofColor( QColor( 177, 169, 124 ) ); 100 : 0 : setWallColor( QColor( 119, 119, 119 ) ); 101 : : 102 : 0 : wallLayer()->setDataDefinedProperty( QgsSymbolLayer::PropertyFillColor, QgsProperty::fromExpression( QString( WALL_SHADING_EXPRESSION ) ) ); 103 : : 104 : 0 : setShadowSpread( 4 ); 105 : 0 : setShadowColor( QColor( 17, 17, 17 ) ); 106 : : 107 : 0 : QgsFeatureRequest::OrderBy orderBy; 108 : 0 : orderBy << QgsFeatureRequest::OrderByClause( 109 : 0 : ORDER_BY_EXPRESSION, 110 : : false ); 111 : : 112 : 0 : setOrderBy( orderBy ); 113 : 0 : setOrderByEnabled( true ); 114 : 0 : } 115 : : 116 : 0 : QDomElement Qgs25DRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) 117 : : { 118 : 0 : QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME ); 119 : : 120 : 0 : rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "25dRenderer" ) ); 121 : : 122 : 0 : QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "symbol" ), mSymbol.get(), doc, context ); 123 : : 124 : 0 : rendererElem.appendChild( symbolElem ); 125 : : 126 : 0 : return rendererElem; 127 : 0 : } 128 : : 129 : 0 : QgsFeatureRenderer *Qgs25DRenderer::create( QDomElement &element, const QgsReadWriteContext &context ) 130 : : { 131 : 0 : Qgs25DRenderer *renderer = new Qgs25DRenderer(); 132 : : 133 : 0 : QDomNodeList symbols = element.elementsByTagName( QStringLiteral( "symbol" ) ); 134 : 0 : if ( symbols.size() ) 135 : : { 136 : 0 : renderer->mSymbol.reset( QgsSymbolLayerUtils::loadSymbol( symbols.at( 0 ).toElement(), context ) ); 137 : 0 : } 138 : : 139 : 0 : return renderer; 140 : 0 : } 141 : : 142 : 0 : void Qgs25DRenderer::startRender( QgsRenderContext &context, const QgsFields &fields ) 143 : : { 144 : 0 : QgsFeatureRenderer::startRender( context, fields ); 145 : : 146 : 0 : mSymbol->startRender( context, fields ); 147 : 0 : } 148 : : 149 : 0 : void Qgs25DRenderer::stopRender( QgsRenderContext &context ) 150 : : { 151 : 0 : QgsFeatureRenderer::stopRender( context ); 152 : : 153 : 0 : mSymbol->stopRender( context ); 154 : 0 : } 155 : : 156 : 0 : QSet<QString> Qgs25DRenderer::usedAttributes( const QgsRenderContext &context ) const 157 : : { 158 : 0 : return mSymbol->usedAttributes( context ); 159 : : } 160 : : 161 : 0 : QgsFeatureRenderer *Qgs25DRenderer::clone() const 162 : : { 163 : 0 : Qgs25DRenderer *c = new Qgs25DRenderer(); 164 : 0 : c->mSymbol.reset( mSymbol->clone() ); 165 : 0 : return c; 166 : 0 : } 167 : : 168 : 0 : QgsSymbol *Qgs25DRenderer::symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const 169 : : { 170 : 0 : Q_UNUSED( feature ) 171 : 0 : Q_UNUSED( context ) 172 : 0 : return mSymbol.get(); 173 : : } 174 : : 175 : 0 : QgsSymbolList Qgs25DRenderer::symbols( QgsRenderContext &context ) const 176 : : { 177 : 0 : Q_UNUSED( context ) 178 : 0 : QgsSymbolList lst; 179 : 0 : lst.append( mSymbol.get() ); 180 : 0 : return lst; 181 : 0 : } 182 : : 183 : 0 : bool Qgs25DRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const 184 : : { 185 : 0 : if ( mSymbol ) 186 : : { 187 : 0 : QgsStyleSymbolEntity entity( mSymbol.get() ); 188 : 0 : return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ); 189 : 0 : } 190 : 0 : return true; 191 : 0 : } 192 : : 193 : 0 : QgsFillSymbolLayer *Qgs25DRenderer::roofLayer() const 194 : : { 195 : 0 : return static_cast<QgsFillSymbolLayer *>( mSymbol->symbolLayer( 2 )->subSymbol()->symbolLayer( 0 ) ); 196 : : } 197 : : 198 : 0 : QgsFillSymbolLayer *Qgs25DRenderer::wallLayer() const 199 : : { 200 : 0 : return static_cast<QgsFillSymbolLayer *>( mSymbol->symbolLayer( 1 )->subSymbol()->symbolLayer( 0 ) ); 201 : : } 202 : : 203 : 0 : QgsOuterGlowEffect *Qgs25DRenderer::glowEffect() const 204 : : { 205 : 0 : QgsEffectStack *stack = static_cast<QgsEffectStack *>( mSymbol->symbolLayer( 0 )->paintEffect() ); 206 : 0 : return static_cast<QgsOuterGlowEffect *>( stack->effect( 0 ) ); 207 : : } 208 : : 209 : 0 : bool Qgs25DRenderer::shadowEnabled() const 210 : : { 211 : 0 : return glowEffect()->enabled(); 212 : : } 213 : : 214 : 0 : void Qgs25DRenderer::setShadowEnabled( bool value ) 215 : : { 216 : 0 : glowEffect()->setEnabled( value ); 217 : 0 : } 218 : : 219 : 0 : QColor Qgs25DRenderer::shadowColor() const 220 : : { 221 : 0 : return glowEffect()->color(); 222 : : } 223 : : 224 : 0 : void Qgs25DRenderer::setShadowColor( const QColor &shadowColor ) 225 : : { 226 : 0 : glowEffect()->setColor( shadowColor ); 227 : 0 : } 228 : : 229 : 0 : double Qgs25DRenderer::shadowSpread() const 230 : : { 231 : 0 : return glowEffect()->spread(); 232 : : } 233 : : 234 : 0 : void Qgs25DRenderer::setShadowSpread( double spread ) 235 : : { 236 : 0 : glowEffect()->setSpread( spread ); 237 : 0 : } 238 : : 239 : 0 : QColor Qgs25DRenderer::wallColor() const 240 : : { 241 : 0 : return wallLayer()->fillColor(); 242 : : } 243 : : 244 : 0 : void Qgs25DRenderer::setWallColor( const QColor &wallColor ) 245 : : { 246 : 0 : wallLayer()->setFillColor( wallColor ); 247 : 0 : wallLayer()->setStrokeColor( wallColor ); 248 : 0 : } 249 : : 250 : 0 : void Qgs25DRenderer::setWallShadingEnabled( bool enabled ) 251 : : { 252 : 0 : wallLayer()->dataDefinedProperties().property( QgsSymbolLayer::PropertyFillColor ).setActive( enabled ); 253 : 0 : } 254 : : 255 : 0 : bool Qgs25DRenderer::wallShadingEnabled() const 256 : : { 257 : 0 : return wallLayer()->dataDefinedProperties().property( QgsSymbolLayer::PropertyFillColor ).isActive(); 258 : : } 259 : : 260 : 0 : QColor Qgs25DRenderer::roofColor() const 261 : : { 262 : 0 : return roofLayer()->fillColor(); 263 : : } 264 : : 265 : 0 : void Qgs25DRenderer::setRoofColor( const QColor &roofColor ) 266 : : { 267 : 0 : roofLayer()->setFillColor( roofColor ); 268 : 0 : roofLayer()->setStrokeColor( roofColor ); 269 : 0 : } 270 : : 271 : 0 : Qgs25DRenderer *Qgs25DRenderer::convertFromRenderer( QgsFeatureRenderer *renderer ) 272 : : { 273 : 0 : if ( renderer->type() == QLatin1String( "25dRenderer" ) ) 274 : : { 275 : 0 : return static_cast<Qgs25DRenderer *>( renderer->clone() ); 276 : : } 277 : : else 278 : : { 279 : 0 : return new Qgs25DRenderer(); 280 : : } 281 : 0 : } 282 : :