1# -*- coding: utf-8 -*- 2 3""" 4*************************************************************************** 5 test_qgsmarkerlinesymbollayer.py 6 --------------------- 7 Date : November 2018 8 Copyright : (C) 2018 by Nyall Dawson 9 Email : nyall dot dawson at gmail dot com 10*************************************************************************** 11* * 12* This program is free software; you can redistribute it and/or modify * 13* it under the terms of the GNU General Public License as published by * 14* the Free Software Foundation; either version 2 of the License, or * 15* (at your option) any later version. * 16* * 17*************************************************************************** 18""" 19 20__author__ = 'Nyall Dawson' 21__date__ = 'November 2018' 22__copyright__ = '(C) 2018, Nyall Dawson' 23 24import qgis # NOQA 25 26import os 27from utilities import unitTestDataPath 28 29from qgis.PyQt.QtCore import QDir, Qt, QSize 30from qgis.PyQt.QtGui import QImage, QColor, QPainter 31from qgis.PyQt.QtXml import QDomDocument 32 33from qgis.core import (QgsGeometry, 34 QgsFillSymbol, 35 QgsRenderContext, 36 QgsFeature, 37 QgsMapSettings, 38 QgsRenderChecker, 39 QgsVectorLayer, 40 QgsReadWriteContext, 41 QgsSymbolLayerUtils, 42 QgsSimpleMarkerSymbolLayer, 43 QgsLineSymbolLayer, 44 QgsTemplatedLineSymbolLayerBase, 45 QgsMarkerLineSymbolLayer, 46 QgsMarkerSymbol, 47 QgsGeometryGeneratorSymbolLayer, 48 QgsSymbol, 49 QgsFontMarkerSymbolLayer, 50 QgsFontUtils, 51 QgsLineSymbol, 52 QgsSymbolLayer, 53 QgsProperty, 54 QgsRectangle, 55 QgsUnitTypes, 56 QgsMultiRenderChecker, 57 QgsSingleSymbolRenderer 58 ) 59 60from qgis.testing import unittest, start_app 61 62start_app() 63TEST_DATA_DIR = unitTestDataPath() 64 65 66class TestQgsMarkerLineSymbolLayer(unittest.TestCase): 67 68 def setUp(self): 69 self.report = "<h1>Python QgsMarkerLineSymbolLayer Tests</h1>\n" 70 71 def tearDown(self): 72 report_file_path = "%s/qgistest.html" % QDir.tempPath() 73 with open(report_file_path, 'a') as report_file: 74 report_file.write(self.report) 75 76 def testWidth(self): 77 ms = QgsMapSettings() 78 extent = QgsRectangle(100, 200, 100, 200) 79 ms.setExtent(extent) 80 ms.setOutputSize(QSize(400, 400)) 81 context = QgsRenderContext.fromMapSettings(ms) 82 context.setScaleFactor(96 / 25.4) # 96 DPI 83 ms.setExtent(QgsRectangle(100, 150, 100, 150)) 84 ms.setOutputDpi(ms.outputDpi() * 2) 85 context2 = QgsRenderContext.fromMapSettings(ms) 86 context2.setScaleFactor(300 / 25.4) 87 88 s = QgsFillSymbol() 89 s.deleteSymbolLayer(0) 90 91 marker_line = QgsMarkerLineSymbolLayer(True) 92 marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex) 93 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 10) 94 marker.setColor(QColor(255, 0, 0)) 95 marker.setStrokeStyle(Qt.NoPen) 96 marker_symbol = QgsMarkerSymbol() 97 marker_symbol.changeSymbolLayer(0, marker) 98 marker_line.setSubSymbol(marker_symbol) 99 100 self.assertEqual(marker_line.width(), 10) 101 self.assertAlmostEqual(marker_line.width(context), 37.795275590551185, 3) 102 self.assertAlmostEqual(marker_line.width(context2), 118.11023622047244, 3) 103 104 marker_line.subSymbol().setSizeUnit(QgsUnitTypes.RenderPixels) 105 self.assertAlmostEqual(marker_line.width(context), 10.0, 3) 106 self.assertAlmostEqual(marker_line.width(context2), 10.0, 3) 107 108 def testRingFilter(self): 109 # test filtering rings during rendering 110 s = QgsFillSymbol() 111 s.deleteSymbolLayer(0) 112 113 marker_line = QgsMarkerLineSymbolLayer(True) 114 marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex) 115 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 116 marker.setColor(QColor(255, 0, 0)) 117 marker.setStrokeStyle(Qt.NoPen) 118 marker_symbol = QgsMarkerSymbol() 119 marker_symbol.changeSymbolLayer(0, marker) 120 marker_line.setSubSymbol(marker_symbol) 121 122 s.appendSymbolLayer(marker_line.clone()) 123 self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.AllRings) 124 s.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.ExteriorRingOnly) 125 self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.ExteriorRingOnly) 126 127 s2 = s.clone() 128 self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.ExteriorRingOnly) 129 130 doc = QDomDocument() 131 context = QgsReadWriteContext() 132 element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) 133 134 s2 = QgsSymbolLayerUtils.loadSymbol(element, context) 135 self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.ExteriorRingOnly) 136 137 # rendering test 138 s3 = QgsFillSymbol() 139 s3.deleteSymbolLayer(0) 140 s3.appendSymbolLayer( 141 QgsMarkerLineSymbolLayer()) 142 s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.ExteriorRingOnly) 143 s3.symbolLayer(0).setAverageAngleLength(0) 144 145 g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') 146 rendered_image = self.renderGeometry(s3, g) 147 assert self.imageCheck('markerline_exterioronly', 'markerline_exterioronly', rendered_image) 148 149 s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.InteriorRingsOnly) 150 g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') 151 rendered_image = self.renderGeometry(s3, g) 152 assert self.imageCheck('markerline_interioronly', 'markerline_interioronly', rendered_image) 153 154 def testRingNumberVariable(self): 155 # test test geometry_ring_num variable 156 s3 = QgsFillSymbol() 157 s3.deleteSymbolLayer(0) 158 s3.appendSymbolLayer( 159 QgsMarkerLineSymbolLayer()) 160 s3.symbolLayer(0).subSymbol()[0].setDataDefinedProperty(QgsSymbolLayer.PropertyFillColor, 161 QgsProperty.fromExpression('case when @geometry_ring_num=0 then \'green\' when @geometry_ring_num=1 then \'blue\' when @geometry_ring_num=2 then \'red\' end')) 162 s3.symbolLayer(0).setAverageAngleLength(0) 163 164 g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') 165 rendered_image = self.renderGeometry(s3, g) 166 assert self.imageCheck('markerline_ring_num', 'markerline_ring_num', rendered_image) 167 168 def testPartNum(self): 169 # test geometry_part_num variable 170 s = QgsLineSymbol() 171 s.deleteSymbolLayer(0) 172 173 sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'segments_to_lines($geometry)'}) 174 sym_layer.setSymbolType(QgsSymbol.Line) 175 s.appendSymbolLayer(sym_layer) 176 177 marker_line = QgsMarkerLineSymbolLayer(False) 178 marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex) 179 f = QgsFontUtils.getStandardTestFont('Bold', 24) 180 marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0)) 181 marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num')) 182 marker_symbol = QgsMarkerSymbol() 183 marker_symbol.changeSymbolLayer(0, marker) 184 marker_line.setSubSymbol(marker_symbol) 185 marker_line.setAverageAngleLength(0) 186 line_symbol = QgsLineSymbol() 187 line_symbol.changeSymbolLayer(0, marker_line) 188 sym_layer.setSubSymbol(line_symbol) 189 190 # rendering test 191 g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') 192 rendered_image = self.renderGeometry(s, g, buffer=4) 193 assert self.imageCheck('part_num_variable', 'part_num_variable', rendered_image) 194 195 marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, 196 QgsProperty.fromExpression('@geometry_part_count')) 197 198 # rendering test 199 g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') 200 rendered_image = self.renderGeometry(s, g, buffer=4) 201 assert self.imageCheck('part_count_variable', 'part_count_variable', rendered_image) 202 203 def testPartNumPolygon(self): 204 # test geometry_part_num variable 205 s = QgsFillSymbol() 206 207 marker_line = QgsMarkerLineSymbolLayer(False) 208 marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex) 209 f = QgsFontUtils.getStandardTestFont('Bold', 24) 210 marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0)) 211 marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num')) 212 marker_symbol = QgsMarkerSymbol() 213 marker_symbol.changeSymbolLayer(0, marker) 214 marker_line.setSubSymbol(marker_symbol) 215 marker_line.setAverageAngleLength(0) 216 s.changeSymbolLayer(0, marker_line) 217 218 # rendering test - a polygon with a smaller part first 219 g = QgsGeometry.fromWkt('MultiPolygon(((0 0, 2 0, 2 2, 0 0)),((10 0, 10 10, 0 10, 10 0)))') 220 rendered_image = self.renderGeometry(s, g, buffer=4) 221 assert self.imageCheck('poly_part_num_variable', 'poly_part_num_variable', rendered_image) 222 223 def testCompoundCurve(self): 224 # test rendering compound curve with markers at vertices and curve points 225 s = QgsLineSymbol() 226 s.deleteSymbolLayer(0) 227 228 marker_line = QgsMarkerLineSymbolLayer(True) 229 marker_line.setPlacement(QgsMarkerLineSymbolLayer.Vertex) 230 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 231 marker.setColor(QColor(255, 0, 0)) 232 marker.setStrokeStyle(Qt.NoPen) 233 marker_symbol = QgsMarkerSymbol() 234 marker_symbol.changeSymbolLayer(0, marker) 235 marker_line.setSubSymbol(marker_symbol) 236 237 s.appendSymbolLayer(marker_line.clone()) 238 239 marker_line2 = QgsMarkerLineSymbolLayer(True) 240 marker_line2.setPlacement(QgsMarkerLineSymbolLayer.CurvePoint) 241 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Square, 4) 242 marker.setColor(QColor(0, 255, 0)) 243 marker.setStrokeStyle(Qt.NoPen) 244 marker_symbol = QgsMarkerSymbol() 245 marker_symbol.changeSymbolLayer(0, marker) 246 marker_line2.setSubSymbol(marker_symbol) 247 248 s.appendSymbolLayer(marker_line2.clone()) 249 250 # rendering test 251 g = QgsGeometry.fromWkt('CompoundCurve (CircularString (2606642.3863534671254456 1228883.61571401031687856, 2606656.45901552261784673 1228882.30281259422190487, 2606652.60236761253327131 1228873.80998155777342618, 2606643.65822671446949244 1228875.45110832806676626, 2606642.3863534671254456 1228883.65674217976629734))') 252 self.assertFalse(g.isNull()) 253 rendered_image = self.renderGeometry(s, g) 254 self.assertTrue(self.imageCheck('markerline_compoundcurve', 'markerline_compoundcurve', rendered_image)) 255 256 def testMultiCurve(self): 257 # test rendering multi curve with markers at vertices and curve points 258 s = QgsLineSymbol() 259 s.deleteSymbolLayer(0) 260 261 marker_line = QgsMarkerLineSymbolLayer(True) 262 marker_line.setPlacement(QgsMarkerLineSymbolLayer.Vertex) 263 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 264 marker.setColor(QColor(255, 0, 0)) 265 marker.setStrokeStyle(Qt.NoPen) 266 marker_symbol = QgsMarkerSymbol() 267 marker_symbol.changeSymbolLayer(0, marker) 268 marker_line.setSubSymbol(marker_symbol) 269 270 s.appendSymbolLayer(marker_line.clone()) 271 272 marker_line2 = QgsMarkerLineSymbolLayer(True) 273 marker_line2.setPlacement(QgsMarkerLineSymbolLayer.CurvePoint) 274 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Square, 4) 275 marker.setColor(QColor(0, 255, 0)) 276 marker.setStrokeStyle(Qt.NoPen) 277 marker_symbol = QgsMarkerSymbol() 278 marker_symbol.changeSymbolLayer(0, marker) 279 marker_line2.setSubSymbol(marker_symbol) 280 281 s.appendSymbolLayer(marker_line2.clone()) 282 283 # rendering test 284 g = QgsGeometry.fromWkt('MultiCurve (CompoundCurve (CircularString (2606668.74491960229352117 1228910.0701227153185755, 2606667.84593895543366671 1228899.48981202743016183, 2606678.70285907341167331 1228879.78139015776105225, 2606701.64743852475658059 1228866.43043032777495682, 2606724.96578619908541441 1228864.70617623627185822)),LineString (2606694.16802780656144023 1228913.44624055083841085, 2606716.84054400492459536 1228890.51009044284000993, 2606752.43112175865098834 1228906.59175890940241516))') 285 self.assertFalse(g.isNull()) 286 rendered_image = self.renderGeometry(s, g) 287 self.assertTrue(self.imageCheck('markerline_multicurve', 'markerline_multicurve', rendered_image)) 288 289 def testCurvePolygon(self): 290 # test rendering curve polygon with markers at vertices and curve points 291 s = QgsFillSymbol() 292 s.deleteSymbolLayer(0) 293 294 marker_line = QgsMarkerLineSymbolLayer(True) 295 marker_line.setPlacement(QgsMarkerLineSymbolLayer.Vertex) 296 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 297 marker.setColor(QColor(255, 0, 0)) 298 marker.setStrokeStyle(Qt.NoPen) 299 marker_symbol = QgsMarkerSymbol() 300 marker_symbol.changeSymbolLayer(0, marker) 301 marker_line.setSubSymbol(marker_symbol) 302 303 s.appendSymbolLayer(marker_line.clone()) 304 305 marker_line2 = QgsMarkerLineSymbolLayer(True) 306 marker_line2.setPlacement(QgsMarkerLineSymbolLayer.CurvePoint) 307 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Square, 4) 308 marker.setColor(QColor(0, 255, 0)) 309 marker.setStrokeStyle(Qt.NoPen) 310 marker_symbol = QgsMarkerSymbol() 311 marker_symbol.changeSymbolLayer(0, marker) 312 marker_line2.setSubSymbol(marker_symbol) 313 314 s.appendSymbolLayer(marker_line2.clone()) 315 316 # rendering test 317 g = QgsGeometry.fromWkt('CurvePolygon (CompoundCurve (CircularString (2606711.1353147104382515 1228875.77055342611856759, 2606715.00784672703593969 1228870.79158369055949152, 2606721.16240653907880187 1228873.35022091586142778),(2606721.16240653907880187 1228873.35022091586142778, 2606711.1353147104382515 1228875.77055342611856759)))') 318 self.assertFalse(g.isNull()) 319 rendered_image = self.renderGeometry(s, g) 320 self.assertTrue(self.imageCheck('markerline_curvepolygon', 'markerline_curvepolygon', rendered_image)) 321 322 def testMultiSurve(self): 323 # test rendering multisurface with markers at vertices and curve points 324 s = QgsFillSymbol() 325 s.deleteSymbolLayer(0) 326 327 marker_line = QgsMarkerLineSymbolLayer(True) 328 marker_line.setPlacement(QgsMarkerLineSymbolLayer.Vertex) 329 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 330 marker.setColor(QColor(255, 0, 0)) 331 marker.setStrokeStyle(Qt.NoPen) 332 marker_symbol = QgsMarkerSymbol() 333 marker_symbol.changeSymbolLayer(0, marker) 334 marker_line.setSubSymbol(marker_symbol) 335 336 s.appendSymbolLayer(marker_line.clone()) 337 338 marker_line2 = QgsMarkerLineSymbolLayer(True) 339 marker_line2.setPlacement(QgsMarkerLineSymbolLayer.CurvePoint) 340 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Square, 4) 341 marker.setColor(QColor(0, 255, 0)) 342 marker.setStrokeStyle(Qt.NoPen) 343 marker_symbol = QgsMarkerSymbol() 344 marker_symbol.changeSymbolLayer(0, marker) 345 marker_line2.setSubSymbol(marker_symbol) 346 347 s.appendSymbolLayer(marker_line2.clone()) 348 349 # rendering test 350 g = QgsGeometry.fromWkt('MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))),Polygon ((2606677.23432376980781555 1228875.74241803237237036, 2606674.27243852382525802 1228874.75512295053340495, 2606675.61874999897554517 1228871.97274590120650828, 2606678.84989754017442465 1228870.35717213083989918, 2606680.64497950719669461 1228873.31905737658962607, 2606677.23432376980781555 1228875.74241803237237036)))') 351 self.assertFalse(g.isNull()) 352 rendered_image = self.renderGeometry(s, g) 353 self.assertTrue(self.imageCheck('markerline_multisurface', 'markerline_multisurface', rendered_image)) 354 355 def testMultiSurfaceOnePart(self): 356 # test rendering multisurface with one part with markers at vertices and curve points 357 s = QgsFillSymbol() 358 s.deleteSymbolLayer(0) 359 360 marker_line = QgsMarkerLineSymbolLayer(True) 361 marker_line.setPlacement(QgsMarkerLineSymbolLayer.Vertex) 362 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 363 marker.setColor(QColor(255, 0, 0)) 364 marker.setStrokeStyle(Qt.NoPen) 365 marker_symbol = QgsMarkerSymbol() 366 marker_symbol.changeSymbolLayer(0, marker) 367 marker_line.setSubSymbol(marker_symbol) 368 369 s.appendSymbolLayer(marker_line.clone()) 370 371 marker_line2 = QgsMarkerLineSymbolLayer(True) 372 marker_line2.setPlacement(QgsMarkerLineSymbolLayer.CurvePoint) 373 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Square, 4) 374 marker.setColor(QColor(0, 255, 0)) 375 marker.setStrokeStyle(Qt.NoPen) 376 marker_symbol = QgsMarkerSymbol() 377 marker_symbol.changeSymbolLayer(0, marker) 378 marker_line2.setSubSymbol(marker_symbol) 379 380 s.appendSymbolLayer(marker_line2.clone()) 381 382 # rendering test 383 g = QgsGeometry.fromWkt('MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))))') 384 self.assertFalse(g.isNull()) 385 rendered_image = self.renderGeometry(s, g) 386 self.assertTrue(self.imageCheck('markerline_one_part_multisurface', 'markerline_one_part_multisurface', rendered_image)) 387 388 def testMarkerAverageAngle(self): 389 s = QgsLineSymbol() 390 s.deleteSymbolLayer(0) 391 392 marker_line = QgsMarkerLineSymbolLayer(True) 393 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Interval) 394 marker_line.setInterval(6) 395 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 396 marker.setColor(QColor(255, 0, 0)) 397 marker.setStrokeStyle(Qt.NoPen) 398 marker_symbol = QgsMarkerSymbol() 399 marker_symbol.changeSymbolLayer(0, marker) 400 marker_line.setSubSymbol(marker_symbol) 401 marker_line.setAverageAngleLength(60) 402 line_symbol = QgsLineSymbol() 403 line_symbol.changeSymbolLayer(0, marker_line) 404 405 s.appendSymbolLayer(marker_line.clone()) 406 407 g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') 408 rendered_image = self.renderGeometry(s, g) 409 assert self.imageCheck('markerline_average_angle', 'markerline_average_angle', rendered_image) 410 411 def testMarkerAverageAngleRing(self): 412 s = QgsLineSymbol() 413 s.deleteSymbolLayer(0) 414 415 marker_line = QgsMarkerLineSymbolLayer(True) 416 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Interval) 417 marker_line.setInterval(6) 418 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 419 marker.setColor(QColor(255, 0, 0)) 420 marker.setStrokeStyle(Qt.NoPen) 421 marker_symbol = QgsMarkerSymbol() 422 marker_symbol.changeSymbolLayer(0, marker) 423 marker_line.setSubSymbol(marker_symbol) 424 marker_line.setAverageAngleLength(60) 425 line_symbol = QgsLineSymbol() 426 line_symbol.changeSymbolLayer(0, marker_line) 427 428 s.appendSymbolLayer(marker_line.clone()) 429 430 g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 10 0, 0 0)') 431 rendered_image = self.renderGeometry(s, g) 432 assert self.imageCheck('markerline_ring_average_angle', 'markerline_ring_average_angle', rendered_image) 433 434 def testMarkerAverageAngleCenter(self): 435 s = QgsLineSymbol() 436 s.deleteSymbolLayer(0) 437 438 marker_line = QgsMarkerLineSymbolLayer(True) 439 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.CentralPoint) 440 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 441 marker.setColor(QColor(255, 0, 0)) 442 marker.setStrokeStyle(Qt.NoPen) 443 marker_symbol = QgsMarkerSymbol() 444 marker_symbol.changeSymbolLayer(0, marker) 445 marker_line.setSubSymbol(marker_symbol) 446 marker_line.setAverageAngleLength(60) 447 line_symbol = QgsLineSymbol() 448 line_symbol.changeSymbolLayer(0, marker_line) 449 450 s.appendSymbolLayer(marker_line.clone()) 451 452 g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') 453 rendered_image = self.renderGeometry(s, g) 454 assert self.imageCheck('markerline_center_average_angle', 'markerline_center_average_angle', rendered_image) 455 456 def testRingNoDupe(self): 457 s = QgsLineSymbol() 458 s.deleteSymbolLayer(0) 459 460 marker_line = QgsMarkerLineSymbolLayer(True) 461 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Interval) 462 marker_line.setInterval(10) 463 marker_line.setIntervalUnit(QgsUnitTypes.RenderMapUnits) 464 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 4) 465 marker.setColor(QColor(255, 0, 0, 100)) 466 marker.setStrokeStyle(Qt.NoPen) 467 marker_symbol = QgsMarkerSymbol() 468 marker_symbol.changeSymbolLayer(0, marker) 469 marker_line.setSubSymbol(marker_symbol) 470 line_symbol = QgsLineSymbol() 471 line_symbol.changeSymbolLayer(0, marker_line) 472 473 s.appendSymbolLayer(marker_line.clone()) 474 475 g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 10 0, 0 0)') 476 rendered_image = self.renderGeometry(s, g) 477 assert self.imageCheck('markerline_ring_no_dupes', 'markerline_ring_no_dupes', rendered_image) 478 479 def testSinglePoint(self): 480 s = QgsLineSymbol() 481 s.deleteSymbolLayer(0) 482 483 marker_line = QgsMarkerLineSymbolLayer(True) 484 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Interval) 485 marker_line.setInterval(1000) 486 marker_line.setIntervalUnit(QgsUnitTypes.RenderMapUnits) 487 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 4) 488 marker.setColor(QColor(255, 0, 0, 100)) 489 marker.setStrokeStyle(Qt.NoPen) 490 marker_symbol = QgsMarkerSymbol() 491 marker_symbol.changeSymbolLayer(0, marker) 492 marker_line.setSubSymbol(marker_symbol) 493 line_symbol = QgsLineSymbol() 494 line_symbol.changeSymbolLayer(0, marker_line) 495 496 s.appendSymbolLayer(marker_line.clone()) 497 498 g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') 499 rendered_image = self.renderGeometry(s, g) 500 assert self.imageCheck('markerline_single', 'markerline_single', rendered_image) 501 502 def testNoPoint(self): 503 s = QgsLineSymbol() 504 s.deleteSymbolLayer(0) 505 506 marker_line = QgsMarkerLineSymbolLayer(True) 507 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Interval) 508 marker_line.setOffsetAlongLine(1000) 509 marker_line.setIntervalUnit(QgsUnitTypes.RenderMapUnits) 510 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 4) 511 marker.setColor(QColor(255, 0, 0, 100)) 512 marker.setStrokeStyle(Qt.NoPen) 513 marker_symbol = QgsMarkerSymbol() 514 marker_symbol.changeSymbolLayer(0, marker) 515 marker_line.setSubSymbol(marker_symbol) 516 line_symbol = QgsLineSymbol() 517 line_symbol.changeSymbolLayer(0, marker_line) 518 519 s.appendSymbolLayer(marker_line.clone()) 520 521 g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') 522 rendered_image = self.renderGeometry(s, g) 523 assert self.imageCheck('markerline_none', 'markerline_none', rendered_image) 524 525 def testCenterSegment(self): 526 s = QgsLineSymbol() 527 s.deleteSymbolLayer(0) 528 529 marker_line = QgsMarkerLineSymbolLayer(True) 530 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.SegmentCenter) 531 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 532 marker.setColor(QColor(255, 0, 0)) 533 marker.setStrokeStyle(Qt.NoPen) 534 marker_symbol = QgsMarkerSymbol() 535 marker_symbol.changeSymbolLayer(0, marker) 536 marker_line.setSubSymbol(marker_symbol) 537 line_symbol = QgsLineSymbol() 538 line_symbol.changeSymbolLayer(0, marker_line) 539 540 s.appendSymbolLayer(marker_line.clone()) 541 542 g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 0 10)') 543 rendered_image = self.renderGeometry(s, g) 544 assert self.imageCheck('markerline_segmentcenter', 'markerline_segmentcenter', rendered_image) 545 546 def testMarkerDataDefinedAngleLine(self): 547 """Test issue https://github.com/qgis/QGIS/issues/38716""" 548 549 s = QgsLineSymbol() 550 s.deleteSymbolLayer(0) 551 552 marker_line = QgsMarkerLineSymbolLayer(True) 553 marker_line.setRotateSymbols(True) 554 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.CentralPoint) 555 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Arrow, 10) 556 marker.setAngle(90) 557 marker.setColor(QColor(255, 0, 0)) 558 marker.setStrokeStyle(Qt.NoPen) 559 marker_symbol = QgsMarkerSymbol() 560 marker_symbol.changeSymbolLayer(0, marker) 561 marker_line.setSubSymbol(marker_symbol) 562 line_symbol = QgsLineSymbol() 563 line_symbol.changeSymbolLayer(0, marker_line) 564 565 s.appendSymbolLayer(marker_line.clone()) 566 567 g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 20 20)') 568 rendered_image = self.renderGeometry(s, g) 569 assert self.imageCheck('markerline_center_angle_dd', 'markerline_center_angle_dd', rendered_image) 570 571 # Now with DD 572 573 s = QgsLineSymbol() 574 s.deleteSymbolLayer(0) 575 576 marker_line = QgsMarkerLineSymbolLayer(True) 577 marker_line.setRotateSymbols(True) 578 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.CentralPoint) 579 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Arrow, 10) 580 # Note: set this to a different value than the reference test (90) 581 marker.setAngle(30) 582 marker.setColor(QColor(255, 0, 0)) 583 marker.setStrokeStyle(Qt.NoPen) 584 marker_symbol = QgsMarkerSymbol() 585 marker_symbol.changeSymbolLayer(0, marker) 586 # This is the same value of the reference test 587 marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression('90')) 588 marker_line.setSubSymbol(marker_symbol) 589 line_symbol = QgsLineSymbol() 590 line_symbol.changeSymbolLayer(0, marker_line) 591 592 s.appendSymbolLayer(marker_line.clone()) 593 594 g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 20 20)') 595 rendered_image = self.renderGeometry(s, g) 596 assert self.imageCheck('markerline_center_angle_dd', 'markerline_center_angle_dd', rendered_image) 597 598 def testDataDefinedAnglePolygon(self): 599 # test rendering curve polygon with markers at vertices and curve points 600 s = QgsFillSymbol() 601 602 marker_line = QgsMarkerLineSymbolLayer(True) 603 marker_line.setPlacement(QgsMarkerLineSymbolLayer.SegmentCenter) 604 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 605 marker.setColor(QColor(255, 0, 0)) 606 marker.setStrokeStyle(Qt.NoPen) 607 marker.setAngle(90) 608 marker_symbol = QgsMarkerSymbol() 609 marker_symbol.changeSymbolLayer(0, marker) 610 marker_line.setSubSymbol(marker_symbol) 611 612 s.appendSymbolLayer(marker_line.clone()) 613 614 g = QgsGeometry.fromWkt('Polygon (LineString (0 5, 5 0, 10 5, 5 10, 0 5))') 615 self.assertFalse(g.isNull()) 616 617 # rendering test with non data-defined angle 618 rendered_image = self.renderGeometry(s, g) 619 self.assertTrue(self.imageCheck('markerline_datadefinedanglepolygon', 'markerline_datadefinedanglepolygon', rendered_image)) 620 621 s = QgsFillSymbol() 622 623 marker_line = QgsMarkerLineSymbolLayer(True) 624 marker_line.setPlacement(QgsMarkerLineSymbolLayer.SegmentCenter) 625 marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) 626 marker.setColor(QColor(255, 0, 0)) 627 marker.setStrokeStyle(Qt.NoPen) 628 marker.setAngle(38) 629 marker_symbol = QgsMarkerSymbol() 630 marker_symbol.changeSymbolLayer(0, marker) 631 marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression('90')) 632 marker_line.setSubSymbol(marker_symbol) 633 634 s.appendSymbolLayer(marker_line.clone()) 635 636 # rendering test with data-defined angle 637 rendered_image = self.renderGeometry(s, g) 638 self.assertTrue(self.imageCheck('markerline_datadefinedanglepolygon', 'markerline_datadefinedanglepolygon', rendered_image)) 639 640 def testOpacityWithDataDefinedColor(self): 641 line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') 642 line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') 643 self.assertTrue(line_layer.isValid()) 644 645 s = QgsLineSymbol() 646 s.deleteSymbolLayer(0) 647 marker_line = QgsMarkerLineSymbolLayer(True) 648 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.CentralPoint) 649 simple_marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 10) 650 simple_marker.setColor(QColor(0, 255, 0)) 651 simple_marker.setStrokeColor(QColor(255, 0, 0)) 652 simple_marker.setStrokeWidth(1) 653 simple_marker.setDataDefinedProperty(QgsSymbolLayer.PropertyFillColor, QgsProperty.fromExpression( 654 "if(Name='Arterial', 'red', 'green')")) 655 simple_marker.setDataDefinedProperty(QgsSymbolLayer.PropertyStrokeColor, QgsProperty.fromExpression( 656 "if(Name='Arterial', 'magenta', 'blue')")) 657 658 marker_symbol = QgsMarkerSymbol() 659 marker_symbol.changeSymbolLayer(0, simple_marker) 660 marker_symbol.setOpacity(0.5) 661 marker_line.setSubSymbol(marker_symbol) 662 s.appendSymbolLayer(marker_line.clone()) 663 664 # set opacity on both the symbol and subsymbol, to test that they get combined 665 s.setOpacity(0.5) 666 667 line_layer.setRenderer(QgsSingleSymbolRenderer(s)) 668 669 ms = QgsMapSettings() 670 ms.setOutputSize(QSize(400, 400)) 671 ms.setOutputDpi(96) 672 ms.setExtent(QgsRectangle(-118.5, 19.0, -81.4, 50.4)) 673 ms.setLayers([line_layer]) 674 675 # Test rendering 676 renderchecker = QgsMultiRenderChecker() 677 renderchecker.setMapSettings(ms) 678 renderchecker.setControlPathPrefix('symbol_markerline') 679 renderchecker.setControlName('expected_markerline_opacityddcolor') 680 res = renderchecker.runTest('expected_markerline_opacityddcolor') 681 self.report += renderchecker.report() 682 self.assertTrue(res) 683 684 def testDataDefinedOpacity(self): 685 line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') 686 line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') 687 self.assertTrue(line_layer.isValid()) 688 689 s = QgsLineSymbol() 690 s.deleteSymbolLayer(0) 691 marker_line = QgsMarkerLineSymbolLayer(True) 692 marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.CentralPoint) 693 simple_marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 10) 694 simple_marker.setColor(QColor(0, 255, 0)) 695 simple_marker.setStrokeColor(QColor(255, 0, 0)) 696 simple_marker.setStrokeWidth(1) 697 simple_marker.setDataDefinedProperty(QgsSymbolLayer.PropertyFillColor, QgsProperty.fromExpression( 698 "if(Name='Arterial', 'red', 'green')")) 699 simple_marker.setDataDefinedProperty(QgsSymbolLayer.PropertyStrokeColor, QgsProperty.fromExpression( 700 "if(Name='Arterial', 'magenta', 'blue')")) 701 702 marker_symbol = QgsMarkerSymbol() 703 marker_symbol.changeSymbolLayer(0, simple_marker) 704 marker_symbol.setOpacity(0.5) 705 marker_line.setSubSymbol(marker_symbol) 706 s.appendSymbolLayer(marker_line.clone()) 707 708 s.setDataDefinedProperty(QgsSymbol.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" = 1, 25, 50)")) 709 710 line_layer.setRenderer(QgsSingleSymbolRenderer(s)) 711 712 ms = QgsMapSettings() 713 ms.setOutputSize(QSize(400, 400)) 714 ms.setOutputDpi(96) 715 ms.setExtent(QgsRectangle(-118.5, 19.0, -81.4, 50.4)) 716 ms.setLayers([line_layer]) 717 718 # Test rendering 719 renderchecker = QgsMultiRenderChecker() 720 renderchecker.setMapSettings(ms) 721 renderchecker.setControlPathPrefix('symbol_markerline') 722 renderchecker.setControlName('expected_markerline_ddopacity') 723 res = renderchecker.runTest('expected_markerline_ddopacity') 724 self.report += renderchecker.report() 725 self.assertTrue(res) 726 727 def renderGeometry(self, symbol, geom, buffer=20): 728 f = QgsFeature() 729 f.setGeometry(geom) 730 731 image = QImage(200, 200, QImage.Format_RGB32) 732 733 painter = QPainter() 734 ms = QgsMapSettings() 735 extent = geom.get().boundingBox() 736 # buffer extent by 10% 737 if extent.width() > 0: 738 extent = extent.buffered((extent.height() + extent.width()) / buffer) 739 else: 740 extent = extent.buffered(buffer / 2) 741 742 ms.setExtent(extent) 743 ms.setOutputSize(image.size()) 744 context = QgsRenderContext.fromMapSettings(ms) 745 context.setPainter(painter) 746 context.setScaleFactor(96 / 25.4) # 96 DPI 747 context.expressionContext().setFeature(f) 748 749 painter.begin(image) 750 try: 751 image.fill(QColor(0, 0, 0)) 752 symbol.startRender(context) 753 symbol.renderFeature(f, context) 754 symbol.stopRender(context) 755 finally: 756 painter.end() 757 758 return image 759 760 def imageCheck(self, name, reference_image, image): 761 self.report += "<h2>Render {}</h2>\n".format(name) 762 temp_dir = QDir.tempPath() + '/' 763 file_name = temp_dir + 'symbol_' + name + ".png" 764 image.save(file_name, "PNG") 765 checker = QgsRenderChecker() 766 checker.setControlPathPrefix("symbol_markerline") 767 checker.setControlName("expected_" + reference_image) 768 checker.setRenderedImage(file_name) 769 checker.setColorTolerance(2) 770 result = checker.compareImages(name, 20) 771 self.report += checker.report() 772 print((self.report)) 773 return result 774 775 776if __name__ == '__main__': 777 unittest.main() 778