Skip to content

Commit 9e80e25

Browse files
author
Sandro Santilli
committedNov 13, 2015
[BUGFIX] Fix endpoint swap on negative marker line offset
Fixes #13811 Includes testcase (cherr-picked from 824fd7b)
1 parent c3572eb commit 9e80e25

File tree

5 files changed

+444
-1
lines changed

5 files changed

+444
-1
lines changed
 

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,11 @@ QList<QPolygonF> offsetLine( QPolygonF polyline, double dist, QGis::GeometryType
750750

751751
if ( QGis::flatType( tempGeometry->wkbType() ) == QGis::WKBLineString )
752752
{
753-
resultLine.append( makeOffsetGeometry( tempGeometry->asPolyline() ) );
753+
QgsPolyline line = tempGeometry->asPolyline();
754+
// Reverse the line if offset was negative, see
755+
// http://hub.qgis.org/issues/13811
756+
if ( dist < 0 ) std::reverse(line.begin(), line.end() );
757+
resultLine.append( makeOffsetGeometry( line ) );
754758
delete tempGeometry;
755759
return resultLine;
756760
}

‎tests/src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ ADD_QGIS_TEST(colorscheme testqgscolorscheme.cpp)
142142
ADD_QGIS_TEST(maptopixeltest testqgsmaptopixel.cpp)
143143
ADD_QGIS_TEST(maprotationtest testqgsmaprotation.cpp)
144144
ADD_QGIS_TEST(mapsettingstest testqgsmapsettings.cpp)
145+
ADD_QGIS_TEST(markerlinessymboltest testqgsmarkerlinesymbol.cpp)
145146
ADD_QGIS_TEST(networkcontentfetcher testqgsnetworkcontentfetcher.cpp )
146147
ADD_QGIS_TEST(legendrenderertest testqgslegendrenderer.cpp )
147148
ADD_QGIS_TEST(vectorlayerjoinbuffer testqgsvectorlayerjoinbuffer.cpp )
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/***************************************************************************
2+
testqgsmarkerlinesymbol.cpp
3+
--------------------------------------
4+
Date : Nov 12 2015
5+
Copyright : (C) 2015 by Sandro Santilli
6+
Email : strk@keybit.net
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include <QtTest/QtTest>
16+
#include <QObject>
17+
#include <QString>
18+
#include <QStringList>
19+
#include <QApplication>
20+
#include <QFileInfo>
21+
#include <QDir>
22+
23+
//qgis includes...
24+
#include "qgsrasterlayer.h"
25+
#include "qgsvectorlayer.h"
26+
#include "qgsmultibandcolorrenderer.h"
27+
#include "qgsmaplayerregistry.h"
28+
#include "qgsapplication.h"
29+
#include "qgsmaprenderer.h"
30+
#include "qgspallabeling.h"
31+
#include "qgsfontutils.h"
32+
33+
//qgis unit test includes
34+
#include <qgsrenderchecker.h>
35+
36+
/** \ingroup UnitTests
37+
* This is a unit test for the Marker Line symbol
38+
*/
39+
class TestQgsMarkerLineSymbol : public QObject
40+
{
41+
Q_OBJECT
42+
public:
43+
TestQgsMarkerLineSymbol()
44+
: mLinesLayer( 0 )
45+
, mMapSettings( 0 )
46+
{
47+
mTestDataDir = QString( TEST_DATA_DIR ) + '/';
48+
}
49+
50+
~TestQgsMarkerLineSymbol();
51+
52+
private slots:
53+
void initTestCase();// will be called before the first testfunction is executed.
54+
void cleanupTestCase();// will be called after the last testfunction was executed.
55+
void init() {} // will be called before each testfunction is executed.
56+
void cleanup() {} // will be called after every testfunction.
57+
58+
void lineOffset();
59+
60+
private:
61+
bool render( const QString& theFileName );
62+
63+
QString mTestDataDir;
64+
QgsVectorLayer* mLinesLayer;
65+
QgsMapSettings *mMapSettings;
66+
QString mReport;
67+
};
68+
69+
//runs before all tests
70+
void TestQgsMarkerLineSymbol::initTestCase()
71+
{
72+
// init QGIS's paths - true means that all path will be inited from prefix
73+
QgsApplication::init();
74+
QgsApplication::initQgis();
75+
76+
mMapSettings = new QgsMapSettings();
77+
78+
QList<QgsMapLayer *> mapLayers;
79+
80+
//create a line layer that will be used in all tests...
81+
QString myLinesFileName = mTestDataDir + "lines_cardinals.shp";
82+
QFileInfo myLinesFileInfo( myLinesFileName );
83+
mLinesLayer = new QgsVectorLayer( myLinesFileInfo.filePath(),
84+
myLinesFileInfo.completeBaseName(), "ogr" );
85+
mapLayers << mLinesLayer;
86+
87+
// Register all layers with the registry
88+
QgsMapLayerRegistry::instance()->addMapLayers( mapLayers );
89+
90+
// This is needed to correctly set rotation center,
91+
// the actual size doesn't matter as QgsRenderChecker will
92+
// re-set it to the size of the expected image
93+
mMapSettings->setOutputSize( QSize( 256, 256 ) );
94+
95+
mReport += "<h1>Line Marker Symbol Tests</h1>\n";
96+
97+
QgsFontUtils::loadStandardTestFonts( QStringList() << "Bold" );
98+
}
99+
100+
TestQgsMarkerLineSymbol::~TestQgsMarkerLineSymbol()
101+
{
102+
103+
}
104+
105+
//runs after all tests
106+
void TestQgsMarkerLineSymbol::cleanupTestCase()
107+
{
108+
delete mMapSettings;
109+
QgsApplication::exitQgis();
110+
111+
QString myReportFile = QDir::tempPath() + "/qgistest.html";
112+
QFile myFile( myReportFile );
113+
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
114+
{
115+
QTextStream myQTextStream( &myFile );
116+
myQTextStream << mReport;
117+
myFile.close();
118+
}
119+
}
120+
121+
void TestQgsMarkerLineSymbol::lineOffset()
122+
{
123+
mMapSettings->setLayers( QStringList() << mLinesLayer->id() );
124+
125+
// Negative offset on marker line
126+
// See http://hub.qgis.org/issues/13811
127+
128+
QString qml = mTestDataDir + "marker_line_offset.qml";
129+
bool success = false;
130+
mLinesLayer->loadNamedStyle( qml, success );
131+
132+
QVERIFY( success );
133+
mMapSettings->setExtent( QgsRectangle(-140,-140,140,140) );
134+
QVERIFY( render( "line_offset" ) );
135+
136+
// TODO: -0.0 offset, see
137+
// http://hub.qgis.org/issues/13811#note-1
138+
}
139+
140+
bool TestQgsMarkerLineSymbol::render( const QString& theTestType )
141+
{
142+
mReport += "<h2>" + theTestType + "</h2>\n";
143+
mMapSettings->setOutputDpi( 96 );
144+
QgsRenderChecker checker;
145+
checker.setControlPathPrefix( "markerlinesymbol" );
146+
checker.setControlName( "expected_" + theTestType );
147+
checker.setMapSettings( *mMapSettings );
148+
bool result = checker.runTest( theTestType );
149+
mReport += "\n\n\n" + checker.report();
150+
return result;
151+
}
152+
153+
QTEST_MAIN( TestQgsMarkerLineSymbol )
154+
#include "testqgsmarkerlinesymbol.moc"
Loading

‎tests/testdata/marker_line_offset.qml

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
2+
<qgis version="2.13.0-Master" minimumScale="1" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="1" maxLabelScale="1e+08" simplifyDrawingTol="1" simplifyMaxScale="1" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
3+
<renderer-v2 attr="LBL" forceraster="0" symbollevels="0" type="categorizedSymbol">
4+
<categories>
5+
<category render="true" symbol="0" value="East" label="East"/>
6+
<category render="true" symbol="1" value="North" label="North"/>
7+
<category render="true" symbol="2" value="West" label="West"/>
8+
<category render="true" symbol="3" value="South" label="South"/>
9+
</categories>
10+
<symbols>
11+
<symbol alpha="1" clip_to_extent="1" type="line" name="0">
12+
<layer pass="0" class="SimpleLine" locked="0">
13+
<prop k="capstyle" v="square"/>
14+
<prop k="customdash" v="5;2"/>
15+
<prop k="customdash_map_unit_scale" v="0,0,0,0,0,0"/>
16+
<prop k="customdash_unit" v="MM"/>
17+
<prop k="draw_inside_polygon" v="0"/>
18+
<prop k="joinstyle" v="bevel"/>
19+
<prop k="line_color" v="203,16,23,255"/>
20+
<prop k="line_style" v="solid"/>
21+
<prop k="line_width" v="1.2"/>
22+
<prop k="line_width_unit" v="MM"/>
23+
<prop k="offset" v="0"/>
24+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
25+
<prop k="offset_unit" v="MM"/>
26+
<prop k="use_custom_dash" v="0"/>
27+
<prop k="width_map_unit_scale" v="0,0,0,0,0,0"/>
28+
</layer>
29+
<layer pass="0" class="MarkerLine" locked="0">
30+
<prop k="interval" v="3"/>
31+
<prop k="interval_map_unit_scale" v="0,0,0,0,0,0"/>
32+
<prop k="interval_unit" v="MM"/>
33+
<prop k="offset" v="3"/>
34+
<prop k="offset_along_line" v="0"/>
35+
<prop k="offset_along_line_map_unit_scale" v="0,0,0,0,0,0"/>
36+
<prop k="offset_along_line_unit" v="MM"/>
37+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
38+
<prop k="offset_unit" v="MM"/>
39+
<prop k="placement" v="lastvertex"/>
40+
<prop k="rotate" v="1"/>
41+
<symbol alpha="1" clip_to_extent="1" type="marker" name="@0@1">
42+
<layer pass="0" class="SimpleMarker" locked="0">
43+
<prop k="angle" v="0"/>
44+
<prop k="color" v="203,16,23,255"/>
45+
<prop k="horizontal_anchor_point" v="1"/>
46+
<prop k="name" v="filled_arrowhead"/>
47+
<prop k="offset" v="2,0"/>
48+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
49+
<prop k="offset_unit" v="MM"/>
50+
<prop k="outline_color" v="0,0,0,0"/>
51+
<prop k="outline_style" v="solid"/>
52+
<prop k="outline_width" v="0"/>
53+
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
54+
<prop k="outline_width_unit" v="MM"/>
55+
<prop k="scale_method" v="area"/>
56+
<prop k="size" v="7"/>
57+
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
58+
<prop k="size_unit" v="MM"/>
59+
<prop k="vertical_anchor_point" v="1"/>
60+
</layer>
61+
</symbol>
62+
</layer>
63+
</symbol>
64+
<symbol alpha="1" clip_to_extent="1" type="line" name="1">
65+
<layer pass="0" class="SimpleLine" locked="0">
66+
<prop k="capstyle" v="square"/>
67+
<prop k="customdash" v="5;2"/>
68+
<prop k="customdash_map_unit_scale" v="0,0,0,0,0,0"/>
69+
<prop k="customdash_unit" v="MM"/>
70+
<prop k="draw_inside_polygon" v="0"/>
71+
<prop k="joinstyle" v="bevel"/>
72+
<prop k="line_color" v="0,0,0,255"/>
73+
<prop k="line_style" v="solid"/>
74+
<prop k="line_width" v="1.2"/>
75+
<prop k="line_width_unit" v="MM"/>
76+
<prop k="offset" v="0"/>
77+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
78+
<prop k="offset_unit" v="MM"/>
79+
<prop k="use_custom_dash" v="0"/>
80+
<prop k="width_map_unit_scale" v="0,0,0,0,0,0"/>
81+
</layer>
82+
<layer pass="0" class="MarkerLine" locked="0">
83+
<prop k="interval" v="3"/>
84+
<prop k="interval_map_unit_scale" v="0,0,0,0,0,0"/>
85+
<prop k="interval_unit" v="MM"/>
86+
<prop k="offset" v="3"/>
87+
<prop k="offset_along_line" v="0"/>
88+
<prop k="offset_along_line_map_unit_scale" v="0,0,0,0,0,0"/>
89+
<prop k="offset_along_line_unit" v="MM"/>
90+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
91+
<prop k="offset_unit" v="MM"/>
92+
<prop k="placement" v="lastvertex"/>
93+
<prop k="rotate" v="1"/>
94+
<symbol alpha="1" clip_to_extent="1" type="marker" name="@1@1">
95+
<layer pass="0" class="SimpleMarker" locked="0">
96+
<prop k="angle" v="0"/>
97+
<prop k="color" v="0,0,0,255"/>
98+
<prop k="horizontal_anchor_point" v="1"/>
99+
<prop k="name" v="filled_arrowhead"/>
100+
<prop k="offset" v="2,0"/>
101+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
102+
<prop k="offset_unit" v="MM"/>
103+
<prop k="outline_color" v="0,0,0,0"/>
104+
<prop k="outline_style" v="solid"/>
105+
<prop k="outline_width" v="0"/>
106+
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
107+
<prop k="outline_width_unit" v="MM"/>
108+
<prop k="scale_method" v="area"/>
109+
<prop k="size" v="7"/>
110+
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
111+
<prop k="size_unit" v="MM"/>
112+
<prop k="vertical_anchor_point" v="1"/>
113+
</layer>
114+
</symbol>
115+
</layer>
116+
</symbol>
117+
<symbol alpha="1" clip_to_extent="1" type="line" name="2">
118+
<layer pass="0" class="SimpleLine" locked="0">
119+
<prop k="capstyle" v="square"/>
120+
<prop k="customdash" v="5;2"/>
121+
<prop k="customdash_map_unit_scale" v="0,0,0,0,0,0"/>
122+
<prop k="customdash_unit" v="MM"/>
123+
<prop k="draw_inside_polygon" v="0"/>
124+
<prop k="joinstyle" v="bevel"/>
125+
<prop k="line_color" v="203,16,23,255"/>
126+
<prop k="line_style" v="solid"/>
127+
<prop k="line_width" v="1.2"/>
128+
<prop k="line_width_unit" v="MM"/>
129+
<prop k="offset" v="0"/>
130+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
131+
<prop k="offset_unit" v="MM"/>
132+
<prop k="use_custom_dash" v="0"/>
133+
<prop k="width_map_unit_scale" v="0,0,0,0,0,0"/>
134+
</layer>
135+
<layer pass="0" class="MarkerLine" locked="0">
136+
<prop k="interval" v="3"/>
137+
<prop k="interval_map_unit_scale" v="0,0,0,0,0,0"/>
138+
<prop k="interval_unit" v="MM"/>
139+
<prop k="offset" v="-3"/>
140+
<prop k="offset_along_line" v="0"/>
141+
<prop k="offset_along_line_map_unit_scale" v="0,0,0,0,0,0"/>
142+
<prop k="offset_along_line_unit" v="MM"/>
143+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
144+
<prop k="offset_unit" v="MM"/>
145+
<prop k="placement" v="lastvertex"/>
146+
<prop k="rotate" v="1"/>
147+
<symbol alpha="1" clip_to_extent="1" type="marker" name="@2@1">
148+
<layer pass="0" class="SimpleMarker" locked="0">
149+
<prop k="angle" v="0"/>
150+
<prop k="color" v="203,16,23,255"/>
151+
<prop k="horizontal_anchor_point" v="1"/>
152+
<prop k="name" v="filled_arrowhead"/>
153+
<prop k="offset" v="2,0"/>
154+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
155+
<prop k="offset_unit" v="MM"/>
156+
<prop k="outline_color" v="0,0,0,0"/>
157+
<prop k="outline_style" v="solid"/>
158+
<prop k="outline_width" v="0"/>
159+
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
160+
<prop k="outline_width_unit" v="MM"/>
161+
<prop k="scale_method" v="area"/>
162+
<prop k="size" v="7"/>
163+
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
164+
<prop k="size_unit" v="MM"/>
165+
<prop k="vertical_anchor_point" v="1"/>
166+
</layer>
167+
</symbol>
168+
</layer>
169+
</symbol>
170+
<symbol alpha="1" clip_to_extent="1" type="line" name="3">
171+
<layer pass="0" class="SimpleLine" locked="0">
172+
<prop k="capstyle" v="square"/>
173+
<prop k="customdash" v="5;2"/>
174+
<prop k="customdash_map_unit_scale" v="0,0,0,0,0,0"/>
175+
<prop k="customdash_unit" v="MM"/>
176+
<prop k="draw_inside_polygon" v="0"/>
177+
<prop k="joinstyle" v="bevel"/>
178+
<prop k="line_color" v="0,0,0,255"/>
179+
<prop k="line_style" v="solid"/>
180+
<prop k="line_width" v="1.2"/>
181+
<prop k="line_width_unit" v="MM"/>
182+
<prop k="offset" v="0"/>
183+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
184+
<prop k="offset_unit" v="MM"/>
185+
<prop k="use_custom_dash" v="0"/>
186+
<prop k="width_map_unit_scale" v="0,0,0,0,0,0"/>
187+
</layer>
188+
<layer pass="0" class="MarkerLine" locked="0">
189+
<prop k="interval" v="3"/>
190+
<prop k="interval_map_unit_scale" v="0,0,0,0,0,0"/>
191+
<prop k="interval_unit" v="MM"/>
192+
<prop k="offset" v="-3"/>
193+
<prop k="offset_along_line" v="0"/>
194+
<prop k="offset_along_line_map_unit_scale" v="0,0,0,0,0,0"/>
195+
<prop k="offset_along_line_unit" v="MM"/>
196+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
197+
<prop k="offset_unit" v="MM"/>
198+
<prop k="placement" v="lastvertex"/>
199+
<prop k="rotate" v="1"/>
200+
<symbol alpha="1" clip_to_extent="1" type="marker" name="@3@1">
201+
<layer pass="0" class="SimpleMarker" locked="0">
202+
<prop k="angle" v="0"/>
203+
<prop k="color" v="0,0,0,255"/>
204+
<prop k="horizontal_anchor_point" v="1"/>
205+
<prop k="name" v="filled_arrowhead"/>
206+
<prop k="offset" v="2,0"/>
207+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
208+
<prop k="offset_unit" v="MM"/>
209+
<prop k="outline_color" v="0,0,0,0"/>
210+
<prop k="outline_style" v="solid"/>
211+
<prop k="outline_width" v="0"/>
212+
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
213+
<prop k="outline_width_unit" v="MM"/>
214+
<prop k="scale_method" v="area"/>
215+
<prop k="size" v="7"/>
216+
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
217+
<prop k="size_unit" v="MM"/>
218+
<prop k="vertical_anchor_point" v="1"/>
219+
</layer>
220+
</symbol>
221+
</layer>
222+
</symbol>
223+
</symbols>
224+
<source-symbol>
225+
<symbol alpha="1" clip_to_extent="1" type="line" name="0">
226+
<layer pass="0" class="SimpleLine" locked="0">
227+
<prop k="capstyle" v="square"/>
228+
<prop k="customdash" v="5;2"/>
229+
<prop k="customdash_map_unit_scale" v="0,0,0,0,0,0"/>
230+
<prop k="customdash_unit" v="MM"/>
231+
<prop k="draw_inside_polygon" v="0"/>
232+
<prop k="joinstyle" v="bevel"/>
233+
<prop k="line_color" v="0,0,0,255"/>
234+
<prop k="line_style" v="solid"/>
235+
<prop k="line_width" v="1.2"/>
236+
<prop k="line_width_unit" v="MM"/>
237+
<prop k="offset" v="0"/>
238+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
239+
<prop k="offset_unit" v="MM"/>
240+
<prop k="use_custom_dash" v="0"/>
241+
<prop k="width_map_unit_scale" v="0,0,0,0,0,0"/>
242+
</layer>
243+
<layer pass="0" class="MarkerLine" locked="0">
244+
<prop k="interval" v="3"/>
245+
<prop k="interval_map_unit_scale" v="0,0,0,0,0,0"/>
246+
<prop k="interval_unit" v="MM"/>
247+
<prop k="offset" v="-3"/>
248+
<prop k="offset_along_line" v="0"/>
249+
<prop k="offset_along_line_map_unit_scale" v="0,0,0,0,0,0"/>
250+
<prop k="offset_along_line_unit" v="MM"/>
251+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
252+
<prop k="offset_unit" v="MM"/>
253+
<prop k="placement" v="lastvertex"/>
254+
<prop k="rotate" v="1"/>
255+
<symbol alpha="1" clip_to_extent="1" type="marker" name="@0@1">
256+
<layer pass="0" class="SimpleMarker" locked="0">
257+
<prop k="angle" v="0"/>
258+
<prop k="color" v="0,0,0,255"/>
259+
<prop k="horizontal_anchor_point" v="1"/>
260+
<prop k="name" v="filled_arrowhead"/>
261+
<prop k="offset" v="2,0"/>
262+
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
263+
<prop k="offset_unit" v="MM"/>
264+
<prop k="outline_color" v="0,0,0,255"/>
265+
<prop k="outline_style" v="solid"/>
266+
<prop k="outline_width" v="0"/>
267+
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
268+
<prop k="outline_width_unit" v="MM"/>
269+
<prop k="scale_method" v="area"/>
270+
<prop k="size" v="7"/>
271+
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
272+
<prop k="size_unit" v="MM"/>
273+
<prop k="vertical_anchor_point" v="1"/>
274+
</layer>
275+
</symbol>
276+
</layer>
277+
</symbol>
278+
</source-symbol>
279+
<colorramp type="randomcolors" name="[source]"/>
280+
<invertedcolorramp value="0"/>
281+
<rotation/>
282+
<sizescale scalemethod="diameter"/>
283+
</renderer-v2>
284+
</qgis>

0 commit comments

Comments
 (0)
Please sign in to comment.