Skip to content

Commit

Permalink
Configure and use fixedAspectRatio in QgsSvgSymbolLayerWidget and Qgs…
Browse files Browse the repository at this point in the history
…SvgSymbolLayer
  • Loading branch information
rldhont committed Sep 28, 2017
1 parent 740ccbe commit 60cf7bd
Show file tree
Hide file tree
Showing 14 changed files with 632 additions and 321 deletions.
27 changes: 27 additions & 0 deletions python/core/symbology/qgsmarkersymbollayer.sip
Expand Up @@ -526,6 +526,20 @@ Constructs SVG marker symbol layer with picture from given absolute path to a SV
%End
void setPath( const QString &path );

double defaultAspectRatio() const;
%Docstring
:rtype: float
%End
double updateDefaultAspectRatio();
%Docstring
:rtype: float
%End
double fixedAspectRatio() const;
%Docstring
:rtype: float
%End
void setFixedAspectRatio( double far );

virtual QColor fillColor() const;
virtual void setFillColor( const QColor &color );

Expand Down Expand Up @@ -576,6 +590,19 @@ Constructs SVG marker symbol layer with picture from given absolute path to a SV

protected:

double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const;
%Docstring
Calculates the marker aspect ratio between width and height.
\param context symbol render context
\param scaledSize size of symbol to render
\param hasDataDefinedAspectRatio will be set to true if marker has data defined aspectRatio
.. note::

not available in Python bindings
:rtype: float
%End



};

Expand Down
2 changes: 1 addition & 1 deletion python/core/symbology/qgssvgcache.sip
Expand Up @@ -185,7 +185,7 @@ Get image data
%End

QByteArray svgContent( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth,
double widthScaleFactor, double fixedAspectRatio = 0);
double widthScaleFactor, double fixedAspectRatio = 0 );
%Docstring
Get SVG content
:rtype: QByteArray
Expand Down
1 change: 1 addition & 0 deletions python/core/symbology/qgssymbollayer.sip
Expand Up @@ -92,6 +92,7 @@ class QgsSymbolLayer
PropertyCharacter,
PropertyWidth,
PropertyHeight,
PropertyPreserveAspectRatio,
PropertyFillStyle,
PropertyJoinStyle,
PropertySecondaryColor,
Expand Down
4 changes: 3 additions & 1 deletion python/gui/symbology/qgssymbollayerwidget.sip
Expand Up @@ -364,7 +364,9 @@ class QgsSvgMarkerSymbolLayerWidget : QgsSymbolLayerWidget
public slots:
void setName( const QModelIndex &idx );
void populateIcons( const QModelIndex &idx );
void setSize();
void setWidth();
void setHeight();
void stateChangedAspectRatio();
void setAngle();
void setOffset();
void on_mFileToolButton_clicked();
Expand Down
100 changes: 96 additions & 4 deletions src/core/symbology/qgsmarkersymbollayer.cpp
Expand Up @@ -1700,6 +1700,7 @@ QgsSvgMarkerSymbolLayer::QgsSvgMarkerSymbolLayer( const QString &path, double si
mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters;
mColor = QColor( Qt::black );
mStrokeColor = QColor( Qt::black );
updateDefaultAspectRatio();
}


Expand Down Expand Up @@ -1766,6 +1767,8 @@ QgsSymbolLayer *QgsSvgMarkerSymbolLayer::create( const QgsStringMap &props )
m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )] ) );
if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )] ) );
if ( props.contains( QStringLiteral( "fixedAspectRatio" ) ) )
m->setFixedAspectRatio( props[QStringLiteral( "fixedAspectRatio" )].toDouble() );
if ( props.contains( QStringLiteral( "offset" ) ) )
m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )] ) );
if ( props.contains( QStringLiteral( "offset_unit" ) ) )
Expand Down Expand Up @@ -1831,6 +1834,8 @@ QgsSymbolLayer *QgsSvgMarkerSymbolLayer::create( const QgsStringMap &props )

m->restoreOldDataDefinedProperties( props );

m->updateDefaultAspectRatio();

return m;
}

Expand Down Expand Up @@ -1888,6 +1893,37 @@ void QgsSvgMarkerSymbolLayer::setPath( const QString &path )
c.setAlphaF( strokeOpacity );
setStrokeColor( c );
}

updateDefaultAspectRatio();
}

double QgsSvgMarkerSymbolLayer::updateDefaultAspectRatio()
{
if ( mDefaultAspectRatio == 0.0 )
{
//size
double size = mSize;
//assume 88 dpi as standard value
double widthScaleFactor = 3.465;
QSizeF svgViewbox = QgsApplication::svgCache()->svgViewboxSize( mPath, size, mColor, mStrokeColor, mStrokeWidth, widthScaleFactor );
// set default aspect ratio
mDefaultAspectRatio = svgViewbox.isValid() ? svgViewbox.height() / svgViewbox.width() : 0.0;
}
return mDefaultAspectRatio;
}

