1# -*- coding: utf-8 -*- 2"""QGIS Unit tests for QgsPointCloudRgbRenderer 3 4.. note:: This program is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2 of the License, or 7(at your option) any later version. 8""" 9__author__ = 'Nyall Dawson' 10__date__ = '09/11/2020' 11__copyright__ = 'Copyright 2020, The QGIS Project' 12 13import qgis # NOQA 14from qgis.PyQt.QtCore import QDir, QSize 15from qgis.PyQt.QtGui import QPainter 16from qgis.PyQt.QtXml import QDomDocument 17from qgis.core import ( 18 QgsProviderRegistry, 19 QgsPointCloudLayer, 20 QgsPointCloudRgbRenderer, 21 QgsReadWriteContext, 22 QgsRenderContext, 23 QgsPointCloudRenderContext, 24 QgsVector3D, 25 QgsMultiRenderChecker, 26 QgsMapSettings, 27 QgsRectangle, 28 QgsContrastEnhancement, 29 QgsUnitTypes, 30 QgsMapUnitScale, 31 QgsCoordinateReferenceSystem, 32 QgsDoubleRange, 33 QgsPointCloudRenderer, 34 QgsMapClippingRegion, 35 QgsGeometry 36) 37from qgis.testing import start_app, unittest 38 39from utilities import unitTestDataPath 40 41start_app() 42 43 44class TestQgsPointCloudRgbRenderer(unittest.TestCase): 45 46 @classmethod 47 def setUpClass(cls): 48 cls.report = "<h1>Python QgsPointCloudRgbRenderer Tests</h1>\n" 49 50 @classmethod 51 def tearDownClass(cls): 52 report_file_path = "%s/qgistest.html" % QDir.tempPath() 53 with open(report_file_path, 'a') as report_file: 54 report_file.write(cls.report) 55 56 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 57 def testSetLayer(self): 58 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 59 self.assertTrue(layer.isValid()) 60 61 # test that a point cloud with RGB attributes is automatically assigned the RGB renderer by default 62 self.assertIsInstance(layer.renderer(), QgsPointCloudRgbRenderer) 63 64 # for this point cloud, we should default to 0-255 ranges (ie. no contrast enhancement) 65 self.assertIsNone(layer.renderer().redContrastEnhancement()) 66 self.assertIsNone(layer.renderer().greenContrastEnhancement()) 67 self.assertIsNone(layer.renderer().blueContrastEnhancement()) 68 69 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 70 def testSetLayer16(self): 71 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb16/ept.json', 'test', 'ept') 72 self.assertTrue(layer.isValid()) 73 74 # test that a point cloud with RGB attributes is automatically assigned the RGB renderer by default 75 self.assertIsInstance(layer.renderer(), QgsPointCloudRgbRenderer) 76 77 # for this point cloud, we should default to 0-65024 ranges with contrast enhancement 78 self.assertEqual(layer.renderer().redContrastEnhancement().minimumValue(), 0) 79 self.assertEqual(layer.renderer().redContrastEnhancement().maximumValue(), 65535.0) 80 self.assertEqual(layer.renderer().redContrastEnhancement().contrastEnhancementAlgorithm(), 81 QgsContrastEnhancement.StretchToMinimumMaximum) 82 self.assertEqual(layer.renderer().greenContrastEnhancement().minimumValue(), 0) 83 self.assertEqual(layer.renderer().greenContrastEnhancement().maximumValue(), 65535.0) 84 self.assertEqual(layer.renderer().greenContrastEnhancement().contrastEnhancementAlgorithm(), 85 QgsContrastEnhancement.StretchToMinimumMaximum) 86 self.assertEqual(layer.renderer().blueContrastEnhancement().minimumValue(), 0) 87 self.assertEqual(layer.renderer().blueContrastEnhancement().maximumValue(), 65535.0) 88 self.assertEqual(layer.renderer().blueContrastEnhancement().contrastEnhancementAlgorithm(), 89 QgsContrastEnhancement.StretchToMinimumMaximum) 90 91 def testBasic(self): 92 renderer = QgsPointCloudRgbRenderer() 93 renderer.setBlueAttribute('b') 94 self.assertEqual(renderer.blueAttribute(), 'b') 95 renderer.setGreenAttribute('g') 96 self.assertEqual(renderer.greenAttribute(), 'g') 97 renderer.setRedAttribute('r') 98 self.assertEqual(renderer.redAttribute(), 'r') 99 100 redce = QgsContrastEnhancement() 101 redce.setMinimumValue(100) 102 redce.setMaximumValue(120) 103 redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchAndClipToMinimumMaximum) 104 renderer.setRedContrastEnhancement(redce) 105 106 greence = QgsContrastEnhancement() 107 greence.setMinimumValue(130) 108 greence.setMaximumValue(150) 109 greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) 110 renderer.setGreenContrastEnhancement(greence) 111 112 bluece = QgsContrastEnhancement() 113 bluece.setMinimumValue(170) 114 bluece.setMaximumValue(190) 115 bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ClipToMinimumMaximum) 116 renderer.setBlueContrastEnhancement(bluece) 117 118 renderer.setMaximumScreenError(18) 119 renderer.setMaximumScreenErrorUnit(QgsUnitTypes.RenderInches) 120 renderer.setPointSize(13) 121 renderer.setPointSizeUnit(QgsUnitTypes.RenderPoints) 122 renderer.setPointSizeMapUnitScale(QgsMapUnitScale(1000, 2000)) 123 124 rr = renderer.clone() 125 self.assertEqual(rr.maximumScreenError(), 18) 126 self.assertEqual(rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderInches) 127 self.assertEqual(rr.pointSize(), 13) 128 self.assertEqual(rr.pointSizeUnit(), QgsUnitTypes.RenderPoints) 129 self.assertEqual(rr.pointSizeMapUnitScale().minScale, 1000) 130 self.assertEqual(rr.pointSizeMapUnitScale().maxScale, 2000) 131 132 self.assertEqual(rr.blueAttribute(), 'b') 133 self.assertEqual(rr.greenAttribute(), 'g') 134 self.assertEqual(rr.redAttribute(), 'r') 135 self.assertEqual(rr.redContrastEnhancement().minimumValue(), 100) 136 self.assertEqual(rr.redContrastEnhancement().maximumValue(), 120) 137 self.assertEqual(rr.redContrastEnhancement().contrastEnhancementAlgorithm(), 138 QgsContrastEnhancement.StretchAndClipToMinimumMaximum) 139 self.assertEqual(rr.greenContrastEnhancement().minimumValue(), 130) 140 self.assertEqual(rr.greenContrastEnhancement().maximumValue(), 150) 141 self.assertEqual(rr.greenContrastEnhancement().contrastEnhancementAlgorithm(), 142 QgsContrastEnhancement.StretchToMinimumMaximum) 143 self.assertEqual(rr.blueContrastEnhancement().minimumValue(), 170) 144 self.assertEqual(rr.blueContrastEnhancement().maximumValue(), 190) 145 self.assertEqual(rr.blueContrastEnhancement().contrastEnhancementAlgorithm(), 146 QgsContrastEnhancement.ClipToMinimumMaximum) 147 148 doc = QDomDocument("testdoc") 149 elem = renderer.save(doc, QgsReadWriteContext()) 150 151 r2 = QgsPointCloudRgbRenderer.create(elem, QgsReadWriteContext()) 152 self.assertEqual(r2.maximumScreenError(), 18) 153 self.assertEqual(r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderInches) 154 self.assertEqual(r2.pointSize(), 13) 155 self.assertEqual(r2.pointSizeUnit(), QgsUnitTypes.RenderPoints) 156 self.assertEqual(r2.pointSizeMapUnitScale().minScale, 1000) 157 self.assertEqual(r2.pointSizeMapUnitScale().maxScale, 2000) 158 159 self.assertEqual(r2.blueAttribute(), 'b') 160 self.assertEqual(r2.greenAttribute(), 'g') 161 self.assertEqual(r2.redAttribute(), 'r') 162 self.assertEqual(r2.redContrastEnhancement().minimumValue(), 100) 163 self.assertEqual(r2.redContrastEnhancement().maximumValue(), 120) 164 self.assertEqual(r2.redContrastEnhancement().contrastEnhancementAlgorithm(), 165 QgsContrastEnhancement.StretchAndClipToMinimumMaximum) 166 self.assertEqual(r2.greenContrastEnhancement().minimumValue(), 130) 167 self.assertEqual(r2.greenContrastEnhancement().maximumValue(), 150) 168 self.assertEqual(r2.greenContrastEnhancement().contrastEnhancementAlgorithm(), 169 QgsContrastEnhancement.StretchToMinimumMaximum) 170 self.assertEqual(r2.blueContrastEnhancement().minimumValue(), 170) 171 self.assertEqual(r2.blueContrastEnhancement().maximumValue(), 190) 172 self.assertEqual(r2.blueContrastEnhancement().contrastEnhancementAlgorithm(), 173 QgsContrastEnhancement.ClipToMinimumMaximum) 174 175 def testUsedAttributes(self): 176 renderer = QgsPointCloudRgbRenderer() 177 renderer.setBlueAttribute('b') 178 renderer.setGreenAttribute('g') 179 renderer.setRedAttribute('r') 180 181 rc = QgsRenderContext() 182 prc = QgsPointCloudRenderContext(rc, QgsVector3D(), QgsVector3D(), 1, 0) 183 184 self.assertEqual(renderer.usedAttributes(prc), {'r', 'g', 'b'}) 185 186 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 187 def testRender(self): 188 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 189 self.assertTrue(layer.isValid()) 190 191 layer.renderer().setPointSize(2) 192 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 193 194 mapsettings = QgsMapSettings() 195 mapsettings.setOutputSize(QSize(400, 400)) 196 mapsettings.setOutputDpi(96) 197 mapsettings.setDestinationCrs(layer.crs()) 198 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 199 mapsettings.setLayers([layer]) 200 201 renderchecker = QgsMultiRenderChecker() 202 renderchecker.setMapSettings(mapsettings) 203 renderchecker.setControlPathPrefix('pointcloudrenderer') 204 renderchecker.setControlName('expected_rgb_render') 205 result = renderchecker.runTest('expected_rgb_render') 206 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 207 self.assertTrue(result) 208 209 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 210 def testRenderCircles(self): 211 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 212 self.assertTrue(layer.isValid()) 213 214 layer.renderer().setPointSize(3) 215 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 216 layer.renderer().setPointSymbol(QgsPointCloudRenderer.Circle) 217 218 mapsettings = QgsMapSettings() 219 mapsettings.setOutputSize(QSize(400, 400)) 220 mapsettings.setOutputDpi(96) 221 mapsettings.setDestinationCrs(layer.crs()) 222 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 223 mapsettings.setLayers([layer]) 224 225 renderchecker = QgsMultiRenderChecker() 226 renderchecker.setMapSettings(mapsettings) 227 renderchecker.setControlPathPrefix('pointcloudrenderer') 228 renderchecker.setControlName('expected_rgb_circle_render') 229 result = renderchecker.runTest('expected_rgb_circle_render') 230 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 231 self.assertTrue(result) 232 233 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 234 def testRenderCrsTransform(self): 235 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 236 self.assertTrue(layer.isValid()) 237 238 layer.renderer().setPointSize(2) 239 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 240 241 mapsettings = QgsMapSettings() 242 mapsettings.setOutputSize(QSize(400, 400)) 243 mapsettings.setOutputDpi(96) 244 mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) 245 mapsettings.setExtent(QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624)) 246 mapsettings.setLayers([layer]) 247 renderchecker = QgsMultiRenderChecker() 248 renderchecker.setMapSettings(mapsettings) 249 renderchecker.setControlPathPrefix('pointcloudrenderer') 250 renderchecker.setControlName('expected_rgb_render_crs_transform') 251 result = renderchecker.runTest('expected_rgb_render_crs_transform') 252 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 253 self.assertTrue(result) 254 255 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 256 def testRenderWithContrast(self): 257 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 258 self.assertTrue(layer.isValid()) 259 260 layer.renderer().setPointSize(2) 261 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 262 263 redce = QgsContrastEnhancement() 264 redce.setMinimumValue(100) 265 redce.setMaximumValue(120) 266 redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) 267 layer.renderer().setRedContrastEnhancement(redce) 268 269 greence = QgsContrastEnhancement() 270 greence.setMinimumValue(130) 271 greence.setMaximumValue(150) 272 greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) 273 layer.renderer().setGreenContrastEnhancement(greence) 274 275 bluece = QgsContrastEnhancement() 276 bluece.setMinimumValue(170) 277 bluece.setMaximumValue(190) 278 bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) 279 layer.renderer().setBlueContrastEnhancement(bluece) 280 281 mapsettings = QgsMapSettings() 282 mapsettings.setOutputSize(QSize(400, 400)) 283 mapsettings.setOutputDpi(96) 284 mapsettings.setDestinationCrs(layer.crs()) 285 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 286 mapsettings.setLayers([layer]) 287 288 renderchecker = QgsMultiRenderChecker() 289 renderchecker.setMapSettings(mapsettings) 290 renderchecker.setControlPathPrefix('pointcloudrenderer') 291 renderchecker.setControlName('expected_rgb_contrast') 292 result = renderchecker.runTest('expected_rgb_contrast') 293 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 294 self.assertTrue(result) 295 296 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 297 def testRenderOpacity(self): 298 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 299 self.assertTrue(layer.isValid()) 300 301 layer.renderer().setPointSize(2) 302 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 303 304 layer.setOpacity(0.5) 305 306 mapsettings = QgsMapSettings() 307 mapsettings.setOutputSize(QSize(400, 400)) 308 mapsettings.setOutputDpi(96) 309 mapsettings.setDestinationCrs(layer.crs()) 310 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 311 mapsettings.setLayers([layer]) 312 313 renderchecker = QgsMultiRenderChecker() 314 renderchecker.setMapSettings(mapsettings) 315 renderchecker.setControlPathPrefix('pointcloudrenderer') 316 renderchecker.setControlName('expected_opacity') 317 result = renderchecker.runTest('expected_opacity') 318 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 319 self.assertTrue(result) 320 321 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 322 def testRenderBlendMode(self): 323 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 324 self.assertTrue(layer.isValid()) 325 326 layer.renderer().setPointSize(2) 327 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 328 329 layer.setBlendMode(QPainter.CompositionMode_ColorBurn) 330 331 mapsettings = QgsMapSettings() 332 mapsettings.setOutputSize(QSize(400, 400)) 333 mapsettings.setOutputDpi(96) 334 mapsettings.setDestinationCrs(layer.crs()) 335 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 336 mapsettings.setLayers([layer]) 337 338 renderchecker = QgsMultiRenderChecker() 339 renderchecker.setMapSettings(mapsettings) 340 renderchecker.setControlPathPrefix('pointcloudrenderer') 341 renderchecker.setControlName('expected_blendmode') 342 result = renderchecker.runTest('expected_blendmode') 343 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 344 self.assertTrue(result) 345 346 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 347 def testRenderPointSize(self): 348 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 349 self.assertTrue(layer.isValid()) 350 351 layer.renderer().setPointSize(0.05) 352 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMapUnits) 353 354 mapsettings = QgsMapSettings() 355 mapsettings.setOutputSize(QSize(400, 400)) 356 mapsettings.setOutputDpi(96) 357 mapsettings.setDestinationCrs(layer.crs()) 358 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 359 mapsettings.setLayers([layer]) 360 361 renderchecker = QgsMultiRenderChecker() 362 renderchecker.setMapSettings(mapsettings) 363 renderchecker.setControlPathPrefix('pointcloudrenderer') 364 renderchecker.setControlName('expected_pointsize') 365 result = renderchecker.runTest('expected_pointsize') 366 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 367 self.assertTrue(result) 368 369 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 370 def testRenderZRange(self): 371 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 372 self.assertTrue(layer.isValid()) 373 374 layer.renderer().setPointSize(2) 375 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 376 377 mapsettings = QgsMapSettings() 378 mapsettings.setOutputSize(QSize(400, 400)) 379 mapsettings.setOutputDpi(96) 380 mapsettings.setDestinationCrs(layer.crs()) 381 mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) 382 mapsettings.setLayers([layer]) 383 mapsettings.setZRange(QgsDoubleRange(1.1, 1.2)) 384 385 renderchecker = QgsMultiRenderChecker() 386 renderchecker.setMapSettings(mapsettings) 387 renderchecker.setControlPathPrefix('pointcloudrenderer') 388 renderchecker.setControlName('expected_zfilter') 389 result = renderchecker.runTest('expected_zfilter') 390 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 391 self.assertTrue(result) 392 393 @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') 394 def testRenderClipRegion(self): 395 layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') 396 self.assertTrue(layer.isValid()) 397 398 layer.renderer().setPointSize(2) 399 layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderMillimeters) 400 401 mapsettings = QgsMapSettings() 402 mapsettings.setOutputSize(QSize(400, 400)) 403 mapsettings.setOutputDpi(96) 404 mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) 405 mapsettings.setExtent(QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624)) 406 mapsettings.setLayers([layer]) 407 408 region = QgsMapClippingRegion(QgsGeometry.fromWkt( 409 'Polygon ((152.97742833685992991 -26.66301088198133584, 152.97742694456141521 -26.66301085776744983, 152.97742676295726483 -26.66301358182974468, 152.97742895431403554 -26.66301349708113833, 152.97742833685992991 -26.66301088198133584))')) 410 region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) 411 region2 = QgsMapClippingRegion(QgsGeometry.fromWkt( 412 'Polygon ((152.97743215054714483 -26.66301111201326535, 152.97742715037946937 -26.66301116044103736, 152.97742754990858316 -26.66301436878107367, 152.97743264693181686 -26.66301491359353193, 152.97743215054714483 -26.66301111201326535))')) 413 region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) 414 mapsettings.addClippingRegion(region) 415 mapsettings.addClippingRegion(region2) 416 417 renderchecker = QgsMultiRenderChecker() 418 renderchecker.setMapSettings(mapsettings) 419 renderchecker.setControlPathPrefix('pointcloudrenderer') 420 renderchecker.setControlName('expected_clip_region') 421 result = renderchecker.runTest('expected_clip_region') 422 TestQgsPointCloudRgbRenderer.report += renderchecker.report() 423 self.assertTrue(result) 424 425 426if __name__ == '__main__': 427 unittest.main() 428