def test_make_features_compatible_geometry(self): """Test corner cases for geometries""" # Make a feature with no geometry layer = self._make_layer('Point') self.assertTrue(layer.isValid()) self.assertTrue(layer.startEditing()) f1 = QgsFeature(layer.fields()) f1.setAttributes([1]) # Check that it is accepted on a Point layer new_features = make_features_compatible([f1], layer) self.assertEqual(len(new_features), 1) self.assertEqual(new_features[0].geometry().asWkt(), '') # Make a geometry-less layer nogeom_layer = QgsMemoryProviderUtils.createMemoryLayer( 'nogeom_layer', layer.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem(4326)) # Check that a geometry-less feature is accepted new_features = make_features_compatible([f1], nogeom_layer) self.assertEqual(len(new_features), 1) self.assertEqual(new_features[0].geometry().asWkt(), '') # Make a geometry-less layer nogeom_layer = QgsMemoryProviderUtils.createMemoryLayer( 'nogeom_layer', layer.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem(4326)) # Check that a Point feature is accepted but geometry was dropped f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = make_features_compatible([f1], nogeom_layer) self.assertEqual(len(new_features), 1) self.assertEqual(new_features[0].geometry().asWkt(), '')
def test_clip(self): mask_layer = QgsMemoryProviderUtils.createMemoryLayer( 'mask_layer', self.vl.fields(), QgsWkbTypes.Polygon, QgsCoordinateReferenceSystem(4326)) self.assertTrue(mask_layer.isValid()) self.assertTrue(mask_layer.startEditing()) f = QgsFeature(mask_layer.fields()) f.setAttributes([1]) f.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')) self.assertTrue(f.isValid()) f2 = QgsFeature(mask_layer.fields()) f2.setAttributes([1]) f2.setGeometry(QgsGeometry.fromWkt('POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))')) self.assertTrue(f2.isValid()) self.assertTrue(mask_layer.addFeatures([f, f2])) mask_layer.commitChanges() mask_layer.rollBack() clip_layer = QgsMemoryProviderUtils.createMemoryLayer( 'clip_layer', self.vl.fields(), QgsWkbTypes.LineString, QgsCoordinateReferenceSystem(4326)) self.assertTrue(clip_layer.isValid()) self.assertTrue(clip_layer.startEditing()) f = QgsFeature(clip_layer.fields()) f.setAttributes([1]) f.setGeometry(QgsGeometry.fromWkt('LINESTRING(-1 -1, 3 3)')) self.assertTrue(f.isValid()) self.assertTrue(clip_layer.addFeatures([f])) self.assertEqual(clip_layer.featureCount(), 1) clip_layer.commitChanges() clip_layer.selectAll() clip_layer.rollBack() QgsProject.instance().addMapLayers([clip_layer, mask_layer]) old_features, new_features = self._alg_tester( 'native:clip', clip_layer, { 'OVERLAY': mask_layer.id(), } ) self.assertEqual(len(new_features), 2) self.assertEqual(new_features[0].geometry().asWkt(), 'LineString (0 0, 1 1)') self.assertEqual(new_features[0].attributes(), [1])
def _make_layer(self, layer_wkb_name): fields = QgsFields() wkb_type = getattr(QgsWkbTypes, layer_wkb_name) fields.append(QgsField('int_f', QVariant.Int)) layer = QgsMemoryProviderUtils.createMemoryLayer( '%s_layer' % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem(4326)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), wkb_type) return layer
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) fields.append(QgsField("binaryfield", QVariant.ByteArray)) fields.append(QgsField("boolfield", QVariant.Bool)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def setUpClass(cls): """Run before all tests""" QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain( "QGIS_TestPyQgsProcessingInPlace.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingInPlace") QgsSettings().clear() Processing.initialize() QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms()) cls.registry = QgsApplication.instance().processingRegistry() fields = QgsFields() fields.append(QgsField('int_f', QVariant.Int)) cls.vl = QgsMemoryProviderUtils.createMemoryLayer( 'mylayer', fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem(4326)) f1 = QgsFeature(cls.vl.fields()) f1['int_f'] = 1 f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) f2 = QgsFeature(cls.vl.fields()) f2['int_f'] = 2 f2.setGeometry(QgsGeometry.fromWkt('Point(9.5 45.6)')) cls.vl.dataProvider().addFeatures([f1, f2]) assert cls.vl.isValid() assert cls.vl.featureCount() == 2 # Multipolygon layer cls.multipoly_vl = QgsMemoryProviderUtils.createMemoryLayer( 'mymultiplayer', fields, QgsWkbTypes.MultiPolygon, QgsCoordinateReferenceSystem(4326)) f3 = QgsFeature(cls.multipoly_vl.fields()) f3.setGeometry(QgsGeometry.fromWkt('MultiPolygon (((2.81856297539240419 41.98170998812887689, 2.81874467773035464 41.98167537995160359, 2.81879535908157752 41.98154066615795443, 2.81866433873670452 41.98144056064155905, 2.81848263699778379 41.98147516865246587, 2.81843195500470811 41.98160988234612034, 2.81856297539240419 41.98170998812887689)),((2.81898589063455907 41.9815711567298635, 2.81892080450418803 41.9816030048432367, 2.81884192631866437 41.98143737613141724, 2.8190679469505846 41.98142270931093378, 2.81898589063455907 41.9815711567298635)))')) f4 = QgsFeature(cls.multipoly_vl.fields()) f4.setGeometry(QgsGeometry.fromWkt('MultiPolygon (((2.81823679385631332 41.98133290154246566, 2.81830770255185703 41.98123540208609228, 2.81825871989355159 41.98112524362621656, 2.81813882853970243 41.98111258462271422, 2.81806791984415872 41.98121008407908761, 2.81811690250246416 41.98132024253896333, 2.81823679385631332 41.98133290154246566)),((2.81835835162010895 41.98123286963267731, 2.8183127674586852 41.98108725356146209, 2.8184520523963692 41.98115436357689134, 2.81835835162010895 41.98123286963267731)))')) cls.multipoly_vl.dataProvider().addFeatures([f3, f4]) assert cls.multipoly_vl.isValid() assert cls.multipoly_vl.featureCount() == 2 QgsProject.instance().addMapLayers([cls.vl, cls.multipoly_vl])
def testTransactionRollback(self): """Test issue https://github.com/qgis/QGIS/issues/48171#issuecomment-1132709901""" d = QTemporaryDir() path = d.path() source_fields = QgsFields() source_fields.append(QgsField('int', QVariant.Int)) vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) f = QgsFeature() f.setAttributes([1]) vl.dataProvider().addFeature(f) tmpfile = os.path.join(path, 'testTransactionRollback.sqlite') options = { 'driverName': 'SpatiaLite', 'layerName': 'test' } err = QgsVectorLayerExporter.exportLayer(vl, tmpfile, "ogr", vl.crs(), False, options) self.assertEqual(err[0], QgsVectorLayerExporter.NoError, 'unexpected import error {0}'.format(err)) vl = QgsVectorLayer( 'dbname=\'{}\' table="test" () sql='.format(tmpfile), 'test', 'spatialite') self.assertTrue(vl.isValid()) p = QgsProject.instance() p.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) self.assertTrue(p.addMapLayer(vl)) cache = QgsVectorLayerCache(vl, 100) am = QgsAttributeTableModel(cache) am.loadLayer() self.assertEqual(am.rowCount(), 1) self.assertTrue(vl.startEditing()) vl.beginEditCommand('edit1') f = QgsFeature() f.setAttributes([2]) self.assertTrue(vl.addFeature(f)) self.assertEqual(am.rowCount(), 2) self.assertEqual(len([f for f in vl.getFeatures()]), 2) vl.endEditCommand() self.assertTrue(vl.rollBack()) self.assertEqual(len([f for f in vl.getFeatures()]), 1) self.assertEqual(am.rowCount(), 1)
def test_make_features_compatible_different_field_length(self): """Test regression #21497""" fields = QgsFields() fields.append(QgsField('int_f1', QVariant.Int)) f1 = QgsFeature(fields) f1.setAttributes([12345]) f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) fields = QgsFields() fields.append(QgsField('int_f2', QVariant.Int)) fields.append(QgsField('int_f1', QVariant.Int)) vl2 = QgsMemoryProviderUtils.createMemoryLayer( 'mymultiplayer', fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem(4326)) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], vl2) self.assertEqual(new_features[0].attributes(), [None, 12345]) f1.setGeometry(QgsGeometry.fromWkt('MultiPoint((9 45))')) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], vl2) self.assertEqual(new_features[0].attributes(), [None, 12345])
def test_make_features_compatible_attributes(self): """Test corner cases for attributes""" # Test feature without attributes fields = QgsFields() fields.append(QgsField('int_f', QVariant.Int)) fields.append(QgsField('str_f', QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer( 'mkfca_layer', fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem(4326)) self.assertTrue(layer.isValid()) f1 = QgsFeature(layer.fields()) f1['int_f'] = 1 f1['str_f'] = 'str' f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(new_features[0].attributes(), f1.attributes()) self.assertTrue(new_features[0].geometry().asWkt(), f1.geometry().asWkt()) # Test pad with 0 with fields f1.setAttributes([]) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], QVariant()) self.assertEqual(new_features[0].attributes()[1], QVariant()) # Test pad with 0 without fields f1 = QgsFeature() f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], QVariant()) self.assertEqual(new_features[0].attributes()[1], QVariant()) # Test drop extra attrs f1 = QgsFeature(layer.fields()) f1.setAttributes([1, 'foo', 'extra']) f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], 1) self.assertEqual(new_features[0].attributes()[1], 'foo')
def test_make_features_compatible_attributes(self): """Test corner cases for attributes""" # Test feature without attributes fields = QgsFields() fields.append(QgsField('int_f', QVariant.Int)) fields.append(QgsField('str_f', QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer( 'mkfca_layer', fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem(4326)) self.assertTrue(layer.isValid()) f1 = QgsFeature(layer.fields()) f1['int_f'] = 1 f1['str_f'] = 'str' f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = make_features_compatible([f1], layer) self.assertEqual(new_features[0].attributes(), f1.attributes()) self.assertTrue(new_features[0].geometry().asWkt(), f1.geometry().asWkt()) # Test pad with 0 with fields f1.setAttributes([]) new_features = make_features_compatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], QVariant()) self.assertEqual(new_features[0].attributes()[1], QVariant()) # Test pad with 0 without fields f1 = QgsFeature() f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = make_features_compatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], QVariant()) self.assertEqual(new_features[0].attributes()[1], QVariant()) # Test drop extra attrs f1 = QgsFeature(layer.fields()) f1.setAttributes([1, 'foo', 'extra']) f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) new_features = make_features_compatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], 1) self.assertEqual(new_features[0].attributes()[1], 'foo')
def parse(self): """ Start parsing the osm file """ # Configuration for OGR gdal.SetConfigOption('OSM_CONFIG_FILE', self._osm_conf) gdal.SetConfigOption('OSM_USE_CUSTOM_INDEXING', 'NO') if not isfile(self.__osmFile): raise GeoAlgorithmException(tr('File does not exist')) uri = self.__osmFile + "|layername=" layers = {} # If loadOnly, no parsing required: # It's used only when we ask to open an osm file if self.__loadOnly: file_name = basename(self.__osmFile) for layer in self.__layers: layers[layer] = QgsVectorLayer(uri + layer, file_name + " " + layer, "ogr") if not layers[layer].isValid(): msg = tr("Error on the layer : {}").format(layer) raise GeoAlgorithmException(msg) return layers # Foreach layers for layer in self.__layers: self.signalText.emit(tr('Parsing layer : {}').format(layer)) layers[layer] = {} # Reading it with a QgsVectorLayer layers[layer]['vectorLayer'] = QgsVectorLayer( uri + layer, "test_" + layer, "ogr") if not layers[layer]['vectorLayer'].isValid(): msg = "Error on the layer : {}".format(layer) raise GeoAlgorithmException(msg) layers[layer]['vectorLayer'].setProviderEncoding('UTF-8') # Set some default tags layers[layer]['tags'] = ['full_id', 'osm_id', 'osm_type'] # Save the geometry type of the layer layers[layer]['geomType'] = layers[layer]['vectorLayer'].wkbType() # Set a featureCount layers[layer]['featureCount'] = 0 # Get the other_tags fields = layers[layer]['vectorLayer'].fields() field_names = [field.name() for field in fields] other_tags_index = field_names.index('other_tags') features = layers[layer]['vectorLayer'].getFeatures() for i, feature in enumerate(features): layers[layer]['featureCount'] += 1 # Improve the parsing if comma in whitelist, # we skip the parsing of tags, but featureCount is needed if self.__whiteListColumn[layer] == ',': continue # Get the "others_tags" field attributes = str(feature.attributes()[other_tags_index]) if attributes: h_store = QgsHstoreUtils.parse(attributes) for key in h_store.keys(): if key not in layers[layer]['tags']: # If the key in OSM is not already in the table if self.__whiteListColumn[layer]: if key in self.__whiteListColumn[layer]: layers[layer]['tags'].append(key) else: layers[layer]['tags'].append(key) percent = int(100 / len(self.__layers) * (i + 1)) self.signalPercentage.emit(percent) # Delete empty layers if this option is set to True if self.__deleteEmptyLayers: delete_layers = [] for keys, values in layers.items(): if values['featureCount'] < 1: delete_layers.append(keys) for layer in delete_layers: del layers[layer] # Creating GeoJSON files for each layers for layer in self.__layers: msg = tr('Creating memory layer : ' + layer) self.signalText.emit(msg) self.signalPercentage.emit(0) # Adding the attribute table fields = QgsFields() for key in layers[layer]['tags']: fields.append(QgsField(key, QVariant.String)) layers[layer]['vector_layer'] = ( QgsMemoryProviderUtils.createMemoryLayer( layer, fields, layers[layer]['geomType'], layers[layer]['vectorLayer'].crs())) layers[layer]['vector_layer'].startEditing() # Foreach feature in the layer features = layers[layer]['vectorLayer'].getFeatures() for i, feature in enumerate(features): fet = QgsFeature() fet.setGeometry(feature.geometry()) new_attributes = [] attributes = feature.attributes() if layer in ['points', 'lines', 'multilinestrings']: if layer == 'points': osm_type = "node" elif layer == 'lines': osm_type = "way" elif layer == 'multilinestrings': osm_type = 'relation' new_attributes.append(self.DIC_OSM_TYPE[osm_type] + str(attributes[0])) new_attributes.append(attributes[0]) new_attributes.append(osm_type) if attributes[1]: h_store = QgsHstoreUtils.parse(str(attributes[1])) for tag in layers[layer]['tags'][3:]: if str(tag) in h_store: new_attributes.append(h_store[tag]) else: new_attributes.append("") fet.setAttributes(new_attributes) layers[layer]['vector_layer'].addFeature(fet) elif layer == 'multipolygons': if attributes[0]: osm_type = "relation" new_attributes.append(self.DIC_OSM_TYPE[osm_type] + str(attributes[0])) new_attributes.append(str(attributes[0])) else: osm_type = "way" new_attributes.append(self.DIC_OSM_TYPE[osm_type] + str(attributes[1])) new_attributes.append(attributes[1]) new_attributes.append(osm_type) h_store = QgsHstoreUtils.parse(str(attributes[2])) for tag in layers[layer]['tags'][3:]: if str(tag) in h_store: new_attributes.append(h_store[tag]) else: new_attributes.append("") fet.setAttributes(new_attributes) layers[layer]['vector_layer'].addFeature(fet) percentage = int(100 / layers[layer]['featureCount'] * (i + 1)) self.signalPercentage.emit(percentage) layers[layer]['vector_layer'].commitChanges() return layers
def processAlgorithm(self, parameters, context, feedback): if DEBUG_MODE: logMessage("processAlgorithm(): {}".format( self.__class__.__name__)) source = self.parameterAsSource(parameters, self.INPUT, context) source_layer = self.parameterAsLayer(parameters, self.INPUT, context) title_field = self.parameterAsString(parameters, self.TITLE_FIELD, context) cf_filter = self.parameterAsBool(parameters, self.CF_FILTER, context) fixed_scale = self.parameterAsEnum(parameters, self.SCALE, context) # == 1 buf = self.parameterAsDouble(parameters, self.BUFFER, context) tex_width = self.parameterAsInt(parameters, self.TEX_WIDTH, context) orig_tex_height = self.parameterAsInt(parameters, self.TEX_HEIGHT, context) out_dir = self.parameterAsString(parameters, self.OUTPUT, context) mapSettings = self.controller.settings.mapSettings baseExtent = self.controller.settings.baseExtent rotation = mapSettings.rotation() orig_size = mapSettings.outputSize() if cf_filter: #TODO: FIX ME #cf_layer = QgsMemoryProviderUtils.createMemoryLayer("current feature", # source_layer.fields(), # source_layer.wkbType(), # source_layer.crs()) doc = QDomDocument("qgis") source_layer.exportNamedStyle(doc) orig_layers = mapSettings.layers() total = source.featureCount() for current, feature in enumerate(source.getFeatures()): if feedback.isCanceled(): break if cf_filter: cf_layer = QgsMemoryProviderUtils.createMemoryLayer( "current feature", source_layer.fields(), source_layer.wkbType(), source_layer.crs()) cf_layer.startEditing() cf_layer.addFeature(feature) cf_layer.commitChanges() cf_layer.importNamedStyle(doc) layers = [ cf_layer if lyr == source_layer else lyr for lyr in orig_layers ] mapSettings.setLayers(layers) title = feature.attribute(title_field) feedback.setProgressText("({}/{}) Exporting {}...".format( current + 1, total, title)) # extent geometry = QgsGeometry(feature.geometry()) geometry.transform(self.transform) center = geometry.centroid().asPoint() if fixed_scale or geometry.type() == QgsWkbTypes.PointGeometry: tex_height = orig_tex_height or int( tex_width * orig_size.height() / orig_size.width()) rect = RotatedRect(center, baseExtent.width(), baseExtent.width() * tex_height / tex_width, rotation).scale(1 + buf / 100) else: geometry.rotate(rotation, center) rect = geometry.boundingBox().scaled(1 + buf / 100) center = RotatedRect.rotatePoint(rect.center(), rotation, center) if orig_tex_height: tex_height = orig_tex_height tex_ratio = tex_width / tex_height rect_ratio = rect.width() / rect.height() if tex_ratio > rect_ratio: rect = RotatedRect(center, rect.height() * tex_ratio, rect.height(), rotation) else: rect = RotatedRect(center, rect.width(), rect.width() / tex_ratio, rotation) else: # fit to buffered geometry bounding box rect = RotatedRect(center, rect.width(), rect.height(), rotation) tex_height = tex_width * rect.height() / rect.width() rect.toMapSettings(mapSettings) mapSettings.setOutputSize(QSize(tex_width, tex_height)) self.controller.settings.setMapSettings(mapSettings) self.export(title, out_dir, feedback) feedback.setProgress(int(current / total * 100)) return {}
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # custom CRS crs = QgsCoordinateReferenceSystem.fromProj( '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs' ) layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM, crs) self.assertTrue(layer.isValid()) self.assertTrue(layer.crs().isValid()) self.assertEqual( layer.crs().toProj(), '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs' ) # clone it, just to check layer2 = layer.clone() self.assertEqual( layer2.crs().toProj(), '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs' ) # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) fields.append(QgsField("binaryfield", QVariant.ByteArray)) fields.append(QgsField("boolfield", QVariant.Bool)) fields.append(QgsField("vallist", QVariant.List, subType=QVariant.Int)) fields.append( QgsField("stringlist", QVariant.StringList, subType=QVariant.String)) fields.append( QgsField("stringlist2", QVariant.List, subType=QVariant.String)) fields.append( QgsField("reallist", QVariant.List, subType=QVariant.Double)) fields.append( QgsField("longlist", QVariant.List, subType=QVariant.LongLong)) fields.append(QgsField("dict", QVariant.Map)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) if layer.fields()[i].name() != 'stringlist2': self.assertEqual(layer.fields()[i].type(), fields[i].type()) else: # we automatically convert List with String subtype to StringList, to match other data providers self.assertEqual(layer.fields()[i].type(), QVariant.StringList) self.assertEqual(layer.fields()[i].length(), fields[i].length()) self.assertEqual(layer.fields()[i].precision(), fields[i].precision(), fields[i].name()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string # field precision fields = QgsFields() fields.append(QgsField("string", QVariant.String, len=10)) fields.append(QgsField("long", QVariant.LongLong, len=6)) fields.append(QgsField("double", QVariant.Double, len=10, prec=7)) fields.append(QgsField("double2", QVariant.Double, len=-1, prec=-1)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) self.assertEqual(layer.fields()[i].length(), fields[i].length()) self.assertEqual(layer.fields()[i].precision(), fields[i].precision())
def layer_to_QgsVectorLayer( source_layer, # pylint: disable=too-many-locals,too-many-branches,too-many-statements input_file, context: Context, fallback_crs=QgsCoordinateReferenceSystem(), defer_layer_uri_set: bool = False): """ Converts a vector layer """ if source_layer.__class__.__name__ == 'CadFeatureLayer': layer = source_layer.layer else: layer = source_layer crs = CrsConverter.convert_crs( layer.layer_extent.crs, context) if layer.layer_extent else QgsCoordinateReferenceSystem() if not crs.isValid(): crs = fallback_crs subset_string = '' if layer.selection_set: subset_string = 'fid in ({})'.format(','.join( [str(s) for s in layer.selection_set])) elif layer.definition_query: subset_string = ExpressionConverter.convert_esri_sql( layer.definition_query) base, _ = os.path.split(input_file) uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri( source_layer=source_layer, obj=layer, base=base, crs=crs, subset=subset_string, context=context) if wkb_type is None or wkb_type == QgsWkbTypes.Unknown: wkb_type = VectorLayerConverter.layer_to_wkb_type(layer) context.layer_type_hint = wkb_type if Qgis.QGIS_VERSION_INT >= 31600: # try to get the layer name so that we can remove it from field references. # e.g. if layer name is polys then qgis won't support to arcgis style "polys.field" format parts = QgsProviderRegistry.instance().decodeUri(provider, uri) context.main_layer_name = parts.get('layerName') if not context.main_layer_name and provider == 'ogr': context.main_layer_name = Path(parts['path']).stem if context.main_layer_name: subset_string = subset_string.replace( context.main_layer_name + '.', '') else: context.main_layer_name = None if provider == 'ogr' and (not file_name or not os.path.exists(file_name) ) and context.invalid_layer_resolver: res = context.invalid_layer_resolver(layer.name, uri, wkb_type) uri = res.uri provider = res.providerKey if Qgis.QGIS_VERSION_INT >= 31000: opts = QgsVectorLayer.LayerOptions() if wkb_type is not None: opts.fallbackWkbType = wkb_type if provider == 'ogr' and subset_string: uri += '|subset={}'.format(subset_string) original_uri = uri if defer_layer_uri_set: uri = 'xxxxxxxxx' + uri vl = QgsVectorLayer(uri, layer.name, provider, opts) if defer_layer_uri_set: vl.setCustomProperty('original_uri', original_uri) else: vl = QgsMemoryProviderUtils.createMemoryLayer( layer.name, QgsFields(), wkb_type, crs) # context.style_folder, _ = os.path.split(output_file) if layer.renderer: renderer = VectorRendererConverter.convert_renderer( layer.renderer, context) try: if not renderer.usingSymbolLevels(): renderer.setUsingSymbolLevels( layer.use_advanced_symbol_levels) except AttributeError: pass if layer.use_page_definition_query: filter_expression = '"{}" {} @atlas_pagename'.format( layer.page_name_field, layer.page_name_match_operator) root_rule = QgsRuleBasedRenderer.Rule(None) # special case -- convert a simple renderer if isinstance(renderer, QgsSingleSymbolRenderer): filter_rule = QgsRuleBasedRenderer.Rule( renderer.symbol().clone()) filter_rule.setFilterExpression(filter_expression) filter_rule.setLabel(layer.name) filter_rule.setDescription(layer.name) root_rule.appendChild(filter_rule) else: source_rule_renderer = QgsRuleBasedRenderer.convertFromRenderer( renderer) filter_rule = QgsRuleBasedRenderer.Rule(None) filter_rule.setFilterExpression(filter_expression) filter_rule.setLabel('Current Atlas Page') filter_rule.setDescription('Current Atlas Page') root_rule.appendChild(filter_rule) for child in source_rule_renderer.rootRule().children(): filter_rule.appendChild(child.clone()) renderer = QgsRuleBasedRenderer(root_rule) if renderer: vl.setRenderer(renderer) vl.triggerRepaint() else: vl.setRenderer(QgsNullSymbolRenderer()) vl.triggerRepaint() metadata = vl.metadata() metadata.setAbstract(layer.description) vl.setMetadata(metadata) # # layer.zoom_max = "don't show when zoomed out beyond" zoom_max = layer.zoom_max # layer.zoom_min = "don't show when zoomed in beyond" zoom_min = layer.zoom_min enabled_scale_range = bool(zoom_max or zoom_min) if zoom_max and zoom_min and zoom_min > zoom_max: # inconsistent scale range -- zoom_max should be bigger number than zoom_min zoom_min, zoom_max = zoom_max, zoom_min # qgis minimum scale = don't show when zoomed out beyond, i.e. ArcGIS zoom_max vl.setMinimumScale( zoom_max if enabled_scale_range else layer.stored_zoom_max) # qgis maximum scale = don't show when zoomed in beyond, i.e. ArcGIS zoom_min vl.setMaximumScale( zoom_min if enabled_scale_range else layer.stored_zoom_min) vl.setScaleBasedVisibility(enabled_scale_range) vl.setOpacity(1.0 - (layer.transparency or 0) / 100) if layer.display_expression_properties and layer.display_expression_properties.expression and layer.display_expression_properties.expression_parser is not None: vl.setDisplayExpression( ExpressionConverter.convert( layer.display_expression_properties.expression, layer.display_expression_properties.expression_parser, layer.display_expression_properties.advanced, context)) if Qgis.QGIS_VERSION_INT < 31000: vl.setDataSource(uri, layer.name, provider) if encoding: vl.dataProvider().setEncoding(encoding) if subset_string: vl.setSubsetString(subset_string) vl.setCrs(crs) for e in layer.extensions: if e.__class__.__name__ == 'ServerLayerExtension': if 'CopyrightText' in e.properties.properties: layer_credits = e.properties.properties['CopyrightText'] metadata = vl.metadata() rights = metadata.rights() rights.append(layer_credits) metadata.setRights(rights) vl.setMetadata(metadata) LabelConverter.convert_annotation_collection( layer.annotation_collection, dest_layer=vl, context=context) vl.setLabelsEnabled(layer.labels_enabled) DiagramConverter.convert_diagrams(layer.renderer, dest_layer=vl, context=context) # setup joins join_layer = VectorLayerConverter.add_joined_layer( source_layer=layer, input_file=input_file, base_layer=vl, context=context) context.dataset_name = '' vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl)) if layer.hyperlinks: VectorLayerConverter.convert_hyperlinks(layer.hyperlinks, vl) vl.setDisplayExpression( QgsExpression.quotedColumnRef(layer.display_field)) res = [vl] if join_layer: res.append(join_layer) context.main_layer_name = None return res
def standalone_table_to_QgsVectorLayer( layer: StandaloneTable, # pylint: disable=too-many-locals,too-many-branches input_file, context: Context): """ Converts a standalone table to a vector layer """ subset_string = '' if layer.definition_query: subset_string = ExpressionConverter.convert_esri_sql( layer.definition_query) base, _ = os.path.split(input_file) uri, wkb_type, provider, encoding, file_name = VectorLayerConverter.get_uri( source_layer=layer, obj=layer, base=base, crs=QgsCoordinateReferenceSystem(), subset=subset_string, context=context) if wkb_type is None: wkb_type = QgsWkbTypes.NoGeometry context.layer_type_hint = wkb_type if provider == 'ogr' and (not file_name or not os.path.exists(file_name) ) and context.invalid_layer_resolver: res = context.invalid_layer_resolver(layer.name, uri, wkb_type) uri = res.uri provider = res.providerKey if Qgis.QGIS_VERSION_INT >= 31000: opts = QgsVectorLayer.LayerOptions() if wkb_type is not None: opts.fallbackWkbType = wkb_type if provider == 'ogr' and subset_string: uri += '|subset={}'.format(subset_string) vl = QgsVectorLayer(uri, layer.name, provider, opts) else: vl = QgsMemoryProviderUtils.createMemoryLayer( layer.name, QgsFields(), wkb_type, QgsCoordinateReferenceSystem()) metadata = vl.metadata() metadata.setAbstract(layer.description) vl.setMetadata(metadata) # if Qgis.QGIS_VERSION_INT < 31000: vl.setDataSource(uri, layer.name, provider) if encoding: vl.dataProvider().setEncoding(encoding) if subset_string: vl.setSubsetString(subset_string) for e in layer.extensions: if e.__class__.__name__ == 'ServerLayerExtension': if 'CopyrightText' in e.properties.properties: layer_credits = e.properties.properties['CopyrightText'] metadata = vl.metadata() rights = metadata.rights() rights.append(layer_credits) metadata.setRights(rights) vl.setMetadata(metadata) # setup joins join_layer = VectorLayerConverter.add_joined_layer( source_layer=layer, input_file=input_file, base_layer=vl, context=context) context.dataset_name = '' vl.setLegend(QgsMapLayerLegend.defaultVectorLegend(vl)) res = [vl] if join_layer: res.append(join_layer) return res
def parse(self): """ Start parsing the osm file """ # Configuration for OGR gdal.SetConfigOption('OSM_CONFIG_FILE', self._osm_conf) gdal.SetConfigOption('OSM_USE_CUSTOM_INDEXING', 'NO') if not isfile(self.__osmFile): raise GeoAlgorithmException(tr('File does not exist')) uri = self.__osmFile + "|layername=" layers = {} # If loadOnly, no parsing required: # It's used only when we ask to open an osm file if self.__loadOnly: file_name = basename(self.__osmFile) for layer in self.__layers: layers[layer] = QgsVectorLayer( uri + layer, file_name + " " + layer, "ogr") if not layers[layer].isValid(): msg = tr("Error on the layer : {}").format(layer) raise GeoAlgorithmException(msg) return layers # Foreach layers for layer in self.__layers: self.signalText.emit(tr('Parsing layer : {}').format(layer)) layers[layer] = {} # Reading it with a QgsVectorLayer layers[layer]['vectorLayer'] = QgsVectorLayer( uri + layer, "test_" + layer, "ogr") if not layers[layer]['vectorLayer'].isValid(): msg = "Error on the layer : {}".format(layer) raise GeoAlgorithmException(msg) layers[layer]['vectorLayer'].setProviderEncoding('UTF-8') # Set some default tags layers[layer]['tags'] = ['full_id', 'osm_id', 'osm_type'] # Save the geometry type of the layer layers[layer]['geomType'] = layers[layer]['vectorLayer'].wkbType() # Set a featureCount layers[layer]['featureCount'] = 0 # Get the other_tags fields = layers[layer]['vectorLayer'].fields() field_names = [field.name() for field in fields] other_tags_index = field_names.index('other_tags') features = layers[layer]['vectorLayer'].getFeatures() for i, feature in enumerate(features): layers[layer]['featureCount'] += 1 # Improve the parsing if comma in whitelist, # we skip the parsing of tags, but featureCount is needed if self.__whiteListColumn[layer] == ',': continue # Get the "others_tags" field attributes = str(feature.attributes()[other_tags_index]) if attributes: h_store = QgsHstoreUtils.parse(attributes) for key in h_store.keys(): if key not in layers[layer]['tags']: # If the key in OSM is not already in the table if self.__whiteListColumn[layer]: if key in self.__whiteListColumn[layer]: layers[layer]['tags'].append(key) else: layers[layer]['tags'].append(key) percent = int(100 / len(self.__layers) * (i + 1)) self.signalPercentage.emit(percent) # Delete empty layers if this option is set to True if self.__deleteEmptyLayers: delete_layers = [] for keys, values in layers.items(): if values['featureCount'] < 1: delete_layers.append(keys) for layer in delete_layers: del layers[layer] # Creating GeoJSON files for each layers for layer in self.__layers: msg = tr('Creating memory layer : ' + layer) self.signalText.emit(msg) self.signalPercentage.emit(0) # Adding the attribute table fields = QgsFields() for key in layers[layer]['tags']: fields.append(QgsField(key, QVariant.String)) layers[layer]['vector_layer'] = QgsMemoryProviderUtils.createMemoryLayer( layer, fields, layers[layer]['geomType'], layers[layer]['vectorLayer'].crs()) layers[layer]['vector_layer'].startEditing() # Foreach feature in the layer features = layers[layer]['vectorLayer'].getFeatures() for i, feature in enumerate(features): fet = QgsFeature() fet.setGeometry(feature.geometry()) new_attributes = [] attributes = feature.attributes() if layer in ['points', 'lines', 'multilinestrings']: if layer == 'points': osm_type = "node" elif layer == 'lines': osm_type = "way" elif layer == 'multilinestrings': osm_type = 'relation' new_attributes.append( self.DIC_OSM_TYPE[osm_type] + str(attributes[0])) new_attributes.append(attributes[0]) new_attributes.append(osm_type) if attributes[1]: h_store = QgsHstoreUtils.parse(str(attributes[1])) for tag in layers[layer]['tags'][3:]: if str(tag) in h_store: new_attributes.append(h_store[tag]) else: new_attributes.append("") fet.setAttributes(new_attributes) layers[layer]['vector_layer'].addFeature(fet) elif layer == 'multipolygons': if attributes[0]: osm_type = "relation" new_attributes.append( self.DIC_OSM_TYPE[osm_type] + str(attributes[0])) new_attributes.append(str(attributes[0])) else: osm_type = "way" new_attributes.append( self.DIC_OSM_TYPE[osm_type] + str(attributes[1])) new_attributes.append(attributes[1]) new_attributes.append(osm_type) h_store = QgsHstoreUtils.parse(str(attributes[2])) for tag in layers[layer]['tags'][3:]: if str(tag) in h_store: new_attributes.append(h_store[tag]) else: new_attributes.append("") fet.setAttributes(new_attributes) layers[layer]['vector_layer'].addFeature(fet) percentage = int( 100 / layers[layer]['featureCount'] * (i + 1)) self.signalPercentage.emit(percentage) layers[layer]['vector_layer'].commitChanges() return layers
def processAlgorithm(self, parameters, context, feedback): if DEBUG_MODE: logMessage( "processAlgorithm(): {}".format(self.__class__.__name__), False) clayer = self.parameterAsLayer(parameters, self.INPUT, context) title_field = self.parameterAsString(parameters, self.TITLE_FIELD, context) cf_filter = self.parameterAsBool(parameters, self.CF_FILTER, context) fixed_scale = self.parameterAsEnum(parameters, self.SCALE, context) # == 1 buf = self.parameterAsDouble(parameters, self.BUFFER, context) tex_width = self.parameterAsInt(parameters, self.TEX_WIDTH, context) orig_tex_height = self.parameterAsInt(parameters, self.TEX_HEIGHT, context) header_exp = QgsExpression( self.parameterAsExpression(parameters, self.HEADER, context)) footer_exp = QgsExpression( self.parameterAsExpression(parameters, self.FOOTER, context)) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.layerScope(clayer)) out_dir = self.parameterAsString(parameters, self.OUTPUT, context) if not QDir(out_dir).exists(): QDir().mkpath(out_dir) if DEBUG_MODE: openDirectory(out_dir) mapSettings = self.controller.settings.mapSettings baseExtent = self.controller.settings.baseExtent rotation = mapSettings.rotation() orig_size = mapSettings.outputSize() if cf_filter: cf_layer = QgsMemoryProviderUtils.createMemoryLayer( "current feature", clayer.fields(), clayer.wkbType(), clayer.crs()) layers = [ cf_layer if lyr == clayer else lyr for lyr in mapSettings.layers() ] mapSettings.setLayers(layers) doc = QDomDocument("qgis") clayer.exportNamedStyle(doc) cf_layer.importNamedStyle(doc) total = clayer.featureCount() for current, feature in enumerate(clayer.getFeatures()): if feedback.isCanceled(): break if cf_filter: cf_layer.startEditing() cf_layer.deleteFeatures( [f.id() for f in cf_layer.getFeatures()]) cf_layer.addFeature(feature) cf_layer.commitChanges() title = feature.attribute(title_field) feedback.setProgressText("({}/{}) Exporting {}...".format( current + 1, total, title)) logMessage("Exporting {}...".format(title), False) # extent geometry = QgsGeometry(feature.geometry()) geometry.transform(self.transform) center = geometry.centroid().asPoint() if fixed_scale or geometry.type() == QgsWkbTypes.PointGeometry: tex_height = orig_tex_height or int( tex_width * orig_size.height() / orig_size.width()) rect = RotatedRect(center, baseExtent.width(), baseExtent.width() * tex_height / tex_width, rotation).scale(1 + buf / 100) else: geometry.rotate(rotation, center) rect = geometry.boundingBox().scaled(1 + buf / 100) center = RotatedRect.rotatePoint(rect.center(), rotation, center) if orig_tex_height: tex_height = orig_tex_height tex_ratio = tex_width / tex_height rect_ratio = rect.width() / rect.height() if tex_ratio > rect_ratio: rect = RotatedRect(center, rect.height() * tex_ratio, rect.height(), rotation) else: rect = RotatedRect(center, rect.width(), rect.width() / tex_ratio, rotation) else: # fit to buffered geometry bounding box rect = RotatedRect(center, rect.width(), rect.height(), rotation) tex_height = tex_width * rect.height() / rect.width() rect.toMapSettings(mapSettings) mapSettings.setOutputSize(QSize(tex_width, tex_height)) self.controller.settings.setMapSettings(mapSettings) # labels exp_context.setFeature(feature) self.controller.settings.setHeaderLabel( header_exp.evaluate(exp_context)) self.controller.settings.setFooterLabel( footer_exp.evaluate(exp_context)) self.export(title, out_dir, feedback) feedback.setProgress(int(current / total * 100)) if P_OPEN_DIRECTORY and not DEBUG_MODE: openDirectory(out_dir) return {}