bool QgsSvgMarkerSymbolLayer::setPreservedAspectRatio( bool par )
{
bool aPreservedAspectRatio = preservedAspectRatio();
if ( aPreservedAspectRatio && !par )
{
mFixedAspectRatio = mDefaultAspectRatio;
}
else if ( !aPreservedAspectRatio && par )
{
mFixedAspectRatio = 0.0;
}
return preservedAspectRatio();
}


Expand Down Expand Up @@ -1925,6 +1961,9 @@ void QgsSvgMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext

p->save();

bool hasDataDefinedAspectRatio = false;
double aspectRatio = calculateAspectRatio( context, scaledSize, hasDataDefinedAspectRatio );

QPointF outputOffset;
double angle = 0.0;
calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
Expand Down Expand Up @@ -1971,7 +2010,7 @@ void QgsSvgMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext
{
usePict = false;
const QImage &img = QgsApplication::svgCache()->svgAsImage( path, size, fillColor, strokeColor, strokeWidth,
context.renderContext().scaleFactor(), fitsInCache );
context.renderContext().scaleFactor(), fitsInCache, aspectRatio );
if ( fitsInCache && img.width() > 1 )
{
//consider transparency
Expand All @@ -1994,7 +2033,7 @@ void QgsSvgMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext
{
p->setOpacity( context.opacity() );
const QPicture &pct = QgsApplication::svgCache()->svgAsPicture( path, size, fillColor, strokeColor, strokeWidth,
context.renderContext().scaleFactor(), context.renderContext().forceVectorOutput() );
context.renderContext().scaleFactor(), context.renderContext().forceVectorOutput(), aspectRatio );

if ( pct.width() > 1 )
{
Expand Down Expand Up @@ -2045,6 +2084,15 @@ double QgsSvgMarkerSymbolLayer::calculateSize( QgsSymbolRenderContext &context,
context.setOriginalValueVariable( mSize );
scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
}
else
{
hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth );
if ( hasDataDefinedSize )
{
context.setOriginalValueVariable( mSize );
scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSize, &ok );
}
}

if ( hasDataDefinedSize && ok )
{
Expand All @@ -2061,6 +2109,48 @@ double QgsSvgMarkerSymbolLayer::calculateSize( QgsSymbolRenderContext &context,
return scaledSize;
}

double QgsSvgMarkerSymbolLayer::calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const
{
hasDataDefinedAspectRatio = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyPreserveAspectRatio ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight );
if ( !hasDataDefinedAspectRatio )
return mFixedAspectRatio;

context.setOriginalValueVariable( mFixedAspectRatio <= 0.0 );
if ( mDataDefinedProperties.valueAsBool( QgsSymbolLayer::PropertyPreserveAspectRatio, context.renderContext().expressionContext(), mFixedAspectRatio <= 0.0 ) )
return 0.0;

double scaledAspectRatio = mDefaultAspectRatio;
if ( mFixedAspectRatio > 0.0 )
scaledAspectRatio = mFixedAspectRatio;

double defaultHeight = mSize * scaledAspectRatio;
scaledAspectRatio = defaultHeight / scaledSize;

bool ok = true;
double scaledHeight = scaledSize * scaledAspectRatio;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) )
{
context.setOriginalValueVariable( defaultHeight );
scaledHeight = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), defaultHeight, &ok );
}

if ( hasDataDefinedAspectRatio && ok )
{
switch ( mScaleMethod )
{
case QgsSymbol::ScaleArea:
scaledHeight = sqrt( scaledHeight );
break;
case QgsSymbol::ScaleDiameter:
break;
}
}

scaledAspectRatio = scaledHeight / scaledSize;

return scaledAspectRatio;
}

void QgsSvgMarkerSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, QPointF &offset, double &angle ) const
{
//offset
Expand Down Expand Up @@ -2107,6 +2197,7 @@ QgsStringMap QgsSvgMarkerSymbolLayer::properties() const
map[QStringLiteral( "size" )] = QString::number( mSize );
map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
map[QStringLiteral( "fixedAspectRatio" )] = QString::number( mFixedAspectRatio );
map[QStringLiteral( "angle" )] = QString::number( mAngle );
map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
Expand All @@ -2125,6 +2216,7 @@ QgsStringMap QgsSvgMarkerSymbolLayer::properties() const
QgsSvgMarkerSymbolLayer *QgsSvgMarkerSymbolLayer::clone() const
{
QgsSvgMarkerSymbolLayer *m = new QgsSvgMarkerSymbolLayer( mPath, mSize, mAngle );
m->setFixedAspectRatio( mFixedAspectRatio );
m->setColor( mColor );
m->setStrokeColor( mStrokeColor );
m->setStrokeWidth( mStrokeWidth );
Expand Down Expand Up @@ -2344,7 +2436,7 @@ bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFa
}

const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( path, size, fillColor, strokeColor, strokeWidth,
context.renderContext().scaleFactor() );
context.renderContext().scaleFactor(), mFixedAspectRatio );

