Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgstransformeffect.cpp 3 : : ---------------------- 4 : : begin : March 2015 5 : : copyright : (C) 2015 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 "qgstransformeffect.h" 19 : : #include "qgssymbollayerutils.h" 20 : : #include "qgsunittypes.h" 21 : : #include <QPicture> 22 : : #include <QTransform> 23 : : 24 : 0 : QgsPaintEffect *QgsTransformEffect::create( const QVariantMap &map ) 25 : : { 26 : 0 : QgsTransformEffect *newEffect = new QgsTransformEffect(); 27 : 0 : newEffect->readProperties( map ); 28 : 0 : return newEffect; 29 : 0 : } 30 : : 31 : 0 : void QgsTransformEffect::draw( QgsRenderContext &context ) 32 : : { 33 : 0 : if ( !source() || !enabled() || !context.painter() ) 34 : 0 : return; 35 : : 36 : 0 : QPainter *painter = context.painter(); 37 : : 38 : : //apply transformations 39 : 0 : QgsScopedQPainterState painterState( painter ); 40 : : 41 : 0 : QTransform t = createTransform( context ); 42 : 0 : painter->setTransform( t, true ); 43 : 0 : drawSource( *painter ); 44 : 0 : } 45 : : 46 : 0 : QVariantMap QgsTransformEffect::properties() const 47 : : { 48 : 0 : QVariantMap props; 49 : 0 : props.insert( QStringLiteral( "reflect_x" ), mReflectX ? "1" : "0" ); 50 : 0 : props.insert( QStringLiteral( "reflect_y" ), mReflectY ? "1" : "0" ); 51 : 0 : props.insert( QStringLiteral( "scale_x" ), QString::number( mScaleX ) ); 52 : 0 : props.insert( QStringLiteral( "scale_y" ), QString::number( mScaleY ) ); 53 : 0 : props.insert( QStringLiteral( "rotation" ), QString::number( mRotation ) ); 54 : 0 : props.insert( QStringLiteral( "shear_x" ), QString::number( mShearX ) ); 55 : 0 : props.insert( QStringLiteral( "shear_y" ), QString::number( mShearY ) ); 56 : 0 : props.insert( QStringLiteral( "translate_x" ), QString::number( mTranslateX ) ); 57 : 0 : props.insert( QStringLiteral( "translate_y" ), QString::number( mTranslateY ) ); 58 : 0 : props.insert( QStringLiteral( "translate_unit" ), QgsUnitTypes::encodeUnit( mTranslateUnit ) ); 59 : 0 : props.insert( QStringLiteral( "translate_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mTranslateMapUnitScale ) ); 60 : 0 : props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" ); 61 : 0 : props.insert( QStringLiteral( "draw_mode" ), QString::number( int( mDrawMode ) ) ); 62 : 0 : return props; 63 : 0 : } 64 : : 65 : 0 : void QgsTransformEffect::readProperties( const QVariantMap &props ) 66 : : { 67 : 0 : mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt(); 68 : 0 : mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() ); 69 : 0 : mReflectX = props.value( QStringLiteral( "reflect_x" ), QStringLiteral( "0" ) ).toInt(); 70 : 0 : mReflectY = props.value( QStringLiteral( "reflect_y" ), QStringLiteral( "0" ) ).toInt(); 71 : 0 : mScaleX = props.value( QStringLiteral( "scale_x" ), QStringLiteral( "1.0" ) ).toDouble(); 72 : 0 : mScaleY = props.value( QStringLiteral( "scale_y" ), QStringLiteral( "1.0" ) ).toDouble(); 73 : 0 : mRotation = props.value( QStringLiteral( "rotation" ), QStringLiteral( "0.0" ) ).toDouble(); 74 : 0 : mShearX = props.value( QStringLiteral( "shear_x" ), QStringLiteral( "0.0" ) ).toDouble(); 75 : 0 : mShearY = props.value( QStringLiteral( "shear_y" ), QStringLiteral( "0.0" ) ).toDouble(); 76 : 0 : mTranslateX = props.value( QStringLiteral( "translate_x" ), QStringLiteral( "0.0" ) ).toDouble(); 77 : 0 : mTranslateY = props.value( QStringLiteral( "translate_y" ), QStringLiteral( "0.0" ) ).toDouble(); 78 : 0 : mTranslateUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "translate_unit" ) ).toString() ); 79 : 0 : mTranslateMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "translate_unit_scale" ) ).toString() ); 80 : 0 : } 81 : : 82 : 0 : QgsTransformEffect *QgsTransformEffect::clone() const 83 : : { 84 : 0 : QgsTransformEffect *newEffect = new QgsTransformEffect( *this ); 85 : 0 : return newEffect; 86 : 0 : } 87 : : 88 : 0 : QRectF QgsTransformEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const 89 : : { 90 : 0 : QTransform t = createTransform( context ); 91 : 0 : return t.mapRect( rect ); 92 : : } 93 : : 94 : 0 : QTransform QgsTransformEffect::createTransform( const QgsRenderContext &context ) const 95 : : { 96 : 0 : QTransform t; 97 : : 98 : 0 : if ( !source() ) 99 : 0 : return t; 100 : : 101 : 0 : int width = source()->boundingRect().width(); 102 : 0 : int height = source()->boundingRect().height(); 103 : 0 : int top = source()->boundingRect().top(); 104 : 0 : int left = source()->boundingRect().left(); 105 : : 106 : : //remember that the below operations are effectively performed in the opposite order 107 : : //so, first the reflection applies, then scale, shear, rotate and lastly translation 108 : : 109 : 0 : double translateX = context.convertToPainterUnits( mTranslateX, mTranslateUnit, mTranslateMapUnitScale ); 110 : 0 : double translateY = context.convertToPainterUnits( mTranslateY, mTranslateUnit, mTranslateMapUnitScale ); 111 : : 112 : 0 : t.translate( translateX + left + width / 2.0, 113 : 0 : translateY + top + height / 2.0 ); 114 : : 115 : 0 : t.rotate( mRotation ); 116 : 0 : t.shear( mShearX, mShearY ); 117 : 0 : t.scale( mScaleX, mScaleY ); 118 : : 119 : 0 : if ( mReflectX || mReflectY ) 120 : : { 121 : 0 : t.scale( mReflectX ? -1 : 1, mReflectY ? -1 : 1 ); 122 : 0 : } 123 : : 124 : 0 : t.translate( -left - width / 2.0, 125 : 0 : -top - height / 2.0 ); 126 : : 127 : 0 : return t; 128 : 0 : }