13
13
* *
14
14
***************************************************************************/
15
15
#include " qgsfillsymbollayerv2.h"
16
+ #include " qgslinesymbollayerv2.h"
16
17
#include " qgsmarkersymbollayerv2.h"
17
18
#include " qgssymbollayerv2utils.h"
18
19
#include " qgsdxfexport.h"
@@ -1566,18 +1567,79 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
1566
1567
{
1567
1568
return ;
1568
1569
}
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
+ }
1569
1576
1570
1577
const QgsRenderContext& ctx = context.renderContext ();
1571
1578
// double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit );
1572
1579
double outputPixelDist = distance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor ( ctx, mDistanceUnit );
1573
1580
double outputPixelOffset = mOffset * QgsSymbolLayerV2Utils::pixelSizeScaleFactor ( ctx, mOffsetUnit );
1574
1581
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
+
1575
1632
// create image
1576
1633
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 ) )
1578
1635
{
1579
1636
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;
1581
1643
}
1582
1644
else
1583
1645
{
@@ -1598,36 +1660,18 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
1598
1660
double dx = 0 ;
1599
1661
double dy = 0 ;
1600
1662
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
-
1619
1663
// Add buffer based on bleed but keep precisely the height/width ratio (angle)
1620
1664
// 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 ) );
1622
1666
1623
1667
// Always buffer at least once so that center of line marker in upper right corner
1624
1668
// does not fall outside due to representation error
1625
1669
bufferMulti = qMax ( bufferMulti, 1 );
1626
1670
1627
- bufferMulti = 0 ;
1628
1671
int xBuffer = width * bufferMulti;
1629
1672
int yBuffer = height * bufferMulti;
1630
-
1673
+ int innerWidth = width;
1674
+ int innerHeight = height;
1631
1675
width += 2 * xBuffer;
1632
1676
height += 2 * yBuffer;
1633
1677
@@ -1642,21 +1686,17 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
1642
1686
QPointF p1, p2, p3, p4, p5, p6;
1643
1687
if ( qgsDoubleNear ( lineAngle, 0.0 ) || qgsDoubleNear ( lineAngle, 360.0 ) || qgsDoubleNear ( lineAngle, 180.0 ) )
1644
1688
{
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 );
1651
1693
}
1652
1694
else if ( qgsDoubleNear ( lineAngle, 90.0 ) || qgsDoubleNear ( lineAngle, 270.0 ) )
1653
1695
{
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 );
1660
1700
}
1661
1701
else if (( lineAngle > 0 && lineAngle < 90 ) || ( lineAngle > 180 && lineAngle < 270 ) )
1662
1702
{
@@ -1733,18 +1773,22 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
1733
1773
lineRenderContext.setMapToPixel ( mtp );
1734
1774
lineRenderContext.setForceVectorOutput ( false );
1735
1775
1736
- mFillLineSymbol ->startRender ( lineRenderContext );
1776
+ fillLineSymbol ->startRender ( lineRenderContext );
1737
1777
1738
1778
QVector<QPolygonF> polygons;
1739
1779
polygons.append ( QPolygonF () << p1 << p2 );
1740
1780
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
+
1742
1786
foreach ( QPolygonF polygon, polygons )
1743
1787
{
1744
- mFillLineSymbol ->renderPolyline ( polygon, context.feature (), lineRenderContext, -1 , context.selected () );
1788
+ fillLineSymbol ->renderPolyline ( polygon, context.feature (), lineRenderContext, -1 , context.selected () );
1745
1789
}
1746
1790
1747
- mFillLineSymbol ->stopRender ( lineRenderContext );
1791
+ fillLineSymbol ->stopRender ( lineRenderContext );
1748
1792
p.end ();
1749
1793
1750
1794
// Cut off the buffer
@@ -1765,6 +1809,8 @@ void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext
1765
1809
QTransform brushTransform;
1766
1810
brushTransform.scale ( 1.0 / context.renderContext ().rasterScaleFactor (), 1.0 / context.renderContext ().rasterScaleFactor () );
1767
1811
brush.setTransform ( brushTransform );
1812
+
1813
+ delete fillLineSymbol;
1768
1814
}
1769
1815
1770
1816
void QgsLinePatternFillSymbolLayer::startRender ( QgsSymbolV2RenderContext& context )
1 commit comments
pcav commentedon Mar 7, 2014
Work done for Regione Toscana - SITA (CIG ZB10C90E5A)