//if current entry image is 0: cache image for entry
// checks to see if image will fit into cache
Expand Down Expand Up @@ -2421,7 +2513,7 @@ QRectF QgsSvgMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &c
}

QSizeF svgViewbox = QgsApplication::svgCache()->svgViewboxSize( path, scaledSize, fillColor, strokeColor, strokeWidth,
context.renderContext().scaleFactor() );
context.renderContext().scaleFactor(), mFixedAspectRatio );

double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;

Expand Down
57 changes: 57 additions & 0 deletions src/core/symbology/qgsmarkersymbollayer.h
Expand Up @@ -481,9 +481,53 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayer : public QgsMarkerSymbolLayer

void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override;

/** Returns the marker SVG path.
* \see setPath()
*/
QString path() const { return mPath; }

/** Set the marker SVG path.
* \param path SVG path
* \see path()
*/
void setPath( const QString &path );

/** Returns the default marker aspect ratio between width and height, 0 if not yet calculated.
* \see updateDefaultAspectRatio()
*/
double defaultAspectRatio() const { return mDefaultAspectRatio; }

/** Calculates the default marker aspect ratio between width and height.
* \returns the default aspect ratio value
* \see defaultAspectRatio()
*/
double updateDefaultAspectRatio();

/** Returns the preserved aspect ratio value, true if fixed aspect ratio has been lower or equal to 0.
* \see setPreservedAspectRatio()
*/
bool preservedAspectRatio() const { return mFixedAspectRatio <= 0.0; }

/** Set preserved the marker aspect ratio between width and height.
* \param par Preserved Aspect Ratio
* \returns the preserved aspect ratio value, true if fixed aspect ratio has been lower or equal to 0
* \see preservedAspectRatio()
*/
bool setPreservedAspectRatio( bool par );

/** Returns the marker aspect ratio between width and height to be used in rendering,
* if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
* \see setFixedAspectRatio() QgsSvgCache
*/
double fixedAspectRatio() const { return mFixedAspectRatio; }

/** Set the marker aspect ratio between width and height to be used in rendering,
* if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
* \param ratio Fixed Aspect Ratio
* \see fixedAspectRatio() QgsSvgCache
*/
void setFixedAspectRatio( double ratio ) { mFixedAspectRatio = ratio; }

QColor fillColor() const override { return color(); }
void setFillColor( const QColor &color ) override { setColor( color ); }

Expand Down Expand Up @@ -518,8 +562,21 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayer : public QgsMarkerSymbolLayer
QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;

protected:

/** Calculates the marker aspect ratio between width and height.
* \param context symbol render context
* \param scaledSize size of symbol to render
* \param hasDataDefinedAspectRatio will be set to true if marker has data defined aspectRatio
* \note not available in Python bindings
*/
double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const;

QString mPath;

//! The marker default aspect ratio
double mDefaultAspectRatio = 0.0;
//! The marker fixed aspect ratio
double mFixedAspectRatio = 0.0;
//param(fill), param(stroke), param(stroke-width) are going
//to be replaced in memory
QColor mStrokeColor;
Expand Down
24 changes: 12 additions & 12 deletions src/core/symbology/qgssvgcache.cpp
Expand Up @@ -110,7 +110,7 @@ QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor &
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
if( currentEntry->fixedAspectRatio > 0 )
if ( currentEntry->fixedAspectRatio > 0 )
{
hwRatio = currentEntry->fixedAspectRatio;
}
Expand Down Expand Up @@ -485,7 +485,7 @@ void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry )
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
if( isFixedAR )
if ( isFixedAR )
{
hwRatio = entry->fixedAspectRatio;
}
Expand Down Expand Up @@ -547,14 +547,14 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput
double hwRatio = 1.0;
if ( r.viewBoxF().width() > 0 )
{
if( isFixedAR )
{
hwRatio = entry->fixedAspectRatio;
}
else
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
if ( isFixedAR )
{
hwRatio = entry->fixedAspectRatio;
}
else
{
hwRatio = r.viewBoxF().height() / r.viewBoxF().width();
}
}

double wSize = entry->size;
Expand Down Expand Up @@ -583,7 +583,7 @@ QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, con
QgsSvgCacheEntry *cacheEntry = *entryIt;
if ( qgsDoubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->stroke == stroke &&
qgsDoubleNear( cacheEntry->strokeWidth, strokeWidth ) && qgsDoubleNear( cacheEntry->widthScaleFactor, widthScaleFactor ) &&
qgsDoubleNear( cacheEntry->fixedAspectRatio, fixedAspectRatio ))
qgsDoubleNear( cacheEntry->fixedAspectRatio, fixedAspectRatio ) )
{
currentEntry = cacheEntry;
break;
Expand All @@ -594,7 +594,7 @@ QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, con
//cache and replace params in svg content
if ( !currentEntry )
{
currentEntry = insertSvg( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio);
currentEntry = insertSvg( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio );
}
else
{
Expand Down

0 comments on commit 60cf7bd

Please sign in to comment.