def testGetClickBbox(self): """ Tests that a click returns a small bbox. """ # pixel coords for fake click self.prepareTestCanvas() myPoint = QgsPoint(50, 15) myBox = self.bucketFill.getClickBbox(myPoint) myExpectedBox = QgsRectangle(49.99850465, 14.99850465, 50.00149535, 15.00149535) myMessage = ('Bounding box was incorrect. Received values %s' ' Expected values %s' % ( str('%s, %s, %s, %s' % ( myBox.xMinimum(), myBox.yMinimum(), myBox.xMaximum(), myBox.yMaximum() )), str('%s, %s, %s, %s' % ( myExpectedBox.xMinimum(), myExpectedBox.yMinimum(), myExpectedBox.xMaximum(), myExpectedBox.yMaximum() )) )) assert (round(myBox.xMinimum(), 9) == round(myExpectedBox.xMinimum(), 9) and round(myBox.xMaximum(), 9) == round(myExpectedBox.xMaximum(), 9) and round(myBox.yMinimum(), 9) == round(myExpectedBox.yMinimum(), 9) and round(myBox.yMaximum(), 9) == round(myExpectedBox.yMaximum(), 9)), myMessage
def testRectangle(self): rect = QgsReferencedRectangle(QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) self.assertEqual(rect.xMinimum(), 0.0) self.assertEqual(rect.yMinimum(), 1.0) self.assertEqual(rect.xMaximum(), 20.0) self.assertEqual(rect.yMaximum(), 10.0) self.assertEqual(rect.crs().authid(), 'EPSG:3111') rect.setCrs(QgsCoordinateReferenceSystem('epsg:28356')) self.assertEqual(rect.crs().authid(), 'EPSG:28356') # in variant v = QVariant(QgsReferencedRectangle(QgsRectangle(1.0, 2.0, 3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111'))) self.assertEqual(v.value().xMinimum(), 1.0) self.assertEqual(v.value().yMinimum(), 2.0) self.assertEqual(v.value().xMaximum(), 3.0) self.assertEqual(v.value().yMaximum(), 4.0) self.assertEqual(v.value().crs().authid(), 'EPSG:3111') # to rectangle r = QgsRectangle(rect) self.assertEqual(r.xMinimum(), 0.0) self.assertEqual(r.yMinimum(), 1.0) self.assertEqual(r.xMaximum(), 20.0) self.assertEqual(r.yMaximum(), 10.0) # test that QgsReferencedRectangle IS a QgsRectangle r2 = QgsRectangle(5, 6, 30, 40) r2.combineExtentWith(rect) self.assertEqual(r2.xMinimum(), 0.0) self.assertEqual(r2.yMinimum(), 1.0) self.assertEqual(r2.xMaximum(), 30.0) self.assertEqual(r2.yMaximum(), 40.0)
def processAlgorithm(self, feedback): extent = str(self.getParameterValue(self.EXTENT)).split(',') spacing = float(self.getParameterValue(self.SPACING)) inset = float(self.getParameterValue(self.INSET)) randomize = self.getParameterValue(self.RANDOMIZE) isSpacing = self.getParameterValue(self.IS_SPACING) crsId = self.getParameterValue(self.CRS) crs = QgsCoordinateReferenceSystem() crs.createFromUserInput(crsId) extent = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Point, crs) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.0 / (area / pSpacing) y = extent.yMaximum() - inset extent_geom = QgsGeometry.fromRect(extent) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry()) extent_engine.prepareGeometry() while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if randomize: geom = QgsGeometry().fromPoint(QgsPoint( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPoint(x, y)) if extent_engine.intersects(geom.geometry()): f.setAttribute('id', count) f.setGeometry(geom) writer.addFeature(f) x += pSpacing count += 1 feedback.setProgress(int(count * total)) y = y - pSpacing del writer
def testInvert(self): rect = QgsRectangle(0, 0.1, 0.2, 0.3) rect.invert() self.assertEqual(rect.xMinimum(), 0.1) self.assertEqual(rect.yMinimum(), 0) self.assertEqual(rect.xMaximum(), 0.3) self.assertEqual(rect.yMaximum(), 0.2)
def getBBox(self, item): ogrFeature = item.data(Qt.UserRole) geom = QgsGeometry.fromWkt(ogrFeature.GetGeometryRef().ExportToWkt()) if (ogrFeature.GetDefnRef().GetGeomType() == ogr.wkbPoint): mapextent = self.plugin.canvas.extent() ww = mapextent.width()/100 mapcrs = self.plugin.canvas.mapSettings().destinationCrs() x = geom.boundingBox().center().x() y = geom.boundingBox().center().y() ww = 50.0 if mapcrs.mapUnits() == QgsUnitTypes.DistanceFeet: ww = 150 if mapcrs.mapUnits() == QgsUnitTypes.DistanceDegrees: ww = 0.0005 bbox = QgsRectangle(x-10*ww, y-10*ww, x+10*ww, y+10*ww) return bbox else: bbox = geom.boundingBox() rubberRect = QgsRectangle(bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum()) return rubberRect
def testCtor(self): rect = QgsRectangle(5.0, 5.0, 10.0, 10.0) myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.xMinimum())) assert rect.xMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.yMinimum())) assert rect.yMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.xMaximum())) assert rect.xMaximum() == 10.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.yMaximum())) assert rect.yMaximum() == 10.0, myMessage
def processAlgorithm(self, progress): extent = self.getParameterValue(self.EXTENT).split(',') xSpace = self.getParameterValue(self.STEP_X) ySpace = self.getParameterValue(self.STEP_Y) bbox = QgsRectangle( float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('xmin', QVariant.Double, '', 24, 15)) fields.append(QgsField('xmax', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymin', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymax', QVariant.Double, '', 24, 15)) fieldCount = 5 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Polygon, mapCRS) feat = QgsFeature() feat.initAttributes(fieldCount) feat.setFields(fields) geom = QgsGeometry() idVar = 0 # counters for progressbar - update every 5% count = 0 count_max = (bbox.yMaximum() - bbox.yMinimum()) / ySpace count_update = count_max * 0.05 y = bbox.yMaximum() while y >= bbox.yMinimum(): x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, y) pt2 = QgsPoint(x + xSpace, y) pt3 = QgsPoint(x + xSpace, y - ySpace) pt4 = QgsPoint(x, y - ySpace) pt5 = QgsPoint(x, y) polygon = [[pt1, pt2, pt3, pt4, pt5]] feat.setGeometry(geom.fromPolygon(polygon)) feat.setAttribute(0, idVar) feat.setAttribute(1, x) feat.setAttribute(2, x + xSpace) feat.setAttribute(3, y - ySpace) feat.setAttribute(4, y) writer.addFeature(feat) idVar += 1 x = x + xSpace y = y - ySpace count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(int(count / count_max * 100)) del writer
def processAlgorithm(self, parameters, context, feedback): expression = self.getParameterValue(self.EXPRESSION) layersValue = self.getParameterValue(self.LAYERS) layersDict = {} if layersValue: layers = [QgsProcessingUtils.mapLayerFromString(f, context) for f in layersValue.split(";")] layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers} for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()): name = lyr.name() if (name + "@") in expression: layersDict[name] = lyr entries = [] for name, lyr in layersDict.items(): for n in range(lyr.bandCount()): entry = QgsRasterCalculatorEntry() entry.ref = '{:s}@{:d}'.format(name, n + 1) entry.raster = lyr entry.bandNumber = n + 1 entries.append(entry) output = self.getOutputValue(self.OUTPUT) extentValue = self.getParameterValue(self.EXTENT) if not extentValue: extentValue = QgsProcessingUtils.combineLayerExtents(layersValue) if extentValue: extent = extentValue.split(',') bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) else: if layersDict: bbox = list(layersDict.values())[0].extent() for lyr in layersDict.values(): bbox.combineExtentWith(lyr.extent()) else: raise GeoAlgorithmExecutionException(self.tr("No layers selected")) def _cellsize(layer): return (layer.extent().xMaximum() - layer.extent().xMinimum()) / layer.width() cellsize = self.getParameterValue(self.CELLSIZE) or min([_cellsize(lyr) for lyr in layersDict.values()]) width = math.floor((bbox.xMaximum() - bbox.xMinimum()) / cellsize) height = math.floor((bbox.yMaximum() - bbox.yMinimum()) / cellsize) driverName = GdalUtils.getFormatShortNameFromFilename(output) calc = QgsRasterCalculator(expression, output, driverName, bbox, width, height, entries) res = calc.processCalculation() if res == QgsRasterCalculator.ParserError: raise GeoAlgorithmExecutionException(self.tr("Error parsing formula"))
def testCtor(self): rect = QgsRectangle(5.0, 5.0, 10.0, 10.0) myExpectedResult = True myResult = rect.isEmpty() myMessage = "Expected: %s Got: %s" % (myExpectedResult, myResult) assert rect.isEmpty(), myMessage myMessage = "Expected: %s\nGot: %s\n" % (5.0, rect.xMinimum()) assert rect.xMinimum() == 5.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % (5.0, rect.yMinimum()) assert rect.yMinimum() == 5.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % (10.0, rect.xMaximum()) assert rect.xMaximum() == 10.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % (10.0, rect.yMaximum()) assert rect.yMaximum() == 10.0, myMessage
def testCtor(self): rect = QgsRectangle(5.0, 5.0, 10.0, 10.0) myExpectedResult = True myResult = rect.isEmpty() myMessage = ('Expected: %s Got: %s' % (myExpectedResult, myResult)) assert rect.isEmpty(), myMessage myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.xMinimum())) assert rect.xMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.yMinimum())) assert rect.yMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.xMaximum())) assert rect.xMaximum() == 10.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.yMaximum())) assert rect.yMaximum() == 10.0, myMessage
def processAlgorithm(self, context, feedback): extent = self.getParameterValue(self.EXTENT).split(',') xSpace = self.getParameterValue(self.STEP_X) ySpace = self.getParameterValue(self.STEP_Y) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('xmin', QVariant.Double, '', 24, 15)) fields.append(QgsField('xmax', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymin', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymax', QVariant.Double, '', 24, 15)) fieldCount = 5 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Polygon, mapCRS, context) feat = QgsFeature() feat.initAttributes(fieldCount) feat.setFields(fields) geom = QgsGeometry() idVar = 0 # counters for progressbar - update every 5% count = 0 count_max = (bbox.yMaximum() - bbox.yMinimum()) / ySpace count_update = count_max * 0.05 y = bbox.yMaximum() while y >= bbox.yMinimum(): x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, y) pt2 = QgsPoint(x + xSpace, y) pt3 = QgsPoint(x + xSpace, y - ySpace) pt4 = QgsPoint(x, y - ySpace) pt5 = QgsPoint(x, y) polygon = [[pt1, pt2, pt3, pt4, pt5]] feat.setGeometry(geom.fromPolygon(polygon)) feat.setAttribute(0, idVar) feat.setAttribute(1, x) feat.setAttribute(2, x + xSpace) feat.setAttribute(3, y - ySpace) feat.setAttribute(4, y) writer.addFeature(feat) idVar += 1 x = x + xSpace y = y - ySpace count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 100)) del writer
def processAlgorithm(self, feedback): expression = self.getParameterValue(self.EXPRESSION) layersValue = self.getParameterValue(self.LAYERS) layersDict = {} if layersValue: layers = [dataobjects.getObjectFromUri(f) for f in layersValue.split(";")] layersDict = {os.path.basename(lyr.source().split(".")[0]): lyr for lyr in layers} for lyr in dataobjects.getRasterLayers(): name = lyr.name() if (name + "@") in expression: layersDict[name] = lyr entries = [] for name, lyr in layersDict.items(): for n in range(lyr.bandCount()): entry = QgsRasterCalculatorEntry() entry.ref = '{:s}@{:d}'.format(name, n + 1) entry.raster = lyr entry.bandNumber = n + 1 entries.append(entry) output = self.getOutputValue(self.OUTPUT) extentValue = self.getParameterValue(self.EXTENT) if extentValue: extent = extentValue.split(',') bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) else: if layersDict: bbox = list(layersDict.values())[0].extent() for lyr in layersDict.values(): bbox.combineExtentWith(lyr.extent()) else: raise GeoAlgorithmExecutionException(self.tr("No layers selected")) def _cellsize(layer): return (layer.extent().xMaximum() - layer.extent().xMinimum()) / layer.width() cellsize = self.getParameterValue(self.CELLSIZE) or min([_cellsize(lyr) for lyr in layersDict.values()]) width = math.floor((bbox.xMaximum() - bbox.xMinimum()) / cellsize) height = math.floor((bbox.yMaximum() - bbox.yMinimum()) / cellsize) driverName = GdalUtils.getFormatShortNameFromFilename(output) calc = QgsRasterCalculator(expression, output, driverName, bbox, width, height, entries) res = calc.processCalculation() if res == QgsRasterCalculator.ParserError: raise GeoAlgorithmExecutionException(self.tr("Error parsing formula"))
def testCtor(self): rect = QgsRectangle( 5.0, 5.0, 10.0, 10.0) assert rect.isEmpty(), "Empty rectangle constructed" myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.xMinimum())) assert rect.xMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (5.0, rect.yMinimum())) assert rect.yMinimum() == 5.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.xMaximum())) assert rect.xMaximum() == 10.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.yMaximum())) assert rect.yMaximum() == 10.0, myMessage
def test_clip_raster(self): """Test we can clip a raster layer.""" layer = load_test_raster_layer('gisv4', 'hazard', 'earthquake.asc') expected = QgsRectangle(106.75, -6.2, 106.80, -6.1) new_layer = clip_by_extent(layer, expected) extent = new_layer.extent() self.assertAlmostEqual(expected.xMinimum(), extent.xMinimum(), 0) self.assertAlmostEqual(expected.xMaximum(), extent.xMaximum(), 0) self.assertAlmostEqual(expected.yMinimum(), extent.yMinimum(), 0) self.assertAlmostEqual(expected.yMaximum(), extent.yMaximum(), 0)
def processAlgorithm(self, progress): extent = str(self.getParameterValue(self.EXTENT)).split(",") spacing = float(self.getParameterValue(self.SPACING)) inset = float(self.getParameterValue(self.INSET)) randomize = self.getParameterValue(self.RANDOMIZE) isSpacing = self.getParameterValue(self.IS_SPACING) extent = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) fields = QgsFields() fields.append(QgsField("id", QVariant.Int, "", 10, 0)) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QGis.WKBPoint, mapCRS) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.00 / (area / pSpacing) y = extent.yMaximum() - inset while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if randomize: geom = QgsGeometry().fromPoint( QgsPoint( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)), ) ) else: geom = QgsGeometry().fromPoint(QgsPoint(x, y)) if geom.intersects(extent): f.setAttribute("id", count) f.setGeometry(geom) writer.addFeature(f) x += pSpacing count += 1 progress.setPercentage(int(count * total)) y = y - pSpacing del writer
def processAlgorithm(self, progress): extent = unicode(self.getParameterValue(self.EXTENT)).split(',') spacing = float(self.getParameterValue(self.SPACING)) inset = float(self.getParameterValue(self.INSET)) randomize = self.getParameterValue(self.RANDOMIZE) isSpacing = self.getParameterValue(self.IS_SPACING) extent = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPoint, mapCRS) if randomize: seed() area = extent.width() * extent.height() if isSpacing: pSpacing = spacing else: pSpacing = sqrt(area / spacing) f = QgsFeature() f.initAttributes(1) f.setFields(fields) count = 0 total = 100.00 / (area / pSpacing) y = extent.yMaximum() - inset while y >= extent.yMinimum(): x = extent.xMinimum() + inset while x <= extent.xMaximum(): if randomize: geom = QgsGeometry().fromPoint(QgsPoint( uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) else: geom = QgsGeometry().fromPoint(QgsPoint(x, y)) if geom.intersects(extent): f.setAttribute('id', count) f.setGeometry(geom) writer.addFeature(f) x += pSpacing count += 1 progress.setPercentage(int(count* total)) y = y - pSpacing del writer
def set_margin(layer, margin): extent = QgsRectangle() extent.setMinimal() extent.combineExtentWith(layer.extent()) xmax = extent.xMaximum() + margin xmin = extent.xMinimum() - margin ymax = extent.yMaximum() + margin ymin = extent.yMinimum() - margin extent.set(xmin, ymin, xmax, ymax) global_vars.iface.mapCanvas().setExtent(extent) global_vars.iface.mapCanvas().refresh()
def extent_rect(self): """Return dict of coordinates extension string :rtype: str """ rect = QgsRectangle().fromWkt(self.extent) return { 'minx': rect.xMinimum(), 'miny': rect.yMinimum(), 'maxx': rect.xMaximum(), 'maxy': rect.yMaximum() }
def add_extent(self, extent: QgsRectangle, precision=4): """ Add extent for the query :param extent: QgsRectangle expected to be in the right extent :param precision: Precision of coordinates :return: """ rnd = lambda c: round(c, precision) self.qr.add_extent(rnd(extent.xMinimum()), rnd(extent.yMinimum()), rnd(extent.xMaximum()), rnd(extent.yMaximum()), srid=self.layer_wrapper.get_layer().crs().srsid())
def testRectangle(self): rect = QgsReferencedRectangle( QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) self.assertEqual(rect.xMinimum(), 0.0) self.assertEqual(rect.yMinimum(), 1.0) self.assertEqual(rect.xMaximum(), 20.0) self.assertEqual(rect.yMaximum(), 10.0) self.assertEqual(rect.crs().authid(), 'EPSG:3111') rect.setCrs(QgsCoordinateReferenceSystem('epsg:28356')) self.assertEqual(rect.crs().authid(), 'EPSG:28356') # in variant v = QVariant( QgsReferencedRectangle(QgsRectangle(1.0, 2.0, 3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111'))) self.assertEqual(v.value().xMinimum(), 1.0) self.assertEqual(v.value().yMinimum(), 2.0) self.assertEqual(v.value().xMaximum(), 3.0) self.assertEqual(v.value().yMaximum(), 4.0) self.assertEqual(v.value().crs().authid(), 'EPSG:3111') # to rectangle r = QgsRectangle(rect) self.assertEqual(r.xMinimum(), 0.0) self.assertEqual(r.yMinimum(), 1.0) self.assertEqual(r.xMaximum(), 20.0) self.assertEqual(r.yMaximum(), 10.0) # test that QgsReferencedRectangle IS a QgsRectangle r2 = QgsRectangle(5, 6, 30, 40) r2.combineExtentWith(rect) self.assertEqual(r2.xMinimum(), 0.0) self.assertEqual(r2.yMinimum(), 1.0) self.assertEqual(r2.xMaximum(), 30.0) self.assertEqual(r2.yMaximum(), 40.0)
def bounds(iface, useCanvas, layers, matchCRS): if useCanvas: canvas = iface.mapCanvas() canvasCrs = canvas.mapSettings().destinationCrs() if not matchCRS: epsg3857 = QgsCoordinateReferenceSystem("EPSG:3857") try: transform = QgsCoordinateTransform(canvasCrs, epsg3857, QgsProject.instance()) except Exception: transform = QgsCoordinateTransform(canvasCrs, epsg3857) try: extent = transform.transformBoundingBox(canvas.extent()) except QgsCsException: extent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) else: extent = canvas.extent() else: extent = None for layer in layers: if not matchCRS: epsg3857 = QgsCoordinateReferenceSystem("EPSG:3857") try: transform = QgsCoordinateTransform(layer.crs(), epsg3857, QgsProject.instance()) except Exception: transform = QgsCoordinateTransform(layer.crs(), epsg3857) try: layerExtent = transform.transformBoundingBox( layer.extent()) except QgsCsException: layerExtent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) else: layerExtent = layer.extent() if extent is None: extent = layerExtent else: extent.combineExtentWith(layerExtent) if extent is None: extent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) return "[%f, %f, %f, %f]" % (extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum())
def testGetClickBbox(self): """ Tests that a click returns a small bbox. """ # pixel coords for fake click self.prepareTestCanvas() myPoint = QgsPoint(50, 15) myBox = self.bucketFill.getClickBbox(myPoint) myExpectedBox = QgsRectangle(49.99850465, 14.99850465, 50.00149535, 15.00149535) myMessage = ( 'Bounding box was incorrect. Received values %s' ' Expected values %s' % (str('%s, %s, %s, %s' % (myBox.xMinimum(), myBox.yMinimum(), myBox.xMaximum(), myBox.yMaximum())), str('%s, %s, %s, %s' % (myExpectedBox.xMinimum(), myExpectedBox.yMinimum(), myExpectedBox.xMaximum(), myExpectedBox.yMaximum())))) assert (round(myBox.xMinimum(), 9) == round( myExpectedBox.xMinimum(), 9) and round(myBox.xMaximum(), 9) == round(myExpectedBox.xMaximum(), 9) and round( myBox.yMinimum(), 9) == round(myExpectedBox.yMinimum(), 9) and round(myBox.yMaximum(), 9) == round( myExpectedBox.yMaximum(), 9)), myMessage
def set_extent_from_canvas_extent(self, rect: QgsRectangle): """ Sets the widget extent from the canvas extent """ ct = QgsCoordinateTransform( self.iface.mapCanvas().mapSettings().destinationCrs(), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance()) try: rect = ct.transformBoundingBox(rect) self.lat_min_spinbox.setValue(rect.yMinimum()) self.lat_max_spinbox.setValue(rect.yMaximum()) self.long_min_spinbox.setValue(rect.xMinimum()) self.long_max_spinbox.setValue(rect.xMaximum()) except QgsCsException: pass
def set_margin(layer, margin): """ Generates a margin around the layer so that it is fully visible on the canvas """ if layer.extent().isNull(): return extent = QgsRectangle() extent.setMinimal() extent.combineExtentWith(layer.extent()) xmin = extent.xMinimum() - margin ymin = extent.yMinimum() - margin xmax = extent.xMaximum() + margin ymax = extent.yMaximum() + margin extent.set(xmin, ymin, xmax, ymax) iface.mapCanvas().setExtent(extent) iface.mapCanvas().refresh()
def extent_to_bbox(extent: QgsRectangle, precision=2) -> str: """ Add extent for the query :param extent: QgsRectangle expected to be in the right extent :param precision: Precision of coordinates :return: string representation xmin,ymin,xmax,ymax """ rnd = lambda c: round(c, precision) bbox = ( rnd(extent.xMinimum()), rnd(extent.yMinimum()), rnd(extent.xMaximum()), rnd(extent.yMaximum()), ) return ','.join(map(str, bbox))
def bounds(iface, useCanvas, layers, matchCRS): if useCanvas: canvas = iface.mapCanvas() canvasCrs = canvas.mapSettings().destinationCrs() if not matchCRS: epsg3857 = QgsCoordinateReferenceSystem("EPSG:3857") try: transform = QgsCoordinateTransform(canvasCrs, epsg3857, QgsProject.instance()) except: transform = QgsCoordinateTransform(canvasCrs, epsg3857) try: extent = transform.transformBoundingBox(canvas.extent()) except QgsCsException: extent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) else: extent = canvas.extent() else: extent = None for layer in layers: if not matchCRS: epsg3857 = QgsCoordinateReferenceSystem("EPSG:3857") try: transform = QgsCoordinateTransform(layer.crs(), epsg3857, QgsProject.instance()) except: transform = QgsCoordinateTransform(layer.crs(), epsg3857) try: layerExtent = transform.transformBoundingBox( layer.extent()) except QgsCsException: layerExtent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) else: layerExtent = layer.extent() if extent is None: extent = layerExtent else: extent.combineExtentWith(layerExtent) if extent is None: extent = QgsRectangle(-20026376.39, -20048966.10, 20026376.39, 20048966.10) return "[%f, %f, %f, %f]" % (extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum())
def geotiffWorldToPixelCoords(geotiff, rectDomain: QgsRectangle, rasterCRS: str, domainCRS: str) -> QgsRectangle: """Transforms QgsRectangle coordinates into geotiff image pixel coordinates :geotiff: geotiff :rect: QgsRectangle """ # Transform and scale rect by width/height to obtain normalized image coordiantes rectRef = geotiffBounds(geotiff) rectRefWidth = rectRef.width() rectRefHeight = rectRef.height() domainX = [rectDomain.xMinimum(), rectDomain.xMaximum()] domainY = [rectDomain.yMinimum(), rectDomain.yMaximum()] inProj = Proj(init=domainCRS) outProj = Proj(init=rasterCRS) #print(inProj, outProj, domainCRS, rasterCRS) # print(domainX, domainY) rasterCRSDomainX, rasterCRSDomainY = transform(inProj, outProj, domainX, domainY) # print(rasterCRSDomainX, rasterCRSDomainY) xMin = (rasterCRSDomainX[0] - rectRef.xMinimum()) / rectRefWidth xMax = (rasterCRSDomainX[1] - rectRef.xMinimum()) / rectRefWidth yMin = (rasterCRSDomainY[0] - rectRef.yMinimum()) / rectRefHeight yMax = (rasterCRSDomainY[1] - rectRef.yMinimum()) / rectRefHeight # Scale by image dimensions to obtain pixel coordinates xMin = xMin * geotiff.RasterXSize xMax = xMax * geotiff.RasterXSize yMin = (1.0 - yMin) * geotiff.RasterYSize yMax = (1.0 - yMax) * geotiff.RasterYSize #print(rasterCRS, domainCRS) #Return pixel coordinates # print(xMin, yMin, xMax, yMax) rectOut = QgsRectangle(xMin, yMin, xMax, yMax) return rectOut
def testTransformQgsRectangle_Regression17600(self): """Test that rectangle transform is in the bindings""" myExtent = QgsRectangle(-1797107, 4392148, 6025926, 6616304) myGeoCrs = QgsCoordinateReferenceSystem('EPSG:4326') myUtmCrs = QgsCoordinateReferenceSystem('EPSG:3857') myXForm = QgsCoordinateTransform(myUtmCrs, myGeoCrs, QgsProject.instance()) myTransformedExtent = myXForm.transform(myExtent) myTransformedExtentForward = myXForm.transform(myExtent, QgsCoordinateTransform.ForwardTransform) self.assertAlmostEqual(myTransformedExtentForward.xMaximum(), myTransformedExtent.xMaximum()) self.assertAlmostEqual(myTransformedExtentForward.xMinimum(), myTransformedExtent.xMinimum()) self.assertAlmostEqual(myTransformedExtentForward.yMaximum(), myTransformedExtent.yMaximum()) self.assertAlmostEqual(myTransformedExtentForward.yMinimum(), myTransformedExtent.yMinimum()) self.assertAlmostEqual(myTransformedExtentForward.xMaximum(), 54.13181426773211) self.assertAlmostEqual(myTransformedExtentForward.xMinimum(), -16.14368685298181) self.assertAlmostEqual(myTransformedExtentForward.yMaximum(), 50.971783118386895) self.assertAlmostEqual(myTransformedExtentForward.yMinimum(), 36.66235970825241) myTransformedExtentReverse = myXForm.transform(myTransformedExtent, QgsCoordinateTransform.ReverseTransform) self.assertAlmostEqual(myTransformedExtentReverse.xMaximum(), myExtent.xMaximum()) self.assertAlmostEqual(myTransformedExtentReverse.xMinimum(), myExtent.xMinimum()) self.assertAlmostEqual(myTransformedExtentReverse.yMaximum(), myExtent.yMaximum()) self.assertAlmostEqual(myTransformedExtentReverse.yMinimum(), myExtent.yMinimum())
def show_extent(self, extent: QgsRectangle): """Display the extent on the canvas""" self.start_point = QgsPointXY(extent.xMinimum(), extent.yMinimum()) self.end_point = QgsPointXY(extent.xMaximum(), extent.yMaximum()) self.transform_coordinates() self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) point1 = QgsPointXY(self.start_point.x(), self.start_point.y()) point2 = QgsPointXY(self.start_point.x(), self.end_point.y()) point3 = QgsPointXY(self.end_point.x(), self.end_point.y()) point4 = QgsPointXY(self.end_point.x(), self.start_point.y()) self.rubberBand.addPoint(point1, False) self.rubberBand.addPoint(point2, False) self.rubberBand.addPoint(point3, False) self.rubberBand.addPoint(point4, True) self.rubberBand.show() rect = QgsRectangle(self.start_point, self.end_point) self.canvas.setExtent(rect)
def viewAllWms(self): server = geodataServers()[self.comboGeodataServer.currentText()] layers = self.publishableLayers() bbox = QgsRectangle() canvasCrs = iface.mapCanvas().mapSettings().destinationCrs() names = [] for layer in layers: if self.isDataPublished[layer.name()]: names.append(layer.name()) xform = QgsCoordinateTransform(layer.crs(), canvasCrs, QgsProject.instance()) extent = xform.transform(layer.extent()) bbox.combineExtentWith(extent) sbbox = ",".join([ str(v) for v in [ bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum() ] ]) server.openPreview(names, sbbox, canvasCrs.authid())
def testTransformQgsRectangle_Regression17600(self): """Test that rectangle transform is in the bindings""" myExtent = QgsRectangle(-1797107, 4392148, 6025926, 6616304) myGeoCrs = QgsCoordinateReferenceSystem() myGeoCrs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) myUtmCrs = QgsCoordinateReferenceSystem() myUtmCrs.createFromId(3857, QgsCoordinateReferenceSystem.EpsgCrsId) myXForm = QgsCoordinateTransform(myUtmCrs, myGeoCrs, QgsProject.instance()) myTransformedExtent = myXForm.transform(myExtent) myTransformedExtentForward = myXForm.transform(myExtent, QgsCoordinateTransform.ForwardTransform) self.assertAlmostEquals(myTransformedExtentForward.xMaximum(), myTransformedExtent.xMaximum()) self.assertAlmostEquals(myTransformedExtentForward.xMinimum(), myTransformedExtent.xMinimum()) self.assertAlmostEquals(myTransformedExtentForward.yMaximum(), myTransformedExtent.yMaximum()) self.assertAlmostEquals(myTransformedExtentForward.yMinimum(), myTransformedExtent.yMinimum()) self.assertAlmostEquals(myTransformedExtentForward.xMaximum(), 54.13181426773211) self.assertAlmostEquals(myTransformedExtentForward.xMinimum(), -16.14368685298181) self.assertAlmostEquals(myTransformedExtentForward.yMaximum(), 50.971783118386895) self.assertAlmostEquals(myTransformedExtentForward.yMinimum(), 36.66235970825241) myTransformedExtentReverse = myXForm.transform(myTransformedExtent, QgsCoordinateTransform.ReverseTransform) self.assertAlmostEquals(myTransformedExtentReverse.xMaximum(), myExtent.xMaximum()) self.assertAlmostEquals(myTransformedExtentReverse.xMinimum(), myExtent.xMinimum()) self.assertAlmostEquals(myTransformedExtentReverse.yMaximum(), myExtent.yMaximum()) self.assertAlmostEquals(myTransformedExtentReverse.yMinimum(), myExtent.yMinimum())
def __init__(self, features): """Constructor that initialize the Epsilon (near zero) object. The dynamic (range) of the feature can vary a lot. We calculate the dynamic of the bounding box of all the features and we use it to estimate an epsilon (zero). when the range of the bounding box is very small the epsilon can be very small and the opposite when the bigger the bounding box is. :param: [QgsFeatures] features: List of QgsFeature to process. :return: None :rtype: None """ if len(features) >= 1: b_box = features[0].geometry().boundingBox( ) # Initialize the bounding box else: b_box = QgsRectangle(0, 0, 1, 1) # Manage empty list of feature for feature in features: b_box.combineExtentWith( feature.geometry().boundingBox()) # Update the bbox delta_x = abs(b_box.xMinimum()) + abs(b_box.xMaximum()) delta_y = abs(b_box.yMinimum()) + abs(b_box.yMaximum()) dynamic_xy = max(delta_x, delta_y) # Dynamic of the bounding box if dynamic_xy == 0.0: dynamic_xy = 1.0E-15 log_loss = int(math.log(dynamic_xy, 10) + 1) max_digit = 15 # Number of meaningful digits for real number security = 2 # Keep 2 order of magnitude of security abs_digit = max_digit - security rel_digit = max_digit - log_loss - security self._zero_relative = (1. / (10**rel_digit)) self._zero_absolute = (1. / (10**abs_digit)) self._zero_angle = math.radians( .0001) # Angle used to decide a flat angle
def processAlgorithm(self, parameters, context, feedback): extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) hOverlay = self.getParameterValue(self.HOVERLAY) vOverlay = self.getParameterValue(self.VOVERLAY) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise GeoAlgorithmExecutionException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr('Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) fields = QgsFields() fields.append(QgsField('left', QVariant.Double, '', 24, 16)) fields.append(QgsField('top', QVariant.Double, '', 24, 16)) fields.append(QgsField('right', QVariant.Double, '', 24, 16)) fields.append(QgsField('bottom', QVariant.Double, '', 24, 16)) fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.LineString, crs, context) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat, QgsFeatureSink.FastInsert) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat, QgsFeatureSink.FastInsert) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) del writer
def processAlgorithm(self, progress): extent = self.getParameterValue(self.EXTENT).split(",") hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException(self.tr("Invalid grid spacing: %s/%s" % (hSpacing, vSpacing))) if width < hSpacing: raise GeoAlgorithmExecutionException(self.tr("Horizontal spacing is too small for the covered area")) if height < vSpacing: raise GeoAlgorithmExecutionException(self.tr("Vertical spacing is too small for the covered area")) fields = [ QgsField("left", QVariant.Double, "", 24, 16), QgsField("top", QVariant.Double, "", 24, 16), QgsField("right", QVariant.Double, "", 24, 16), QgsField("bottom", QVariant.Double, "", 24, 16), QgsField("id", QVariant.Int, "", 10, 0), QgsField("coord", QVariant.Double, "", 24, 15), ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.LineString, crs) feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPointV2(bbox.xMinimum(), y) pt2 = QgsPointV2(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat) y = y - vSpacing id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(int(count / count_max * 50)) progress.setPercentage(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPointV2(x, bbox.yMaximum()) pt2 = QgsPointV2(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat) x = x + hSpacing id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(50 + int(count / count_max * 50)) del writer
def processAlgorithm(self, progress): """ Based on code by Matthew Perry https://gist.github.com/perrygeo/5667173 """ layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_VECTOR)) rasterPath = unicode(self.getParameterValue(self.INPUT_RASTER)) bandNumber = self.getParameterValue(self.RASTER_BAND) columnPrefix = self.getParameterValue(self.COLUMN_PREFIX) useGlobalExtent = self.getParameterValue(self.GLOBAL_EXTENT) rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() rasterBand = rasterDS.GetRasterBand(bandNumber) noData = rasterBand.GetNoDataValue() cellXSize = abs(geoTransform[1]) cellYSize = abs(geoTransform[5]) rasterXSize = rasterDS.RasterXSize rasterYSize = rasterDS.RasterYSize rasterBBox = QgsRectangle(geoTransform[0], geoTransform[3] - cellYSize * rasterYSize, geoTransform[0] + cellXSize * rasterXSize, geoTransform[3]) rasterGeom = QgsGeometry.fromRect(rasterBBox) crs = osr.SpatialReference() crs.ImportFromProj4(str(layer.crs().toProj4())) if useGlobalExtent: xMin = rasterBBox.xMinimum() xMax = rasterBBox.xMaximum() yMin = rasterBBox.yMinimum() yMax = rasterBBox.yMaximum() (startColumn, startRow) = mapToPixel(xMin, yMax, geoTransform) (endColumn, endRow) = mapToPixel(xMax, yMin, geoTransform) width = endColumn - startColumn height = endRow - startRow srcOffset = (startColumn, startRow, width, height) srcArray = rasterBand.ReadAsArray(*srcOffset) newGeoTransform = ( geoTransform[0] + srcOffset[0] * geoTransform[1], geoTransform[1], 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, geoTransform[5], ) memVectorDriver = ogr.GetDriverByName('Memory') memRasterDriver = gdal.GetDriverByName('MEM') fields = layer.pendingFields() (idxMin, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'min', 21, 6) (idxMax, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'max', 21, 6) (idxSum, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'sum', 21, 6) (idxCount, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'count', 21, 6) (idxMean, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'mean', 21, 6) (idxStd, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'std', 21, 6) (idxUnique, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'unique', 21, 6) (idxRange, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'range', 21, 6) (idxVar, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'var', 21, 6) # idxMedian, fields = ftools_utils.findOrCreateField(layer, fields, # columnPrefix + "median", 21, 6) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), layer.dataProvider().geometryType(), layer.crs()) outFeat = QgsFeature() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) current = 0 features = vector.features(layer) total = 100.0 / len(features) for f in features: geom = f.geometry() intersectedGeom = rasterGeom.intersection(geom) ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.exportToWkt()) if not useGlobalExtent: bbox = intersectedGeom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startColumn, startRow) = mapToPixel(xMin, yMax, geoTransform) (endColumn, endRow) = mapToPixel(xMax, yMin, geoTransform) width = endColumn - startColumn height = endRow - startRow if width == 0 or height == 0: continue srcOffset = (startColumn, startRow, width, height) srcArray = rasterBand.ReadAsArray(*srcOffset) newGeoTransform = ( geoTransform[0] + srcOffset[0] * geoTransform[1], geoTransform[1], 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, geoTransform[5], ) # Create a temporary vector layer in memory memVDS = memVectorDriver.CreateDataSource('out') memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon) ft = ogr.Feature(memLayer.GetLayerDefn()) ft.SetGeometry(ogrGeom) memLayer.CreateFeature(ft) ft.Destroy() # Rasterize it rasterizedDS = memRasterDriver.Create('', srcOffset[2], srcOffset[3], 1, gdal.GDT_Byte) rasterizedDS.SetGeoTransform(newGeoTransform) gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1]) rasterizedArray = rasterizedDS.ReadAsArray() srcArray = numpy.nan_to_num(srcArray) masked = numpy.ma.MaskedArray(srcArray, mask=numpy.logical_or(srcArray == noData, numpy.logical_not(rasterizedArray))) outFeat.setGeometry(geom) attrs = f.attributes() attrs.insert(idxMin, float(masked.min())) attrs.insert(idxMax, float(masked.max())) attrs.insert(idxSum, float(masked.sum())) attrs.insert(idxCount, int(masked.count())) attrs.insert(idxMean, float(masked.mean())) attrs.insert(idxStd, float(masked.std())) attrs.insert(idxUnique, numpy.unique(masked.compressed()).size) attrs.insert(idxRange, float(masked.max()) - float(masked.min())) attrs.insert(idxVar, float(masked.var())) # attrs.insert(idxMedian, float(masked.median())) outFeat.setAttributes(attrs) writer.addFeature(outFeat) memVDS = None rasterizedDS = None current += 1 progress.setPercentage(int(current * total)) rasterDS = None del writer
def closePublishing(self): name = self.projectName() extent = QgsRectangle() epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326") for layer in self._layers: trans = QgsCoordinateTransform(layer.crs(), epsg4326, QgsProject.instance()) layerExtent = trans.transform(layer.extent()) extent.combineExtentWith(layerExtent) sExtent = " ".join([ str(v) for v in [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] ]) def _quote(t): return '"%s"' % t for layer in self._layers: add = {} layerFilename = layer.name() + ".shp" add["DATA"] = _quote(layerFilename) if isinstance(layer, QgsRasterLayer): layerType = "raster" elif isinstance(layer, QgsVectorLayer): layerType = QgsWkbTypes.geometryDisplayString( layer.geometryType()) add["TYPE"] = layerType bbox = layer.extent() if bbox.isEmpty(): bbox.grow(1) metadata = { "wms_abstract": _quote(layer.metadata().abstract()), "wms_title": _quote(layer.name()), "ows_srs": _quote("EPSG:4326 EPSG:3857 " + layer.crs().authid()), "wms_extent": _quote(" ".join([ str(v) for v in [ bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum() ] ])) } if layer.name() in self._metadataLinks: metadata["ows_metadataurl_href"] = _quote( self._metadataLinks[layer.name()]) metadata["ows_metadataurl_type"] = _quote("TC211") metadata["ows_metadataurl_format"] = _quote("XML") add["METADATA"] = metadata warnings = layerStyleAsMapfileFolder(layer, self.mapsFolder(), add) for w in warnings: self.logWarning(w) web = { "IMAGEPATH": '"../data/bridge/webdav/images"', "IMAGEURL": '"http://localhost/images"', "METADATA": { '"wms_title"': _quote(name), '"wms_onlineresource"': _quote(self.layerWmsUrl(layer.name())), '"ows_enable_request"': '"*"', '"ows_srs"': '"EPSG:4326"', '"wms_feature_info_mime_type"': '"text/html"' } } mapElement = { "NAME": _quote(name), "STATUS": 'ON', "CONFIG": '"PROJ_LIB" "%s"' % self.projFolder, "EXTENT": sExtent, "PROJECTION": { 'AUTO': '' }, #todo: add projection info "SYMBOLSET": '"symbols.txt"', "MAXSIZE": 8000, "SHAPEPATH": '"../data"', "SIZE": "700 700", "UNITS": "METERS", "WEB": web, "OUTPUTFORMAT": { "DRIVER": '"AGG/PNG"', "EXTENSION": '"png"', "IMAGEMODE": '"RGB"', "MIMETYPE": '"image/png"' }, "SCALEBAR": { "ALIGN": "CENTER", "OUTLINECOLOR": "0 0 0" } } mapElement["LAYERS"] = [{ "INCLUDE": '"%s.txt"' % layer.name() } for layer in self._layers] mapElement["SYMBOLS"] = [{ "INCLUDE": '"%s_symbols.txt"' % layer.name() } for layer in self._layers] mapfile = {"MAP": mapElement} s = convertDictToMapfile(mapfile) mapfilePath = os.path.join(self.mapsFolder(), name + ".map") with open(mapfilePath, "w") as f: f.write(s) src = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "mapserver", "symbols.txt") dst = self.mapsFolder() shutil.copy2(src, dst) if not self.useLocalFolder: self.uploadFolder(dst)
def processAlgorithm(self, feedback): """ Based on code by Matthew Perry https://gist.github.com/perrygeo/5667173 """ layer = dataobjects.getLayerFromString( self.getParameterValue(self.INPUT_VECTOR)) rasterPath = str(self.getParameterValue(self.INPUT_RASTER)) bandNumber = self.getParameterValue(self.RASTER_BAND) columnPrefix = self.getParameterValue(self.COLUMN_PREFIX) useGlobalExtent = self.getParameterValue(self.GLOBAL_EXTENT) rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geoTransform = rasterDS.GetGeoTransform() rasterBand = rasterDS.GetRasterBand(bandNumber) noData = rasterBand.GetNoDataValue() cellXSize = abs(geoTransform[1]) cellYSize = abs(geoTransform[5]) rasterXSize = rasterDS.RasterXSize rasterYSize = rasterDS.RasterYSize rasterBBox = QgsRectangle(geoTransform[0], geoTransform[3] - cellYSize * rasterYSize, geoTransform[0] + cellXSize * rasterXSize, geoTransform[3]) rasterGeom = QgsGeometry.fromRect(rasterBBox) crs = osr.SpatialReference() crs.ImportFromProj4(str(layer.crs().toProj4())) if useGlobalExtent: xMin = rasterBBox.xMinimum() xMax = rasterBBox.xMaximum() yMin = rasterBBox.yMinimum() yMax = rasterBBox.yMaximum() (startColumn, startRow) = mapToPixel(xMin, yMax, geoTransform) (endColumn, endRow) = mapToPixel(xMax, yMin, geoTransform) width = endColumn - startColumn height = endRow - startRow srcOffset = (startColumn, startRow, width, height) srcArray = rasterBand.ReadAsArray(*srcOffset) srcArray = srcArray * rasterBand.GetScale() + rasterBand.GetOffset( ) newGeoTransform = ( geoTransform[0] + srcOffset[0] * geoTransform[1], geoTransform[1], 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, geoTransform[5], ) memVectorDriver = ogr.GetDriverByName('Memory') memRasterDriver = gdal.GetDriverByName('MEM') fields = layer.fields() (idxMin, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'min', 21, 6) (idxMax, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'max', 21, 6) (idxSum, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'sum', 21, 6) (idxCount, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'count', 21, 6) (idxMean, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'mean', 21, 6) (idxStd, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'std', 21, 6) (idxUnique, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'unique', 21, 6) (idxRange, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'range', 21, 6) (idxVar, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'var', 21, 6) (idxMedian, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'median', 21, 6) if hasSciPy: (idxMode, fields) = vector.findOrCreateField(layer, fields, columnPrefix + 'mode', 21, 6) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), layer.wkbType(), layer.crs()) outFeat = QgsFeature() outFeat.initAttributes(len(fields)) outFeat.setFields(fields) features = vector.features(layer) total = 100.0 / len(features) for current, f in enumerate(features): geom = f.geometry() intersectedGeom = rasterGeom.intersection(geom) ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.exportToWkt()) if not useGlobalExtent: bbox = intersectedGeom.boundingBox() xMin = bbox.xMinimum() xMax = bbox.xMaximum() yMin = bbox.yMinimum() yMax = bbox.yMaximum() (startColumn, startRow) = mapToPixel(xMin, yMax, geoTransform) (endColumn, endRow) = mapToPixel(xMax, yMin, geoTransform) width = endColumn - startColumn height = endRow - startRow if width == 0 or height == 0: continue srcOffset = (startColumn, startRow, width, height) srcArray = rasterBand.ReadAsArray(*srcOffset) srcArray = srcArray * rasterBand.GetScale( ) + rasterBand.GetOffset() newGeoTransform = ( geoTransform[0] + srcOffset[0] * geoTransform[1], geoTransform[1], 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, geoTransform[5], ) # Create a temporary vector layer in memory memVDS = memVectorDriver.CreateDataSource('out') memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon) ft = ogr.Feature(memLayer.GetLayerDefn()) ft.SetGeometry(ogrGeom) memLayer.CreateFeature(ft) ft.Destroy() # Rasterize it rasterizedDS = memRasterDriver.Create('', srcOffset[2], srcOffset[3], 1, gdal.GDT_Byte) rasterizedDS.SetGeoTransform(newGeoTransform) gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1]) rasterizedArray = rasterizedDS.ReadAsArray() srcArray = numpy.nan_to_num(srcArray) masked = numpy.ma.MaskedArray( srcArray, mask=numpy.logical_or(srcArray == noData, numpy.logical_not(rasterizedArray))) outFeat.setGeometry(geom) attrs = f.attributes() v = float(masked.min()) attrs.insert(idxMin, None if numpy.isnan(v) else v) v = float(masked.max()) attrs.insert(idxMax, None if numpy.isnan(v) else v) v = float(masked.sum()) attrs.insert(idxSum, None if numpy.isnan(v) else v) attrs.insert(idxCount, int(masked.count())) v = float(masked.mean()) attrs.insert(idxMean, None if numpy.isnan(v) else v) v = float(masked.std()) attrs.insert(idxStd, None if numpy.isnan(v) else v) attrs.insert(idxUnique, numpy.unique(masked.compressed()).size) v = float(masked.max()) - float(masked.min()) attrs.insert(idxRange, None if numpy.isnan(v) else v) v = float(masked.var()) attrs.insert(idxVar, None if numpy.isnan(v) else v) v = float(numpy.ma.median(masked)) attrs.insert(idxMedian, None if numpy.isnan(v) else v) if hasSciPy: attrs.insert(idxMode, float(mode(masked, axis=None)[0][0])) outFeat.setAttributes(attrs) writer.addFeature(outFeat) memVDS = None rasterizedDS = None feedback.setProgress(int(current * total)) rasterDS = None del writer
def generate(self, writer, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) self.min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) self.max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) self.tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if self.tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) self.wgs_extent = src_to_wgs.transformBoundingBox(extent) self.wgs_extent = [self.wgs_extent.xMinimum(), self.wgs_extent.yMinimum(), self.wgs_extent.xMaximum(), self.wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(self.min_zoom, self.max_zoom + 1): metatiles = get_metatiles(self.wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': self.tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height, 'min_zoom': self.min_zoom, 'max_zoom': self.max_zoom, 'extent': self.wgs_extent, } writer.set_parameters(tile_params) for zoom in range(self.min_zoom, self.max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): if feedback.isCanceled(): break size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) if hasattr(settings, 'setLabelBoundaryGeometry'): label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.write_tile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close()
def processAlgorithm(self, parameters, context, feedback): """ Process algorithm. """ # Points: # origin: user origin point in proj crs # fire_origin: user fire origin point in proj crs # wgs84_origin: origin point in wgs84 crs, used for choosing utm_crs # wgs84_fire_origin: fire origin point in wgs84 crs # utm_origin: origin point in utm crs # utm_fire_origin: fire origin point in utm crs # CRSs: # project_crs: project crs # wgs84_crs: wgs84 crs # utm_crs: utm crs, calculated from wgs84_origin # dem_crs: dem crs, used for grid alignment # Extents: # extent: user selected terrain extent in its own crs. # utm_extent: extent to utm crs, used for FDS domain (MESH), # contains the extent, contained in the following dem_extent. # dem_extent: utm_extent to dem crs, used for FDS terrain (GEOM), # contains the utm_extent, contained in the following tex_extent. # Required for sampling grid alignment with dem raster data. # tex_extent: dem_extent to utm crs, used for FDS terrain texture crop, # contains dem_extent. # Required because the texture should be oriented as utm and # perfectly overlapping to dem_extent results, outputs, project = {}, {}, QgsProject.instance() # Get some of the parameters chid = self.parameterAsString(parameters, "chid", context) project.writeEntry("qgis2fds", "chid", parameters["chid"]) path = self.parameterAsFile(parameters, "path", context) project.writeEntry("qgis2fds", "path", parameters["path"]) landuse_type = self.parameterAsEnum(parameters, "landuse_type", context) project.writeEntry("qgis2fds", "landuse_type", parameters["landuse_type"]) dem_sampling = self.parameterAsInt(parameters, "dem_sampling", context) project.writeEntry("qgis2fds", "dem_sampling", parameters["dem_sampling"]) extent = self.parameterAsExtent(parameters, "extent", context) project.writeEntry("qgis2fds", "extent", parameters["extent"]) # Get layers in their respective crs: dem_layer, landuse_layer, tex_layer dem_layer = self.parameterAsRasterLayer(parameters, "dem_layer", context) project.writeEntry("qgis2fds", "dem_layer", parameters["dem_layer"]) if not parameters["landuse_layer"]: # it is optional landuse_layer = None else: landuse_layer = self.parameterAsRasterLayer( parameters, "landuse_layer", context) project.writeEntry("qgis2fds", "landuse_layer", parameters["landuse_layer"]) if not parameters["tex_layer"]: # it is optional tex_layer = None else: tex_layer = self.parameterAsRasterLayer(parameters, "tex_layer", context) project.writeEntry("qgis2fds", "tex_layer", parameters["tex_layer"]) # Get tex_pixel_size tex_pixel_size = self.parameterAsDouble(parameters, "tex_pixel_size", context) project.writeEntryDouble("qgis2fds", "tex_pixel_size", parameters["tex_pixel_size"]) # Prepare CRSs and check their validity project_crs = QgsProject.instance().crs() project.writeEntry("qgis2fds", "project_crs", project_crs.description()) if not project_crs.isValid(): raise QgsProcessingException( f"Project CRS <{project_crs.description()}> is not valid, cannot proceed." ) wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326") dem_crs = dem_layer.crs() if not dem_crs.isValid(): raise QgsProcessingException( f"DEM layer CRS <{dem_crs.description()}> is not valid, cannot proceed." ) if landuse_layer: landuse_crs = landuse_layer.crs() if not landuse_crs.isValid(): raise QgsProcessingException( f"Landuse layer CRS <{landuse_crs.description()}> is not valid, cannot proceed." ) if tex_layer: tex_crs = tex_layer.crs() if not tex_crs.isValid(): raise QgsProcessingException( f"Texture layer CRS <{tex_crs.description()}> is not valid, cannot proceed." ) # Get origin in WGS84 CRS project_to_wgs84_tr = QgsCoordinateTransform(project_crs, wgs84_crs, QgsProject.instance()) if parameters["origin"] is not None: # preventing a QGIS bug when using parameterAsPoint with crs=wgs84_crs origin = self.parameterAsPoint(parameters, "origin", context) project.writeEntry("qgis2fds", "origin", parameters["origin"]) wgs84_origin = QgsPoint(origin) wgs84_origin.transform(project_to_wgs84_tr) else: # no origin wgs84_origin = QgsPoint(extent.center()) wgs84_origin.transform(project_to_wgs84_tr) feedback.pushInfo( f"Domain origin: {wgs84_origin.x():.6f}, {wgs84_origin.y():.6f} (WGS 84)" ) # Get fire origin in WGS84 CRS if parameters["fire_origin"] is not None: # preventing a QGIS bug when using parameterAsPoint with crs=wgs84_crs fire_origin = self.parameterAsPoint(parameters, "fire_origin", context) project.writeEntry("qgis2fds", "fire_origin", parameters["fire_origin"]) wgs84_fire_origin = QgsPoint(fire_origin) wgs84_fire_origin.transform(project_to_wgs84_tr) else: # no fire origin wgs84_fire_origin = wgs84_origin.clone() feedback.pushInfo( f"Fire origin: {wgs84_fire_origin.x():.6f}, {wgs84_fire_origin.y():.6f} (WGS 84)" ) # Calc utm_crs from wgs84_origin utm_epsg = utils.lonlat_to_epsg(lon=wgs84_origin.x(), lat=wgs84_origin.y()) utm_crs = QgsCoordinateReferenceSystem(utm_epsg) # Feedback on CRSs feedback.pushInfo(f"\nProject CRS: <{project_crs.description()}>") feedback.pushInfo(f"DEM layer CRS: <{dem_crs.description()}>") feedback.pushInfo( f"Landuse layer CRS: <{landuse_layer and landuse_crs.description() or 'no landuse'}>" ) feedback.pushInfo( f"Texture layer CRS: <{tex_layer and tex_crs.description() or 'no texture'}>" ) feedback.pushInfo(f"FDS CRS: <{utm_crs.description()}>") # Get origin in utm_crs wgs84_to_utm_tr = QgsCoordinateTransform(wgs84_crs, utm_crs, QgsProject.instance()) utm_origin = wgs84_origin.clone() utm_origin.transform(wgs84_to_utm_tr) # Check for QGIS bug if utm_origin == wgs84_origin: raise QgsProcessingException( f"[QGIS bug] UTM Origin <{utm_origin}> and WGS84 Origin <{wgs84_origin}> are identical, cannot proceed.\n{wgs84_to_utm_tr}\n{wgs84_crs} {utm_crs}" ) # Get fire origin in utm_crs utm_fire_origin = wgs84_fire_origin.clone() utm_fire_origin.transform(wgs84_to_utm_tr) # Get utm_extent in utm_crs from extent (for MESH) # and dem_extent in dem_crs from utm_extent (for dem_layer sampling to GEOM) utm_extent = self.parameterAsExtent( parameters, "extent", context, crs=utm_crs, ) utm_to_dem_tr = QgsCoordinateTransform(utm_crs, dem_crs, QgsProject.instance()) dem_extent = utm_to_dem_tr.transformBoundingBox(utm_extent) # Get dem_layer resolution and top left extent corner coordinates, # because raster grid starts from top left corner of dem_layer extent dem_layer_xres = dem_layer.rasterUnitsPerPixelX() dem_layer_yres = dem_layer.rasterUnitsPerPixelY() dem_layer_x0, dem_layer_y1 = ( dem_layer.extent().xMinimum(), dem_layer.extent().yMaximum(), ) # Aligning dem_extent top left corner to dem_layer resolution, # never reduce its size x0, y0, x1, y1 = ( dem_extent.xMinimum(), dem_extent.yMinimum(), dem_extent.xMaximum(), dem_extent.yMaximum(), ) x0 = ( dem_layer_x0 # start lower + int( (x0 - dem_layer_x0) / dem_layer_xres) * dem_layer_xres # align - dem_layer_xres / 2.0 # to previous raster pixel center ) y1 = ( dem_layer_y1 # start upper - int( (dem_layer_y1 - y1) / dem_layer_yres) * dem_layer_yres # align + dem_layer_yres / 2.0 # to following raster pixel center ) dem_layer_xres *= dem_sampling # down sampling, if requested dem_layer_yres *= dem_sampling x1 = ( x0 # start lower + (ceil((x1 - x0) / dem_layer_xres) + 0.000001 ) # prevent rounding errors * dem_layer_xres # ceil multiple of xres ) y0 = ( y1 # start upper - (ceil((y1 - y0) / dem_layer_yres) + 0.000001 ) # prevent rounding errors * dem_layer_yres # ceil multiple of yres ) dem_extent = QgsRectangle(x0, y0, x1, y1) # Check dem_layer contains updated dem_extent if not dem_layer.extent().contains(dem_extent): feedback.reportError( "Terrain extent (GEOM) is larger than DEM layer extent, unknown elevations will be set to zero." ) # Calc and check number of dem sampling point dem_sampling_xn = int((x1 - x0) / dem_layer_xres) + 1 dem_sampling_yn = int((y1 - y0) / dem_layer_yres) + 1 if dem_sampling_xn < 3: raise QgsProcessingException( f"Too few sampling points <{dem_sampling_xn}> along x axis, cannot proceed." ) if dem_sampling_yn < 3: raise QgsProcessingException( f"Too few sampling points <{dem_sampling_yn}> along y axis, cannot proceed." ) nverts = (dem_sampling_xn + 1) * (dem_sampling_yn + 1) nfaces = dem_sampling_xn * dem_sampling_yn * 2 # Get tex_extent in utm_crs from dem_crs, # texture shall be aligned to MESH, and exactly cover the GEOM terrain dem_to_utm_tr = QgsCoordinateTransform(dem_crs, utm_crs, QgsProject.instance()) tex_extent = dem_to_utm_tr.transformBoundingBox(dem_extent) # Get FDS domain size in meters utm_extent_xm = utm_extent.xMaximum() - utm_extent.xMinimum() utm_extent_ym = utm_extent.yMaximum() - utm_extent.yMinimum() # Feedback feedback.pushInfo(f"\nFDS domain (MESH)") feedback.pushInfo( f"size: {utm_extent_xm:.1f} x {utm_extent_ym:.1f} meters") feedback.pushInfo(f"\nDEM layer sampling for FDS terrain (GEOM)") feedback.pushInfo( f"resolution: {dem_layer_xres:.1f} x {dem_layer_yres:.1f} meters") feedback.pushInfo(f"geometry: {nverts} verts, {nfaces} faces") feedback.pushInfo(f"\nPress <Cancel> to interrupt the execution.") if DEBUG: # Show utm_extent layer feedback.pushInfo(f"\n[DEBUG] Drawing utm_extent...") x0, y0, x1, y1 = ( utm_extent.xMinimum(), utm_extent.yMinimum(), utm_extent.xMaximum(), utm_extent.yMaximum(), ) alg_params = { "INPUT": f"{x0}, {x1}, {y0}, {y1} [{utm_crs.authid()}]", "OUTPUT": parameters["utm_extent_layer"], } outputs["CreateLayerFromExtent"] = processing.run( "native:extenttolayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) results["utm_extent_layer"] = outputs["CreateLayerFromExtent"][ "OUTPUT"] # Show dem_extent layer feedback.pushInfo(f"[DEBUG] Drawing dem_extent...") x0, y0, x1, y1 = ( dem_extent.xMinimum(), dem_extent.yMinimum(), dem_extent.xMaximum(), dem_extent.yMaximum(), ) alg_params = { "INPUT": f"{x0}, {x1}, {y0}, {y1} [{dem_crs.authid()}]", "OUTPUT": parameters["dem_extent_layer"], } outputs["CreateLayerFromExtent"] = processing.run( "native:extenttolayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) results["dem_extent_layer"] = outputs["CreateLayerFromExtent"][ "OUTPUT"] # Show tex_extent layer feedback.pushInfo(f"[DEBUG] Drawing tex_extent...") x0, y0, x1, y1 = ( tex_extent.xMinimum(), tex_extent.yMinimum(), tex_extent.xMaximum(), tex_extent.yMaximum(), ) alg_params = { "INPUT": f"{x0}, {x1}, {y0}, {y1} [{utm_crs.authid()}]", "OUTPUT": parameters["tex_extent_layer"], } outputs["CreateLayerFromExtent"] = processing.run( "native:extenttolayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) results["tex_extent_layer"] = outputs["CreateLayerFromExtent"][ "OUTPUT"] # Writing texture image to disk if feedback.isCanceled(): return {} feedback.setProgressText( "\n(1/7) Rendering, cropping, and writing texture image, timeout in 30s..." ) utils.write_texture( feedback=feedback, tex_layer=tex_layer, tex_extent=tex_extent, tex_pixel_size=tex_pixel_size, utm_crs=utm_crs, filepath=f"{path}/{chid}_tex.png", imagetype="png", ) # QGIS geographic transformations # Creating sampling grid in DEM crs if feedback.isCanceled(): return {} feedback.setProgressText( "\n(2/7) Creating sampling grid from DEM layer...") alg_params = { "CRS": dem_crs, "EXTENT": dem_extent, "HOVERLAY": 0, "HSPACING": dem_layer_xres, "TYPE": 0, # Points "VOVERLAY": 0, "VSPACING": dem_layer_yres, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateGrid"] = processing.run( "native:creategrid", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # QGIS geographic transformations # Draping Z values to sampling grid in DEM crs if feedback.isCanceled(): return {} feedback.setProgressText( "\n(3/7) Draping elevations from DEM layer to sampling grid...") alg_params = { "BAND": 1, "INPUT": outputs["CreateGrid"]["OUTPUT"], "NODATA": 0, "RASTER": dem_layer, "SCALE": 1, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DrapeSetZValueFromRaster"] = processing.run( "native:setzfromraster", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # QGIS geographic transformations # Sampling landuse layer with sampling grid in UTM CRS if feedback.isCanceled(): return {} feedback.setProgressText("\n(4/7) Sampling landuse layer...") if landuse_layer: alg_params = { "COLUMN_PREFIX": "landuse", "INPUT": outputs["DrapeSetZValueFromRaster"]["OUTPUT"], "RASTERCOPY": parameters["landuse_layer"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["RasterSampling"] = processing.run( "qgis:rastersampling", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) else: feedback.pushInfo("No landuse layer provided, no sampling.") # QGIS geographic transformations # Reprojecting sampling grid to UTM CRS if feedback.isCanceled(): return {} feedback.setProgressText( "\n(5/7) Reprojecting sampling grid layer to UTM CRS...") alg_params = { "INPUT": landuse_layer and outputs["RasterSampling"]["OUTPUT"] or outputs["DrapeSetZValueFromRaster"]["OUTPUT"], "TARGET_CRS": utm_crs, "OUTPUT": parameters["sampling_layer"], } outputs["ReprojectLayer"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) results["sampling_layer"] = outputs["ReprojectLayer"]["OUTPUT"] # Get point_layer and check it point_layer = context.getMapLayer(results["sampling_layer"]) if point_layer.featureCount() < 9: raise QgsProcessingException( f"[QGIS bug] Too few features in sampling layer, cannot proceed.\n{point_layer.featureCount()}" ) # Prepare geometry if feedback.isCanceled(): return {} feedback.setProgressText("\n(6/7) Building FDS geometry...") verts, faces, landuses = geometry.get_geometry( feedback=feedback, point_layer=point_layer, utm_origin=utm_origin, landuse_layer=landuse_layer, ) # Write the FDS case file if feedback.isCanceled(): return {} feedback.setProgressText("\n(7/7) Writing the FDS case file...") fds.write_case( feedback=feedback, dem_layer=dem_layer, landuse_layer=landuse_layer, path=path, chid=chid, wgs84_origin=wgs84_origin, utm_origin=utm_origin, wgs84_fire_origin=wgs84_fire_origin, utm_fire_origin=utm_fire_origin, utm_crs=utm_crs, verts=verts, faces=faces, landuses=landuses, landuse_type=landuse_type, utm_extent=utm_extent, ) return results
def processAlgorithm(self, progress): extent = self.getParameterValue(self.EXTENT).split(',') xSpace = self.getParameterValue(self.STEP_X) ySpace = self.getParameterValue(self.STEP_Y) polygon = self.getParameterValue(self.TYPE) == 0 bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) if polygon: fields.append(QgsField('xmin', QVariant.Double, '', 24, 15)) fields.append(QgsField('xmax', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymin', QVariant.Double, '', 24, 15)) fields.append(QgsField('ymax', QVariant.Double, '', 24, 15)) fieldCount = 5 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPolygon, mapCRS) else: fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) fieldCount = 2 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBLineString, mapCRS) feat = QgsFeature() feat.initAttributes(fieldCount) feat.setFields(fields) geom = QgsGeometry() idVar = 0 if not polygon: count = 0 count_max = (bbox.yMaximum() - bbox.yMinimum()) / ySpace count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = [pt1, pt2] feat.setGeometry(geom.fromPolyline(line)) feat.setAttribute(0, idVar) feat.setAttribute(1, y) writer.addFeature(feat) y = y - ySpace idVar += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(int(count / count_max * 50)) progress.setPercentage(50) # counters for progressbar - update every 5% count = 0 count_max = (bbox.xMaximum() - bbox.xMinimum()) / xSpace count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = [pt1, pt2] feat.setGeometry(geom.fromPolyline(line)) feat.setAttribute(0, idVar) feat.setAttribute(1, x) writer.addFeature(feat) x = x + xSpace idVar += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(50 + int(count / count_max * 50)) else: # counters for progressbar - update every 5% count = 0 count_max = (bbox.yMaximum() - bbox.yMinimum()) / ySpace count_update = count_max * 0.05 y = bbox.yMaximum() while y >= bbox.yMinimum(): x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, y) pt2 = QgsPoint(x + xSpace, y) pt3 = QgsPoint(x + xSpace, y - ySpace) pt4 = QgsPoint(x, y - ySpace) pt5 = QgsPoint(x, y) polygon = [[pt1, pt2, pt3, pt4, pt5]] feat.setGeometry(geom.fromPolygon(polygon)) feat.setAttribute(0, idVar) feat.setAttribute(1, x) feat.setAttribute(2, x + xSpace) feat.setAttribute(3, y - ySpace) feat.setAttribute(4, y) writer.addFeature(feat) idVar += 1 x = x + xSpace y = y - ySpace count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(int(count / count_max * 100)) del writer
def processAlgorithm(self, feedback): extent = self.getParameterValue(self.EXTENT).split(',') xSpace = self.getParameterValue(self.STEP_X) ySpace = self.getParameterValue(self.STEP_Y) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) fieldCount = 2 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, mapCRS) feat = QgsFeature() feat.initAttributes(fieldCount) feat.setFields(fields) geom = QgsGeometry() idVar = 0 count = 0 count_max = (bbox.yMaximum() - bbox.yMinimum()) / ySpace count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = [pt1, pt2] feat.setGeometry(geom.fromPolyline(line)) feat.setAttribute(0, idVar) feat.setAttribute(1, y) writer.addFeature(feat) y = y - ySpace idVar += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # counters for progressbar - update every 5% count = 0 count_max = (bbox.xMaximum() - bbox.xMinimum()) / xSpace count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = [pt1, pt2] feat.setGeometry(geom.fromPolyline(line)) feat.setAttribute(0, idVar) feat.setAttribute(1, x) writer.addFeature(feat) x = x + xSpace idVar += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) del writer
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException(self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException(self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results
class HeatmapPixelSizeWidget(BASE, WIDGET): def __init__(self): super(HeatmapPixelSizeWidget, self).__init__(None) self.setupUi(self) self.layer_bounds = QgsRectangle() self.layer = None self.raster_bounds = QgsRectangle() self.radius = 100 self.radius_field = None self.mCellXSpinBox.setShowClearButton(False) self.mCellYSpinBox.setShowClearButton(False) self.mRowsSpinBox.setShowClearButton(False) self.mColumnsSpinBox.setShowClearButton(False) self.mCellYSpinBox.valueChanged.connect(self.mCellXSpinBox.setValue) self.mCellXSpinBox.valueChanged.connect(self.pixelSizeChanged) self.mRowsSpinBox.valueChanged.connect(self.rowsChanged) self.mColumnsSpinBox.valueChanged.connect(self.columnsChanged) def setRadius(self, radius): self.radius = radius self.recalculate_bounds() def setRadiusField(self, radius_field): self.radius_field = radius_field self.recalculate_bounds() def setLayer(self, layer): if not layer: return bounds = layer.extent() if bounds.isNull(): return self.layer = layer self.layer_bounds = bounds self.recalculate_bounds() def recalculate_bounds(self): self.raster_bounds = QgsRectangle(self.layer_bounds) if not self.layer: return max_radius = self.radius if self.radius_field: idx = self.layer.fields().lookupField(self.radius_field) try: max_radius = float(self.layer.maximumValue(idx)) except: pass self.raster_bounds.setXMinimum(self.raster_bounds.xMinimum() - max_radius) self.raster_bounds.setYMinimum(self.raster_bounds.yMinimum() - max_radius) self.raster_bounds.setXMaximum(self.raster_bounds.xMaximum() + max_radius) self.raster_bounds.setYMaximum(self.raster_bounds.yMaximum() + max_radius) self.pixelSizeChanged() def pixelSizeChanged(self): cell_size = self.mCellXSpinBox.value() if cell_size <= 0: return self.mCellYSpinBox.blockSignals(True) self.mCellYSpinBox.setValue(cell_size) self.mCellYSpinBox.blockSignals(False) rows = max(round(self.raster_bounds.height() / cell_size) + 1, 1) cols = max(round(self.raster_bounds.width() / cell_size) + 1, 1) self.mRowsSpinBox.blockSignals(True) self.mRowsSpinBox.setValue(rows) self.mRowsSpinBox.blockSignals(False) self.mColumnsSpinBox.blockSignals(True) self.mColumnsSpinBox.setValue(cols) self.mColumnsSpinBox.blockSignals(False) def rowsChanged(self): rows = self.mRowsSpinBox.value() if rows <= 0: return cell_size = self.raster_bounds.height() / rows cols = max(round(self.raster_bounds.width() / cell_size) + 1, 1) self.mColumnsSpinBox.blockSignals(True) self.mColumnsSpinBox.setValue(cols) self.mColumnsSpinBox.blockSignals(False) for w in [self.mCellXSpinBox, self.mCellYSpinBox]: w.blockSignals(True) w.setValue(cell_size) w.blockSignals(False) def columnsChanged(self): cols = self.mColumnsSpinBox.value() if cols < 2: return cell_size = self.raster_bounds.width() / (cols - 1) rows = max(round(self.raster_bounds.height() / cell_size), 1) self.mRowsSpinBox.blockSignals(True) self.mRowsSpinBox.setValue(rows) self.mRowsSpinBox.blockSignals(False) for w in [self.mCellXSpinBox, self.mCellYSpinBox]: w.blockSignals(True) w.setValue(cell_size) w.blockSignals(False) def setValue(self, value): try: numeric_value = float(value) except: return False self.mCellXSpinBox.setValue(numeric_value) self.mCellYSpinBox.setValue(numeric_value) return True def value(self): return self.mCellXSpinBox.value()
def search_data(self, **kwargs): """ Get plot geometries associated with parcels, both collected and supplies, zoom to them, fill comparison table and activate map swipe tool. To fill the comparison table we build two search dicts, one for supplies (already given because the alphanumeric search is on supplies db source), and another one for collected. For the latter, we have 3 cases. We specify them below (inline). :param kwargs: key-value (field name-field value) to search in parcel tables, both collected and supplies Normally, keys are parcel_number, old_parcel_number or FMI, but if duplicates are found, an additional t_id disambiguates only for the collected source. In the supplies source we assume we will not find duplicates, if there are, we will choose the first record found an will not deal with letting the user choose one of the duplicates by hand (as we do for the collected source). """ self.chk_show_all_plots.setEnabled(False) self.chk_show_all_plots.setChecked(True) self.initialize_tools_and_layers() # Reset any filter on layers plots_supplies = list() plots_collected = list() self.clear_result_table() search_option = self.cbo_parcel_fields.currentData() search_field_supplies = get_supplies_search_options( self.utils._supplies_db.names)[search_option] search_field_collected = get_collected_search_options( self.utils._db.names)[search_option] search_value = list(kwargs.values())[0] # Build search criterion for both supplies and collected search_criterion_supplies = {search_field_supplies: search_value} # Get supplies parcel's t_id and get related plot(s) expression_supplies = QgsExpression("{}='{}'".format( search_field_supplies, search_value)) request = QgsFeatureRequest(expression_supplies) field_idx = self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].fields().indexFromName( self.utils._supplies_db.names.T_ID_F) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([field_idx ]) # Note: this adds a new flag supplies_parcels = [ feature for feature in self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PARCEL_T].getFeatures(request) ] if len(supplies_parcels) > 1: # We do not expect duplicates in the supplies source! pass # We'll choose the first one anyways elif len(supplies_parcels) == 0: self.logger.info( __name__, "No supplies parcel found! Search: {}={}".format( search_field_supplies, search_value)) supplies_plot_t_ids = [] if supplies_parcels: supplies_plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels_supplies( self.utils._supplies_db, [supplies_parcels[0][self.utils._supplies_db.names.T_ID_F]], self.utils._supplies_db.names.T_ID_F, self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) if supplies_plot_t_ids: self._current_supplies_substring = "\"{}\" IN ('{}')".format( self.utils._supplies_db.names.T_ID_F, "','".join([str(t_id) for t_id in supplies_plot_t_ids])) plots_supplies = self.utils.ladm_data.get_features_from_t_ids( self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T], self.utils._supplies_db.names.T_ID_F, supplies_plot_t_ids, True) # Now get COLLECTED parcel's t_id to build the search dict for collected collected_parcel_t_id = None if 'collected_parcel_t_id' in kwargs: # This is the case when this panel is called and we already know the parcel number is duplicated collected_parcel_t_id = kwargs['collected_parcel_t_id'] search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } # As there are duplicates, we need to use t_ids else: # This is the case when: # + Either this panel was called and we know the parcel number is not duplicated, or # + This panel was shown without knowing about duplicates (e.g., individual parcel search) and we still # need to discover whether we have duplicates for this search criterion search_criterion_collected = {search_field_collected: search_value} expression_collected = QgsExpression("{}='{}'".format( search_field_collected, search_value)) request = QgsFeatureRequest(expression_collected) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes( [self.utils._db.names.T_ID_F], self.utils._layers[self.utils._db.names.LC_PARCEL_T].fields( )) # Note this adds a new flag collected_parcels = self.utils._layers[ self.utils._db.names.LC_PARCEL_T].getFeatures(request) collected_parcels_t_ids = [ feature[self.utils._db.names.T_ID_F] for feature in collected_parcels ] if collected_parcels_t_ids: collected_parcel_t_id = collected_parcels_t_ids[0] if len(collected_parcels_t_ids ) > 1: # Duplicates in collected source after a search QApplication.restoreOverrideCursor( ) # Make sure cursor is not waiting (it is if on an identify) QCoreApplication.processEvents() dlg_select_parcel = SelectDuplicateParcelDialog( self.utils, collected_parcels_t_ids, self.parent) dlg_select_parcel.exec_() if dlg_select_parcel.parcel_t_id: # User selected one of the duplicated parcels collected_parcel_t_id = dlg_select_parcel.parcel_t_id search_criterion_collected = { self.utils._db.names.T_ID_F: collected_parcel_t_id } else: return # User just cancelled the dialog, there is nothing more to do self.fill_table(search_criterion_supplies, search_criterion_collected) # Now get related plot(s) for both collected and supplies, if collected_parcel_t_id is not None: plot_t_ids = self.utils.ladm_data.get_plots_related_to_parcels( self.utils._db, [collected_parcel_t_id], self.utils._db.names.T_ID_F, plot_layer=self.utils._layers[self.utils._db.names.LC_PLOT_T], uebaunit_table=self.utils._layers[ self.utils._db.names.COL_UE_BAUNIT_T]) if plot_t_ids: self._current_substring = "{} IN ('{}')".format( self.utils._db.names.T_ID_F, "','".join([str(t_id) for t_id in plot_t_ids])) plots_collected = self.utils.ladm_data.get_features_from_t_ids( self.utils._layers[self.utils._db.names.LC_PLOT_T], self.utils._db.names.T_ID_F, plot_t_ids, True) # Zoom to combined extent plot_features = plots_supplies + plots_collected # Feature list plots_extent = QgsRectangle() for plot in plot_features: plots_extent.combineExtentWith(plot.geometry().boundingBox()) if not plots_extent.isEmpty(): self.utils.iface.mapCanvas().zoomToFeatureExtent(plots_extent) if plots_supplies and plots_collected: # Otherwise the map swipe tool doesn't add any value :) # Activate Swipe Tool self.utils.app.gui.activate_layer(self.utils._supplies_layers[ self.utils._supplies_db.names.GC_PLOT_T]) self.parent.activate_map_swipe_tool() # Send a custom mouse move on the map to make the map swipe tool's limit appear on the canvas coord_x = plots_extent.xMaximum() - (plots_extent.xMaximum( ) - plots_extent.xMinimum()) / 9 # 90% coord_y = plots_extent.yMaximum() - (plots_extent.yMaximum( ) - plots_extent.yMinimum()) / 2 # 50% coord_transform = self.utils.iface.mapCanvas( ).getCoordinateTransform() map_point = coord_transform.transform(coord_x, coord_y) widget_point = map_point.toQPointF().toPoint() global_point = self.utils.canvas.mapToGlobal(widget_point) self.utils.canvas.mousePressEvent( QMouseEvent(QEvent.MouseButtonPress, global_point, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseMoveEvent( QMouseEvent(QEvent.MouseMove, widget_point + QPoint(1, 0), Qt.NoButton, Qt.LeftButton, Qt.NoModifier)) self.utils.canvas.mouseReleaseEvent( QMouseEvent(QEvent.MouseButtonRelease, widget_point + QPoint(1, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) # Once the query is done, activate the checkbox to alternate all plots/only selected plot self.chk_show_all_plots.setEnabled(True)
def processAlgorithm(self, feedback): extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) hOverlay = self.getParameterValue(self.HOVERLAY) vOverlay = self.getParameterValue(self.VOVERLAY) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: {0}/{1}').format( hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise GeoAlgorithmExecutionException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr( 'Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) fields = [ QgsField('left', QVariant.Double, '', 24, 16), QgsField('top', QVariant.Double, '', 24, 16), QgsField('right', QVariant.Double, '', 24, 16), QgsField('bottom', QVariant.Double, '', 24, 16), QgsField('id', QVariant.Int, '', 10, 0), QgsField('coord', QVariant.Double, '', 24, 15) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, crs) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPointV2(bbox.xMinimum(), y) pt2 = QgsPointV2(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPointV2(x, bbox.yMaximum()) pt2 = QgsPointV2(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) del writer
def rect_to_bbox(rect: QgsRectangle) -> BoundingBox2D: return BoundingBox2D(minx=rect.xMinimum(), maxx=rect.xMaximum(), miny=rect.yMinimum(), maxy=rect.yMaximum())
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException(self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException(self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results