def testTrueNorth(self): """ test calculating bearing to true north""" # short circuit - already a geographic crs crs = QgsCoordinateReferenceSystem.fromEpsgId(4326) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(0, 0)), 0) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 0)), 0) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, -43)), 0) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 43)), 0) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, 200)), 0) self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(44, -200)), 0) # no short circuit crs = QgsCoordinateReferenceSystem.fromEpsgId(3111) self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(2508807, 2423425)), 0.06, 2) # try a south-up crs crs = QgsCoordinateReferenceSystem.fromEpsgId(2053) self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(29, -27.55)), -180.0, 1) # try a north pole crs crs = QgsCoordinateReferenceSystem.fromEpsgId(3575) self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(-780770, 652329)), 129.9, 1) self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, QgsPoint(513480, 873173)), -149.5, 1)
def testMetadata(self): """ Test that metadata is correctly acquired from provider """ endpoint = self.basetestpath + '/metadata_fake_qgis_http_endpoint' with open(sanitize(endpoint, '?f=json'), 'wb') as f: f.write(""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, "defaultVisibility":true, "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3, "spatialReference":{"wkid":4326,"latestWkid":4326}}, "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText", "displayField":"LABEL","typeIdField":null, "fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}], "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""".encode( 'UTF-8')) with open(sanitize(endpoint, '/query?f=json_where=OBJECTID=OBJECTID_returnIdsOnly=true'), 'wb') as f: f.write(""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } """.encode('UTF-8')) # Create test layer vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') self.assertTrue(vl.isValid()) extent = QgsLayerMetadata.Extent() extent1 = QgsLayerMetadata.SpatialExtent() extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(4326) extent1.bounds = QgsBox3d(QgsRectangle(-71.123, 66.33, -65.32, 78.3)) extent.setSpatialExtents([extent1]) self.assertEqual(vl.metadata().extent(), extent) self.assertEqual(vl.metadata().crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(vl.metadata().identifier(), 'http://' + sanitize(endpoint, '')) self.assertEqual(vl.metadata().parentIdentifier(), 'http://' + self.basetestpath + '/2') self.assertEqual(vl.metadata().type(), 'dataset') self.assertEqual(vl.metadata().abstract(), 'QGIS Provider Test Layer') self.assertEqual(vl.metadata().title(), 'QGIS Test') self.assertEqual(vl.metadata().rights(), ['not copyright']) l = QgsLayerMetadata.Link() l.name = 'Source' l.type = 'WWW:LINK' l.url = 'http://' + sanitize(endpoint, '') self.assertEqual(vl.metadata().links(), [l])
def testTrueNorth(self): """Test syncing picture to true north""" layout = QgsLayout(QgsProject.instance()) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(0, 0, 10, 10)) map.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) map.setExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) layout.addLayoutItem(map) picture = QgsLayoutItemPicture(layout) layout.addLayoutItem(picture) picture.setLinkedMap(map) self.assertEqual(picture.linkedMap(), map) picture.setNorthMode(QgsLayoutItemPicture.TrueNorth) self.assertAlmostEqual(picture.pictureRotation(), 37.20, 1) # shift map map.setExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) self.assertAlmostEqual(picture.pictureRotation(), -38.18, 1) # rotate map map.setMapRotation(45) self.assertAlmostEqual(picture.pictureRotation(), -38.18 + 45, 1) # add an offset picture.setNorthOffset(-10) self.assertAlmostEqual(picture.pictureRotation(), -38.18 + 35, 1)
def testTrueNorth(self): """Test syncing picture to true north""" mapSettings = QgsMapSettings() composition = QgsComposition(mapSettings, QgsProject.instance()) composerMap = QgsComposerMap(composition) composerMap.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) composerMap.setNewExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) composition.addComposerMap(composerMap) composerPicture = QgsComposerPicture(composition) composition.addComposerPicture(composerPicture) composerPicture.setRotationMap(composerMap.id()) self.assertTrue(composerPicture.rotationMap() >= 0) composerPicture.setNorthMode(QgsComposerPicture.TrueNorth) self.assertAlmostEqual(composerPicture.pictureRotation(), 37.20, 1) # shift map composerMap.setNewExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18, 1) # rotate map composerMap.setMapRotation(45) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 45, 1) # add an offset composerPicture.setNorthOffset(-10) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 35, 1)
def testEquality(self): # spatial extent extent = QgsLayerMetadata.SpatialExtent() extent.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) self.assertEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) self.assertNotEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) self.assertNotEqual(extent, extent2) # extent extent = QgsLayerMetadata.Extent() extent1 = QgsLayerMetadata.SpatialExtent() extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent1.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) extent.setSpatialExtents([extent1, extent2]) dates = [ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) ] extent.setTemporalExtents(dates) extent_copy = QgsLayerMetadata.Extent(extent) self.assertEqual(extent, extent_copy) extent_copy.setTemporalExtents([ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49))) ]) self.assertNotEqual(extent, extent_copy) extent_copy = QgsLayerMetadata.Extent(extent) extent3 = QgsLayerMetadata.SpatialExtent() extent3.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent3.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 19.0) extent_copy.setSpatialExtents([extent1, extent3]) self.assertNotEqual(extent, extent_copy) constraint = QgsLayerMetadata.Constraint('c', 'type1') self.assertEqual(constraint, QgsLayerMetadata.Constraint('c', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c2', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c', 'type2'))
def testGettersSetters(self): m = QgsLayerMetadata() m.setIdentifier('identifier') self.assertEqual(m.identifier(), 'identifier') m.setParentIdentifier('parent identifier') self.assertEqual(m.parentIdentifier(), 'parent identifier') m.setLanguage('en-us') self.assertEqual(m.language(), 'en-us') m.setType('type') self.assertEqual(m.type(), 'type') m.setTitle('title') self.assertEqual(m.title(), 'title') m.setCategories(['category']) self.assertEqual(m.categories(), ['category']) m.setAbstract('abstract') self.assertEqual(m.abstract(), 'abstract') m.setFees('fees') self.assertEqual(m.fees(), 'fees') m.setConstraints([QgsLayerMetadata.Constraint('constraint a'), QgsLayerMetadata.Constraint('constraint b')]) m.addConstraint(QgsLayerMetadata.Constraint('constraint c')) self.assertEqual(m.constraints()[0].constraint, 'constraint a') self.assertEqual(m.constraints()[1].constraint, 'constraint b') self.assertEqual(m.constraints()[2].constraint, 'constraint c') m.setRights(['right a', 'right b']) self.assertEqual(m.rights(), ['right a', 'right b']) m.setLicenses(['l a', 'l b']) self.assertEqual(m.licenses(), ['l a', 'l b']) m.setHistory(['loaded into QGIS']) self.assertEqual(m.history(), ['loaded into QGIS']) m.setHistory(['accidentally deleted some features']) self.assertEqual(m.history(), ['accidentally deleted some features']) m.addHistoryItem('panicked and deleted more') self.assertEqual(m.history(), ['accidentally deleted some features', 'panicked and deleted more']) m.setEncoding('encoding') self.assertEqual(m.encoding(), 'encoding') m.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertEqual(m.crs().authid(), 'EPSG:3111')
def testExtent(self): e = QgsLayerMetadata.Extent() se = QgsLayerMetadata.SpatialExtent() se.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) se.bounds = QgsBox3d(1, 2, 3, 4, 5, 6) e.setSpatialExtents([se]) e.setTemporalExtents([QgsDateTimeRange(QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56)), QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57)))]) m = QgsLayerMetadata() m.setExtent(e) extents = m.extent().spatialExtents() self.assertEqual(extents[0].extentCrs.authid(), 'EPSG:3111') self.assertEqual(extents[0].bounds.xMinimum(), 1.0) self.assertEqual(extents[0].bounds.yMinimum(), 2.0) self.assertEqual(extents[0].bounds.zMinimum(), 3.0) self.assertEqual(extents[0].bounds.xMaximum(), 4.0) self.assertEqual(extents[0].bounds.yMaximum(), 5.0) self.assertEqual(extents[0].bounds.zMaximum(), 6.0) self.assertEqual(m.extent().temporalExtents()[0].begin(), QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56))) self.assertEqual(m.extent().temporalExtents()[0].end(), QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57)))
def testWriterWithExtentAndReprojection(self): """Check writing using extent filter with reprojection.""" source_file = os.path.join(TEST_DATA_DIR, 'points.shp') source_layer = QgsVectorLayer(source_file, 'Points', 'ogr') self.assertTrue(source_layer.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'ESRI Shapefile' options.filterExtent = QgsRectangle(-12511460, 3045157, -10646621, 4683497) options.ct = QgsCoordinateTransform(source_layer.crs(), QgsCoordinateReferenceSystem.fromEpsgId(3785), QgsProject.instance()) dest_file_name = os.path.join(str(QDir.tempPath()), 'extent_transform.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( source_layer, dest_file_name, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') features = [f for f in created_layer.getFeatures()] self.assertEqual(len(features), 5) for f in features: self.assertTrue(f.geometry().intersects(options.filterExtent))
def testMetadata(self): metadata = self.vl.metadata() self.assertEqual(metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(metadata.type(), 'dataset') self.assertEqual(metadata.abstract(), 'QGIS Test Table')
def testEquality(self): # spatial extent extent = QgsLayerMetadata.SpatialExtent() extent.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) self.assertEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) self.assertNotEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) self.assertNotEqual(extent, extent2) # extent extent = QgsLayerMetadata.Extent() extent1 = QgsLayerMetadata.SpatialExtent() extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent1.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) extent.setSpatialExtents([extent1, extent2]) dates = [ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) ] extent.setTemporalExtents(dates) extent_copy = QgsLayerMetadata.Extent(extent) self.assertEqual(extent, extent_copy) extent_copy.setTemporalExtents([ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49))) ]) self.assertNotEqual(extent, extent_copy) extent_copy = QgsLayerMetadata.Extent(extent) extent3 = QgsLayerMetadata.SpatialExtent() extent3.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent3.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 19.0) extent_copy.setSpatialExtents([extent1, extent3]) self.assertNotEqual(extent, extent_copy) constraint = QgsLayerMetadata.Constraint('c', 'type1') self.assertEqual(constraint, QgsLayerMetadata.Constraint('c', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c2', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c', 'type2')) a = QgsLayerMetadata.Address() a.type = 'postal' a.address = '13 north rd' a.city = 'huxleys haven' a.administrativeArea = 'land of the queens' a.postalCode = '4123' a.country = 'straya!' a2 = QgsLayerMetadata.Address(a) self.assertEqual(a, a2) a2.type = 'postal2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.address = 'address2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.city = 'city' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.administrativeArea = 'area2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.postalCode = 'postal2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.country = 'country2' self.assertNotEqual(a, a2) c = QgsLayerMetadata.Contact() c.name = 'name' c.organization = 'org' c.position = 'pos' c.voice = '1500 515 555' c.fax = 'fax' c.email = 'email' c.role = 'role' a = QgsLayerMetadata.Address() a.type = 'postal' a2 = QgsLayerMetadata.Address() a2.type = 'street' c.addresses = [a, a2] c2 = QgsLayerMetadata.Contact(c) self.assertEqual(c, c2) c2.name = 'name2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.organization = 'org2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.position = 'pos2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.voice = 'voice2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.fax = 'fax2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.email = 'email2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.role = 'role2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.addresses = [a2] self.assertNotEqual(c, c2) # link l = QgsLayerMetadata.Link() l.name = 'name' l.type = 'type' l.description = 'desc' l.url = 'url' l.format = 'format' l.mimeType = 'mime' l.size = '112' l2 = QgsLayerMetadata.Link(l) self.assertEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.name = 'name2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.type = 'type2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.description = 'desc2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.url = 'url2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.format = 'format2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.mimeType = 'mime2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.size = '113' self.assertNotEqual(l, l2)
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # custom CRS crs = QgsCoordinateReferenceSystem.fromProj( '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs' ) layer = QgsMemoryProviderUtils.createMemoryLayer( 'my name', QgsFields(), QgsWkbTypes.PolygonZM, crs) self.assertTrue(layer.isValid()) self.assertTrue(layer.crs().isValid()) self.assertEqual( layer.crs().toProj(), '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs' ) # clone it, just to check layer2 = layer.clone() self.assertEqual( layer2.crs().toProj(), '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs' ) # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) fields.append(QgsField("binaryfield", QVariant.ByteArray)) fields.append(QgsField("boolfield", QVariant.Bool)) fields.append(QgsField("vallist", QVariant.List, subType=QVariant.Int)) fields.append( QgsField("stringlist", QVariant.StringList, subType=QVariant.String)) fields.append( QgsField("stringlist2", QVariant.List, subType=QVariant.String)) fields.append( QgsField("reallist", QVariant.List, subType=QVariant.Double)) fields.append( QgsField("longlist", QVariant.List, subType=QVariant.LongLong)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) if layer.fields()[i].name() != 'stringlist2': self.assertEqual(layer.fields()[i].type(), fields[i].type()) else: # we automatically convert List with String subtype to StringList, to match other data providers self.assertEqual(layer.fields()[i].type(), QVariant.StringList) self.assertEqual(layer.fields()[i].length(), fields[i].length()) self.assertEqual(layer.fields()[i].precision(), fields[i].precision(), fields[i].name()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string # field precision fields = QgsFields() fields.append(QgsField("string", QVariant.String, len=10)) fields.append(QgsField("long", QVariant.LongLong, len=6)) fields.append(QgsField("double", QVariant.Double, len=10, prec=7)) fields.append(QgsField("double2", QVariant.Double, len=-1, prec=-1)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) self.assertEqual(layer.fields()[i].length(), fields[i].length()) self.assertEqual(layer.fields()[i].precision(), fields[i].precision())
def _test_operations(self, md, conn): """Common tests""" capabilities = conn.capabilities() # Schema operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema and capabilities & QgsAbstractDatabaseProviderConnection.Schemas and capabilities & QgsAbstractDatabaseProviderConnection.DropSchema): # Start clean if 'myNewSchema' in conn.schemas(): conn.dropSchema('myNewSchema', True) # Create conn.createSchema('myNewSchema') schemas = conn.schemas() self.assertTrue('myNewSchema' in schemas) # Create again with self.assertRaises(QgsProviderConnectionException) as ex: conn.createSchema('myNewSchema') # Test rename if capabilities & QgsAbstractDatabaseProviderConnection.RenameSchema: # Rename conn.renameSchema('myNewSchema', 'myVeryNewSchema') schemas = conn.schemas() self.assertTrue('myVeryNewSchema' in schemas) self.assertFalse('myNewSchema' in schemas) conn.renameSchema('myVeryNewSchema', 'myNewSchema') schemas = conn.schemas() self.assertFalse('myVeryNewSchema' in schemas) self.assertTrue('myNewSchema' in schemas) # Drop conn.dropSchema('myNewSchema') schemas = conn.schemas() self.assertFalse('myNewSchema' in schemas) # UTF8 schema conn.createSchema('myUtf8\U0001f604NewSchema') schemas = conn.schemas() conn.dropSchema('myUtf8\U0001f604NewSchema') schemas = conn.schemas() self.assertFalse('myUtf8\U0001f604NewSchema' in schemas) # Table operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.Tables and capabilities & QgsAbstractDatabaseProviderConnection.DropVectorTable): if capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema: schema = 'myNewSchema' conn.createSchema('myNewSchema') else: schema = 'public' # Start clean if 'myNewTable' in self._table_names(conn.tables(schema)): conn.dropVectorTable(schema, 'myNewTable') fields = QgsFields() fields.append(QgsField("string_t", QVariant.String)) fields.append(QgsField("long_t", QVariant.LongLong)) fields.append(QgsField("double_t", QVariant.Double)) fields.append(QgsField("integer_t", QVariant.Int)) fields.append(QgsField("date_t", QVariant.Date)) fields.append(QgsField("datetime_t", QVariant.DateTime)) fields.append(QgsField("time_t", QVariant.Time)) options = {} crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) typ = QgsWkbTypes.LineString # Create conn.createVectorTable(schema, 'myNewTable', fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in table_names) # Create UTF8 table conn.createVectorTable(schema, 'myUtf8\U0001f604Table', fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in table_names) self.assertTrue('myUtf8\U0001f604Table' in table_names) conn.dropVectorTable(schema, 'myUtf8\U0001f604Table') table_names = self._table_names(conn.tables(schema)) self.assertFalse('myUtf8\U0001f604Table' in table_names) self.assertTrue('myNewTable' in table_names) # insert something, because otherwise MSSQL cannot guess if self.providerKey == 'mssql': f = QgsFeature(fields) f.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)')) vl = QgsVectorLayer(conn.tableUri('myNewSchema', 'myNewTable'), 'vl', 'mssql') vl.dataProvider().addFeatures([f]) # Check table information table_properties = conn.tables(schema) table_property = self._table_by_name(table_properties, 'myNewTable') self.assertEqual(table_property.maxCoordinateDimensions(), 2) self.assertIsNotNone(table_property) self.assertEqual(table_property.tableName(), 'myNewTable') self.assertEqual(table_property.geometryColumnCount(), 1) self.assertEqual(table_property.geometryColumnTypes()[0].wkbType, QgsWkbTypes.LineString) cols = table_property.geometryColumnTypes() self.assertEqual(cols[0].crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(table_property.defaultName(), 'myNewTable') # Check aspatial tables conn.createVectorTable(schema, 'myNewAspatialTable', fields, QgsWkbTypes.NoGeometry, crs, True, options) table_properties = conn.tables(schema, QgsAbstractDatabaseProviderConnection.Aspatial) table_property = self._table_by_name(table_properties, 'myNewAspatialTable') self.assertIsNotNone(table_property) self.assertEqual(table_property.maxCoordinateDimensions(), 0) self.assertEqual(table_property.tableName(), 'myNewAspatialTable') self.assertEqual(table_property.geometryColumnCount(), 0) self.assertEqual(table_property.geometryColumn(), '') self.assertEqual(table_property.defaultName(), 'myNewAspatialTable') cols = table_property.geometryColumnTypes() # We always return geom col types, even when there is no geometry self.assertEqual(cols[0].wkbType, QgsWkbTypes.NoGeometry) self.assertFalse(cols[0].crs.isValid()) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) # Check executeSql has_schema = capabilities & QgsAbstractDatabaseProviderConnection.Schemas if capabilities & QgsAbstractDatabaseProviderConnection.ExecuteSql: if has_schema: table = "\"%s\".\"myNewAspatialTable\"" % schema else: table = 'myNewAspatialTable' # MSSQL literal syntax for UTF8 requires 'N' prefix sql = "INSERT INTO %s (string_t, long_t, double_t, integer_t, date_t, datetime_t, time_t) VALUES (%s'QGIS Rocks - \U0001f604', 666, 1.234, 1234, '2019-07-08', '2019-07-08T12:00:12', '12:00:13.00')" % ( table, 'N' if self.providerKey == 'mssql' else '') res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT string_t, long_t, double_t, integer_t, date_t, datetime_t FROM %s" % table res = conn.executeSql(sql) # GPKG and spatialite have no type for time self.assertEqual(res, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, QtCore.QDate(2019, 7, 8), QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) sql = "SELECT time_t FROM %s" % table res = conn.executeSql(sql) # This does not work in MSSQL and returns a QByteArray, we have no way to know that it is a time # value and there is no way we can convert it. if self.providerKey != 'mssql': self.assertIn(res, ([[QtCore.QTime(12, 0, 13)]], [['12:00:13.00']])) sql = "DELETE FROM %s WHERE string_t = %s'QGIS Rocks - \U0001f604'" % ( table, 'N' if self.providerKey == 'mssql' else '') res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT string_t, integer_t FROM %s" % table res = conn.executeSql(sql) self.assertEqual(res, []) # Check that we do NOT get the aspatial table when querying for vectors table_names = self._table_names(conn.tables(schema, QgsAbstractDatabaseProviderConnection.Vector)) self.assertTrue('myNewTable' in table_names) self.assertFalse('myNewAspatialTable' in table_names) # Query for rasters (in qgis_test schema or no schema for GPKG, spatialite has no support) if self.providerKey not in ('spatialite', 'mssql'): table_properties = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.Raster) # At least one raster should be there (except for spatialite) self.assertTrue(len(table_properties) >= 1) table_property = table_properties[0] self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) if capabilities & QgsAbstractDatabaseProviderConnection.RenameVectorTable: # Rename conn.renameVectorTable(schema, 'myNewTable', 'myVeryNewTable') tables = self._table_names(conn.tables(schema)) self.assertFalse('myNewTable' in tables) self.assertTrue('myVeryNewTable' in tables) # Rename it back conn.renameVectorTable(schema, 'myVeryNewTable', 'myNewTable') tables = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in tables) self.assertFalse('myVeryNewTable' in tables) # Vacuum if capabilities & QgsAbstractDatabaseProviderConnection.Vacuum: conn.vacuum('myNewSchema', 'myNewTable') # Spatial index spatial_index_exists = False # we don't initially know if a spatial index exists -- some formats may create them by default, others not if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: spatial_index_exists = conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: if spatial_index_exists: conn.deleteSpatialIndex('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) if capabilities & QgsAbstractDatabaseProviderConnection.CreateSpatialIndex: options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions() options.geometryColumnName = 'geom' conn.createSpatialIndex('myNewSchema', 'myNewTable', options) if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertTrue(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) # now we know for certain a spatial index exists, let's retry dropping it if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: conn.deleteSpatialIndex('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema (should fail) with self.assertRaises(QgsProviderConnectionException) as ex: conn.dropSchema('myNewSchema') # Check some column types operations table = self._table_by_name(conn.tables(schema), 'myNewTable') self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new (existing type) table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new one table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(len(table.geometryColumnTypes()), 2) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) ct = table.geometryColumnTypes()[1] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Check fields fields = conn.fields('myNewSchema', 'myNewTable') for f in ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t', 'time_t']: self.assertTrue(f in fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.AddField: field = QgsField('short_lived_field', QVariant.Int, 'integer') conn.addField(field, 'myNewSchema', 'myNewTable') fields = conn.fields('myNewSchema', 'myNewTable') self.assertTrue('short_lived_field' in fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.DeleteField: conn.deleteField('short_lived_field', 'myNewSchema', 'myNewTable') # This fails on Travis for spatialite, for no particular reason if self.providerKey == 'spatialite' and not os.environ.get('TRAVIS', False): fields = conn.fields('myNewSchema', 'myNewTable') self.assertFalse('short_lived_field' in fields.names()) # Drop table conn.dropVectorTable(schema, 'myNewTable') conn.dropVectorTable(schema, 'myNewAspatialTable') table_names = self._table_names(conn.tables(schema)) self.assertFalse('myNewTable' in table_names) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema conn.dropSchema('myNewSchema') self.assertFalse('myNewSchema' in conn.schemas()) conns = md.connections() self.assertTrue(isinstance(list(conns.values())[0], QgsAbstractDatabaseProviderConnection)) # Remove connection spy_deleted = QSignalSpy(md.connectionDeleted) md.deleteConnection('qgis_test1') self.assertEqual(list(md.connections().values()), []) self.assertEqual(len(spy_deleted), 1)
def testMetadata(self): """ Test that metadata is correctly acquired from provider """ endpoint = self.basetestpath + '/metadata_fake_qgis_http_endpoint' with open(sanitize(endpoint, '?f=json'), 'wb') as f: f.write(""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, "defaultVisibility":true, "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3, "spatialReference":{"wkid":4326,"latestWkid":4326}}, "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText", "displayField":"LABEL","typeIdField":null, "fields":[{"name":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}], "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" .encode('UTF-8')) with open( sanitize( endpoint, '/query?f=json_where=OBJECTID=OBJECTID_returnIdsOnly=true' ), 'wb') as f: f.write(""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } """.encode('UTF-8')) # Create test layer vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') self.assertTrue(vl.isValid()) extent = QgsLayerMetadata.Extent() extent1 = QgsLayerMetadata.SpatialExtent() extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(4326) extent1.bounds = QgsBox3d(QgsRectangle(-71.123, 66.33, -65.32, 78.3)) extent.setSpatialExtents([extent1]) self.assertEqual(vl.metadata().extent(), extent) self.assertEqual(vl.metadata().crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(vl.metadata().identifier(), 'http://' + sanitize(endpoint, '')) self.assertEqual(vl.metadata().parentIdentifier(), 'http://' + self.basetestpath + '/2') self.assertEqual(vl.metadata().type(), 'dataset') self.assertEqual(vl.metadata().abstract(), 'QGIS Provider Test Layer') self.assertEqual(vl.metadata().title(), 'QGIS Test') self.assertEqual(vl.metadata().rights(), ['not copyright']) l = QgsLayerMetadata.Link() l.name = 'Source' l.type = 'WWW:LINK' l.url = 'http://' + sanitize(endpoint, '') self.assertEqual(vl.metadata().links(), [l])
def processAlgorithm(self, parameters, context, feedback): try: # read out algorithm parameters input_points = self.parameterAsVectorLayer(parameters, self.INPUT, context) distance_treshold = parameters[self.DISTANCE_TRESHOLD] result_type_str = [ self.predicates[i][0] for i in self.parameterAsEnums(parameters, self.RESULT_TYPE, context) ][0] result_type = LsType[result_type_str] input_fields = [x.strip() for x in parameters[self.FIELDS].split(",")] input_layer_fields = input_points.fields() input_layer_fields_names = [field.name() for field in input_layer_fields] field_mapping = {} for input_field in input_fields: mapped_field_name = input_field if input_field == "weergavenaam": mapped_field_name = f"weergavenaam_{result_type.value}" # TODO: improve field mapping, since no check if ls_{input_field} exists # in input_layer_fields_names if mapped_field_name in input_layer_fields_names: mapped_field_name = f"ls_{input_field}" field_mapping[input_field] = mapped_field_name for input_field in input_fields: input_layer_fields.append( QgsField(field_mapping[input_field], QVariant.String) ) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, input_layer_fields, QgsWkbTypes.Point, input_points.sourceCrs(), ) # Setup transformation if required in_crs = input_points.crs() out_crs = QgsCoordinateReferenceSystem.fromEpsgId(28992) transform = None if in_crs.authid() != "EPSG:28992": transform = QgsCoordinateTransform( in_crs, out_crs, QgsProject.instance() ) if feedback.isCanceled(): return {} # start processing features for point in input_points.getFeatures(): geom = point.geometry() fid = point.id() if transform: geom.transform(transform) point_geom = QgsGeometry.asPoint(geom) pxy = QgsPointXY(point_geom) x = pxy.x() y = pxy.y() # afstand field required, add if not requested by user if "afstand" not in input_fields: input_fields.append("afstand") data = reverse_lookup(x, y, input_fields, TypeFilter([result_type])) # TODO: add exception handling reverse_lookup result = None if len(data) > 0: if ( distance_treshold != None and data[0]["afstand"] > distance_treshold ): distance = data[0]["afstand"] feedback.pushInfo( f"feature id: {fid} - distance treshold ({distance_treshold}) exceeded: {distance}" ) pass else: result = {} for key in field_mapping: if key in data[0]: result[key] = data[0][key] else: feedback.pushInfo( f'feature id: {fid} - field "{key}" not in response' ) else: feedback.pushInfo( f"feature id: {fid} - no objects found for x,y ({x},{y}) with result_type: {result_type.value}" ) attrs = point.attributes() new_ft = QgsFeature(input_layer_fields) for i in range(len(attrs)): attr = attrs[i] field_name = input_layer_fields_names[i] new_ft.setAttribute(field_name, attr) for key in result: new_ft.setAttribute(field_mapping[key], result[key]) new_ft.setGeometry(point.geometry()) sink.addFeature(new_ft, QgsFeatureSink.FastInsert) if feedback.isCanceled(): return {} results = {} results[self.OUTPUT] = dest_id return results except Exception as e: traceback_str = traceback.format_exc() raise QgsProcessingException( f"Unexpected error occured while running PDOKReverseGeocoder: {str(e)} - {traceback_str}" )
def doReverseGeocode(self): apiKey = self.dockwidget.apiKeyEdit.text() if apiKey is None or apiKey == '': self.iface.messageBar().pushMessage(u"Erro", u"API key não definida!", level=Qgis.Critical, duration=5) return progressDialog = QProgressDialog() progressDialog.setMinimum(0) progressDialog.setCancelButtonText('Cancelar') progressDialog.setWindowModality(Qt.WindowModal) progressDialog.setMinimumWidth(300) progressDialog.show() layer = self.dockwidget.layersCombo.currentLayer() inputCRS = layer.crs() destCRS = QgsCoordinateReferenceSystem.fromEpsgId(4326) transformer = QgsCoordinateTransform(inputCRS, destCRS, QgsProject.instance()) totalFeatures = layer.featureCount() progressDialog.setMaximum(totalFeatures) progressDialog.setWindowTitle(u'Geocodificando ' + str(totalFeatures) + u' feições...') layer.startEditing() novoAttr = QgsField(self.dockwidget.newAttributeEdit.text(), QVariant.String) layer.dataProvider().addAttributes([novoAttr]) layer.updateFields() addrIdx = len(layer.fields()) - 1 geolocator = self.getGeocoder() counter = 0 for f in layer.getFeatures(): if progressDialog.wasCanceled(): self.iface.messageBar().clearWidgets() self.iface.messageBar().pushMessage( u"Geocodificação cancelada", u'Salvos ' + str(counter - 2) + u' endereços.', level=Qgis.Info, duration=5) break oldPoint = f.geometry().asPoint() newPoint = transformer.transform(oldPoint) address, (latitude, longitude) = geolocator.reverse( str(newPoint.y()) + ', ' + str(newPoint.x())) layer.changeAttributeValue(f.id(), addrIdx, address) counter += 1 progressDialog.setValue(counter) print(address, latitude, longitude) layer.commitChanges() self.iface.messageBar().pushMessage( u"Successo", u"Endereços recuperados para {} pontos!".format(counter), level=Qgis.Success, duration=5)
def processAlgorithm(self, parameters, context, feedback): ors_client = self._get_ors_client_from_provider( parameters[self.IN_PROVIDER], feedback) profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] preference = dict( enumerate(PREFERENCES))[parameters[self.IN_PREFERENCE]] mode = dict(enumerate(self.MODE_SELECTION))[parameters[self.IN_MODE]] options = self.parseOptions(parameters, context) # Get parameter values source = self.parameterAsSource(parameters, self.IN_START, context) source_field_name = parameters[self.IN_START_FIELD] source_field = source.fields().field( source_field_name) if source_field_name else None sort_start_by = parameters[self.IN_SORT_START_BY] if sort_start_by: def sort_start(f): return f.attribute(sort_start_by) else: def sort_start(f): return f.id() destination = self.parameterAsSource(parameters, self.IN_END, context) destination_field_name = parameters[self.IN_END_FIELD] destination_field = destination.fields().field( destination_field_name) if destination_field_name else None sort_end_by = parameters[self.IN_SORT_END_BY] if sort_end_by: def sort_end(f): return f.attribute(sort_end_by) else: def sort_end(f): return f.id() route_dict = self._get_route_dict(source, source_field, sort_start, destination, destination_field, sort_end) if mode == 'Row-by-Row': route_count = min( [source.featureCount(), destination.featureCount()]) else: route_count = source.featureCount() * destination.featureCount() # get types of set ID fields field_types = dict() if source_field: field_types.update({"from_type": source_field.type()}) if destination_field: field_types.update({"to_type": destination_field.type()}) sink_fields = directions_core.get_fields(**field_types) (sink, dest_id) = self.parameterAsSink( parameters, self.OUT, context, sink_fields, QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) counter = 0 for coordinates, values in directions_core.get_request_point_features( route_dict, mode): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break params = directions_core.build_default_parameters( preference, coordinates=coordinates, options=options) try: response = ors_client.request('/v2/directions/' + profile + '/geojson', {}, post_json=params) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"Route from {values[0]} to {values[1]} caused a {e.__class__.__name__}:\n{str(e)}" feedback.reportError(msg) logger.log(msg) continue sink.addFeature( directions_core.get_output_feature_directions( response, profile, preference, from_value=values[0], to_value=values[1])) counter += 1 feedback.setProgress(int(100.0 / route_count * counter)) return {self.OUT: dest_id}
def physiocap_filtrer(self, src, csv_sans_0, csv_avec_0, csv_0_seul, nom_dir_segment, nom_session, chemin_session, diametre_filtre, nom_fichier_synthese, err, mindiam, maxdiam, max_sarments_metre, segment_mini_vitesse, segment_maxi_vitesse, segment_mini_point, segment_max_pdop, segment_max_derive, segment_pas_de_derive, details, eer, eec, d, hv, laProjectionCRS, laProjectionTXT, version_3="NO"): """Fonction de traitement. Filtre ligne brute par ligne brute les données de source (src) pour les valeurs comprises entre mindiam et maxdiam et verifie si on n'a pas atteint le max_sarments_metre. Le résultat est écrit au fur et à mesure dans les fichiers csv_sans_0, csv_avec_0 et depuis v3 dans csv_0_seul mais aussi diametre_filtre La synthese est allongé "details" pilote l'ecriture de 5 parametres ou de la totalité des 10 parametres """ leModeDeTrace = self.fieldComboModeTrace.currentText() # S'il n'existe pas de données parcellaire, le script travaille avec les données brutes titre = "" titre_partie_details = " ; NBSARMM2 ; NBSARCEP ; BIOMMM2 ; BIOMGM2 ; BIOMGCEP " if version_3 == "NO": titre_sans_detail = "X ; Y ; XL93 ; YL93 ; NBSARM ; DIAM ; BIOM ; DATE ; VITESSE" else: # Ajout en version 3 de l'altitude titre_sans_detail = "ID;X ; Y ; XL93 ; YL93 ; ALTITUDE; PDOP ; DISTANCE; DERIVE; AZIMUTH; NBSART; NBSARM ; DIAM ; BIOM ; DATE ; VITESSE" if details == "NO": titre = titre_sans_detail else: #S'il existe des données parcellaire, le script travaille avec les données brutes et les données calculées titre = titre_sans_detail + titre_partie_details # Ecriture de l'entete pour tous les cas csv_sans_0.write("{0}\n".format(titre)) csv_avec_0.write("{0}\n".format(titre)) csv_0_seul.write("{0}\n".format(titre)) # Pour progress bar entre 15 et 40 lignes_brutes = src.readlines() max_lignes = len(lignes_brutes) progress_step = int(max_lignes / 25) #physiocap_log("Bar step: " + str( progress_step), leModeDeTrace) progress_bar = 15 barre = 1 precedent = [] on_coupe = "PREMIER" segment_en_cours = [] gid_en_cours = [] gid_sans_mesure = [] manquant_en_cours = [] info_en_cours = {} derive_en_cours = [] mes_lignes_sans_coupure = [] info_lignes_sans_coupure = [] nombre_segments_sans_coupure = 0 # Récuperer le CRS choisi, les extensions et le calculateur de distance distancearea, EXT_CRS_SHP, EXT_CRS_PRJ, EXT_CRS_RASTER, \ laProjectionCRS, laProjectionTXT, EPSG_NUMBER = \ physiocap_quelle_projection_et_lib_demandee( self) for numero_point, ligne_brute in enumerate(lignes_brutes): if not ligne_brute: break # Progress BAR de 15 à 40 % if (numero_point > barre * progress_step): progress_bar = progress_bar + 1 barre = barre + 1 self.progressBar.setValue(progress_bar) comptage = ligne_brute.count(",") # compte le nombre de virgules result = ligne_brute.split(",") # split en fonction des virgules try: # Transform GPS en L93 # on extrait les Colonnnes 1 à 8 (XY, puis GPS jusqu'à vitesse) # en on les transforme en float ### On utilise XY[0 et 1] puis Altitude XY[2] Pdop XY[5] et vitesse XY[7] XY = [float(x) for x in result[1:9]] # Puis on transforme les WGS84 (du capteur) en L93 (probablement utile) # TODO: ?V3.x autres EPSG ? et eviter cet appel dans la boucle crsDest = QgsCoordinateReferenceSystem.fromEpsgId( EPSG_NUMBER_L93) # Lambert 93 crsSrc = QgsCoordinateReferenceSystem.fromEpsgId( EPSG_NUMBER_GPS) # WGS 84 transformer = QgsCoordinateTransform() transformer.setSourceCrs(crsSrc) transformer.setDestinationCrs(crsDest) if not transformer.isValid(): raise physiocap_exception_no_transform(numero_point) # On assure la tranformation par compatibilité du CVS en GPS et L93 point_L93 = transformer.transform(QgsPointXY(XY[0], XY[1])) XY_L93 = [point_L93.x(), point_L93.y()] # aMsg = "Transformation faite X {0} et Y {1}". \ # format( XY_L93[0], XY_L93[1]) # physiocap_log( aMsg , leModeDeTrace) # physiocap_log( "La projection {0}". format( laProjectionTXT), leModeDeTrace) if (laProjectionTXT == "GPS"): le_point_projete = QgsPointXY(XY[0], XY[1]) else: # Pour le moment seulement L93 le_point_projete = QgsPointXY(XY_L93[0], XY_L93[1]) XY_projete = [le_point_projete.x(), le_point_projete.y()] except: aMsg = "{0} Erreur bloquante durant tranformation SCR : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # monter directemenr exception raise # TODO: ?V3.x marquer les points à conserver (non filtré et dans un segment) # pour creer un 4eme csv POINTS_VALIDES # ce qui reste compliqué pour les segments courts que je ne connais pas encore try: # SEGMENT si V3 # On regarde les points sans mesure avant SEGMENT diams = [float(x) for x in result[9:NB_VIRGULES + 1] ] # on extrait les diams et on les transforme en float diamsF = [ i for i in diams if i > mindiam and i < maxdiam ] # on filtre les diams avec les paramètres entrés ci-dessus derive = 0.0 ma_distance = 0.0 mon_azimuth = 0.0 # SEGMENT si V3 if version_3 == "NO": pass elif precedent == [] or on_coupe == "PREMIER": #physiocap_log( "SEGMENT ==>> point {0} PREMIER".format( numero_point), TRACE_SEGMENT + "_DEBUG") # Stocker le premier point pour comparer au prochain tour # et la Date début precedent = XY_projete # TODO: ?V3.y passage en 3D mettre en Z la dérive info_en_cours[DATE_DEBUT] = result[0] if len(diamsF) == 0: # On ne STOCKE pas les points sans MESURE gid_sans_mesure.append(numero_point) else: gid_en_cours.append(numero_point) derive_en_cours.append(0) segment_en_cours.append(QgsPointXY(le_point_projete)) on_coupe = "NON" else: # On vérifie qualité de mesure # ################################################ # Filtre des points pour découpage en SEGMENT ou # pour montrer les limites de la capture # On cherche si le point est dans la zone attendue # calcul basé sur la vitesse annoncé par GPS sur # le point en cours et PDOP # ################################################# # Quand vitesse plus de 2.5 et moins de 8 et pdop reste cohérent segment_max_pdop if XY[7] >= segment_mini_vitesse and XY[ 7] < segment_maxi_vitesse and XY[5] < segment_max_pdop: # on est en vitesse de croisière # Calcul de la distance théorique par rapport au precedent # Introduire un calcul de distance length et l'azimuth le_point_precedent = QgsPointXY(precedent[0], precedent[1]) ma_distance = distancearea.measureLine( le_point_projete, le_point_precedent) mon_azimuth = le_point_projete.azimuth(le_point_precedent) # TODO: ?V3.y Traiter l'azimuth depuis le début du segment distance_theorique = XY[ 7] * 1000 / 3600 # On suppose une seconde d'avancement derive = (ma_distance - distance_theorique) / distance_theorique * 100 # physiocap_log( "Vitesse {3} Distance théorique {1:.2f} et ma distance {0:.2f} \ # sont distantes de \n {2:.1f} soit une derive de {4:.1f}".\ # format(ma_distance, distance_theorique, \ # ( ma_distance - distance_theorique), XY[7], derive ), \ # TRACE_SEGMENT) #remplacer le precedent par l'actuel precedent = XY_projete # Vérification de dérive if abs(derive) > (segment_max_derive + (2 * segment_pas_de_derive)): physiocap_log( "{0} DECOUPAGE point {1} : l'avancée dérive GRAVE ===> {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" elif abs(derive) > (segment_max_derive + segment_pas_de_derive): physiocap_log( "{0} DECOUPAGE point {1} : l'avancée dérive de PLUS d'un PAS ==> {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" elif abs(derive) > segment_max_derive: physiocap_log("{0} DECOUPAGE point {1} : l'avancée dérive => {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" else: # La derive < segment_max_derive en % : # Stocker ligne "droite" = orientation et sens d'avancement # Créer un flux des avancement stables pour identifier l'écartement problable # Ajouter un point à la ligne segment_en_cours.append(QgsPointXY(le_point_projete)) info_en_cours[DATE_FIN] = result[0] if len(diamsF) == 0: # On ne STOCKE pas les points sans MESURE gid_sans_mesure.append(numero_point) else: gid_en_cours.append(numero_point) derive_en_cours.append(derive) on_coupe = "NON" else: # Cas d'arret (fin de rang) ou pdop on_coupe = "OUI" # Tracer cas decoupe vitessse if XY[7] < segment_mini_vitesse: if len(segment_en_cours) > 0: physiocap_log("{0} DECOUPAGE point {1} : vitesse {2:.1f} alors que min est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[7], segment_mini_vitesse), \ TRACE_SEGMENT_DECOUPES) if XY[7] > segment_maxi_vitesse: if len(segment_en_cours) > 0: physiocap_log("{0} DECOUPAGE point {1} : vitesse {2:.1f} que max est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[7], segment_maxi_vitesse), \ TRACE_SEGMENT_DECOUPES) # Tracer cas decoupe pdop if XY[5] >= segment_max_pdop: physiocap_log("{0} DECOUPAGE point {1} : pdop {2:.1f} max est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[5], segment_max_pdop ), \ TRACE_SEGMENT_DECOUPES) if on_coupe == "OUI": # Cas de fin de ligne if len(segment_en_cours) > segment_mini_point: # Le segment est à garder manquant_en_cours.append(numero_point) # Mémoriser la ligne des points cohérents mes_lignes_sans_coupure.append(segment_en_cours) info_en_cours[NUM_SEG] = nombre_segments_sans_coupure info_en_cours[DATE_FIN] = result[0] info_en_cours[NOMBRE] = len(segment_en_cours) info_en_cours[GID_GARDE] = gid_en_cours info_en_cours[GID_SANS_MESURE] = gid_sans_mesure info_en_cours[GID_TROU] = manquant_en_cours info_en_cours[DERIVE] = np.mean(derive_en_cours) # stocker jour_heure début et fin et derive moyenne ... info_lignes_sans_coupure.append(info_en_cours) nombre_segments_sans_coupure = nombre_segments_sans_coupure + 1 manquant_en_cours = [] else: # Vérifier les gid_sans_mesure # On ne perd pas les points manquants qui seront ajouter dans GID_TROU pour le segment suivant # On aditionne des gid en cours avec les manquants... for gid_perdu in gid_en_cours: manquant_en_cours.append(gid_perdu) manquant_en_cours.append(numero_point) if len(segment_en_cours) > 0: physiocap_log("{0} SEGMENT {1} IGNORE : trop cours == {2} points, le mini est {3} ".\ format(PHYSIOCAP_WARNING, nombre_segments_sans_coupure, len(segment_en_cours), segment_mini_point ), TRACE_SEGMENT_DECOUPES) info_en_cours = {} gid_en_cours = [] gid_sans_mesure = [] precedent = [] on_coupe = "PREMIER" segment_en_cours = [] except: aMsg = "{0} Erreur bloquante durant extraction des segments : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # monter directemenr exception raise try: # On filtre vraiement if details == "NO": if len( diamsF ) == 0: # si le nombre de diamètre après filtrage = 0 alors pas de mesures nbsarm = 0 nbsart = 0 diam = 0 biom = 0 # Ecrire les seuls_0 et aussi les points avec 0 if version_3 == "NO": csv_0_seul.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv avec ZERO SEUL csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le fcsv avec ZERO else: # V3 on ajoute altitude, pdop, distance au point precedent et la dérive # puis AZIMUTH et NBSART = 0 a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};0;0;0;0;{10};{11:.7f}\n" . \ format(numero_point, XY[0],XY[1],XY_L93[0],XY_L93[1], \ XY[2],XY[5],ma_distance,derive,mon_azimuth, result[0],XY[7]) csv_0_seul.write(a_ecrire) csv_avec_0.write(a_ecrire) elif comptage == NB_VIRGULES and len( diamsF ) > 0: # si le nombre de diamètre après filtrage != 0 alors mesures # Nombre sarment total nbsart = len(diamsF) if XY[7] != 0: # Si vitesse non nulle nbsarm = len(diamsF) / (XY[7] * 1000 / 3600) else: nbsarm = 0 if nbsarm > 1 and nbsarm < max_sarments_metre: diam = sum(diamsF) / len(diamsF) biom = 3.1416 * (diam / 2) * (diam / 2) * nbsarm if version_3 == "NO": csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%0.2f%s%.2f%s%.2f%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv avec ZERO csv_sans_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%0.2f%s%.2f%s%.2f%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv sans ZERO else: # V3 on ajoute altitude, pdop,distance au point precedent et risque de dérive # puis AZIMUTH et NBSART a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};{10}; \ {11:.2f}; {12:.2f};{13:.2f};{14};{15:.7f}\n" . \ format( numero_point, XY[0], XY[1], XY_L93[0] ,XY_L93[1], \ XY[2],XY[5],ma_distance,derive,mon_azimuth,nbsart, \ nbsarm,diam,biom,result[0],XY[7]) csv_avec_0.write(a_ecrire) csv_sans_0.write(a_ecrire) for n in range(len(diamsF)): diametre_filtre.write("%f%s" % (diamsF[n], ";")) elif details == "YES": if len( diamsF ) == 0: # si le nombre de diamètre après filtrage = 0 alors pas de mesures nbsart = 0 nbsarm = 0 diam = 0 biom = 0 nbsarmm2 = 0 nbsarcep = 0 biommm2 = 0 biomgm2 = 0 biomgcep = 0 if version_3 == "NO": csv_0_seul.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f%s%i%s%i%s%i%s%i%s%i\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f%s%i%s%i%s%i%s%i%s%i\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) else: # Q3 on ajoute altitude, pdop, distance au point precedent et la dérive # puis AZIMUTH et NBSART = 0 a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};0;0;0;0;{10};{11:.7f}" . \ format(numero_point, XY[0],XY[1],XY_L93[0],XY_L93[1], XY[2],XY[5],ma_distance,derive,mon_azimuth, result[0],XY[7]) a_ecrire_detail = ";0;0;0;0;0\n" a_ecrire_complet = a_ecrire + a_ecrire_detail csv_0_seul.write(a_ecrire_complet) csv_avec_0.write(a_ecrire_complet) elif comptage == NB_VIRGULES and len( diamsF ) > 0: # si le nombre de diamètre après filtrage != 0 alors mesures nbsart = len(diamsF) if XY[7] != 0: nbsarm = len(diamsF) / (XY[7] * 1000 / 3600) else: nbsarm = 0 if nbsarm > 1 and nbsarm < max_sarments_metre: diam = sum(diamsF) / len(diamsF) biom = 3.1416 * (diam / 2) * (diam / 2) * nbsarm nbsarmm2 = nbsarm / eer * 100 nbsarcep = nbsarm * eec / 100 biommm2 = biom / eer * 100 biomgm2 = biom * d * hv / eer biomgcep = biom * d * hv * eec / 100 / 100 if version_3 == "NO": csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%.2f%s%.2f%s%.2f%s%s%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) csv_sans_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%.2f%s%.2f%s%.2f%s%s%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) else: # Q3 on ajoute altitude, pdop,distance au point precedent et risque de dérive # puis AZIMUTH et NBSART a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};{10}; \ {11:.2f}; {12:.2f};{13:.2f};{14};{15:.7f}" . \ format( numero_point, XY[0], XY[1], XY_L93[0] ,XY_L93[1], XY[2],XY[5],ma_distance,derive,mon_azimuth,nbsart, nbsarm,diam,biom,result[0],XY[7]) a_ecrire_detail = ";{0:.7f};{1:.7f};{2:.7f};{3:.7f};{4:.7f}\n". \ format( nbsarmm2, nbsarcep,biommm2,biomgm2,biomgcep) a_ecrire_complet = a_ecrire + a_ecrire_detail csv_avec_0.write(a_ecrire_complet) csv_sans_0.write(a_ecrire_complet) # Memorise diametre filtré pour histo for n in range(len(diamsF)): diametre_filtre.write("%f%s" % (diamsF[n], ";")) except: aMsg = "{0} Erreur bloquante durant filtrage : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # Pour monter directement exception raise physiocap_exception_err_csv(nom_court_csv_concat) if version_3 == "NO": vecteur_segment = None vecteur_segment_brise = None else: if len(info_lignes_sans_coupure) != nombre_segments_sans_coupure: physiocap_error( self, "{0} on a trouvé {1} segments et {2} infos". \ format( PHYSIOCAP_INFO, nombre_segments_sans_coupure, len( info_lignes_sans_coupure))) raise physiocap_exception_calcul_segment_invalid( "Segment et leurs infos sont différents") i = 0 for info_segment in info_lignes_sans_coupure: i = i + 1 try: physiocap_log( "{0} Segment {1} contient {2} points et une dérive moyenne de {3:.1f}". \ format( PHYSIOCAP_INFO, i, info_segment[NOMBRE], info_segment[DERIVE]), TRACE_SEGMENT) physiocap_log( "gid des points :{0} \net les sans mesure\n{1}". \ format(info_segment[GID_GARDE], info_segment[GID_SANS_MESURE]), TRACE_SEGMENT) except: physiocap_error( self, "Problème : manque attribut dans info segment") raise physiocap_exception_calcul_segment_invalid( "Un attribut n'est pas présent") # try: # physiocap_log( "Date début {0} et fin {1}". \ # format( info_segment[DATE_DEBUT], info_segment[DATE_FIN]), # TRACE_SEGMENT) # except: # physiocap_error( self, "Problème : pas de date dans le segment") # raise physiocap_exception_calcul_segment_invalid( "Date non présente") # Creer les lignes simplifiés ou brisés de ces segments et infos vecteur_segment = physiocap_segment_vers_vecteur( self, chemin_session, nom_dir_segment, nom_session, mes_lignes_sans_coupure, info_lignes_sans_coupure, version_3) vecteur_segment_brise = physiocap_segment_vers_vecteur( self, chemin_session, nom_dir_segment, nom_session, mes_lignes_sans_coupure, info_lignes_sans_coupure, version_3, "BRISE") physiocap_log( "{0} {1} Fin du filtrage OK des {2} lignes.". \ format( PHYSIOCAP_INFO, PHYSIOCAP_UNI, str(numero_point - 1)), leModeDeTrace) return vecteur_segment, vecteur_segment_brise
def setupCrsTransform(self): if QgsCoordinateReferenceSystem is not None: srcCrs = QgsCoordinateReferenceSystem.fromEpsgId(25832) dstCrs = qgisutils.getCurrentCrs(self.qgisIface) self.crsTransform = QgsCoordinateTransform(srcCrs, dstCrs, QgsProject.instance())
def testEquality(self): # spatial extent extent = QgsLayerMetadata.SpatialExtent() extent.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) self.assertEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) self.assertNotEqual(extent, extent2) extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) self.assertNotEqual(extent, extent2) # extent extent = QgsLayerMetadata.Extent() extent1 = QgsLayerMetadata.SpatialExtent() extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) extent1.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) extent2 = QgsLayerMetadata.SpatialExtent() extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0) extent.setSpatialExtents([extent1, extent2]) dates = [ QgsDateTimeRange(QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange(QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) ] extent.setTemporalExtents(dates) extent_copy = QgsLayerMetadata.Extent(extent) self.assertEqual(extent, extent_copy) extent_copy.setTemporalExtents([ QgsDateTimeRange(QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), QgsDateTimeRange(QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49))) ]) self.assertNotEqual(extent, extent_copy) extent_copy = QgsLayerMetadata.Extent(extent) extent3 = QgsLayerMetadata.SpatialExtent() extent3.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113) extent3.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 19.0) extent_copy.setSpatialExtents([extent1, extent3]) self.assertNotEqual(extent, extent_copy) constraint = QgsLayerMetadata.Constraint('c', 'type1') self.assertEqual(constraint, QgsLayerMetadata.Constraint('c', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c2', 'type1')) self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c', 'type2')) a = QgsLayerMetadata.Address() a.type = 'postal' a.address = '13 north rd' a.city = 'huxleys haven' a.administrativeArea = 'land of the queens' a.postalCode = '4123' a.country = 'straya!' a2 = QgsLayerMetadata.Address(a) self.assertEqual(a, a2) a2.type = 'postal2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.address = 'address2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.city = 'city' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.administrativeArea = 'area2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.postalCode = 'postal2' self.assertNotEqual(a, a2) a2 = QgsLayerMetadata.Address(a) a2.country = 'country2' self.assertNotEqual(a, a2) c = QgsLayerMetadata.Contact() c.name = 'name' c.organization = 'org' c.position = 'pos' c.voice = '1500 515 555' c.fax = 'fax' c.email = 'email' c.role = 'role' a = QgsLayerMetadata.Address() a.type = 'postal' a2 = QgsLayerMetadata.Address() a2.type = 'street' c.addresses = [a, a2] c2 = QgsLayerMetadata.Contact(c) self.assertEqual(c, c2) c2.name = 'name2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.organization = 'org2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.position = 'pos2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.voice = 'voice2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.fax = 'fax2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.email = 'email2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.role = 'role2' self.assertNotEqual(c, c2) c2 = QgsLayerMetadata.Contact(c) c2.addresses = [a2] self.assertNotEqual(c, c2) # link l = QgsLayerMetadata.Link() l.name = 'name' l.type = 'type' l.description = 'desc' l.url = 'url' l.format = 'format' l.mimeType = 'mime' l.size = '112' l2 = QgsLayerMetadata.Link(l) self.assertEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.name = 'name2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.type = 'type2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.description = 'desc2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.url = 'url2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.format = 'format2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.mimeType = 'mime2' self.assertNotEqual(l, l2) l2 = QgsLayerMetadata.Link(l) l2.size = '113' self.assertNotEqual(l, l2)
def testAnnotationsVariationsRotatedThresholds(self): """ Tests various rotated grid threshold settings """ layout = QgsLayout(QgsProject.instance()) layout.initializeDefaults() map_configs = [ (10, 30, QgsLayoutItemMapGrid.OutsideMapFrame, QgsLayoutItemMapGrid.InteriorTicks, True, False), (10, 120, QgsLayoutItemMapGrid.InsideMapFrame, QgsLayoutItemMapGrid.ExteriorTicks, True, False), (170, 30, QgsLayoutItemMapGrid.OutsideMapFrame, QgsLayoutItemMapGrid.InteriorTicks, False, True), (170, 120, QgsLayoutItemMapGrid.InsideMapFrame, QgsLayoutItemMapGrid.ExteriorTicks, False, True), ] for x, y, pos, style, limit_rot, limit_corners in map_configs: map = QgsLayoutItemMap(layout) layout.addLayoutItem(map) map.attemptSetSceneRect(QRectF(x, y, 100, 50)) map.setExtent(QgsRectangle(5000000, 800000, 6000000, 1300000)) map.setBackgroundColor(QColor(200, 200, 200)) map.setMapRotation(0) map.setFrameEnabled(True) map.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(2056)) map.grid().setCrs(QgsCoordinateReferenceSystem.fromEpsgId(4326)) map.grid().setFrameStyle(style) map.grid().setFrameWidth(7) map.grid().setFramePenSize(1) map.grid().setFramePenColor(QColor(255, 0, 0)) map.grid().setEnabled(True) map.grid().setIntervalX(2) map.grid().setIntervalY(2) map.grid().setAnnotationEnabled(True) map.grid().setGridLineColor(QColor(0, 255, 0)) map.grid().setGridLineWidth(0.5) map.grid().setRotatedTicksLengthMode(QgsLayoutItemMapGrid.NormalizedTicks) map.grid().setAnnotationFont(getTestFont('Bold', 15)) map.grid().setAnnotationFontColor(QColor(0, 0, 255, 150)) map.grid().setAnnotationPrecision(0) map.grid().setAnnotationFrameDistance(2.5) map.grid().setRotatedTicksEnabled(True) map.grid().setRotatedAnnotationsEnabled(True) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.Top) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.Right) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.Bottom) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.Left) map.grid().setAnnotationDirection(QgsLayoutItemMapGrid.OnTick, QgsLayoutItemMapGrid.Top) map.grid().setAnnotationDirection(QgsLayoutItemMapGrid.OnTick, QgsLayoutItemMapGrid.Right) map.grid().setAnnotationDirection(QgsLayoutItemMapGrid.OnTick, QgsLayoutItemMapGrid.Bottom) map.grid().setAnnotationDirection(QgsLayoutItemMapGrid.OnTick, QgsLayoutItemMapGrid.Left) if limit_rot: map.grid().setRotatedAnnotationsMinimumAngle(30) map.grid().setRotatedTicksMinimumAngle(30) if limit_corners: map.grid().setRotatedAnnotationsMarginToCorner(10) map.grid().setRotatedTicksMarginToCorner(10) map.updateBoundingRect() checker = QgsLayoutChecker('composermap_annotations_variations_rotated_thresholds', layout) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testLayout() self.assertTrue(myTestResult, myMessage)
def create(self, path: str, qgis_project: QgsProject): qgis_project.setAutoTransaction(self.auto_transaction) qgis_project.setEvaluateDefaultValues(self.evaluate_default_values) qgis_layers = list() for layer in self.layers: qgis_layer = layer.create() self.layer_added.emit(qgis_layer.id()) if not self.crs and qgis_layer.isSpatial(): self.crs = qgis_layer.crs() qgis_layers.append(qgis_layer) qgis_project.addMapLayers(qgis_layers, not self.legend) if self.crs: if isinstance(self.crs, QgsCoordinateReferenceSystem): qgis_project.setCrs(self.crs) else: qgis_project.setCrs( QgsCoordinateReferenceSystem.fromEpsgId(self.crs)) qgis_relations = list( qgis_project.relationManager().relations().values()) dict_domains = { layer.layer.id(): layer.is_domain for layer in self.layers } for relation in self.relations: rel = relation.create(qgis_project, qgis_relations) assert rel.isValid() qgis_relations.append(rel) if rel.referencedLayerId() in dict_domains and dict_domains[ rel.referencedLayerId()]: editor_widget_setup = QgsEditorWidgetSetup( 'RelationReference', { 'Relation': rel.id(), 'ShowForm': False, 'OrderByValue': True, 'ShowOpenFormButton': False }) else: editor_widget_setup = QgsEditorWidgetSetup( 'RelationReference', { 'Relation': rel.id(), 'ShowForm': False, 'OrderByValue': True, 'ShowOpenFormButton': False, 'AllowAddFeatures': True }) referencing_layer = rel.referencingLayer() referencing_layer.setEditorWidgetSetup(rel.referencingFields()[0], editor_widget_setup) qgis_project.relationManager().setRelations(qgis_relations) # Set Bag of Enum widget for layer_name, bag_of_enum in self.bags_of_enum.items(): for attribute, bag_of_enum_info in bag_of_enum.items(): layer_obj = bag_of_enum_info[0] cardinality = bag_of_enum_info[1] domain_table = bag_of_enum_info[2] key_field = bag_of_enum_info[3] value_field = bag_of_enum_info[4] allow_null = cardinality.startswith('0') allow_multi = cardinality.endswith('*') current_layer = layer_obj.create() field_widget = 'ValueRelation' field_widget_config = { 'AllowMulti': allow_multi, 'UseCompleter': False, 'Value': value_field, 'OrderByValue': False, 'AllowNull': allow_null, 'Layer': domain_table.create().id(), 'FilterExpression': '', 'Key': key_field, 'NofColumns': 1 } field_idx = current_layer.fields().indexOf(attribute) setup = QgsEditorWidgetSetup(field_widget, field_widget_config) current_layer.setEditorWidgetSetup(field_idx, setup) for layer in self.layers: layer.create_form(self) if self.legend: self.legend.create(qgis_project) if path: qgis_project.write(path)
def testCreateLayerViaExport(self): def runTest(crs, primaryKey, attributeNames, attributeValues): self.assertTrue(crs.isValid()) layer = QgsVectorLayer(f"Point?crs={crs.authid()}", "new_table", "memory") pr = layer.dataProvider() fields = [QgsField("fldid", QVariant.LongLong), QgsField("fldtxt", QVariant.String), QgsField("fldint", QVariant.Int)] if primaryKey == "fldid": constraints = QgsFieldConstraints() constraints.setConstraint(QgsFieldConstraints.ConstraintNotNull, QgsFieldConstraints.ConstraintOriginProvider) constraints.setConstraint(QgsFieldConstraints.ConstraintUnique, QgsFieldConstraints.ConstraintOriginProvider) fields[0].setConstraints(constraints) layer.startEditing() for f in fields: layer.addAttribute(f) layer.commitChanges(True) f1 = QgsFeature() f1.setAttributes([1, "test", 11]) f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2))) f2 = QgsFeature() f2.setAttributes([2, "test2", 13]) f3 = QgsFeature() f3.setAttributes([3, "test2", NULL]) f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(3, 2))) f4 = QgsFeature() f4.setAttributes([4, NULL, 13]) f4.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(4, 3))) pr.addFeatures([f1, f2, f3, f4]) layer.commitChanges() QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data') uri = self.uri + f' key=\'{primaryKey}\' table="{self.schemaName}"."import_data" (geom) sql=' error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'hana', crs) self.assertEqual(error, QgsVectorLayerExporter.NoError) import_layer = self.createVectorLayer( f'key=\'{primaryKey}\' table="{self.schemaName}"."import_data" (geom) sql=', 'testimportedlayer') self.assertEqual(import_layer.wkbType(), QgsWkbTypes.Point) self.assertEqual([f.name() for f in import_layer.fields()], attributeNames) features = [f.attributes() for f in import_layer.getFeatures()] self.assertEqual(features, attributeValues) geom = [f.geometry().asWkt() for f in import_layer.getFeatures()] self.assertEqual(geom, ['Point (1 2)', '', 'Point (3 2)', 'Point (4 3)']) QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data') def is_crs_installed(srid): num_crs = QgsHanaProviderUtils.executeSQLFetchOne(self.conn, f'SELECT COUNT(*) FROM SYS.ST_SPATIAL_REFERENCE_SYSTEMS ' f'WHERE SRS_ID = {srid}') return num_crs == 1 crs_4326 = QgsCoordinateReferenceSystem('EPSG:4326') # primary key already exists in the imported layer runTest(crs_4326, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13], [3, 'test2', NULL], [4, NULL, 13]]) # primary key doesn't exist in the imported layer runTest(crs_4326, 'pk', ['pk', 'fldid', 'fldtxt', 'fldint'], [[1, 1, 'test', 11], [2, 2, 'test2', 13], [3, 3, 'test2', NULL], [4, 4, NULL, 13]]) # crs id that do not exist # unfortunately, we cannot test new units of measure as # QgsCoordinateReferenceSystem does not allow creating # a new crs object from WKT that contain custom AUTHORITY # or UNIT values. unknown_srid = 3395 if not is_crs_installed(unknown_srid): crs = QgsCoordinateReferenceSystem.fromEpsgId(unknown_srid) runTest(crs, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13], [3, 'test2', NULL], [4, NULL, 13]]) self.assertTrue(is_crs_installed(unknown_srid)) QgsHanaProviderUtils.executeSQL(self.conn, f'DROP SPATIAL REFERENCE SYSTEM "{crs.description()}"')
def testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def setUpClass(cls) -> None: cls.WGS = QgsCoordinateReferenceSystem.fromEpsgId(4326) cls.PSEUDO = QgsCoordinateReferenceSystem.fromEpsgId(3857)
def project_info(project_path): """Extracts project information and returns it as a dictionary""" info = {} p = QgsProject() canvas = QgsMapCanvas() def _readCanvasSettings(xmlDocument): canvas.readProject(xmlDocument) p.readProject.connect(_readCanvasSettings, Qt.DirectConnection) if p.read(project_path): # initial extent extent = canvas.extent() if p.crs().authid() != 4326: ct = QgsCoordinateTransform( p.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326), p.transformContext()) extent = ct.transform(extent) info['initial_extent'] = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum(), ] #################################################### # Main section info['title'] = p.metadata().title() if not info['title']: info['title'] = QgsServerProjectUtils.owsServiceTitle(p) if not info['title']: info['title'] = p.title() if not info['title']: info['title'] = p.baseName() info['description'] = p.metadata().abstract() if not info['description']: info['description'] = QgsServerProjectUtils.owsServiceAbstract(p) # Extent, CRS and published WMS layers typenames wmsOutputCrsList = QgsServerProjectUtils.wmsOutputCrsList(p) info[ 'crs'] = 'EPSG:4326' if 'EPSG:4326' in wmsOutputCrsList else wmsOutputCrsList[ 0] extent, info['wms_layers'] = project_wms(p, info['crs']) info['extent'] = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] geographic_extent = extent if info['crs'] != 'EPSG:4326': extent_crs = QgsCoordinateReferenceSystem.fromEpsgId( int(info['crs'].split(':')[1])) ct = QgsCoordinateTransform( extent_crs, QgsCoordinateReferenceSystem.fromEpsgId(4326), p.transformContext()) geographic_extent = ct.transform(geographic_extent) info['geographic_extent'] = [ geographic_extent.xMinimum(), geographic_extent.yMinimum(), geographic_extent.xMaximum(), geographic_extent.yMaximum() ] #################################################### # Metadata section m = p.metadata() metadata = {} for prop in ( 'title', 'identifier', 'parentIdentifier', 'abstract', 'author', 'language', 'categories', 'history', 'type', ): metadata[prop] = getattr(m, prop)() # links array metadata['links'] = _read_links(m) # contacts array metadata['contacts'] = _read_contacts(m) metadata['creationDateTime'] = m.creationDateTime().toString( Qt.ISODate) info['metadata'] = metadata #################################################### # WMS Service Capabilities section capabilities = {} for c in ('owsServiceAbstract', 'owsServiceAccessConstraints', 'owsServiceCapabilities', 'owsServiceContactMail', 'owsServiceContactOrganization', 'owsServiceContactPerson', 'owsServiceContactPhone', 'owsServiceContactPosition', 'owsServiceFees', 'owsServiceKeywords', 'owsServiceOnlineResource', 'owsServiceTitle', 'wcsLayerIds', 'wcsServiceUrl', 'wfsLayerIds', 'wfsServiceUrl', 'wfstDeleteLayerIds', 'wfstInsertLayerIds', 'wfstUpdateLayerIds', 'wmsDefaultMapUnitsPerMm', 'wmsExtent', 'wmsFeatureInfoAddWktGeometry', 'wmsFeatureInfoDocumentElement', 'wmsFeatureInfoDocumentElementNs', 'wmsFeatureInfoLayerAliasMap', 'wmsFeatureInfoPrecision', 'wmsFeatureInfoSchema', 'wmsFeatureInfoSegmentizeWktGeometry', 'wmsImageQuality', 'wmsInfoFormatSia2045', 'wmsInspireActivate', 'wmsInspireLanguage', 'wmsInspireMetadataDate', 'wmsInspireMetadataUrl', 'wmsInspireMetadataUrlType', 'wmsInspireTemporalReference', 'wmsMaxAtlasFeatures', 'wmsMaxHeight', 'wmsMaxWidth', 'wmsOutputCrsList', 'wmsRestrictedComposers', 'wmsRestrictedLayers', 'wmsRootName', 'wmsServiceUrl', 'wmsTileBuffer', 'wmsUseLayerIds', 'wmtsServiceUrl'): capabilities[c] = getattr(QgsServerProjectUtils, c)(p) info['capabilities'] = capabilities #################################################### # WMS Layers section info['wms_root_name'] = capabilities['wmsRootName'] if capabilities[ 'wmsRootName'] else p.title() restricted_wms = capabilities['wmsRestrictedLayers'] wms_layers = {} use_ids = capabilities['wmsUseLayerIds'] # Map layer title to layer name (or id if use_ids) wms_layers_map = {} # Maps a typename to a layer id wms_layers_typename_id_map = {} wms_layers_searchable = [] wms_layers_queryable = [] for l in p.mapLayers().values(): if l.name() not in restricted_wms: wms_layers[l.id()] = layer_info(l) name = l.title() if l.title() else l.name() short_name = l.shortName() if l.shortName() else l.name() wms_layers_typename_id_map[short_name] = l.id() wms_layers_map[name] = l.id() if use_ids else short_name if bool(l.flags() & QgsMapLayer.Searchable): wms_layers_searchable.append(l.id()) if bool(l.flags() & QgsMapLayer.Identifiable): wms_layers_queryable.append(l.id()) info['wms_layers'] = wms_layers info['wms_layers_map'] = wms_layers_map info['wms_layers_searchable'] = wms_layers_searchable info['wms_layers_queryable'] = wms_layers_queryable info['wms_layers_typename_id_map'] = wms_layers_typename_id_map #################################################### # TOC tree (WMS published only) info['toc'] = get_toc(p, info) return info
def _test_operations(self, md, conn): """Common tests""" capabilities = conn.capabilities() # Schema operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema and capabilities & QgsAbstractDatabaseProviderConnection.Schemas and capabilities & QgsAbstractDatabaseProviderConnection.RenameSchema and capabilities & QgsAbstractDatabaseProviderConnection.DropSchema): if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema and 'myNewSchema' in conn.schemas(): conn.dropSchema('myNewSchema', True) # Create conn.createSchema('myNewSchema') schemas = conn.schemas() self.assertTrue('myNewSchema' in schemas) # Create again with self.assertRaises(QgsProviderConnectionException) as ex: conn.createSchema('myNewSchema') # Rename conn.renameSchema('myNewSchema', 'myVeryNewSchema') schemas = conn.schemas() self.assertTrue('myVeryNewSchema' in schemas) self.assertFalse('myNewSchema' in schemas) # Drop conn.dropSchema('myVeryNewSchema') schemas = conn.schemas() self.assertFalse('myVeryNewSchema' in schemas) # Table operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.Tables and capabilities & QgsAbstractDatabaseProviderConnection.RenameVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.DropVectorTable): if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema and 'myNewSchema' in conn.schemas(): conn.dropSchema('myNewSchema', True) if capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema: schema = 'myNewSchema' conn.createSchema('myNewSchema') else: schema = 'public' if 'myNewTable' in self._table_names(conn.tables(schema)): conn.dropVectorTable(schema, 'myNewTable') fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) options = {} crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) typ = QgsWkbTypes.LineString # Create conn.createVectorTable(schema, 'myNewTable', fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in table_names) # Check table information table_properties = conn.tables(schema) table_property = self._table_by_name(table_properties, 'myNewTable') self.assertEqual(table_property.maxCoordinateDimensions(), 2) self.assertIsNotNone(table_property) self.assertEqual(table_property.tableName(), 'myNewTable') self.assertEqual(table_property.geometryColumnCount(), 1) self.assertEqual(table_property.geometryColumnTypes()[0].wkbType, QgsWkbTypes.LineString) self.assertEqual(table_property.geometryColumnTypes()[0].crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(table_property.defaultName(), 'myNewTable') # Check aspatial tables conn.createVectorTable(schema, 'myNewAspatialTable', fields, QgsWkbTypes.NoGeometry, crs, True, options) table_properties = conn.tables(schema, QgsAbstractDatabaseProviderConnection.Aspatial) table_property = self._table_by_name(table_properties, 'myNewAspatialTable') self.assertIsNotNone(table_property) self.assertEqual(table_property.maxCoordinateDimensions(), 0) self.assertEqual(table_property.tableName(), 'myNewAspatialTable') self.assertEqual(table_property.geometryColumnCount(), 0) self.assertEqual(table_property.geometryColumn(), '') self.assertEqual(table_property.defaultName(), 'myNewAspatialTable') self.assertEqual(table_property.geometryColumnTypes()[0].wkbType, QgsWkbTypes.NoGeometry) self.assertFalse(table_property.geometryColumnTypes()[0].crs.isValid()) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) # Check executeSql has_schema = capabilities & QgsAbstractDatabaseProviderConnection.Schemas if capabilities & QgsAbstractDatabaseProviderConnection.ExecuteSql: if has_schema: table = "\"%s\".\"myNewAspatialTable\"" % schema else: table = 'myNewAspatialTable' sql = "INSERT INTO %s (string, long, double, integer, date, datetime, time) VALUES ('QGIS Rocks - \U0001f604', 666, 1.234, 1234, '2019-07-08', '2019-07-08T12:00:12', '12:00:13.00')" % table res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT string, long, double, integer, date, datetime FROM %s" % table res = conn.executeSql(sql) # GPKG has no type for time self.assertEqual(res, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, QtCore.QDate(2019, 7, 8), QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) sql = "SELECT time FROM %s" % table res = conn.executeSql(sql) self.assertIn(res, ([[QtCore.QTime(12, 0, 13)]], [['12:00:13.00']])) sql = "DELETE FROM %s WHERE string = 'QGIS Rocks - \U0001f604'" % table res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT string, integer FROM %s" % table res = conn.executeSql(sql) self.assertEqual(res, []) # Check that we do NOT get the aspatial table when querying for vectors table_names = self._table_names(conn.tables(schema, QgsAbstractDatabaseProviderConnection.Vector)) self.assertTrue('myNewTable' in table_names) self.assertFalse('myNewAspatialTable' in table_names) # Query for rasters (in qgis_test schema or no schema for GPKG) table_properties = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.Raster) # At leasy one raster should be there self.assertTrue(len(table_properties) >= 1) table_property = table_properties[0] self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) # Rename conn.renameVectorTable(schema, 'myNewTable', 'myVeryNewTable') tables = self._table_names(conn.tables(schema)) self.assertFalse('myNewTable' in tables) self.assertTrue('myVeryNewTable' in tables) # Vacuum if capabilities & QgsAbstractDatabaseProviderConnection.Vacuum: conn.vacuum('myNewSchema', 'myVeryNewTable') if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema (should fail) with self.assertRaises(QgsProviderConnectionException) as ex: conn.dropSchema('myNewSchema') # Check some column types operations table = self._table_by_name(conn.tables(schema), 'myVeryNewTable') self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new (existing type) table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new one table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(len(table.geometryColumnTypes()), 2) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) ct = table.geometryColumnTypes()[1] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Drop table conn.dropVectorTable(schema, 'myVeryNewTable') conn.dropVectorTable(schema, 'myNewAspatialTable') table_names = self._table_names(conn.tables(schema)) self.assertFalse('myVeryNewTable' in table_names) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema conn.dropSchema('myNewSchema') self.assertFalse('myNewSchema' in conn.schemas()) conns = md.connections() self.assertTrue(isinstance(list(conns.values())[0], QgsAbstractDatabaseProviderConnection)) # Remove connection md.deleteConnection('qgis_test1') self.assertEqual(list(md.connections().values()), [])
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 testCreateMemoryLayer(self): """ Test QgsMemoryProviderUtils.createMemoryLayer() """ # no fields layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertTrue(layer.isValid()) self.assertEqual(layer.name(), 'my name') self.assertTrue(layer.fields().isEmpty()) # similar layers should have unique sources layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Point) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) # crs layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111)) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM) self.assertTrue(layer.crs().isValid()) self.assertEqual(layer.crs().authid(), 'EPSG:3111') # fields fields = QgsFields() fields.append(QgsField("string", QVariant.String)) fields.append(QgsField("long", QVariant.LongLong)) fields.append(QgsField("double", QVariant.Double)) fields.append(QgsField("integer", QVariant.Int)) fields.append(QgsField("date", QVariant.Date)) fields.append(QgsField("datetime", QVariant.DateTime)) fields.append(QgsField("time", QVariant.Time)) fields.append(QgsField("#complex_name", QVariant.String)) fields.append(QgsField("complex/name", QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) self.assertEqual(layer.fields()[i].type(), fields[i].type()) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(layer.fields()[0].name(), 'rect') self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def processAlgorithm(self, parameters, context, feedback): ors_client = self._get_ors_client_from_provider( parameters[self.IN_PROVIDER], feedback) profile = dict(enumerate(PROFILES))[parameters[self.IN_PROFILE]] preference = dict( enumerate(PREFERENCES))[parameters[self.IN_PREFERENCE]] optimization_mode = parameters[self.IN_OPTIMIZE] options = self.parseOptions(parameters, context) # Get parameter values source = self.parameterAsSource(parameters, self.IN_POINTS, context) source_field_name = parameters[self.IN_FIELD] get_fields_options = dict() if source_field_name: get_fields_options.update( from_type=source.fields().field(source_field_name).type(), from_name=source_field_name) sink_fields = directions_core.get_fields(**get_fields_options, line=True) (sink, dest_id) = self.parameterAsSink( parameters, self.OUT, context, sink_fields, QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) sort_by = parameters[self.IN_SORTBY] if sort_by: def sort(f): return f.attribute(sort_by) else: def sort(f): return f.id() count = source.featureCount() input_points = list() from_values = list() x_former = transform.transformToWGS(source.sourceCrs()) if QgsWkbTypes.flatType(source.wkbType()) == QgsWkbTypes.Point: points = list() for feat in sorted(source.getFeatures(), key=sort): points.append( x_former.transform(QgsPointXY(feat.geometry().asPoint()))) input_points.append(points) from_values.append(None) elif QgsWkbTypes.flatType(source.wkbType()) == QgsWkbTypes.MultiPoint: # loop through multipoint features for feat in sorted(source.getFeatures(), key=sort): points = list() for point in feat.geometry().asMultiPoint(): points.append(x_former.transform(QgsPointXY(point))) input_points.append(points) from_values.append( feat[source_field_name] if source_field_name else None) for num, (points, from_value) in enumerate(zip(input_points, from_values)): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break try: if optimization_mode is not None: params = get_params_optimize(points, profile, optimization_mode) response = ors_client.request('/optimization', {}, post_json=params) sink.addFeature( directions_core.get_output_features_optimization( response, profile, from_value=from_value)) else: params = directions_core.build_default_parameters( preference, point_list=points, options=options) response = ors_client.request('/v2/directions/' + profile + '/geojson', {}, post_json=params) sink.addFeature( directions_core.get_output_feature_directions( response, profile, preference, from_value=from_value)) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"Feature ID {from_value} caused a {e.__class__.__name__}:\n{str(e)}" feedback.reportError(msg) logger.log(msg) continue feedback.setProgress(int(100.0 / count * num)) return {self.OUT: dest_id}