def testOperations(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:26745')) self.assertEqual(len(spy), 0) w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertGreaterEqual(len(w.availableOperations()), 6) self.assertEqual( w.defaultOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().isAvailable) op = QgsCoordinateOperationWidget.OperationDetails() op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' op.allowFallback = True w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' op.allowFallback = False w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 3) op.allowFallback = True w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 4) context = QgsCoordinateTransformContext() op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' w.setSelectedOperation(op) w.setSelectedOperationUsingContext(context) # should go to default, because there's nothing in the context matching these crs self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertEqual(len(spy), 6) # put something in the context context.addCoordinateOperation( w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) w.setSelectedOperationUsingContext(context) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 7) context.addCoordinateOperation( w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84', False) w.setSelectedOperationUsingContext(context) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 8)
def search(self): fields = PLOTS_LAYER_DEFAULT_FIELDS + self.additional_output_fields self.layer_found.startEditing() self.layer_found.dataProvider().addAttributes(fields) self.layer_not_found.startEditing() self.layer_not_found.dataProvider().addAttributes([ QgsField("tresc_bledu", QVariant.String), ]) self.uldk_search = ULDKSearchPoint( "dzialka", ("geom_wkt", "wojewodztwo", "powiat", "gmina", "obreb", "numer", "teryt")) self.uldk_search = ULDKSearchLogger(self.uldk_search) feature_iterator = self.source_layer.getSelectedFeatures( ) if self.selected_only else self.source_layer.getFeatures() source_geom_type = self.source_layer.wkbType() source_crs = self.source_layer.sourceCrs() self.geometries = [] self.not_found_geometries = [] self.parcels_geometry = QgsGeometry.fromMultiPolygonXY([]) self.transformation = None if source_crs != CRS_2180: self.transformation = QgsCoordinateTransform( source_crs, CRS_2180, QgsCoordinateTransformContext()) geom_type = self._get_non_z_geom_type(source_geom_type) if geom_type == QgsWkbTypes.Point or geom_type == QgsWkbTypes.MultiPoint: self.count_not_found_as_progressed = True for index, f in enumerate(feature_iterator): point = f.geometry().asPoint() if self.transformation: point = self.transformation.transform(point) f.setGeometry(QgsGeometry.fromPointXY(point)) self._process_feature(f, True) else: self.count_not_found_as_progressed = False if self.additional_output_fields: self.fields_to_add = QgsFields() for field in self.additional_output_fields: self.fields_to_add.append(field) for f in feature_iterator: additional_attributes = [] if self.additional_output_fields: additional_attributes = [ f.attribute(field.name()) for field in self.additional_output_fields ] points = self._feature_to_points(f, source_geom_type, additional_attributes) continue_search = True while points != []: saved_features = [ self._process_feature(point) for point in points ] if any(saved_features): points = self._feature_to_points( f, source_geom_type, additional_attributes) else: points = [] self.__commit() self.progressed.emit(self.layer_found, self.layer_not_found, True, 0, False, True) self.finished.emit(self.layer_found, self.layer_not_found)
def testStartEditingCommitRollBack(self): ml = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(ml.isValid()) # Layer A geopackage A d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'test_EditBufferGroup_A.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) # Layer B geopackage B options.layerName = 'layer_b' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'test_EditBufferGroup_B.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_b = QgsVectorLayer(newFileName + '|layername=layer_b') self.assertTrue(layer_b.isValid()) # Layer C memory layer_c = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(layer_c.isValid()) project = QgsProject() project.addMapLayers([layer_a, layer_b, layer_c]) project.setTransactionMode(Qgis.TransactionMode.BufferedGroups) editBufferGroup = project.editBufferGroup() # Check layers in group self.assertIn(layer_a, editBufferGroup.layers()) self.assertIn(layer_b, editBufferGroup.layers()) self.assertIn(layer_c, editBufferGroup.layers()) self.assertFalse(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.startEditing()) self.assertTrue(editBufferGroup.isEditing()) self.assertTrue(layer_a.editBuffer()) self.assertTrue(layer_b.editBuffer()) self.assertTrue(layer_c.editBuffer()) self.assertEqual(len(editBufferGroup.modifiedLayers()), 0) commitErrors = [] self.assertTrue(editBufferGroup.commitChanges(commitErrors, False)) self.assertTrue(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.commitChanges(commitErrors, True)) self.assertFalse(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.startEditing()) self.assertTrue(editBufferGroup.isEditing()) f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(len(editBufferGroup.modifiedLayers()), 1) self.assertIn(layer_a, editBufferGroup.modifiedLayers()) # Check feature in layer edit buffer but not in provider till commit self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 0) rollbackErrors = [] self.assertTrue(editBufferGroup.rollBack(rollbackErrors, False)) self.assertTrue(editBufferGroup.isEditing()) self.assertEqual(layer_a.featureCount(), 0) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 0) self.assertTrue(editBufferGroup.commitChanges(commitErrors, True)) self.assertFalse(editBufferGroup.isEditing()) self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 1)
crs: QgsCoordinateReferenceSystem = layer.crs() print(crs) if crs.isGeographic(): raise TypeError("Cannot process data with geographic coordinate system.") fields: QgsFields = layer.fields() save_options = QgsVectorFileWriter.SaveVectorOptions() save_options.fileEncoding = "UTF-8" writer: QgsVectorFileWriter = QgsVectorFileWriter.create( str(path_data_output), fields, QgsWkbTypes.Point, layer.crs(), QgsCoordinateTransformContext(), save_options) features: QgsFeatureIterator = layer.getFeatures() feature: QgsFeature for feature in features: new_feature = QgsFeature(fields) old_geom: QgsGeometry = feature.geometry() new_geom: QgsGeometry = old_geom.poleOfInaccessibility(precision)[0] new_feature.setAttributes(feature.attributes()) new_feature.setGeometry(new_geom)
def testShapefilesWithNoAttributes(self): """Test issue GH #38834""" ml = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'ESRI Shapefile' options.layerName = 'writetest' err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'writetest.shp'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(os.path.join(d.path(), 'writetest.shp'))) vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp')) self.assertTrue(bool(vl.dataProvider().capabilities() & QgsVectorDataProvider.AddFeatures)) # Let's try if we can really add features feature = QgsFeature(vl.fields()) geom = QgsGeometry.fromWkt('POINT(9 45)') feature.setGeometry(geom) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([feature])) self.assertTrue(vl.commitChanges()) del (vl) vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp')) self.assertEqual(vl.featureCount(), 1)
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456]) buffer = layer_a.editBuffer() # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.attribute('int2'), None) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [f.id(), 2, None]) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [f.id(), 1, 123]) # Change geometry f = next(layer_a.getFeatures()) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertTrue(len(spy_geometry_changed), 1) self.assertEqual(spy_geometry_changed[0][0], f.id()) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is another surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') # Change single attribute self.assertTrue(layer_a.startEditing()) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 123) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [1, 1, 111]) self.assertEqual(spy_attribute_changed[1], [1, 2, 654]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 111, 654]) self.assertEqual(buffer.changedAttributeValues(), {1: { 1: 111, 2: 654 }}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [1, 1, 123]) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [1, 2, None]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 123, None]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) layer_a.undoStack().undo() self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(7 45)').asWkt()) self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [ f for f in layer_a.getFeatures() if f.attribute('int') == 555 ][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) # This is totally broken at least on OGR/GPKG: the rollback # does not restore the original fields if False: layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) # Rollback! self.assertTrue(layer_a.rollBack()) self.assertIn('attr1', layer_a.dataProvider().fields().names()) self.assertIn('attr1', layer_a.fields().names()) self.assertEqual(layer_a.fields().names(), layer_a.dataProvider().fields().names()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) ########################################### # Rename attribute attr_idx = layer_a.fields().lookupField(field.name()) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) ############################################# # Try hard to make this fail for transactions if autoTransaction: self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) # Do for i in range(10): spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 2, i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: i }}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), i) # Undo/redo for i in range(9): # Undo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Redo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().redo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 9 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 9 - i]) # Undo again spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Last check f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 0 }}) layer_a.undoStack().undo() buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), None)
def create_shapefile_full_layer_data_provider(path, name, srid, attributes, types, values, coords): """ Creates a shapefile using the Shapefile Data Provider Parameters ---------- path : `str` folder where the shapefile is to be saved name : `str` name of the shapefile srid : `str` CRS of the newly created shapefile attributes: array_like list of attribute (field) names types : array_like list of types (field) types, in sync with the `attributes` parameter values : array_like coordinates and attribute data, one array for each feature (F, C + A), F for features, C for coordinates and A for attribute data coords : array_like indices of the coordinate values within the `values` array Returns ------- vl : `QgsVectorLayer` the newly-created layer """ # create new layer with given attributes filename = path + "/" + name + ".shp" # create an instance of vector file writer, which will create the vector file. writer = None options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = "ESRI Shapefile" options.fileEncoding = 'utf-8' if len(coords) == 2: type = 'point' writer = QgsVectorFileWriter.create(filename, QgsFields(), QgsWkbTypes.Point, srid, QgsCoordinateTransformContext(), options) elif len(coords) == 4: type = 'line' writer = QgsVectorFileWriter.create(filename, QgsFields(), QgsWkbTypes.LineString, srid, QgsCoordinateTransformContext(), options) if writer.hasError() != QgsVectorFileWriter.NoError: print("Error when creating shapefile: ", writer.hasError()) return None del writer # open the newly created file vl = QgsVectorLayer(filename, name, "ogr") pr = vl.dataProvider() # create the required fields for i, attr in enumerate(attributes): pr.addAttributes([QgsField(attr, types[i])]) vl.commitChanges() # add features by iterating the values feat = QgsFeature() for i, val in enumerate(values): # add geometry try: if type == 'point': geometry = QgsGeometry.fromPoint([QgsPoint(float(val[coords[0]]), float(val[coords[1]]))]) elif type == 'line': geometry = QgsGeometry.fromPolyline([QgsPoint(float(val[coords[0]]), float(val[coords[1]])), QgsPoint(float(val[coords[2]]), float(val[coords[3]]))]) feat.setGeometry(geometry) except: pass # add attributes attrs = [] for j, attr in enumerate(attributes): attrs.append(val[j]) feat.setAttributes(attrs) pr.addFeature(feat) vl.updateExtents() vl = QgsVectorLayer(filename, name, "ogr") if not vl.isValid(): raise IOError("Layer could not be created") return None return vl
def testOperations(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28355')) self.assertEqual(len(spy), 0) w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:7855')) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertEqual(len(w.availableOperations()), 3) self.assertEqual( w.defaultOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertTrue(w.selectedOperation().isAvailable) op = QgsCoordinateOperationWidget.OperationDetails() op.proj = '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual(len(spy), 2) w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual(len(spy), 2) op.proj = '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=utm +zone=55 +south +ellps=GRS80' w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual(len(spy), 3) context = QgsCoordinateTransformContext() op.proj = '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' w.setSelectedOperation(op) w.setSelectedOperationUsingContext(context) # should go to default, because there's nothing in the context matching these crs self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual(len(spy), 5) # put something in the context context.addCoordinateOperation( w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' ) w.setSelectedOperationUsingContext(context) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +inv +proj=utm +zone=55 +south +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=utm +zone=55 +south +ellps=GRS80' ) self.assertEqual(len(spy), 6)
def testWriteReadXmlProj6(self): # setup a context context = QgsCoordinateTransformContext() proj_1 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-18.944 +y=-379.364 +z=-24.063 +rx=-0.04 +ry=0.764 +rz=-6.431 +s=3.657 +convention=coordinate_frame +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' proj_2 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-150 +y=-250 +z=-1 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' proj_3 = '+proj=pipeline +step +proj=axisswap +order=2,1' self.assertTrue( context.addCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:4204'), QgsCoordinateReferenceSystem('EPSG:4326'), proj_1, True)) self.assertTrue( context.addCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:4205'), QgsCoordinateReferenceSystem('EPSG:4326'), proj_2, False)) # also insert a crs with no authid available self.assertTrue( context.addCoordinateOperation( QgsCoordinateReferenceSystem.fromProj( "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" ), QgsCoordinateReferenceSystem('EPSG:4326'), proj_3, False)) self.assertEqual( context.coordinateOperations(), { ('EPSG:4204', 'EPSG:4326'): proj_1, ('EPSG:4205', 'EPSG:4326'): proj_2, ('', 'EPSG:4326'): proj_3 }) # save to xml doc = QDomDocument("testdoc") elem = doc.createElement("test") context.writeXml(elem, QgsReadWriteContext()) # restore from xml context2 = QgsCoordinateTransformContext() context2.readXml(elem, QgsReadWriteContext()) # check result self.assertEqual( context2.coordinateOperations(), { ('EPSG:4204', 'EPSG:4326'): proj_1, ('EPSG:4205', 'EPSG:4326'): proj_2, ('', 'EPSG:4326'): proj_3 }) self.assertEqual( context2.calculateCoordinateOperation( QgsCoordinateReferenceSystem.fromProj( "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" ), QgsCoordinateReferenceSystem('EPSG:4326')), '+proj=pipeline +step +proj=axisswap +order=2,1') self.assertFalse( context2.mustReverseCoordinateOperation( QgsCoordinateReferenceSystem.fromProj( "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" ), QgsCoordinateReferenceSystem('EPSG:4326'))) self.assertEqual( context2.calculateCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem.fromProj( "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs") ), '+proj=pipeline +step +proj=axisswap +order=2,1') self.assertTrue( context2.mustReverseCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem.fromProj( "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs") )) self.assertTrue( context2.allowFallbackTransform( QgsCoordinateReferenceSystem('EPSG:4204'), QgsCoordinateReferenceSystem('EPSG:4326'))) self.assertFalse( context2.allowFallbackTransform( QgsCoordinateReferenceSystem('EPSG:4205'), QgsCoordinateReferenceSystem('EPSG:4326')))
def get_feature_ids_that_intersect_bbox(layer, rect, crs): request = (QgsFeatureRequest() .setFilterRect(rect) .setDestinationCrs(crs=crs, context=QgsCoordinateTransformContext()) .setNoAttributes().setFlags(QgsFeatureRequest.NoGeometry)) return [f.id() for f in layer.getFeatures(request)]
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg'))) options.layerName = 'layer_b' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a')) self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change geometry f = next(layer_a.getFeatures()) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is anothr surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertTrue(layer_a.startEditing()) layer_a.changeAttributeValue(f.id(), 1, 321) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') layer_a.undoStack().undo() self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertTrue(layer_a.rollBack()) ########################################### # Rename attribute self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
def run(self): """Run method that performs all the real work""" # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start == True: self.first_start = False self.dlg = HarmonyQGISDialog() # get stored settings settings = QgsSettings() # Fetch the currently loaded layers layers = QgsProject.instance().layerTreeRoot().children() layerNames = [layer.name() for layer in layers] # Clear the contents of the comboBox from previous runs self.dlg.comboBox.clear() # Populate the comboBox with names of all the loaded layers self.dlg.comboBox.addItems(layerNames) # use the previous layer as the default if it is in the existing layers # layerName = settings.value("harmony_qgis/layer") # if layerName and layerName in layerNames: # self.dlg.comboBox.setCurrentIndex(layerNames.index(layerName)) layer = self.iface.activeLayer() if layer: self.dlg.comboBox.setCurrentIndex(layerNames.index(layer.name())) # fill the harmnoy url input with the saved setting if available harmonyUrl = settings.value("harmony_qgis/harmony_url") if harmonyUrl: self.dlg.harmonyUrlLineEdit.setText(harmonyUrl) collectionId = settings.value("harmony_qgis/collection_id") if collectionId: self.dlg.collectionField.setText(collectionId) version = settings.value("harmony_qgis/version") or "1.0.0" self.dlg.versionField.setText(version) variable = settings.value("harmony_qgis/variable") if variable: self.dlg.variableField.setText(variable) # clear the table self.dlg.tableWidget.setRowCount(0) # set the table header self.dlg.tableWidget.setHorizontalHeaderLabels('Parameter;Value'.split(';')) # add a parameter/value when the 'Add' button is clicked self.dlg.addButton.clicked.connect(self.addSearchParameter) # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: collectionId = str(self.dlg.collectionField.text()) version = str(self.dlg.versionField.text()) variable = str(self.dlg.variableField.text()) layerName = str(self.dlg.comboBox.currentText()) # TODO handle the case where there is more than one layer by this name layer = QgsProject.instance().mapLayersByName(layerName)[0] opts = QgsVectorFileWriter.SaveVectorOptions() opts.driverName = 'GeoJson' tempFile = '/tmp/qgis.json' QgsVectorFileWriter.writeAsVectorFormatV2(layer, tempFile, QgsCoordinateTransformContext(), opts) harmonyUrl = self.dlg.harmonyUrlLineEdit.text() path = collectionId + "/" + "ogc-api-coverages/" + version + "/collections/" + variable + "/coverage/rangeset" url = harmonyUrl + "/" + path print(url) tempFileHandle = open(tempFile, 'r') contents = tempFileHandle.read() tempFileHandle.close() geoJson = rewind(contents) tempFileHandle = open(tempFile, 'w') tempFileHandle.write(geoJson) tempFileHandle.close() tempFileHandle = open(tempFile, 'rb') multipart_form_data = { 'shapefile': (layerName + '.geojson', tempFileHandle, 'application/geo+json') } rowCount = self.dlg.tableWidget.rowCount() for row in range(rowCount): parameter = self.dlg.tableWidget.item(row, 0).text() value = self.dlg.tableWidget.item(row, 1).text() multipart_form_data[parameter] = (None, value) resp = requests.post(url, files=multipart_form_data, stream=True) tempFileHandle.close() # print(resp) # print(resp.text) with open('/tmp/harmony_output_image.tif', 'wb') as fd: for chunk in resp.iter_content(chunk_size=128): fd.write(chunk) os.remove(tempFile) self.iface.addRasterLayer('/tmp/harmony_output_image.tif', layerName + '-' + variable) # QgsRasterLayer('/tmp/harmony_output_image.tif', layerName) # save settings if collectionId != "": settings.setValue("harmony_qgis/collection_id", collectionId) if version != "": settings.setValue("harmony_qgis/version", version) if variable != "": settings.setValue("harmony_qgis/variable", variable) if harmonyUrl != "": settings.setValue("harmony_qgis/harmony_url", harmonyUrl) settings.setValue("harmony_qgis/layer", layerName)
def test_nested_groups(self): """ Test logic relating to nested groups with group layers """ p = QgsProject() layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer, False) layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer2, False) layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") p.addMapLayer(layer3, False) layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") p.addMapLayer(layer4, False) group_node = p.layerTreeRoot().addGroup('my group') group_node.addLayer(layer) group_node.addLayer(layer2) child_group = group_node.addGroup('child') layer3_node = child_group.addLayer(layer3) grandchild_group = child_group.addGroup('grandchild') layer4_node = grandchild_group.addLayer(layer4) self.assertEqual(p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4]) spy = QSignalSpy(p.layerTreeRoot().layerOrderChanged) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) group_layer = group_node.convertToGroupLayer(options) p.addMapLayer(group_layer, False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [layer4, layer3, layer2, layer]) spy_count = len(spy) self.assertEqual(spy_count, 1) grandchild_group_layer = grandchild_group.convertToGroupLayer(options) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer4_node.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) self.assertEqual(grandchild_group_layer.childLayers(), []) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer4_node.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) grandchild_group.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [layer3, layer2, layer]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) grandchild_group.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) child_group_layer = child_group.convertToGroupLayer(options) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer4_node.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) self.assertEqual(grandchild_group_layer.childLayers(), []) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer4_node.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) grandchild_group.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [layer3]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) grandchild_group.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer3_node.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) layer3_node.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) grandchild_group.setGroupLayer(None) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) self.assertEqual(child_group_layer.childLayers(), [layer4, layer3]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) child_group.setGroupLayer(None) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [layer4, layer3, layer2, layer]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) group_node.setGroupLayer(None) self.assertEqual(p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4]) self.assertGreater(len(spy), spy_count)
def processAlgorithm(self, parameters, context, model_feedback): # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the # overall progress through the model feedback = QgsProcessingMultiStepFeedback(25, model_feedback) results = {} outputs = {} nlcd_rast_output = self.parameterAsBool(parameters, "OutputNLCDLandCoverRaster", context) nlcd_vect_output = self.parameterAsBool(parameters, "OutputNLCDLandCoverVector", context) nlcd_rast_imp_output = self.parameterAsBool( parameters, "OutputNLCDImperviousRaster", context) soil_output = self.parameterAsBool(parameters, "OutputSoilLayer", context) curve_number_output = self.parameterAsBool(parameters, "OutputCurveNumberLayer", context) # Assiging Default CN_Lookup Table if parameters["cnlookup"] == None: csv_uri = ("file:///" + os.path.join(cmd_folder, "CN_Lookup.csv") + "?delimiter=,") csv = QgsVectorLayer(csv_uri, "CN_Lookup.csv", "delimitedtext") parameters["cnlookup"] = csv area_layer = self.parameterAsVectorLayer(parameters, "areaboundary", context) EPSGCode = area_layer.crs().authid() origEPSGCode = EPSGCode # preserve orignal EPSGCode to project back to it # feedback.pushInfo(str(EPSGCode)) if check_crs_acceptable(EPSGCode): pass else: # Reproject layer to EPSG:5070 alg_params = { "INPUT": parameters["areaboundary"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem("EPSG:5070"), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectLayer5070"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) area_layer = context.takeResultLayer( outputs["ReprojectLayer5070"]["OUTPUT"]) EPSGCode = area_layer.crs().authid() # Check if area of the extent is less than 100,000 Acres d = QgsDistanceArea() tr_cont = QgsCoordinateTransformContext() d.setSourceCrs(area_layer.crs(), tr_cont) # d.setEllipsoid(area_layer.crs().ellipsoidAcronym()) extent_area = d.measureArea(QgsGeometry().fromRect( area_layer.extent())) area_acres = d.convertAreaMeasurement(extent_area, QgsUnitTypes.AreaAcres) if area_acres > 500000: feedback.reportError( f"Area Boundary layer extent area should be less than 500,000 acres.\nArea Boundary layer extent area is {round(area_acres,4):,} acres.\n\nExecution Failed", True, ) return results elif area_acres > 100000: feedback.reportError( f"Your Area Boundary layer extent area is {round(area_acres,4):,} acres. The recommended extent area is 100,000 acres or less. If the Algorithm fails, rerun with a smaller input layer.\n", False, ) else: feedback.pushInfo( f"Area Boundary layer extent area is {round(area_acres,4):,} acres\n" ) # Get extent of the area boundary layer xmin = area_layer.extent().xMinimum() ymin = area_layer.extent().yMinimum() xmax = area_layer.extent().xMaximum() ymax = area_layer.extent().yMaximum() BBOX_width = (xmax - xmin) / 30 BBOX_height = (ymax - ymin) / 30 BBOX_width_int = round(BBOX_width) BBOX_height_int = round(BBOX_height) # NLCD Impervious Raster if nlcd_rast_imp_output == True: request_URL = f"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Impervious_L48/ows?version=1.3.0&service=WMS&layers=NLCD_2016_Impervious_L48&styles&crs={str(EPSGCode)}&format=image/geotiff&request=GetMap&width={str(BBOX_width_int)}&height={str(BBOX_height_int)}&BBOX={str(xmin)},{str(ymin)},{str(xmax)},{str(ymax)}&" # Download NLCD Impervious Raster try: ping_URL = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Impervious_L48/ows" r = requests.head(ping_URL, verify=False) r.raise_for_status() alg_params = { "URL": request_URL, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcdImp"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except (QgsProcessingException, requests.exceptions.HTTPError) as e: feedback.reportError( f"Error: {str(e)}\n\nError requesting land use data from 'www.mrlc.gov'. Most probably because either their server is down or there is a certification issue.\nThis should be temporary. Try again later.\n", True, ) return results feedback.setCurrentStep(1) if feedback.isCanceled(): return {} # reproject to original crs # Warp (reproject) if EPSGCode != origEPSGCode: alg_params = { "DATA_TYPE": 0, "EXTRA": "", "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "MULTITHREADING": False, "NODATA": None, "OPTIONS": "", "RESAMPLING": 0, "SOURCE_CRS": None, "TARGET_CRS": QgsCoordinateReferenceSystem(str(origEPSGCode)), "TARGET_EXTENT": None, "TARGET_EXTENT_CRS": None, "TARGET_RESOLUTION": None, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcdImp"] = processing.run( "gdal:warpreproject", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # Set layer style alg_params = { "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Raster_Imp.qml"), } try: # for QGIS Version later than 3.12 outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForRasterLayer"] = processing.run( "qgis:setstyleforrasterlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(2) if feedback.isCanceled(): return {} # NLCD Land Cover Data if (curve_number_output == True or nlcd_vect_output == True or nlcd_rast_output == True): request_URL = f"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Land_Cover_L48/ows?version=1.3.0&service=WMS&layers=NLCD_2016_Land_Cover_L48&styles&crs={str(EPSGCode)}&format=image/geotiff&request=GetMap&width={str(BBOX_width_int)}&height={str(BBOX_height_int)}&BBOX={str(xmin)},{str(ymin)},{str(xmax)},{str(ymax)}&" # Download NLCD try: ping_URL = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Land_Cover_L48/ows" r = requests.head(ping_URL, verify=False) r.raise_for_status() alg_params = { "URL": request_URL, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcd"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except (QgsProcessingException, requests.exceptions.HTTPError) as e: feedback.reportError( f"Error: {str(e)}\n\nError requesting land use data from 'www.mrlc.gov'. Most probably because either their server is down or there is a certification issue.\nThis should be temporary. Try again later.\n", True, ) return results feedback.setCurrentStep(3) if feedback.isCanceled(): return {} # reproject to original crs # Warp (reproject) if EPSGCode != origEPSGCode: alg_params = { "DATA_TYPE": 0, "EXTRA": "", "INPUT": outputs["DownloadNlcd"]["OUTPUT"], "MULTITHREADING": False, "NODATA": None, "OPTIONS": "", "RESAMPLING": 0, "SOURCE_CRS": None, "TARGET_CRS": QgsCoordinateReferenceSystem(str(origEPSGCode)), "TARGET_EXTENT": None, "TARGET_EXTENT_CRS": None, "TARGET_RESOLUTION": None, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcd"] = processing.run( "gdal:warpreproject", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # Reclassify by table alg_params = { "DATA_TYPE": 5, "INPUT_RASTER": outputs["DownloadNlcd"]["OUTPUT"], "NODATA_FOR_MISSING": False, "NO_DATA": -9999, "RANGE_BOUNDARIES": 0, "RASTER_BAND": 1, "TABLE": QgsExpression( "'0,1,11,1,2,12,2,3,21,3,4,22,4,5,23,5,6,24,6,7,31,7,8,32,8,9,41,9,10,42,10,11,43,11,12,51,12,13,52,13,14,71,14,15,72,15,16,73,16,17,74,17,18,81,18,19,82,19,20,90,20,21,95'" ).evaluate(), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReclassifyByTable"] = processing.run( "native:reclassifybytable", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(4) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Raster.qml"), } try: # for QGIS Version later than 3.12 outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForRasterLayer"] = processing.run( "qgis:setstyleforrasterlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(5) if feedback.isCanceled(): return {} if curve_number_output == True or nlcd_vect_output == True: # Polygonize (raster to vector) alg_params = { "BAND": 1, "EIGHT_CONNECTEDNESS": False, "EXTRA": "", "FIELD": "VALUE", "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["PolygonizeRasterToVector"] = processing.run( "gdal:polygonize", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(6) if feedback.isCanceled(): return {} # Fix geometries alg_params = { "INPUT": outputs["PolygonizeRasterToVector"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["FixGeometries"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(7) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["FixGeometries"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Vector.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(8) if feedback.isCanceled(): return {} # Soil Layer if soil_output == True or curve_number_output == True: # Reproject layer alg_params = { "INPUT": parameters["areaboundary"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem("EPSG:4326"), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectLayer4326"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(9) if feedback.isCanceled(): return {} # Get Area Boundary layer extent in EPSG:4326 area_layer_reprojected = context.takeResultLayer( outputs["ReprojectLayer4326"]["OUTPUT"]) # Download Soil try: # request using post rest # create vector layer structure to store data feedback.pushInfo("Creating POST request...") uri = "Polygon?crs=epsg:4326" soil_layer = QgsVectorLayer(uri, "soil layer", "memory") provider = soil_layer.dataProvider() attributes = [] attr_dict = [ { "name": "musym", "type": "str" }, { "name": "muname", "type": "str" }, { "name": "mustatus", "type": "str" }, { "name": "slopegraddcp", "type": "str" }, { "name": "slopegradwta", "type": "str" }, { "name": "brockdepmin", "type": "str" }, { "name": "wtdepannmin", "type": "str" }, { "name": "wtdepaprjunmin", "type": "str" }, { "name": "flodfreqdcd", "type": "str" }, { "name": "flodfreqmax", "type": "str" }, { "name": "pondfreqprs", "type": "str" }, { "name": "aws025wta", "type": "str" }, { "name": "aws050wta", "type": "str" }, { "name": "aws0100wta", "type": "str" }, { "name": "aws0150wta", "type": "str" }, { "name": "drclassdcd", "type": "str" }, { "name": "drclasswettest", "type": "str" }, { "name": "hydgrpdcd", "type": "str" }, { "name": "iccdcd", "type": "str" }, { "name": "iccdcdpct", "type": "str" }, { "name": "niccdcd", "type": "str" }, { "name": "niccdcdpct", "type": "str" }, { "name": "engdwobdcd", "type": "str" }, { "name": "engdwbdcd", "type": "str" }, { "name": "engdwbll", "type": "str" }, { "name": "engdwbml", "type": "str" }, { "name": "engstafdcd", "type": "str" }, { "name": "engstafll", "type": "str" }, { "name": "engstafml", "type": "str" }, { "name": "engsldcd", "type": "str" }, { "name": "engsldcp", "type": "str" }, { "name": "englrsdcd", "type": "str" }, { "name": "engcmssdcd", "type": "str" }, { "name": "engcmssmp", "type": "str" }, { "name": "urbrecptdcd", "type": "str" }, { "name": "urbrecptwta", "type": "str" }, { "name": "forpehrtdcp", "type": "str" }, { "name": "hydclprs", "type": "str" }, { "name": "awmmfpwwta", "type": "str" }, { "name": "mukey", "type": "str" }, { "name": "mupolygonkey", "type": "str" }, { "name": "areasymbol", "type": "str" }, { "name": "nationalmusym", "type": "str" }, ] # initialize fields for field in attr_dict: attributes.append(QgsField(field["name"], QVariant.String)) provider.addAttributes(attributes) soil_layer.updateFields() # get area layer extent polygon as WKT in 4326 aoi_reproj_wkt = area_layer_reprojected.extent().asWktPolygon() # send post request body = { "format": "JSON", "query": f"select Ma.*, M.mupolygonkey, M.areasymbol, M.nationalmusym, M.mupolygongeo from mupolygon M, muaggatt Ma where M.mupolygonkey in (select * from SDA_Get_Mupolygonkey_from_intersection_with_WktWgs84('{aoi_reproj_wkt.lower()}')) and M.mukey=Ma.mukey", } url = "https://sdmdataaccess.sc.egov.usda.gov/TABULAR/post.rest" soil_response = requests.post(url, json=body).json() feedback.setCurrentStep(10) if feedback.isCanceled(): return {} for row in soil_response["Table"]: # None attribute for empty data row = [None if not attr else attr for attr in row] feat = QgsFeature(soil_layer.fields()) # populate data for index, col in enumerate(row): if index != len(attr_dict): feat.setAttribute(attr_dict[index]["name"], col) else: feat.setGeometry(QgsGeometry.fromWkt(col)) provider.addFeatures([feat]) feedback.setCurrentStep(11) if feedback.isCanceled(): return {} except: # try wfs request feedback.reportError( "Error getting soil data through post request. Your input layer maybe too large. Trying WFS download now.\nIf the Algorithm get stuck during download. Terminate the Algorithm and rerun with a smaller input layer.", False, ) xmin_reprojected = area_layer_reprojected.extent().xMinimum() ymin_reprojected = area_layer_reprojected.extent().yMinimum() xmax_reprojected = area_layer_reprojected.extent().xMaximum() ymax_reprojected = area_layer_reprojected.extent().yMaximum() request_URL_soil = f"https://sdmdataaccess.sc.egov.usda.gov/Spatial/SDMWGS84GEOGRAPHIC.wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=mapunitpolyextended&SRSNAME=EPSG:4326&BBOX={str(xmin_reprojected)},{str(ymin_reprojected)},{str(xmax_reprojected)},{str(ymax_reprojected)}" alg_params = { "URL": request_URL_soil, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadSoil"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(12) if feedback.isCanceled(): return {} # Swap X and Y coordinates alg_params = { "INPUT": outputs["DownloadSoil"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["SwapXAndYCoordinates"] = processing.run( "native:swapxy", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(13) if feedback.isCanceled(): return {} soil_layer = outputs["SwapXAndYCoordinates"]["OUTPUT"] # Fix soil layer geometries alg_params = { "INPUT": soil_layer, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT } outputs["FixGeometries2"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(14) if feedback.isCanceled(): return {} # Clip Soil Layer alg_params = { "INPUT": outputs["FixGeometries2"]["OUTPUT"], "OVERLAY": parameters["areaboundary"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["Clip"] = processing.run( "native:clip", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(15) if feedback.isCanceled(): return {} # Reproject Soil alg_params = { "INPUT": outputs["Clip"]["OUTPUT"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem(origEPSGCode), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectSoil"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(16) if feedback.isCanceled(): return {} # Fix soil layer geometries second time alg_params = { "INPUT": outputs["ReprojectSoil"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["FixGeometries3"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(17) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "Soil_Layer.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(18) if feedback.isCanceled(): return {} # Curve Number Calculations if curve_number_output == True: feedback.pushInfo( "Generating Curve Number Layer. This may take a while. Do not cancel." ) # Intersection alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "INPUT_FIELDS": ["MUSYM", "HYDGRPDCD", "MUNAME"], "OVERLAY": outputs["FixGeometries"]["OUTPUT"], "OVERLAY_FIELDS": ["VALUE"], "OVERLAY_FIELDS_PREFIX": "", "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["Intersection"] = processing.run( "native:intersection", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(19) if feedback.isCanceled(): return {} # Create GDCodeTemp alg_params = { "FIELD_LENGTH": 5, "FIELD_NAME": "GDCodeTemp", "FIELD_PRECISION": 3, "FIELD_TYPE": 2, "FORMULA": 'IF ("HYDGRPDCD" IS NOT NULL, "Value" || "HYDGRPDCD", IF (("MUSYM" = \'W\' OR lower("MUSYM") = \'water\' OR lower("MUNAME") = \'water\' OR "MUNAME" = \'W\'), 11, "VALUE"))', "INPUT": outputs["Intersection"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateGdcodetemp"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(20) if feedback.isCanceled(): return {} # Create GDCode alg_params = { "FIELD_LENGTH": 5, "FIELD_NAME": "GDCode", "FIELD_PRECISION": 3, "FIELD_TYPE": 2, "FORMULA": "if( var('drainedsoilsleaveuncheckedifnotsure') = True,replace(\"GDCodeTemp\", '/D', ''),replace(\"GDCodeTemp\", map('A/', '', 'B/', '', 'C/', '')))", "INPUT": outputs["CreateGdcodetemp"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateGdcode"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(21) if feedback.isCanceled(): return {} # Create NLCD_LU alg_params = { "FIELD_LENGTH": 2, "FIELD_NAME": "NLCD_LU", "FIELD_PRECISION": 3, "FIELD_TYPE": 1, "FORMULA": '"Value"', "INPUT": outputs["CreateGdcode"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateNlcd_lu"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(22) if feedback.isCanceled(): return {} # Join with CNLookup alg_params = { "DISCARD_NONMATCHING": False, "FIELD": "GDCode", "FIELDS_TO_COPY": ["CN_Join"], "FIELD_2": "GDCode", "INPUT": outputs["CreateNlcd_lu"]["OUTPUT"], "INPUT_2": parameters["cnlookup"], "METHOD": 1, "PREFIX": "", "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["JoinWithCnlookup"] = processing.run( "native:joinattributestable", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(23) if feedback.isCanceled(): return {} # Create Integer CN alg_params = { "FIELD_LENGTH": 3, "FIELD_NAME": "CN", "FIELD_PRECISION": 0, "FIELD_TYPE": 1, "FORMULA": "CN_Join * 1", "INPUT": outputs["JoinWithCnlookup"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateIntegerCn"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(24) if feedback.isCanceled(): return {} # Drop field(s) alg_params = { "COLUMN": ["VALUE", "GDCodeTemp", "CN_Join"], "INPUT": outputs["CreateIntegerCn"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DropFields"] = processing.run( "qgis:deletecolumn", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(25) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["DropFields"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "CN_Grid.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_rast_output: # Load NLCD Raster into project alg_params = { "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "NAME": "NLCD Land Cover Raster", } outputs["LoadLayerIntoProject1"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_vect_output: # Load NLCD Vector Layer into project alg_params = { "INPUT": outputs["FixGeometries"]["OUTPUT"], "NAME": "NLCD Land Cover Vector", } outputs["LoadLayerIntoProject2"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_rast_imp_output: # Load NLCD Impervious Raster into project alg_params = { "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "NAME": "NLCD Impervious Raster", } outputs["LoadLayerIntoProject3"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if soil_output: # Load Soil Layer into project alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "NAME": "SSURGO Soil Layer", } outputs["LoadLayerIntoProject4"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if curve_number_output: # Load Curve Number Layer into project alg_params = { "INPUT": outputs["DropFields"]["OUTPUT"], "NAME": "Curve Number Layer", } outputs["LoadLayerIntoProject5"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # log usage with open(os.path.join(cmd_folder, "usage_counter.log"), "r+") as f: counter = int(f.readline()) f.seek(0) f.write(str(counter + 1)) # check if counter is milestone if (counter + 1) % 25 == 0: appeal_file = NamedTemporaryFile("w", suffix=".html", delete=False) self.createHTML(appeal_file.name, counter + 1) results["Message"] = appeal_file.name return results
def convert_to_gpkg(self, target_path): """ Convert a layer to geopackage in the target path and adjust its datasource. If a layer is already a geopackage, the dataset will merely be copied to the target path. :param layer: The layer to copy :param target_path: A path to a folder into which the data will be copied :param keep_existent: if True and target file already exists, keep it as it is """ if not self.layer.type( ) == QgsMapLayer.VectorLayer or not self.layer.isValid(): return file_path = self.filename suffix = "" uri_parts = self.layer.source().split("|", 1) if len(uri_parts) > 1: suffix = uri_parts[1] dest_file = "" new_source = "" # check if the source is a geopackage, and merely copy if it's the case if (os.path.isfile(file_path) and self.layer.dataProvider().storageType() == "GPKG"): source_path, file_name = os.path.split(file_path) dest_file = os.path.join(target_path, file_name) if not os.path.isfile(dest_file): shutil.copy(os.path.join(source_path, file_name), dest_file) if self.provider_metadata is not None: metadata = self.metadata metadata["path"] = dest_file new_source = self.provider_metadata.encodeUri(metadata) if new_source == "": new_source = os.path.join(target_path, file_name) if suffix != "": new_source = "{}|{}".format(new_source, suffix) layer_subset_string = self.layer.subsetString() if new_source == "": pattern = re.compile("[\W_]+") # NOQA cleaned_name = pattern.sub("", self.layer.name()) dest_file = os.path.join(target_path, "{}.gpkg".format(cleaned_name)) suffix = 0 while os.path.isfile(dest_file): suffix += 1 dest_file = os.path.join( target_path, "{}_{}.gpkg".format(cleaned_name, suffix)) # clone vector layer and strip it of filter, joins, and virtual fields source_layer = self.layer.clone() source_layer.setSubsetString("") source_layer_joins = source_layer.vectorJoins() for join in source_layer_joins: source_layer.removeJoin(join.joinLayerId()) fields = source_layer.fields() virtual_field_count = 0 for i in range(0, len(fields)): if fields.fieldOrigin(i) == QgsFields.OriginExpression: source_layer.removeExpressionField(i - virtual_field_count) virtual_field_count += 1 options = QgsVectorFileWriter.SaveVectorOptions() options.fileEncoding = "UTF-8" options.driverName = "GPKG" (error, returned_dest_file) = QgsVectorFileWriter.writeAsVectorFormatV2( source_layer, dest_file, QgsCoordinateTransformContext(), options) if error != QgsVectorFileWriter.NoError: return if returned_dest_file: new_source = returned_dest_file else: new_source = dest_file self._change_data_source(new_source, "ogr") if layer_subset_string: self.layer.setSubsetString(layer_subset_string) return dest_file
def test_geocode(self): geocoder = QgsGoogleMapsGeocoder('my key') geocoder.setEndpoint(self.endpoint) with open( geocoder.requestUrl( '20 green st, twaddlingham').toString().replace( 'file://', ''), 'wb') as f: f.write(""" { "results" : [ { "address_components" : [ { "long_name" : "1600", "short_name" : "1600", "types" : [ "street_number" ] }, { "long_name" : "Amphitheatre Pkwy", "short_name" : "Amphitheatre Pkwy", "types" : [ "route" ] }, { "long_name" : "Mountain View", "short_name" : "Mountain View", "types" : [ "locality", "political" ] }, { "long_name" : "Santa Clara County", "short_name" : "Santa Clara County", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "California", "short_name" : "CA", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "United States", "short_name" : "US", "types" : [ "country", "political" ] }, { "long_name" : "94043", "short_name" : "94043", "types" : [ "postal_code" ] } ], "formatted_address" : "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", "geometry" : { "location" : { "lat" : 37.4224764, "lng" : -122.0842499 }, "location_type" : "ROOFTOP", "viewport" : { "northeast" : { "lat" : 37.4238253802915, "lng" : -122.0829009197085 }, "southwest" : { "lat" : 37.4211274197085, "lng" : -122.0855988802915 } } }, "place_id" : "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", "plus_code": { "compound_code": "CWC8+W5 Mountain View, California, United States", "global_code": "849VCWC8+W5" }, "types" : [ "street_address" ] } ], "status" : "OK" } """.encode('UTF-8')) context = QgsGeocoderContext(QgsCoordinateTransformContext()) results = geocoder.geocodeString('20 green st, twaddlingham', context) self.assertEqual(len(results), 1) self.assertEqual( results[0].identifier(), '1600 Amphitheatre Parkway, Mountain View, CA 94043, USA') self.assertEqual(results[0].geometry().asWkt(1), 'Point (-122.1 37.4)') self.assertEqual( results[0].additionalAttributes(), { 'administrative_area_level_1': 'California', 'administrative_area_level_2': 'Santa Clara County', 'country': 'United States', 'formatted_address': '1600 Amphitheatre Parkway, Mountain View, CA 94043, USA', 'locality': 'Mountain View', 'location_type': 'ROOFTOP', 'place_id': 'ChIJ2eUgeAK6j4ARbn5u_wAGqWA', 'postal_code': '94043', 'route': 'Amphitheatre Pkwy', 'street_number': '1600' })
def search(self): plots_found = [] features_not_found = [] fields = PLOTS_LAYER_DEFAULT_FIELDS + self.additional_output_fields self.layer_found.startEditing() self.layer_found.dataProvider().addAttributes(fields) self.layer_not_found.startEditing() self.layer_not_found.dataProvider().addAttributes([ QgsField("tresc_bledu", QVariant.String), ]) features = [] features_iterator = self.source_layer.getSelectedFeatures( ) if self.selected_only else self.source_layer.getFeatures() source_crs = self.source_layer.sourceCrs() if source_crs != CRS_2180: transformation = (QgsCoordinateTransform( source_crs, CRS_2180, QgsCoordinateTransformContext())) for f in features_iterator: point = f.geometry().asPoint() point = transformation.transform(point) f.setGeometry(QgsGeometry.fromPointXY(point)) features.append(f) else: transformation = None features = features_iterator uldk_search = self.uldk_api.ULDKSearchPoint( "dzialka", ("geom_wkt", "wojewodztwo", "powiat", "gmina", "obreb", "numer", "teryt")) found_features = [] for source_feature in features: if QThread.currentThread().isInterruptionRequested(): self.__commit() self.interrupted.emit(self.layer_found, self.layer_not_found) return skip = False for found_feature in found_features: if found_feature.geometry().intersects( source_feature.geometry()): if not self.skip_duplicates: self.layer_found.dataProvider().addFeature( found_feature) skip = True if skip: self.progressed.emit(True, 1 if self.skip_duplicates else 0) continue point = source_feature.geometry().asPoint() uldk_point = self.uldk_api.ULDKPoint(point.x(), point.y(), 2180) try: uldk_response_row = uldk_search.search(uldk_point) additional_attributes = [] for field in self.additional_output_fields: additional_attributes.append(source_feature[field.name()]) found_feature = uldk_response_to_qgs_feature( uldk_response_row, additional_attributes) found_features.append(found_feature) self.layer_found.dataProvider().addFeature(found_feature) self.progressed.emit(True, 0) except Exception as e: not_found_feature = self.__make_not_found_feature( source_feature.geometry(), e) self.layer_not_found.dataProvider().addFeature( not_found_feature) self.progressed.emit(False, 0) self.__commit() self.finished.emit(self.layer_found, self.layer_not_found)
def setUp(self): """Prepare tc""" super(TestQgsRasterLayerTransformContext, self).setUp() self.ctx = QgsCoordinateTransformContext() self.ctx.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem(4326), QgsCoordinateReferenceSystem(3857), 1234, 1235) self.rpath = os.path.join(unitTestDataPath(), 'landsat.tif')
def testSourceDestinationDatumTransformsProj6(self): context = QgsCoordinateTransformContext() self.assertEqual(context.sourceDestinationDatumTransforms(), {}) proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' self.assertFalse( context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'), proj_string)) self.assertTrue( context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) self.assertFalse( context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4326'))) self.assertFalse( context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3113'), QgsCoordinateReferenceSystem('EPSG:4283'))) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string}) self.assertTrue(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) self.assertTrue( context.hasTransform(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283')), proj_string) self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) # ideally not equal, but for now it's all we can do, and return True for mustReverseCoordinateOperation here self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111')), proj_string) self.assertTrue(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) proj_string_2 = 'dummy' self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'), proj_string_2)) self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111')), proj_string_2) self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111')) proj_string_2 = '+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem(4283), proj_string_2)) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2}) proj_string_3 = '+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=utm +zone=57 +south +ellps=GRS80' self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem(28357), proj_string_3)) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): proj_string_3}) self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28357'), 'some other proj string')) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) # invalid additions self.assertFalse(context.addCoordinateOperation(QgsCoordinateReferenceSystem(), QgsCoordinateReferenceSystem('EPSG:28357'), 'bad proj')) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) self.assertFalse(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem(), 'bad proj')) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) # indicate no transform required self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem(28357), QgsCoordinateReferenceSystem(28356), '')) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string', ('EPSG:28357', 'EPSG:28356'): ''}) # remove non-existing context.removeCoordinateOperation(QgsCoordinateReferenceSystem(3113), QgsCoordinateReferenceSystem(3111)) self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, ('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string', ('EPSG:28357', 'EPSG:28356'): ''}) # remove existing context.removeCoordinateOperation(QgsCoordinateReferenceSystem(3111), QgsCoordinateReferenceSystem(4283)) self.assertEqual(context.coordinateOperations(), {('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28356', 'EPSG:28357'): 'some other proj string', ('EPSG:28357', 'EPSG:28356'): ''}) context.removeCoordinateOperation(QgsCoordinateReferenceSystem(28356), QgsCoordinateReferenceSystem(28357)) self.assertEqual(context.coordinateOperations(), {('EPSG:28356', 'EPSG:4283'): proj_string_2, ('EPSG:28357', 'EPSG:28356'): ''}) context.clear() self.assertEqual(context.coordinateOperations(), {})
def test_insert_srsName(self): """Test srsName is respected when insering""" post_data = """ <Transaction xmlns="http://www.opengis.net/wfs" xsi:schemaLocation="http://www.qgis.org/gml http://localhost:8000/?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=as_symbols" service="WFS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="{version}" xmlns:gml="http://www.opengis.net/gml"> <Insert xmlns="http://www.opengis.net/wfs"> <as_symbols xmlns="http://www.qgis.org/gml"> <name xmlns="http://www.qgis.org/gml">{name}</name> <geometry xmlns="http://www.qgis.org/gml"> <gml:Point srsName="{srsName}"> <gml:coordinates cs="," ts=" ">{coordinates}</gml:coordinates> </gml:Point> </geometry> </as_symbols> </Insert> </Transaction> """ project = self.testdata_path + \ "test_project_wms_grouped_layers.qgs" assert os.path.exists(project), "Project file not found: " + project query_string = '?SERVICE=WFS&MAP={}'.format( urllib.parse.quote(project)) request = post_data.format(name='4326-test1', version='1.1.0', srsName='EPSG:4326', coordinates='10.67,52.48') header, body = self._execute_request( query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) # Verify vl = QgsVectorLayer( self.testdata_path + 'test_project_wms_grouped_layers.gpkg|layername=as_symbols', 'as_symbols') self.assertTrue(vl.isValid()) feature = next( vl.getFeatures( QgsFeatureRequest(QgsExpression('"name" = \'4326-test1\'')))) geom = feature.geometry() tr = QgsCoordinateTransform( QgsCoordinateReferenceSystem.fromEpsgId(4326), vl.crs(), QgsCoordinateTransformContext()) geom_4326 = QgsGeometry.fromWkt('point( 10.67 52.48)') geom_4326.transform(tr) self.assertEqual(geom.asWkt(0), geom_4326.asWkt(0)) # Now: insert a feature in layer's CRS request = post_data.format(name='25832-test1', version='1.1.0', srsName='EPSG:25832', coordinates='613412,5815738') header, body = self._execute_request( query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) feature = next( vl.getFeatures( QgsFeatureRequest(QgsExpression('"name" = \'25832-test1\'')))) geom = feature.geometry() self.assertEqual(geom.asWkt(0), geom_4326.asWkt(0)) # Tests for inverted axis issue GH #36584 # Cleanup self.assertTrue(vl.startEditing()) vl.selectByExpression('"name" LIKE \'4326-test%\'') vl.deleteSelectedFeatures() self.assertTrue(vl.commitChanges()) self.i = 0 def _test(version, srsName, lat_lon=False): self.i += 1 name = '4326-test_%s' % self.i request = post_data.format( name=name, version=version, srsName=srsName, coordinates='52.48,10.67' if lat_lon else '10.67,52.48') header, body = self._execute_request( query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) feature = next( vl.getFeatures( QgsFeatureRequest(QgsExpression('"name" = \'%s\'' % name)))) geom = feature.geometry() self.assertEqual( geom.asWkt(0), geom_4326.asWkt(0), "Transaction Failed: %s , %s, lat_lon=%s" % (version, srsName, lat_lon)) _test('1.1.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) _test('1.1.0', 'http://www.opengis.net/def/crs/EPSG/0/4326', lat_lon=True) _test('1.1.0', 'http://www.opengis.net/gml/srs/epsg.xml#4326', lat_lon=False) _test('1.1.0', 'EPSG:4326', lat_lon=False) _test('1.0.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) _test('1.0.0', 'http://www.opengis.net/def/crs/EPSG/0/4326', lat_lon=True) _test('1.0.0', 'http://www.opengis.net/gml/srs/epsg.xml#4326', lat_lon=False) _test('1.0.0', 'EPSG:4326', lat_lon=False) def _test_getFeature(version, srsName, lat_lon=False): # Now get the feature through WFS using BBOX filter bbox = QgsGeometry.fromWkt('point( 10.7006 52.4317)').boundingBox() bbox.grow(0.0001) bbox_text = "%s,%s,%s,%s" % ( (bbox.yMinimum(), bbox.xMinimum(), bbox.yMaximum(), bbox.xMaximum()) if lat_lon else (bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum())) req = query_string + '&REQUEST=GetFeature&VERSION={version}&TYPENAME=as_symbols&SRSNAME={srsName}&BBOX={bbox},{srsName}'.format( version=version, srsName=srsName, bbox=bbox_text) header, body = self._execute_request(req) self.assertTrue( b'gid>7' in body, "GetFeature Failed: %s , %s, lat_lon=%s" % (version, srsName, lat_lon)) _test_getFeature('1.1.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) _test_getFeature('1.1.0', 'EPSG:4326', lat_lon=False) _test_getFeature('1.0.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) _test_getFeature('1.0.0', 'EPSG:4326', lat_lon=False) # Cleanup self.assertTrue(vl.startEditing()) vl.selectByExpression('"name" LIKE \'4326-test%\'') vl.deleteSelectedFeatures() self.assertTrue(vl.commitChanges())
def testSuccess(self): """test successfully writing a layer""" path = os.path.join(unitTestDataPath(), 'raster', 'with_color_table.tif') raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) pipe = QgsRasterPipe() self.assertTrue(pipe.set(raster_layer.dataProvider().clone())) tmp = create_temp_filename('success.tif') writer = QgsRasterFileWriter(tmp) task = QgsRasterFileWriterTask(writer, pipe, 100, 100, raster_layer.extent(), raster_layer.crs(), QgsCoordinateTransformContext()) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) QgsApplication.taskManager().addTask(task) while not self.success and not self.fail: QCoreApplication.processEvents() self.assertTrue(self.success) self.assertFalse(self.fail) self.assertTrue(os.path.exists(tmp))
def response_geotiff_mode(self, request): """ Export raster as geotiff i.e: 192.168.1.137:8006/raster/api/geotiff/qdjango/190/sfondo_clip_c60533a4_743e_4734_9b95_514ac765ec4e/ 192.168.1.137:8006/raster/api/geotiff/qdjango/190/europa_dem_8f0a9c30_5b96_4661_b747_8ce4f2679d6b/?map_extent=10.515901325263899%2C43.875701513907146%2C10.55669628723769%2C43.92294901234999 :param request: Http Django request object :return: http response with attached file """ #if not self.layer.download: # return HttpResponseForbidden() tmp_dir = tempfile.TemporaryDirectory() filename = f"{self.metadata_layer.qgis_layer.name()}.tif" file_path = os.path.join(tmp_dir.name, filename) writer = QgsRasterFileWriter(file_path) provider = self.metadata_layer.qgis_layer.dataProvider() renderer = self.metadata_layer.qgis_layer.renderer() # Check for Url Params if request.query_params.get('map_extent'): me = request.query_params.get('map_extent').split(',') orig_extent =provider.extent() extent = QgsRectangle(float(me[0]), float(me[1]), float(me[2]), float(me[3])) # If crs layer is not equal to project crs if self.reproject: ct = QgsCoordinateTransform( QgsCoordinateReferenceSystem(f'EPSG:{self.layer.project.group.srid.srid}'), self.metadata_layer.qgis_layer.crs(), QgsCoordinateTransformContext() ) extent = ct.transform(extent) # Calc columns and rows cols = int((extent.xMaximum() - extent.xMinimum()) / (orig_extent.xMaximum() - orig_extent.xMinimum()) * provider.xSize()) rows = int((extent.yMaximum() - extent.yMinimum()) / (orig_extent.yMaximum() - orig_extent.yMinimum()) * provider.ySize()) # For cols or rows lower than 0, we have to recalculate extent to guarantee minimal raster cell if cols < 1: cols = 1 new_wide_x_extent = (orig_extent.xMaximum() - orig_extent.xMinimum()) / provider.xSize() off = (new_wide_x_extent - (extent.xMaximum() - extent.xMinimum())) / 2 extent.setXMinimum(extent.xMinimum() - off) extent.setXMaximum(extent.xMaximum() + off) if rows < 1: rows = 1 new_wide_y_extent = (orig_extent.yMaximum() - orig_extent.yMinimum()) / provider.ySize() off = (new_wide_y_extent - (extent.yMaximum() - extent.yMinimum())) / 2 extent.setYMinimum(extent.yMinimum() - off) extent.setYMaximum(extent.yMaximum() + off) else: extent = provider.extent() cols = provider.xSize() rows = provider.ySize() pipe = QgsRasterPipe() pipe.set(provider.clone()) pipe.set(renderer.clone()) error_code = writer.writeRaster( pipe, cols, rows, extent, self.metadata_layer.qgis_layer.crs(), self.metadata_layer.qgis_layer.transformContext() ) if error_code != QgsRasterFileWriter.NoError: tmp_dir.cleanup() raise APIException(f"An error occoured on create raster file for export") # Grab ZIP file from in-memory, make response with correct MIME-type response = HttpResponse( open(file_path, 'rb').read(), content_type='image/tif') response['Content-Disposition'] = f'attachment; filename={filename}' response.set_cookie('fileDownload', 'true') return response
def testLayerRemovalBeforeRun(self): """test behavior when layer is removed before task begins""" path = os.path.join(unitTestDataPath(), 'raster', 'with_color_table.tif') raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) pipe = QgsRasterPipe() self.assertTrue(pipe.set(raster_layer.dataProvider().clone())) tmp = create_temp_filename('remove_layer.tif') writer = QgsRasterFileWriter(tmp) task = QgsRasterFileWriterTask(writer, pipe, 100, 100, raster_layer.extent(), raster_layer.crs(), QgsCoordinateTransformContext()) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) # remove layer raster_layer = None QgsApplication.taskManager().addTask(task) while not self.success and not self.fail: QCoreApplication.processEvents() # in this case will still get a positive result - since the pipe is cloned before the task # begins the task is no longer dependent on the original layer self.assertTrue(self.success) self.assertFalse(self.fail) self.assertTrue(os.path.exists(tmp))
def testContextProj6(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 'proj') transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')]) # should be no coordinate operation self.assertEqual(transform.coordinateOperation(), '') # should default to allowing fallback transforms self.assertTrue(transform.allowFallbackTransforms()) transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertTrue(transform.allowFallbackTransforms()) context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 'proj', False) transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertFalse(transform.allowFallbackTransforms()) # matching source transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(transform.coordinateOperation(), '') # matching dest transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), '') # matching src/dest pair transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), 'proj') # test manual overwriting transform.setCoordinateOperation('proj2') self.assertEqual(transform.coordinateOperation(), 'proj2') transform.setAllowFallbackTransforms(False) self.assertFalse(transform.allowFallbackTransforms()) transform.setAllowFallbackTransforms(True) self.assertTrue(transform.allowFallbackTransforms()) # test that auto operation setting occurs when updating src/dest crs transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') # delayed context set transform = QgsCoordinateTransform() self.assertEqual(transform.coordinateOperation(), '') transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), '') transform.setContext(context) self.assertEqual(transform.coordinateOperation(), 'proj') self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')])
def to_layer(features, crs, encoding, geom_type, layer_type, path): first_feat = features[0] fields = first_feat.fields() layer = None if layer_type == 'memory': layer = QgsVectorLayer(geom_type + '?crs=' + crs.authid(), path, "memory") pr = layer.dataProvider() pr.addAttributes(fields.toList()) layer.updateFields() layer.startEditing() pr.addFeatures(features) layer.commitChanges() elif layer_type == 'shapefile': wkbTypes = { 'Point': QgsWkbTypes.Point, 'Linestring': QgsWkbTypes.LineString, 'Polygon': QgsWkbTypes.Polygon } options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = "ESRI Shapefile" options.fileEncoding = encoding file_writer = QgsVectorFileWriter.create( path, fields, wkbTypes[geom_type], crs, QgsCoordinateTransformContext(), options) if file_writer.hasError() != QgsVectorFileWriter.NoError: print("Error when creating shapefile: ", file_writer.errorMessage()) del file_writer layer = QgsVectorLayer(path, ntpath.basename(path)[:-4], "ogr") pr = layer.dataProvider() layer.startEditing() pr.addFeatures(features) layer.commitChanges() elif layer_type == 'postgis': # this is needed to load the table later # uri = connstring + """ type=""" + geom_types[geom_type] + """ table=\"""" + schema_name + """\".\"""" + table_name + """\" (geom) """ connstring, schema_name, table_name = path uri = connstring + """ type=""" + geom_type + """ table=\"""" + schema_name + """\".\"""" + table_name + """\" (geom) """ crs_id = crs.postgisSrid() try: con = psycopg2.connect(connstring) cur = con.cursor() create_query = cur.mogrify( """DROP TABLE IF EXISTS "%s"."%s"; CREATE TABLE "%s"."%s"( geom geometry(%s, %s))""", (AsIs(schema_name), AsIs(table_name), AsIs(schema_name), AsIs(table_name), geom_type, AsIs(crs_id))) cur.execute(create_query) con.commit() post_q_flds = { 2: 'bigint', 6: 'numeric', 1: 'bool', 'else': 'text', 4: 'numeric' } for f in fields: f_type = f.type() if f_type not in [2, 6, 1]: f_type = 'else' attr_query = cur.mogrify( """ALTER TABLE "%s"."%s" ADD COLUMN "%s" %s""", (AsIs(schema_name), AsIs(table_name), AsIs( f.name()), AsIs(post_q_flds[f_type]))) cur.execute(attr_query) con.commit() field_names = ",".join(['"' + f.name() + '"' for f in fields]) for feature in features: attrs = [i if i else None for i in feature.attributes()] insert_query = cur.mogrify( """INSERT INTO "%s"."%s" (%s, geom) VALUES %s, ST_GeomFromText(%s,%s))""", (AsIs(schema_name), AsIs(table_name), AsIs(field_names), tuple(attrs), feature.geometry().asWkt(), AsIs(crs_id))) idx = insert_query.find(b', ST_GeomFromText') - 1 insert_query = insert_query[:idx] + insert_query[(idx + 1):] # QgsMessageLog.logMessage('sql query %s' % insert_query, level=Qgis.Critical) cur.execute(insert_query) # con.commit() pkey_query = cur.mogrify( """ALTER TABLE "%s"."%s" DROP COLUMN IF EXISTS rcl_id; ALTER TABLE "%s"."%s" ADD COLUMN rcl_id serial PRIMARY KEY NOT NULL;""", (AsIs(schema_name), AsIs(table_name), AsIs(schema_name), AsIs(table_name))) cur.execute(pkey_query) con.commit() con.close() layer = QgsVectorLayer(uri, table_name, 'postgres') except psycopg2.DatabaseError as e: print(e) return layer