Skip to content

Commit c21973f

Browse files
committedJan 24, 2014
fixed horizontal and vertical marker line fill using maximum markers interval, fixes partially #8975
1 parent 79b7415 commit c21973f

File tree

1 file changed

+85
-39
lines changed

1 file changed

+85
-39
lines changed
 

‎src/core/symbology-ng/qgsfillsymbollayerv2.cpp

Lines changed: 85 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* *
1414
***************************************************************************/
1515
#include "qgsfillsymbollayerv2.h"
16+
#include "qgslinesymbollayerv2.h"
1617
#include "qgsmarkersymbollayerv2.h"
1718
#include "qgssymbollayerv2utils.h"
1819
#include "qgsdxfexport.h"
@@ -1566,18 +1567,79 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
15661567
{
15671568
return;
15681569
}
1570+
// We have to make a copy because marker intervals will have to be adjusted
1571+
QgsLineSymbolV2* fillLineSymbol = dynamic_cast<QgsLineSymbolV2*>( mFillLineSymbol->clone() );
1572+
if ( !fillLineSymbol )
1573+
{
1574+
return;
1575+
}
15691576

15701577
const QgsRenderContext& ctx = context.renderContext();
15711578
//double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit );
15721579
double outputPixelDist = distance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit );
15731580
double outputPixelOffset = mOffset * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mOffsetUnit );
15741581

1582+
// To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
1583+
// For marker lines we have to get markers interval.
1584+
double outputPixelBleed = 0;
1585+
double outputPixelInterval = 0; // maximum interval
1586+
for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
1587+
{
1588+
QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
1589+
double layerBleed = layer->estimateMaxBleed();
1590+
// TODO: to get real bleed we have to scale it using context and units,
1591+
// unfortunately estimateMaxBleed() ignore units completely, e.g.
1592+
// QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
1593+
// offset regardless units. This has to be fixed especially
1594+
// in estimateMaxBleed(), context probably has to be used.
1595+
// For now, we only support milimeters
1596+
double outputPixelLayerBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
1597+
outputPixelBleed = qMax( outputPixelBleed, outputPixelLayerBleed );
1598+
1599+
QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
1600+
if ( markerLineLayer )
1601+
{
1602+
double outputPixelLayerInterval = markerLineLayer->interval() * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, markerLineLayer->intervalUnit() );
1603+
1604+
// There may be multiple marker lines with different intervals.
1605+
// In theory we should find the least common multiple, but that could be too
1606+
// big (multiplication of intervals in the worst case).
1607+
// Because patterns without small common interval would look strange, we
1608+
// believe that the longest interval should usually be sufficient.
1609+
outputPixelInterval = qMax( outputPixelInterval, outputPixelLayerInterval );
1610+
}
1611+
}
1612+
1613+
if ( outputPixelInterval > 0 )
1614+
{
1615+
// We have to adjust marker intervals to integer pixel size to get
1616+
// repeatable pattern.
1617+
double intervalScale = qRound( outputPixelInterval ) / outputPixelInterval;
1618+
outputPixelInterval = qRound( outputPixelInterval );
1619+
1620+
for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
1621+
{
1622+
QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
1623+
1624+
QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
1625+
if ( markerLineLayer )
1626+
{
1627+
markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
1628+
}
1629+
}
1630+
}
1631+
15751632
//create image
15761633
int height, width;
1577-
if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 180 ) || qgsDoubleNear( lineAngle, 270 ) )
1634+
if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
15781635
{
15791636
height = outputPixelDist;
1580-
width = height; //width can be set to arbitrary value
1637+
width = outputPixelInterval > 0 ? outputPixelInterval : height;
1638+
}
1639+
else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
1640+
{
1641+
width = outputPixelDist;
1642+
height = outputPixelInterval > 0 ? outputPixelInterval : width;
15811643
}
15821644
else
15831645
{
@@ -1598,36 +1660,18 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
15981660
double dx = 0;
15991661
double dy = 0;
16001662

1601-
// To get all patterns into image, we have to consider symbols size (estimateMaxBleed())
1602-
1603-
double bleed = 0;
1604-
for ( int i = 0; i < mFillLineSymbol->symbolLayerCount(); i++ )
1605-
{
1606-
QgsSymbolLayerV2 *layer = mFillLineSymbol->symbolLayer( i );
1607-
double layerBleed = layer->estimateMaxBleed();
1608-
// TODO: to get real bleed we have to scale it using context and units,
1609-
// unfortunately estimateMaxBleed() ignore units completely, e.g.
1610-
// QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
1611-
// offset regardless units. This has to be fixed especially
1612-
// in estimateMaxBleed(), context probably has to be used.
1613-
// For now, we only support milimeters
1614-
double outputPixelBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
1615-
1616-
bleed = qMax( bleed, outputPixelBleed );
1617-
}
1618-
16191663
// Add buffer based on bleed but keep precisely the height/width ratio (angle)
16201664
// thus we add integer multiplications of width and heigh covering the bleed
1621-
int bufferMulti = qMax( qCeil( bleed / width ), qCeil( bleed / width ) );
1665+
int bufferMulti = qMax( qCeil( outputPixelBleed / width ), qCeil( outputPixelBleed / width ) );
16221666

16231667
// Always buffer at least once so that center of line marker in upper right corner
16241668
// does not fall outside due to representation error
16251669
bufferMulti = qMax( bufferMulti, 1 );
16261670

1627-
bufferMulti = 0;
16281671
int xBuffer = width * bufferMulti;
16291672
int yBuffer = height * bufferMulti;
1630-
1673+
int innerWidth = width;
1674+
int innerHeight = height;
16311675
width += 2 * xBuffer;
16321676
height += 2 * yBuffer;
16331677

@@ -1642,21 +1686,17 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
16421686
QPointF p1, p2, p3, p4, p5, p6;
16431687
if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
16441688
{
1645-
p1 = QPointF( 0, height );
1646-
p2 = QPointF( width, height );
1647-
p3 = QPointF( 0, 0 );
1648-
p4 = QPointF( width, 0 );
1649-
p5 = QPointF( 0, 2 * height );
1650-
p6 = QPointF( width, 2 * height );
1689+
p1 = QPointF( 0, yBuffer );
1690+
p2 = QPointF( width, yBuffer );
1691+
p3 = QPointF( 0, yBuffer + innerHeight );
1692+
p4 = QPointF( width, yBuffer + innerHeight );
16511693
}
16521694
else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
16531695
{
1654-
p1 = QPointF( 0, height );
1655-
p2 = QPointF( 0, 0 );
1656-
p3 = QPointF( width, height );
1657-
p4 = QPointF( width, 0 );
1658-
p5 = QPointF( -width, height );
1659-
p6 = QPointF( -width, 0 );
1696+
p1 = QPointF( xBuffer, height );
1697+
p2 = QPointF( xBuffer, 0 );
1698+
p3 = QPointF( xBuffer + innerWidth, height );
1699+
p4 = QPointF( xBuffer + innerWidth, 0 );
16601700
}
16611701
else if (( lineAngle > 0 && lineAngle < 90 ) || ( lineAngle > 180 && lineAngle < 270 ) )
16621702
{
@@ -1733,18 +1773,22 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
17331773
lineRenderContext.setMapToPixel( mtp );
17341774
lineRenderContext.setForceVectorOutput( false );
17351775

1736-
mFillLineSymbol->startRender( lineRenderContext );
1776+
fillLineSymbol->startRender( lineRenderContext );
17371777

17381778
QVector<QPolygonF> polygons;
17391779
polygons.append( QPolygonF() << p1 << p2 );
17401780
polygons.append( QPolygonF() << p3 << p4 );
1741-
polygons.append( QPolygonF() << p5 << p6 );
1781+
if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
1782+
{
1783+
polygons.append( QPolygonF() << p5 << p6 );
1784+
}
1785+
17421786
foreach ( QPolygonF polygon, polygons )
17431787
{
1744-
mFillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
1788+
fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
17451789
}
17461790

1747-
mFillLineSymbol->stopRender( lineRenderContext );
1791+
fillLineSymbol->stopRender( lineRenderContext );
17481792
p.end();
17491793

17501794
// Cut off the buffer
@@ -1765,6 +1809,8 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
17651809
QTransform brushTransform;
17661810
brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
17671811
brush.setTransform( brushTransform );
1812+
1813+
delete fillLineSymbol;
17681814
}
17691815

17701816
void QgsLinePatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context )

1 commit comments

Comments
 (1)

pcav commented on Mar 7, 2014

@pcav
Member

Work done for Regione Toscana - SITA (CIG ZB10C90E5A)

Please sign in to comment.