def test_processRestriction(self): testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format( type=QgsWkbTypes.displayString(QgsWkbTypes.LineString))), 'test1', 'memory') self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.LineString) #print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType()))) testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int), QgsField("GeomShapeID", QVariant.Int), QgsField("AzimuthToRoadCentreLine", QVariant.Double) ]) testFieldsA = testProviderA.fields() """for field in testFields: print ('** {}'.format(field.name()))""" testFeature1 = QgsFeature(testFieldsA) testFeature1.setGeometry(testLineString1) testFeature1.setAttributes(["Smith", 101, 1, 0]) testProviderA.addFeatures([testFeature1]) testLayerA.reload() self.testClass.processRestriction(testFeature1, testLayerA) print('*************************** Count: {}'.format( testLayerA.featureCount())) self.assertEqual(testLayerA.featureCount(), 2)
def testSubsetStringFids(self): """ - tests that feature ids are stable even if a subset string is set - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) """ tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) f.SetField(0, 1) f.SetField(1, 11) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) f.SetField(0, 1) f.SetField(1, 12) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) f.SetField(0, 1) f.SetField(1, 13) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) f.SetField(0, 2) f.SetField(1, 14) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) f.SetField(0, 2) f.SetField(1, 15) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) f.SetField(0, 2) f.SetField(1, 16) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertTrue(vl.fields().at(0).name() == "orig_ogc_fid") req = QgsFeatureRequest() req.setFilterExpression("value=16") it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertTrue(f.id() == 5) # Check that subset string is correctly set on reload vl.reload() self.assertTrue(vl.fields().at(0).name() == "orig_ogc_fid")
def points_along_line(layerout, startpoint, endpoint, distance, layer, selected_only=True, force_last=False, force_first_last=False, divide=0): """Adding Points along the line """ crs = layer.crs().authid() layer_type = "memory" virt_layer = QgsVectorLayer("Point?crs=%s" % crs, layerout, layer_type) provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unitname = QgsUnitTypes.toString(units) provider.addAttributes([ QgsField("fid", QVariant.Int), QgsField("cng" + unitname, QVariant.Double) ]) def get_features(): """Getting the features """ if selected_only: return layer.selectedFeatures() else: return layer.getFeatures() # Loop through all (selected) features for feature in get_features(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsMessageLog.logMessage("No geometry", "QChainage") continue features = create_points(startpoint, endpoint, distance, geom, fid, force_last, force_first_last, divide) provider.addFeatures(features) virt_layer.updateExtents() proj = QgsProject.instance() proj.addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() virt_layer.triggerRepaint() return
def to_line_layer(self): source = "LineString?index=yes&crs={}".format(self.crs_id) layer = QgsVectorLayer(source, self.name, "memory") pr = layer.dataProvider() fields = QgsFields() # Section fields fields.append(QgsField("sec_id", QVariant.Int)) fields.append(QgsField("sec_name", QVariant.String)) fields.append(QgsField("abs_long", QVariant.Double)) # Point fields fields.append(QgsField("p_id", QVariant.String)) fields.append(QgsField("abs_lat", QVariant.String)) fields.append(QgsField("zfond", QVariant.String)) assert pr.addAttributes(fields) for section in self.sections.values(): points = section.get_points() f = QgsFeature() f.setAttributes([ section.id, section.name, section.pk, ",".join([str(i) for i in range(0, len(points))]), ",".join([str(p.d) for p in points]), ",".join([str(p.z) for p in points]), ]) f.setGeometry( QgsGeometry( QgsLineString([ QgsPoint( point.x, point.y, ) if str(point.z) == "NULL" else QgsPoint( point.x, point.y, point.z, ) for point in points ]))) pr.addFeature(f) layer.reload() return layer
def test_prepareNewLayer(self): testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format( type=QgsWkbTypes.displayString(QgsWkbTypes.LineString))), 'test1', 'memory') self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.LineString) #print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType()))) testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int), QgsField("GeomShapeID", QVariant.Int), QgsField("AzimuthToRoadCentreLine", QVariant.Double) ]) testFieldsA = testProviderA.fields() """for field in testFields: print ('** {}'.format(field.name()))""" testFeature1 = QgsFeature(testFieldsA) testFeature1.setGeometry(testLineString1) testFeature1.setAttributes(["Smith", 101, 1, 0]) testProviderA.addFeatures([testFeature1]) testLayerA.reload() #print ('++++++ type: {}'.format(QgsWkbTypes.displayString(QgsWkbTypes.LineString))) self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.LineString) requiredFields = [ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int) ] newLayerName = 'Test1_3' geomWbkType = QgsWkbTypes.MultiLineString newLayer = self.testClass.prepareNewLayer(testLayerA, newLayerName, geomWbkType, requiredFields) self.assertIsNotNone(newLayer) self.assertEqual(newLayer.fields().count(), 2) #print ('++++++ new type: {}'.format(QgsWkbTypes.displayString(newLayer.wkbType()))) self.assertEqual(newLayer.wkbType(), QgsWkbTypes.MultiLineString) print('==== newLayer crs:'.format(newLayer.crs().authid()))
def points_along_line(layerout, startpoint, endpoint, distance, layer): #,selected_only=True):#more from qchainage """Adding Points along the line""" # Create a new memory layer and add a distance attribute self.layerNameLine #layer_crs = virt_layer.setCrs(layer.crs()) virt_layer = QgsVectorLayer("Point?crs=%s" % layer.crs().authid(), layerout, "memory") provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unit_dic = { QgsUnitTypes.DistanceDegrees: 'Degrees', QgsUnitTypes.DistanceMeters: 'Meters', QgsUnitTypes.DistanceFeet: 'Feet', QgsUnitTypes.DistanceUnknownUnit: 'Unknown' } unit = unit_dic.get(units, 'Unknown') provider.addAttributes([QgsField("fid", qgis.PyQt.QtCore.QVariant.Int)]) provider.addAttributes( [QgsField("cum_dist", qgis.PyQt.QtCore.QVariant.Int)]) provider.addAttributes( [QgsField("unit", qgis.PyQt.QtCore.QVariant.String)]) # Loop through all (selected) features for feature in layer.getSelectedFeatures(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsApplication.messageLog().logMessage("No geometry", "QChainage") continue features, xarray = create_points_at(startpoint, endpoint, distance, geom, fid, unit) provider.addFeatures(features) virt_layer.updateExtents() QgsProject.instance().addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() virt_layer.triggerRepaint() return virt_layer, xarray
def test_lazy(self): l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l1.isValid(), True) QgsProject.instance().addMapLayer(l1) df = QgsVirtualLayerDefinition() df.setQuery('select * from "françéà"') df.setLazy(True) vl = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertEqual(vl.isValid(), True) ids = [f.id() for f in vl.getFeatures()] self.assertEqual(len(ids), 0) vl.reload() ids = [f.id() for f in vl.getFeatures()] self.assertEqual(len(ids), 4) QgsProject.instance().removeMapLayer(l1.id())
def to_point_layer(self): source = "Point?index=yes&crs={}".format(self.crs_id) layer = QgsVectorLayer(source, self.name, "memory") pr = layer.dataProvider() fields = QgsFields() # Section fields fields.append(QgsField("sec_id", QVariant.Int)) fields.append(QgsField("sec_name", QVariant.String)) fields.append(QgsField("abs_long", QVariant.Double)) # Point fields fields.append(QgsField("p_id", QVariant.Int)) fields.append(QgsField("abs_lat", QVariant.Double)) fields.append(QgsField("zfond", QVariant.Double)) assert pr.addAttributes(fields) f = QgsFeature() for section in self.sections.values(): for index, point in enumerate(section.get_points()): f.setAttributes([ section.id, section.name, section.pk, index, point.d, point.z ]) if str(point.z) == "NULL": f.setGeometry(QgsGeometry(QgsPoint( point.x, point.y, ))) else: f.setGeometry( QgsGeometry(QgsPoint( point.x, point.y, point.z, ))) pr.addFeature(f) layer.reload() return layer
def taskFinished(self, data): self.dialog.runButton.setEnabled(True) self.dialog.cancel_button.setEnabled(False) self.sendDialogLog('process has been completed', self.greenColor) self.task.terminate() if self.dialog.addLayersWithError.isChecked(): failPoints = data[0] failMultilines = data[1] if len(failPoints) != 0 or len(failMultilines) != 0: for l2rem in QgsProject.instance().mapLayersByName( 'AJBL_error_target_points'): QgsProject.instance().removeMapLayer(l2rem) epsg = self.targetLayer.sourceCrs().authid() layer = QgsVectorLayer(f'Point?crs={epsg}', 'AJBL_error_target_points', 'memory') QgsProject.instance().addMapLayer(layer, False) layerTree = self.iface.layerTreeCanvasBridge().rootGroup() layerTree.insertChildNode(0, QgsLayerTreeLayer(layer)) layer.dataProvider().addAttributes( [QgsField('Fail', QVariant.String)]) for f in failPoints: layer.startEditing() feature = QgsFeature() feature.setGeometry(f[0].geometry()) feature.setAttributes([f[1]]) layer.addFeature(feature) layer.commitChanges() for f in failMultilines: layer.startEditing() feature = QgsFeature() feature.setGeometry(f[0].geometry()) feature.setAttributes([f[1]]) layer.addFeature(feature) layer.commitChanges() layer.reload()
def testreloadData(self): ''' Test reloadData() ''' tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) srcpath = os.path.join(TEST_DATA_DIR, 'provider') for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): shutil.copy(os.path.join(srcpath, file), tmpdir) datasource = os.path.join(tmpdir, 'shapefile.shp') vl1 = QgsVectorLayer('{}|layerid=0'.format(datasource), 'test', 'ogr') vl2 = QgsVectorLayer('{}|layerid=0'.format(datasource), 'test', 'ogr') self.assertTrue(vl1.startEditing()) self.assertTrue(vl1.deleteAttributes([1])) self.assertTrue(vl1.commitChanges()) self.assertEqual(len(vl1.fields()) + 1, len(vl2.fields())) # Reload vl2.reload() # And now check that fields are up-to-date self.assertEqual(len(vl1.fields()), len(vl2.fields()))
def testreloadData(self): """ Test reloadData() """ tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) srcpath = os.path.join(TEST_DATA_DIR, "provider") for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) datasource = os.path.join(tmpdir, "shapefile.shp") vl1 = QgsVectorLayer(u"{}|layerid=0".format(datasource), u"test", u"ogr") vl2 = QgsVectorLayer(u"{}|layerid=0".format(datasource), u"test", u"ogr") self.assertTrue(vl1.startEditing()) self.assertTrue(vl1.deleteAttributes([1])) self.assertTrue(vl1.commitChanges()) self.assertEquals(len(vl1.fields()) + 1, len(vl2.fields())) # Reload vl2.reload() # And now check that fields are up-to-date self.assertEquals(len(vl1.fields()), len(vl2.fields()))
def testReloadDataAndFeatureCount(self): filename = '/vsimem/test.json' gdal.FileFromMemBuffer(filename, """{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } }, { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [3, 50] } } ] }""") vl = QgsVectorLayer(filename, 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) gdal.FileFromMemBuffer(filename, """{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } } ] }""") vl.reload() self.assertEqual(vl.featureCount(), 1) gdal.Unlink(filename)
def addPointToLayer(self, x, y, z): x = float(x) y = float(y) z = float(z) name = 'Obliczone wysokości - GUGiK NMT' layers = QgsProject.instance().mapLayersByName(name) if not layers: layer = QgsVectorLayer( 'PointZ?crs=epsg:2180&field=x:double&field=y:double&field=z:double', name, 'memory') QgsProject.instance().addMapLayer(layer, False) layerTree = self.iface.layerTreeCanvasBridge().rootGroup() layerTree.insertChildNode(0, QgsLayerTreeLayer(layer)) treeRoot = QgsProject.instance().layerTreeRoot() if treeRoot.hasCustomLayerOrder(): order = treeRoot.customLayerOrder() order.insert( 0, order.pop( order.index( QgsProject.instance().mapLayersByName(name)[0]))) treeRoot.setCustomLayerOrder(order) layer.loadNamedStyle( os.path.join(self.plugin_dir, 'layer_style.qml'), True) else: layer = layers[0] feature = QgsFeature() point = QgsGeometry(QgsPoint(x, y, z)) feature.setGeometry(point) feature.setAttributes([x, y, z]) layer.startEditing() layer.addFeature(feature) layer.commitChanges() layer.reload()
def test_processLayer(self): testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format( type=QgsWkbTypes.displayString(QgsWkbTypes.MultiLineString))), 'testA', 'memory') self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.MultiLineString) # print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType()))) testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int), QgsField("GeomShapeID", QVariant.Int), QgsField("AzimuthToRoadCentreLine", QVariant.Double) ]) testFieldsA = testProviderA.fields() """for field in testFields: print ('** {}'.format(field.name()))""" testFeature1 = QgsFeature(testFieldsA) testFeature1.setGeometry(testLineString1) testFeature1.setAttributes(["Smith", 101, 1, 0]) testProviderA.addFeatures([testFeature1]) testLayerA.reload() requiredFields = ["GeometryID", "RestrictionTypeID"] outputLayersList = self.testClass.processLayer(testLayerA, requiredFields) self.assertEqual(len(outputLayersList), 1) self.assertEqual(len(outputLayersList[0][1].fields()), 2) # TODO: Need to include tests for relations - finding lookup fields and returning values ... """ Cases are:
def test_setFieldsForTOMsExportLayer(self): TOMsRequiredFields = [ "GeometryID", "RestrictionTypeID", "RestType", "NrBays", "TimePeriodID", "PayTypeID", "MaxStayID", "NoReturnID", "BaysWordingID", "RoadName", "USRN", "OpenDate", "CPZ", "ParkingTariffArea", "Restriction_Length", # for bays "NoWaitingTimeID", "NoLoadingTimeID", # for lines "AreaPermitCode" # for polygons ] testLayerA = QgsVectorLayer(('LineString?crs=epsg:27700&index=yes'), 'test1', 'memory') testProviderA = testLayerA.dataProvider() testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int), QgsField("NrBays", QVariant.Int), QgsField("size2", QVariant.Double) ]) testLayerA.reload() reqFields = self.testClass.setFieldsForTOMsExportLayer( testLayerA, TOMsRequiredFields) self.assertEqual(len(reqFields), 3)
def test_saveLayerToGpkg(self): testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format( type=QgsWkbTypes.displayString(QgsWkbTypes.MultiLineString))), 'testA', 'memory') self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.MultiLineString) #print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType()))) testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("RestrictionTypeID", QVariant.Int), QgsField("GeomShapeID", QVariant.Int), QgsField("AzimuthToRoadCentreLine", QVariant.Double) ]) testFieldsA = testProviderA.fields() """for field in testFields: print ('** {}'.format(field.name()))""" testFeature1 = QgsFeature(testFieldsA) testFeature1.setGeometry(testLineString1) testFeature1.setAttributes(["Smith", 101, 1, 0]) testProviderA.addFeatures([testFeature1]) testLayerA.reload() fileName = 'C:\\Users\\marie_000\\Documents\\MHTC\\tmp\\test1.gpkg' self.testClass.saveLayerToGpkg(testLayerA, fileName) ds = ogr.Open(fileName) lyr = ds.GetLayerByName('testA') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['GeometryID'], 'Smith')
def points_along_line(layerout, startpoint, endpoint, distance, label, layer, selected_only=True, force=False, divide=0): """Adding Points along the line """ # Create a new memory layer and add a distance attribute self.layerNameLine #layer_crs = virt_layer.setCrs(layer.crs()) virt_layer = QgsVectorLayer("Point?crs=%s" % layer.crs().authid(), layerout, "memory") provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unit_dic = { QGis.Degrees: 'Degrees', QGis.Meters: 'Meters', QGis.Feet: 'Feet', QGis.UnknownUnit: 'Unknown'} unit = unit_dic.get(units, 'Unknown') provider.addAttributes([QgsField("fid", QVariant.Int)]) provider.addAttributes([QgsField("cng_("+unit+")", QVariant.Int)]) def get_features(): """Getting the features """ if selected_only: return layer.selectedFeatures() else: return layer.getFeatures() # Loop through all (selected) features for feature in get_features(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsMessageLog.logMessage("No geometry", "QChainage") continue features = create_points_at(startpoint, endpoint, distance, geom, fid, force, divide) provider.addFeatures(features) virt_layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() #from here Add labeling #generic labeling properties if label: virt_layer.setCustomProperty("labeling", "pal") virt_layer.setCustomProperty("labeling/enabled", "true") virt_layer.setCustomProperty("labeling/fieldName", "cng_("+unit+")") virt_layer.setCustomProperty("labeling/fontSize", "10") virt_layer.setCustomProperty("labeling/multiLineLabels", "true") #virt_layer.setCustomProperty("labeling/Size", "5") # symbol = QgsMarkerSymbolV2.createSimple({"name": "capital"}) # virt_layer.setRendererV2(QgsSingleSymbolRendererV2(symbol)) virt_layer.triggerRepaint() return
def testSubsetStringFids(self): """ - tests that feature ids are stable even if a subset string is set - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) """ tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) f.SetField(0, 1) f.SetField(1, 11) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) f.SetField(0, 1) f.SetField(1, 12) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) f.SetField(0, 1) f.SetField(1, 13) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) f.SetField(0, 2) f.SetField(1, 14) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) f.SetField(0, 2) f.SetField(1, 15) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) f.SetField(0, 2) f.SetField(1, 16) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertTrue(vl.fields().at(vl.fields().count() - 1).name() == "orig_ogc_fid") req = QgsFeatureRequest() req.setFilterExpression("value=16") it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertTrue(f.id() == 5) # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed req = QgsFeatureRequest() req.setSubsetOfAttributes([]) it = vl.getFeatures(req) ids = [] while it.nextFeature(f): ids.append(f.id()) self.assertTrue(len(ids) == 3) self.assertTrue(3 in ids) self.assertTrue(4 in ids) self.assertTrue(5 in ids) # Check that subset string is correctly set on reload vl.reload() self.assertTrue(vl.fields().at(vl.fields().count() - 1).name() == "orig_ogc_fid")
def points_along_line(layerout, startpoint, endpoint, distance, label, layer, selected_only=True, force=False, fo_fila=False, divide=0, decimal=2): """Adding Points along the line """ crs = layer.crs().authid() # TODO check for virtual or shapelayer and set virt_layer according to it shape = False if shape: # define fields for feature attributes. A list of QgsField objects is needed fields = [QgsField("first", QVariant.Int), QgsField("second", QVariant.String)] # create an instance of vector file writer, which will create the vector file. # Arguments: # 1. path to new file (will fail if exists already) # 2. encoding of the attributes # 3. field map # 4. geometry type - from WKBTYPE enum # 5. layer's spatial reference (instance of # QgsCoordinateReferenceSystem) - optional # 6. driver name for the output file writer = QgsVectorFileWriter("my_shapes.shp", "CP1250", fields, QGis.WKBPoint, crs, "ESRI Shapefile") if writer.hasError() != QgsVectorFileWriter.NoError: print "Error when creating shapefile: ", writer.hasError() # add a feature fet = QgsFeature() fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10))) fet.setAttributes([1, "text"]) writer.addFeature(fet) # delete the writer to flush features to disk (optional) del writer layer_type = "Shapefile" # TODO Add Shapefile functionality here else: layer_type = "memory" virt_layer = QgsVectorLayer("Point?crs=%s" % crs, layerout, layer_type) provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unit_dic = { QGis.Degrees: 'Degrees', QGis.Meters: 'Meters', QGis.Feet: 'Feet', QGis.UnknownUnit: 'Unknown'} unit = unit_dic.get(units, 'Unknown') provider.addAttributes([QgsField("fid", QVariant.Int), QgsField("cng_("+unit+")", QVariant.Double)]) def get_features(): """Getting the features """ if selected_only: return layer.selectedFeatures() else: return layer.getFeatures() # Loop through all (selected) features for feature in get_features(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsMessageLog.logMessage("No geometry", "QChainage") continue features = create_points_at(startpoint, endpoint, distance, geom, fid, force, fo_fila, divide) provider.addFeatures(features) virt_layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() # from here Add labeling # generic labeling properties if label: virt_layer.setCustomProperty("labeling", "pal") virt_layer.setCustomProperty("labeling/enabled", "true") virt_layer.setCustomProperty("labeling/fieldName", "cng_("+unit+")") virt_layer.setCustomProperty("labeling/fontSize", "10") virt_layer.setCustomProperty("labeling/multiLineLabels", "true") virt_layer.setCustomProperty("labeling/formatNumbers", "true") virt_layer.setCustomProperty("labeling/decimals", decimal) # virt_layer.setCustomProperty("labeling/Size", "5") # symbol = QgsMarkerSymbolV2.createSimple({"name": "capital"}) # virt_layer.setRendererV2(QgsSingleSymbolRendererV2(symbol)) virt_layer.triggerRepaint() return
class ImportPhotos: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'ImportPhotos_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&ImportPhotos') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'ImportPhotos') self.toolbar.setObjectName(u'ImportPhotos') # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('ImportPhotos', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ # Create the dialog (after translation) and keep reference icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/ImportPhotos/svg/ImportImage.svg' self.add_action( icon_path, text=self.tr(u'Import Photos'), callback=self.run, parent=self.iface.mainWindow()) icon_path = ':/plugins/ImportPhotos/svg/SelectImage.svg' self.clickPhotos = self.add_action( icon_path, text=self.tr(u'Click Photos'), callback=self.mouseClick, parent=self.iface.mainWindow()) self.dlg = ImportPhotosDialog() self.dlg.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint) self.dlg.ok.clicked.connect(self.ok) self.dlg.closebutton.clicked.connect(self.close) self.dlg.toolButtonImport.clicked.connect(self.toolButtonImport) self.dlg.toolButtonOut.clicked.connect(self.toolButtonOut) self.clickPhotos.setCheckable(True) self.clickPhotos.setEnabled(True) self.listPhotos = [] self.layernamePhotos = [] self.canvas = self.iface.mapCanvas() self.toolMouseClick = MouseClick(self.canvas, self) self.fields = ['ID', 'Name', 'Date', 'Time', 'Lon', 'Lat', 'Altitude', 'North', 'Azimuth', 'Camera Maker', 'Camera Model', 'Path'] self.extension_switch = { ".shp": "ESRI Shapefile", ".geojson": "GeoJSON", ".gpkg":"GPKG", ".csv": "CSV", ".kml": "KML", ".tab": "MapInfo File", ".ods": "ODS" } def mouseClick(self): try: self.iface.setActiveLayer(self.canvas.layers()[0]) except: pass self.canvas.setMapTool(self.toolMouseClick) self.clickPhotos.setChecked(True) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&ImportPhotos'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar def run(self): self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) self.clickPhotos.setEnabled(True) self.dlg.out.setText('') self.dlg.imp.setText('') self.dlg.show() def close(self): self.dlg.close() def toolButtonOut(self): typefiles = 'ESRI Shapefile (*.shp *.SHP);; GeoJSON (*.geojson *.GEOJSON);; GeoPackage (*.gpkg *.GPKG);; Comma Separated Value (*.csv *.CSV);; Keyhole Markup Language (*.kml *.KML);; Mapinfo TAB (*.tab *.TAB);; Open Document Spreadsheet (*.ods *.ODS)' if platform.system() == 'Linux': try: self.outputPath, self.extension = QFileDialog.getSaveFileNameAndFilter(None, 'Save File', os.path.join( os.path.join(os.path.expanduser('~')), 'Desktop'), typefiles) except: self.outputPath = QFileDialog.getSaveFileName(None, 'Save File', os.path.join( os.path.join(os.path.expanduser('~')), 'Desktop'), typefiles) #hack line else: self.outputPath = QFileDialog.getSaveFileName(None, 'Save File', os.path.join( os.path.join(os.path.expanduser('~')), 'Desktop'), typefiles) self.outputPath = self.outputPath[0] self.dlg.out.setText(self.outputPath) def toolButtonImport(self): self.directoryPhotos = QFileDialog.getExistingDirectory(None, 'Select a folder:', os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'), QFileDialog.ShowDirsOnly) self.dlg.imp.setText(self.directoryPhotos) def selectDir(self): title = 'Warning' msg = 'Please select a directory photos.' self.showMessage(title, msg, 'Warning') return True def selectOutp(self): title = 'Warning' msg = 'Please define output file location.' self.showMessage(title, msg, 'Warning') return True def noImageFound(self): title = 'Warning' msg = 'No image path found.' self.showMessage(title, msg, 'Warning') return True def ok(self): if self.dlg.imp.text() == '': if self.selectDir(): return if not os.path.isdir(self.dlg.imp.text()): if self.selectDir(): return if self.dlg.out.text() == '': if self.selectOutp(): return if not os.path.isabs(self.dlg.out.text()): if self.selectOutp(): return if platform.system() == 'Linux': self.lphoto = os.path.basename(self.outputPath) try: self.extension = '.'+self.extension.split()[-1][2:-1].lower() except: self.extension = '.shp' #hack line, temporary else: _ , self.extension = os.path.splitext(self.outputPath) basename = os.path.basename(self.outputPath) self.lphoto = basename[:-len(self.extension)] self.outputPath = self.dlg.out.text() self.directoryPhotos = self.dlg.imp.text() self.outDirectoryPhotosGeoJSON = self.plugin_dir + '/tmp.geojson' self.dlg.ok.setEnabled(False) self.dlg.closebutton.setEnabled(False) self.dlg.toolButtonImport.setEnabled(False) self.dlg.toolButtonOut.setEnabled(False) # get paths of photos extens = ['jpg', 'jpeg', 'JPG', 'JPEG'] self.photos = [] for root, dirs, files in os.walk(self.directoryPhotos): self.photos.extend(os.path.join(root, name) for name in files if name.lower().endswith(tuple(extens))) self.initphotos = len(self.photos) if self.initphotos == 0: title = 'Warning' msg = 'No photos.' self.showMessage(title, msg, 'Warning') self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) self.clickPhotos.setChecked(True) return self.canvas.setMapTool(self.toolMouseClick) self.truePhotosCount = 0 self.Qpr_inst = QgsProject.instance() if platform.system()=='Darwin': self.layernamePhotos.append(self.lphoto+' OGRGeoJSON Point') else: self.layernamePhotos.append(self.lphoto) if platform.system() == 'Linux': self.outputPath = self.outputPath + self.extension self.extension = self.extension_switch[self.extension] else: self.extension = self.extension_switch[self.extension.lower()] self.exifread_module = False self.pil_module = False if CHECK_MODULE == '': self.showMessage('Python Modules', 'Please install python module "exifread" or "PIL".' , 'Warning') #self.import_photos_task('', '') self.call_import_photos() self.dlg.close() def refresh(self): # Deselect features mc = self.canvas for layer in mc.layers(): if layer.type() == layer.VectorLayer: layer.removeSelection() mc.refresh() def showMessage(self, title, msg, icon): if icon == 'Warning': icon = QMessageBox.Warning elif icon == 'Information': icon = QMessageBox.Information msgBox = QMessageBox() msgBox.setIcon(icon) msgBox.setWindowTitle(title) msgBox.setText(msg) msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint) msgBox.exec_() def completed(self, exception, result=None): geojson = {"type": "FeatureCollection", "name": self.lphoto, "crs": {"type": "name", "properties": {"name": "crs:OGC:1.3:CRS84"}}, "features": self.geoPhotos} geofile = open(self.plugin_dir + '/tmp.geojson', 'w') json.dump(geojson, geofile) geofile.close() del self.geoPhotos, geojson try: for layer in self.canvas.layers(): if layer.publicSource() == self.outputPath: self.Qpr_inst.instance().removeMapLayer(layer.id()) os.remove(self.outputPath) except: pass self.layerPhotos = QgsVectorLayer(self.outDirectoryPhotosGeoJSON, self.lphoto, "ogr") QgsVectorFileWriter.writeAsVectorFormat(self.layerPhotos, self.outputPath, "utf-8", QgsCoordinateReferenceSystem(self.layerPhotos.crs().authid()), self.extension) self.layerPhotos_final = QgsVectorLayer(self.outputPath, self.lphoto, "ogr") # clear temp.geojson file try: f = open(self.outDirectoryPhotosGeoJSON, 'r+') f.truncate(0) # need '0' when using r+ except: pass try: self.layerPhotos_final.loadNamedStyle(self.plugin_dir + "/svg/photos.qml") except: title = 'Warning' msg = 'No geo-tagged images were detected.' self.showMessage(title, msg, 'Warning') self.taskPhotos.destroyed() return self.layerPhotos_final.setReadOnly(False) self.layerPhotos_final.reload() self.layerPhotos_final.triggerRepaint() try: xmin = min(self.lon) ymin = min(self.lat) xmax = max(self.lon) ymax = max(self.lat) self.canvas.zoomToSelected(self.layerPhotos_final) self.canvas.setExtent(QgsRectangle(xmin, ymin, xmax, ymax)) except: pass ########################################### self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) self.clickPhotos.setChecked(True) noLocationPhotosCounter = self.initphotos - self.truePhotosCount if self.truePhotosCount == noLocationPhotosCounter == 0 or self.truePhotosCount == 0: title = 'Import Photos' msg = 'Import Completed.\n\nDetails:\n No new photos were added.' self.showMessage(title, msg, 'Information') self.taskPhotos.destroyed() return elif (self.truePhotosCount == self.initphotos) or ((noLocationPhotosCounter + self.truePhotosCount) == self.initphotos): title = 'Import Photos' msg = 'Import Completed.\n\nDetails:\n ' + str( int(self.truePhotosCount)) + ' photo(s) added without error.\n ' + str( int(noLocationPhotosCounter)) + ' photo(s) skipped (because of missing location).' self.showMessage(title, msg, 'Information') self.Qpr_inst.addMapLayers([self.layerPhotos_final]) self.taskPhotos.destroyed() def stopped(self, task): QgsMessageLog.logMessage( 'Task "{name}" was canceled'.format( name=task.description()), 'ImportPhotos', Qgis.Info) def import_photos_task(self, task, wait_time): self.geoPhotos = [] self.lon = [] self.lat = [] for count, imgpath in enumerate(self.photos): try: name = os.path.basename(imgpath) if CHECK_MODULE == 'exifread' and not self.pil_module: self.exifread_module = True self.taskPhotos.setProgress(count/self.initphotos) with open(imgpath, 'rb') as imgpathF: tags = exifread.process_file(imgpathF, details=False) if not tags.keys() & {"GPS GPSLongitude", "GPS GPSLatitude"}: continue lat, lon = self.get_exif_location(tags, "lonlat") try: altitude = float(tags["GPS GPSAltitude"].values[0].num) / float( tags["GPS GPSAltitude"].values[0].den) except: altitude = '' uuid_ = str(uuid.uuid4()) try: dt1, dt2 = tags["EXIF DateTimeOriginal"].values.split() date = dt1.replace(':', '/') time_ = dt2 timestamp = dt1.replace(':', '-') + 'T' + time_ except: try: date = tags["GPS GPSDate"].values.replace(':', '/') tt = [str(i) for i in tags["GPS GPSTimeStamp"].values] time_ = "{:0>2}:{:0>2}:{:0>2}".format(tt[0], tt[1], tt[2]) timestamp = tags["GPS GPSDate"].values.replace(':', '-') + 'T' + time_ except: date = '' time_ = '' timestamp = '' try: azimuth = float(tags["GPS GPSImgDirection"].values[0].num) / float( tags["GPS GPSImgDirection"].values[0].den) except: azimuth = '' try: north = str(tags["GPS GPSImgDirectionRef"].values) except: north = '' try: maker = tags['Image Make'] except: maker = '' try: model = tags['Image Model'] except: model = '' if CHECK_MODULE == 'PIL' and not self.exifread_module: self.pil_module = True a = {} info = Image.open(imgpath) info = info._getexif() if info == None: continue for tag, value in info.items(): if TAGS.get(tag, tag) == 'GPSInfo' or TAGS.get(tag, tag) == 'DateTime' or TAGS.get(tag, tag) == 'DateTimeOriginal': a[TAGS.get(tag, tag)] = value if a == {}: continue if a['GPSInfo'] != {}: if 1 and 2 and 3 and 4 in a['GPSInfo']: lat = [float(x) / float(y) for x, y in a['GPSInfo'][2]] latref = a['GPSInfo'][1] lon = [float(x) / float(y) for x, y in a['GPSInfo'][4]] lonref = a['GPSInfo'][3] lat = lat[0] + lat[1] / 60 + lat[2] / 3600 lon = lon[0] + lon[1] / 60 + lon[2] / 3600 if latref == 'S': lat = -lat if lonref == 'W': lon = -lon else: continue uuid_ = str(uuid.uuid4()) if 'DateTime' or 'DateTimeOriginal' in a: if 'DateTime' in a: dt1, dt2 = a['DateTime'].split() if 'DateTimeOriginal' in a: dt1, dt2 = a['DateTimeOriginal'].split() date = dt1.replace(':', '/') time_ = dt2 timestamp = dt1.replace(':', '-') + 'T' + time_ if 6 in a['GPSInfo']: if len(a['GPSInfo'][6]) > 1: mAltitude = float(a['GPSInfo'][6][0]) mAltitudeDec = float(a['GPSInfo'][6][1]) altitude = mAltitude / mAltitudeDec else: altitude = '' if 16 and 17 in a['GPSInfo']: north = str(a['GPSInfo'][16]) azimuth = float(a['GPSInfo'][17][0]) / float(a['GPSInfo'][17][1]) else: north = '' azimuth = '' maker = '' model = '' self.lon.append(lon) self.lat.append(lat) self.truePhotosCount = self.truePhotosCount + 1 geo_info = {"type": "Feature", "properties": {'ID': uuid_, 'Name': name, 'Date': date, 'Time': time_, 'Lon': lon, 'Lat': lat, 'Altitude': altitude, 'North': north, 'Azimuth': azimuth, 'Camera Maker': str(maker), 'Camera Model': str(model), 'Path': imgpath, 'Timestamp': timestamp}, "geometry": {"coordinates": [lon, lat], "type": "Point"}} self.geoPhotos.append(geo_info) if self.taskPhotos.isCanceled(): self.stopped(self.taskPhotos) self.taskPhotos.destroyed() return None except: pass return True def call_import_photos(self): self.taskPhotos = QgsTask.fromFunction(u'ImportPhotos', self.import_photos_task, on_finished=self.completed, wait_time=4) QgsApplication.taskManager().addTask(self.taskPhotos) ###################################################### # based on http://www.codegists.com/snippet/python/exif_gpspy_snakeye_python def _get_if_exist(self, data, key): if key in data: return data[key] return None def _convert_to_degress(self, value): """ Helper function to convert the GPS coordinates stored in the EXIF to degress in float format :param value: :type value: exifread.utils.Ratio :rtype: float """ d = float(value.values[0].num) / float(value.values[0].den) m = float(value.values[1].num) / float(value.values[1].den) s = float(value.values[2].num) / float(value.values[2].den) return d + (m / 60.0) + (s / 3600.0) def get_exif_location(self, exif_data, lonlat): """ Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above) """ if lonlat=='lonlat': lat = '' lon = '' gps_latitude = self._get_if_exist(exif_data, 'GPS GPSLatitude') gps_latitude_ref = self._get_if_exist(exif_data, 'GPS GPSLatitudeRef') gps_longitude = self._get_if_exist(exif_data, 'GPS GPSLongitude') gps_longitude_ref = self._get_if_exist(exif_data, 'GPS GPSLongitudeRef') if gps_latitude and gps_latitude_ref and gps_longitude and gps_longitude_ref: lat = self._convert_to_degress(gps_latitude) if gps_latitude_ref.values[0] != 'N': lat = 0 - lat lon = self._convert_to_degress(gps_longitude) if gps_longitude_ref.values[0] != 'E': lon = 0 - lon return lat, lon
def get_inner_rings_layer(self, plot_layer, id_field=ID_FIELD, use_selection=False): id_field_idx = plot_layer.fields().indexFromName(id_field) request = QgsFeatureRequest().setSubsetOfAttributes([id_field_idx]) polygons = plot_layer.getSelectedFeatures( request) if use_selection else plot_layer.getFeatures(request) layer = QgsVectorLayer("LineString?crs=EPSG:{}".format(DEFAULT_EPSG), "rings", "memory") data_provider = layer.dataProvider() data_provider.addAttributes([QgsField(ID_FIELD, QVariant.Int)]) layer.updateFields() features = [] for polygon in polygons: polygon_geom = polygon.geometry() is_multipart = polygon_geom.isMultipart() # Does the current multipolygon have inner rings? has_inner_rings = False multi_polygon = None single_polygon = None if is_multipart: multi_polygon = polygon_geom.constGet() # TODO: remove when the error is resolved if type(multi_polygon) != QgsMultiPolygon: geom = QgsMultiPolygon() geom.fromWkt(polygon_geom.asWkt()) multi_polygon = geom for part in range(multi_polygon.numGeometries()): if multi_polygon.ringCount(part) > 1: has_inner_rings = True break else: single_polygon = polygon_geom.constGet() # TODO: remove when the error is resolved if type(single_polygon) != QgsPolygon: geom = QgsPolygon() geom.fromWkt(polygon_geom.asWkt()) single_polygon = geom if single_polygon.numInteriorRings() > 0: has_inner_rings = True if has_inner_rings: if is_multipart and multi_polygon: for i in range(multi_polygon.numGeometries()): temp_polygon = multi_polygon.geometryN(i) # TODO: remove when the error is resolved if type(temp_polygon) != QgsPolygon: geom = QgsPolygon() geom.fromWkt(temp_polygon.asWkt()) temp_polygon = geom for j in range(temp_polygon.numInteriorRings()): new_feature = QgsVectorLayerUtils().createFeature( layer, QgsGeometry( temp_polygon.interiorRing(j).clone()), {0: polygon[id_field]}) features.append(new_feature) elif not is_multipart and single_polygon: for j in range(single_polygon.numInteriorRings()): new_feature = QgsVectorLayerUtils().createFeature( layer, QgsGeometry( single_polygon.interiorRing(j).clone()), {0: polygon[id_field]}) features.append(new_feature) layer.dataProvider().addFeatures(features) layer.updateExtents() layer.reload() return layer
class ImageViewer: timer = None """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'ImageViewer_{}.qm'.format(locale)) threadcount = QThread.idealThreadCount() # use all available cores and parallel rendering QgsApplication.setMaxThreads(threadcount) QSettings().setValue("/qgis/parallel_rendering", True) # OpenCL acceleration QSettings().setValue("/core/OpenClEnabled", True) self.canvas = self.iface.mapCanvas() self.dlg1 = None if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Image Viewer') # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads def createTimer(self): self.timer = QTimer() self.timer.timeout.connect(self.onTimer) self.timer.start(10) def onTimer(self): try: cefpython.MessageLoopWork() except Exception: None def stopTimer(self): self.timer.stop() def StartCefPython(self): ''' Start CefPython ''' settings = {} settings["browser_subprocess_path"] = "%s/%s" % ( cefpython.GetModuleDirectory(), "subprocess") settings["log_severity"] = cefpython.LOGSEVERITY_DISABLE settings["context_menu"] = { "enabled": False, "navigation": False, # Back, Forward, Reload "print": False, "view_source": False, "external_browser": False, # Open in external browser "devtools": False, # Developer Tools } sys.argv = [''] cefpython.Initialize(settings) # cefpython.Initialize(settings={"file_access_from_file_urls_allowed": True}) # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('ImageViewer', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ # Create the dialog (after translation) and keep reference icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" log.initLogging() icon_path = ':/plugins/image_viewer/icon.png' self.add_action( icon_path, text=self.tr(u'ImageViewer'), callback=self.run, parent=self.iface.mainWindow()) icon_path = ':/plugins/image_viewer/icon.png' self.add_action( icon_path, text=self.tr(u'360viewer'), callback=self.mouseClick, parent=self.iface.mainWindow()) self.dlg = ImageViewerDialog() self.dlg.ok.clicked.connect(self.ok) self.dlg.closebutton.clicked.connect(self.close) self.dlg.toolButtonImport.clicked.connect(self.toolButtonImport) self.dlg.toolButtonOut.clicked.connect(self.toolButtonOut) self.listPhotos = [] self.layernamePhotos = [] self.canvas = self.iface.mapCanvas() self.fields = ['Order', 'Name', 'Date', 'Time', 'Lon', 'Lat', 'Altitude', 'North', 'Azimuth', 'Camera Maker', 'Camera Model', 'Title', 'Comment', 'Path', 'RelPath', 'Timestamp'] self.extension_switch = { ".shp": "ESRI Shapefile", ".geojson": "GeoJSON", ".gpkg": "GPKG", ".csv": "CSV", ".kml": "KML", ".tab": "MapInfo File" } self.extension_switch2 = { "ESRI Shapefile (*.shp *.SHP)": ".shp", "GeoJSON (*.geojson *.GEOJSON)": ".geojson", "GeoPackage (*.gpkg *.GPKG)": ".gpkg", "Comma Separated Value (*.csv *.CSV)": ".csv", "Keyhole Markup Language (*.kml *.KML)": ".kml", "Mapinfo TAB (*.tab *.TAB)": ".tab" } self.extension_switch_types = { ".shp": "ESRI Shapefile", ".geojson": "GeoJSON", ".gpkg": "GPKG", ".csv": "CSV", ".kml": "KML", ".tab": "MapInfo File" } def mouseClick(self): ''' Run click feature ''' self.plugin_path = os.path.dirname(os.path.realpath(__file__)) # Check if photo is loaded lys = self.canvas.layers() if len(lys) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return # Folder viewer for local server folder = QgsApplication.qgisSettingsDirPath() + 'python/plugins/image_viewer/viewer' # Start local server in plugin folder openWebApp(folder) self.StartCefPython() # Create Timer is necessary for cefpython self.createTimer() f = open(self.plugin_path + "/layer_names.txt","r") for layer in lys: for x in f: if layer.name() in x: self.checkLayer = True self.mapTool = SelectTool(self.iface, parent=self, layer=layer) self.iface.mapCanvas().setMapTool(self.mapTool) return if self.checkLayer is False: qgsutils.showUserAndLogMessage( u"Information: ", u"You need to upload the photo layer.") return def ShowDialog(self, featuresId=None, layer=None): ''' Run dialog Geo360 ''' self.featuresId = featuresId self.layer = layer if self.dlg1 is None: self.dlg1 = Geo360Dialog(self.iface, parent=self, featuresId=featuresId, layer=self.layer) self.dlg1.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) self.dlg1.show() else: self.dlg1.ReloadView(self.featuresId) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&Image Viewer'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) self.dlg.out.setText('') self.dlg.imp.setText('') self.dlg.show() def close(self): self.dlg.close() def toolButtonOut(self): typefiles = 'ESRI Shapefile (*.shp *.SHP);; GeoJSON (*.geojson *.GEOJSON);; GeoPackage (*.gpkg *.GPKG);; Comma Separated Value (*.csv *.CSV);; Keyhole Markup Language (*.kml *.KML);; Mapinfo TAB (*.tab *.TAB)' self.outputPath = QFileDialog.getSaveFileName(None, 'Save File', os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'), typefiles) self.extension_type = self.outputPath[1] self.outputPath = self.outputPath[0] if self.extension_type: self.extension2 = self.extension_switch2[self.extension_type] self.dlg.out.setText(self.outputPath) def toolButtonImport(self): self.directoryPhotos = QFileDialog.getExistingDirectory(None, 'Select a folder:', os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'), QFileDialog.ShowDirsOnly) self.selected_folder = self.directoryPhotos[:]#เอาหมด self.selected_folder = './' + os.path.basename(os.path.normpath(self.selected_folder)) + '/'#normpath ตัด // เป็น / self.dlg.imp.setText(self.directoryPhotos) def selectDir(self): title = 'Warning' msg = 'Please select a directory photos.' self.showMessage(title, msg, 'Warning') return True def selectOutp(self): title = 'Warning' msg = 'Please define output file location.' self.showMessage(title, msg, 'Warning') return True def noImageFound(self): title = 'Warning' msg = 'No image path found.' self.showMessage(title, msg, 'Warning') return True def ok(self): if self.dlg.imp.text() == '': if self.selectDir(): return if not os.path.isdir(self.dlg.imp.text()): if self.selectDir(): return if self.dlg.out.text() == '': if self.selectOutp(): return if not os.path.isabs(self.dlg.out.text()): if self.selectOutp(): return self.outputPath = self.dlg.out.text() self.directoryPhotos = self.dlg.imp.text() showMessageHide = True self.import_photos(self.directoryPhotos, self.outputPath, showMessageHide) def import_photos(self, directoryPhotos, outputPath, showMessageHide=True): self.plugin_path = os.path.dirname(os.path.realpath(__file__)) self.showMessageHide = showMessageHide self.outputPath = outputPath self.directoryPhotos = directoryPhotos _ , self.extension = os.path.splitext(self.outputPath)#splitext เอาเฉพาะสกุลไฟล์ basename = os.path.basename(self.outputPath)#basename เอาเฉพาะชื่อไฟล์+สกุลไฟล์ self.myPhoto = basename[:-len(self.extension)]#แยกเอาแค่ชื่อไฟล์ vector self.outDirectoryPhotosGeoJSON = os.path.join(self.plugin_dir, 'tmp.geojson') f = open(self.plugin_path + "/layer_names.txt","r") self.equal_layer = False for x in f: if self.myPhoto in x: self.equal_layer = True else: pass if self.equal_layer is False: f = open(self.plugin_path + "/layer_names.txt","a") f.write(self.myPhoto + "\n") f.close() self.dlg.ok.setEnabled(False) self.dlg.closebutton.setEnabled(False) self.dlg.toolButtonImport.setEnabled(False) self.dlg.toolButtonOut.setEnabled(False) # get paths of photos extens = ['jpg', 'jpeg', 'JPG', 'JPEG'] self.photos = [] self.photos_names = [] self.sorted_photos = [] for root, dirs, files in os.walk(self.directoryPhotos): for name in files: if name.lower().endswith(tuple(extens)): self.photos.append(os.path.join(root, name)) self.photos_names.append(name) self.initphotos = len(self.photos) self.sorted_photos = natsort.natsorted(self.photos, reverse=False) if self.initphotos == 0 and self.showMessageHide: title = 'Warning' msg = 'No photos.' self.showMessage(title, msg, 'Warning') self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) return # Folder viewer for local server #self.canvas.setMapTool(self.toolMouseClick) self.truePhotosCount = 0 self.out_of_extent_photos = 0 self.Qpr_inst = QgsProject.instance()#เป็นการสรา้ง Object จาก class และเก็บไว้ในตัวแปร if platform.system()=='Darwin': self.layernamePhotos.append(self.myPhoto+' OGRGeoJSON Point') else: self.layernamePhotos.append(self.myPhoto) if platform.system() == 'Linux': self.outputPath = self.outputPath + self.extension self.extension = self.extension_switch[self.extension] else: self.extension = self.extension_switch[self.extension.lower()] self.exifread_module = False self.pil_module = False if CHECK_MODULE == '' and self.showMessageHide: self.showMessage('Python Modules', 'Please install python module "exifread" or "PIL".' , 'Warning') #self.import_photos_task('', '') self.call_import_photos() self.dlg.close() def refresh(self): # Deselect features mc = self.canvas for layer in mc.layers(): if layer.type() == layer.VectorLayer: layer.removeSelection() mc.refresh() def showMessage(self, title, msg, icon): if icon == 'Warning': icon = QMessageBox.Warning elif icon == 'Information': icon = QMessageBox.Information msgBox = QMessageBox() msgBox.setIcon(icon) msgBox.setWindowTitle(title) msgBox.setText(msg) msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint) msgBox.exec_() def completed(self, exception, result=None): geojson = {"type": "FeatureCollection", "name": self.myPhoto, "crs": {"type": "name", "properties": {"name": "crs:OGC:1.3:CRS84"}}, "features": self.geoPhotos} geofile = open(self.outDirectoryPhotosGeoJSON, 'w')#temp.geojson json.dump(geojson, geofile) #write file geojson to geofile geofile.close() del self.geoPhotos, geojson try: for layer in self.canvas.layers(): if layer.publicSource() == self.outputPath: self.Qpr_inst.instance().removeMapLayer(layer.id()) os.remove(self.outputPath) except: pass #เก็บข้อมูลรูปภาพเป็น layer เป็นลักษณะ vecter file format self.layerPhotos = QgsVectorLayer(self.outDirectoryPhotosGeoJSON, self.myPhoto, "ogr") QgsVectorFileWriter.writeAsVectorFormat(self.layerPhotos, self.outputPath, "utf-8", QgsCoordinateReferenceSystem(self.layerPhotos.crs().authid()), self.extension) self.layerPhotos_final = QgsVectorLayer(self.outputPath, self.myPhoto, "ogr") # clear temp.geojson file try: f = open(self.outDirectoryPhotosGeoJSON, 'r+') f.truncate(0) # need '0' when using r+ except: pass self.layerPhotos_final.setReadOnly(False) self.layerPhotos_final.reload() self.layerPhotos_final.triggerRepaint() try: xmin = min(self.lon) ymin = min(self.lat) xmax = max(self.lon) ymax = max(self.lat) self.canvas.zoomToSelected(self.layerPhotos_final)#ซูมจุด vector self.canvas.setExtent(QgsRectangle(xmin, ymin, xmax, ymax))#Sets the extent of the map canvas to the specified rectangle. except: pass ########################################### self.dlg.ok.setEnabled(True) self.dlg.closebutton.setEnabled(True) self.dlg.toolButtonImport.setEnabled(True) self.dlg.toolButtonOut.setEnabled(True) noLocationPhotosCounter = self.initphotos - self.truePhotosCount - self.out_of_extent_photos if (self.truePhotosCount == noLocationPhotosCounter == 0 or self.truePhotosCount == 0 ) and self.showMessageHide: title = 'Import Photos' msg = 'Import Completed.\n\nDetails:\n No new photos were added.' self.showMessage(title, msg, 'Information') self.taskPhotos.destroyed() return elif ((self.truePhotosCount == self.initphotos) or ((noLocationPhotosCounter + self.truePhotosCount + self.out_of_extent_photos) == self.initphotos) )and self.showMessageHide: title = 'Import Photos' msg = 'Import Completed.\n\nDetails:\n ' + str( int(self.truePhotosCount)) + ' photo(s) added without error.\n ' + str( int(noLocationPhotosCounter)) + ' photo(s) skipped (because of missing location).\n ' self.showMessage(title, msg, 'Information') #add layer photo เป็นลำดับในลักษณะ Tree g = self.Qpr_inst.layerTreeRoot().insertGroup(0, self.myPhoto) self.Qpr_inst.addMapLayer(self.layerPhotos_final, False)#Add a layer to the map of loaded layers. nn = QgsLayerTreeLayer(self.layerPhotos_final) g.insertChildNode(0, nn) def stopped(self, task): QgsMessageLog.logMessage( 'Task "{name}" was canceled'.format( name=task.description()), 'ImportPhotos', Qgis.Info) def import_photos_task(self, task, wait_time): self.geoPhotos = [] self.lon = [] self.lat = [] order = 0 #names = [] i = 0 #self.sorted_names = [] for count, imgpath in enumerate(self.sorted_photos): try: name = os.path.basename(imgpath) #names.append(name) RelPath = self.selected_folder + self.photos_names[count]#name.jpg if CHECK_MODULE == 'exifread' and not self.pil_module: self.exifread_module = True self.taskPhotos.setProgress(count / self.initphotos) with open(imgpath, 'rb') as imgpathF: tags = exifread.process_file(imgpathF, details=False) if not tags.keys() & {"GPS GPSLongitude", "GPS GPSLatitude"}: continue lat, lon = self.get_exif_location(tags, "lonlat") try: if 'GPS GPSAltitude' in tags: altitude = float(tags["GPS GPSAltitude"].values[0].num) / float( tags["GPS GPSAltitude"].values[0].den) else: altitude = '' except: altitude = '' order = order + 1 try: dt1, dt2 = tags["EXIF DateTimeOriginal"].values.split() date = dt1.replace(':', '/') time_ = dt2 timestamp = dt1.replace(':', '-') + 'T' + time_ except: try: date = tags["GPS GPSDate"].values.replace(':', '/') tt = [str(i) for i in tags["GPS GPSTimeStamp"].values] time_ = "{:0>2}:{:0>2}:{:0>2}".format(tt[0], tt[1], tt[2]) timestamp = tags["GPS GPSDate"].values.replace(':', '-') + 'T' + time_ except: date = '' time_ = '' timestamp = '' try: if 'GPS GPSImgDirection' in tags: direction = float(tags["GPS GPSImgDirection"].values[0].num) / float( tags["GPS GPSImgDirection"].values[0].den) else: direction = float(0) except: direction = '' try: if 'GPS GPSImgDirectionRef' in tags: north = str(tags["GPS GPSImgDirectionRef"].values) else: north = '' except: north = '' try: if 'Image Make' in tags: maker = tags['Image Make'] else: maker = '' except: maker = '' try: if 'Image Model' in tags: model = tags['Image Model'] else: model = '' except: model = '' try: if 'Image ImageDescription' in tags: title = tags['Image ImageDescription'] else: title = '' except: title = '' try: if 'EXIF UserComment' in tags: user_comm = tags['EXIF UserComment'].printable else: user_comm = '' except: user_comm = '' if CHECK_MODULE == 'PIL' and not self.exifread_module: self.pil_module = True a = {} info = Image.open(imgpath) info = info._getexif() if info == None: continue for tag, value in info.items(): if TAGS.get(tag, tag) == 'GPSInfo' or TAGS.get(tag, tag) == 'DateTime' or TAGS.get(tag, tag) == 'DateTimeOriginal': a[TAGS.get(tag, tag)] = value if a == {}: continue if a['GPSInfo'] != {}: if 1 and 2 and 3 and 4 in a['GPSInfo']: lat = [float(x) / float(y) for x, y in a['GPSInfo'][2]] latref = a['GPSInfo'][1] lon = [float(x) / float(y) for x, y in a['GPSInfo'][4]] lonref = a['GPSInfo'][3] lat = lat[0] + lat[1] / 60 + lat[2] / 3600 lon = lon[0] + lon[1] / 60 + lon[2] / 3600 if latref == 'S': lat = -lat if lonref == 'W': lon = -lon else: continue order = order + 1 if 'DateTime' or 'DateTimeOriginal' in a: if 'DateTime' in a: dt1, dt2 = a['DateTime'].split() if 'DateTimeOriginal' in a: dt1, dt2 = a['DateTimeOriginal'].split() date = dt1.replace(':', '/') time_ = dt2 timestamp = dt1.replace(':', '-') + 'T' + time_ try: if 6 in a['GPSInfo']: if len(a['GPSInfo'][6]) > 1: mAltitude = float(a['GPSInfo'][6][0]) mAltitudeDec = float(a['GPSInfo'][6][1]) altitude = mAltitude / mAltitudeDec else: altitude = '' except: altitude = '' try: if 16 and 17 in a['GPSInfo']: north = str(a['GPSInfo'][16]) direction = float(a['GPSInfo'][17][0]) / float(a['GPSInfo'][17][1]) else: north = '' direction = '' except: north = '' direction = '' maker = '' model = '' user_comm = '' title = '' self.lon.append(lon) self.lat.append(lat) self.truePhotosCount = self.truePhotosCount + 1 #self.sorted_names = natsort.natsorted(names, reverse=True) geo_info = {"type": "Feature", "properties": {'Order': order, 'Name': name, 'Date': date, 'Time': time_, 'Lon': lon, 'Lat': lat, 'Altitude': altitude, 'North': north, 'Direction': direction, 'Camera Maker': str(maker), 'Camera Model': str(model), 'Title': str(title), 'Comment': user_comm, 'Path': imgpath, 'RelPath': RelPath, 'Timestamp': timestamp}, "geometry": {"coordinates": [lon, lat], "type": "Point"}} i = i + 1 self.geoPhotos.append(geo_info) if self.taskPhotos.isCanceled(): self.stopped(self.taskPhotos) self.taskPhotos.destroyed() return None except: pass return True def call_import_photos(self): self.taskPhotos = QgsTask.fromFunction(u'ImportPhotos', self.import_photos_task, on_finished=self.completed, wait_time=4) QgsApplication.taskManager().addTask(self.taskPhotos) ###################################################### # based on http://www.codegists.com/snippet/python/exif_gpspy_snakeye_python def _get_if_exist(self, data, key): if key in data: return data[key] return None def _convert_to_degress(self, value): """ Helper function to convert the GPS coordinates stored in the EXIF to degress in float format :param value: :type value: exifread.utils.Ratio :rtype: float """ d = float(value.values[0].num) / float(value.values[0].den) m = float(value.values[1].num) / float(value.values[1].den) s = float(value.values[2].num) / float(value.values[2].den) return d + (m / 60.0) + (s / 3600.0) def get_exif_location(self, exif_data, lonlat): """ Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above) """ if lonlat=='lonlat': lat = '' lon = '' gps_latitude = self._get_if_exist(exif_data, 'GPS GPSLatitude') gps_latitude_ref = self._get_if_exist(exif_data, 'GPS GPSLatitudeRef') gps_longitude = self._get_if_exist(exif_data, 'GPS GPSLongitude') gps_longitude_ref = self._get_if_exist(exif_data, 'GPS GPSLongitudeRef') if gps_latitude and gps_latitude_ref and gps_longitude and gps_longitude_ref: lat = self._convert_to_degress(gps_latitude) if gps_latitude_ref.values[0] != 'N': lat = 0 - lat lon = self._convert_to_degress(gps_longitude) if gps_longitude_ref.values[0] != 'E': lon = 0 - lon return lat, lon
def read2dm(self): try: crs = self.crs except(AttributeError): crs = QgsCoordinateReferenceSystem( 3826, QgsCoordinateReferenceSystem.EpsgCrsId) meshFile = self.dlg.meshFileEdit.text() f = open(meshFile, 'r') nodeFields = QgsFields() nodeFields.append(QgsField("id", QVariant.Int)) nodeFields.append(QgsField("z", QVariant.Double)) nodePath = os.path.join(self.dlg.folderLineEdit.text(), 'Nodes.shp') nodeWriter = QgsVectorFileWriter(nodePath, 'UTF-8', nodeFields, QGis.WKBPoint, crs, 'ESRI Shapefile') data = f.readlines() NodeDict = dict() Regions = list() NodeStrings = list() oneString = list() for line in data: line = line.split() if line[0] == 'ND': NodeDict.update( {int(line[1]): (float(line[2]), float(line[3]), float(line[4]))}) geoString = ('POINT (' + line[2] + ' ' + line[3] + ')') feature = QgsFeature() feature.setGeometry(QgsGeometry.fromWkt(geoString)) feature.setAttributes([int(line[1]), float(line[4])]) nodeWriter.addFeature(feature) elif line[0] in meshType.keys(): Regions.append(int(line[-1])) elif line[0] == 'NS': for i in range(1, len(line)): oneString.append(fabs(int(line[i]))) if int(line[-1]) < 0: NodeStrings.append(oneString) oneString = list() del nodeWriter Regions = list(set(Regions)) Regions.sort() group = QgsProject.instance().layerTreeRoot().addGroup( os.path.basename(meshFile)) regionWriters = list() fields = QgsFields() fields.append(QgsField("id", QVariant.Int)) layerList = list() layerList.append(nodePath) for i in range(0, len(Regions)): layerName = 'Material' + str(Regions[i]) path = os.path.join(self.dlg.folderLineEdit.text(), layerName + '.shp') self.iface.messageBar().pushMessage(path) regionWriters.append( QgsVectorFileWriter(path, 'UTF-8', fields, QGis.WKBPolygon, crs, 'ESRI Shapefile')) layerList.append(path) for line in data: line = line.split() if line[0] in meshType.keys(): n = meshType[line[0]] geoString = 'POLYGON ((' for k in range(2, 2+n): Coor = NodeDict[int(line[k])] geoString += (str(Coor[0]) + ' ' + str(Coor[1]) + ', ') Coor = NodeDict[int(line[2])] geoString += (str(Coor[0]) + ' ' + str(Coor[1])) geoString += '))' writer = regionWriters[int(line[-1])-1] feature = QgsFeature() feature.setGeometry(QgsGeometry().fromWkt(geoString)) feature.setAttributes([int(line[1])]) writer.addFeature(feature) if writer.hasError() != QgsVectorFileWriter.NoError: self.iface.messageBar().pushMessage( "Error when creating shapefile: ", writer.errorMessage()) for writer in regionWriters: del writer counter = 1 for lineString in NodeStrings: path = os.path.join(self.dlg.folderLineEdit.text(), 'NodeString' + str(counter) + '.shp') writer = QgsVectorFileWriter(path, 'UTF-8', fields, QGis.WKBLineString, crs, 'ESRI Shapefile') layerList.append(path) geoString = 'LINESTRING (' for i in range(0, len(lineString)): nodeCoor = NodeDict[lineString[i]] geoString += (str(nodeCoor[0]) + " " + str(nodeCoor[1]) + ", ") geoString = geoString[:-2] + ')' feature = QgsFeature() feature.setGeometry(QgsGeometry().fromWkt(geoString)) feature.setAttributes([counter]) writer.addFeature(feature) del writer counter += 1 for i in range(0, len(layerList)): layer = QgsVectorLayer( layerList[i], QFileInfo(layerList[i]).baseName(), 'ogr') QgsMapLayerRegistry.instance().addMapLayer(layer, False) group.addLayer(layer) layer.reload()
def testSubsetStringFids(self): """ - tests that feature ids are stable even if a subset string is set - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) """ tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) f.SetField(0, 1) f.SetField(1, 11) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) f.SetField(0, 1) f.SetField(1, 12) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) f.SetField(0, 1) f.SetField(1, 13) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) f.SetField(0, 2) f.SetField(1, 14) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) f.SetField(0, 2) f.SetField(1, 15) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) f.SetField(0, 2) f.SetField(1, 16) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)')) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer(tmpfile, 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) original_fields = vl.fields() vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr') self.assertTrue(vl.isValid()) def run_checks(): self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) # expression req = QgsFeatureRequest() req.setFilterExpression("value=16") it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter fid req = QgsFeatureRequest() req.setFilterFid(5) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter fids req = QgsFeatureRequest() req.setFilterFids([5]) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # check with subset of attributes req = QgsFeatureRequest() req.setFilterFids([5]) req.setSubsetOfAttributes([2]) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes()[2], 16) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter rect and expression req = QgsFeatureRequest() req.setFilterExpression("value=16 or value=14") req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5)) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter rect and fids req = QgsFeatureRequest() req.setFilterFids([3, 5]) req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5)) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed req = QgsFeatureRequest() req.setSubsetOfAttributes([]) it = vl.getFeatures(req) ids = [] geoms = {} while it.nextFeature(f): ids.append(f.id()) geoms[f.id()] = f.geometry().asWkt() self.assertCountEqual(ids, [3, 4, 5]) self.assertEqual(geoms, {3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)'}) run_checks() # Check that subset string is correctly set on reload vl.reload() run_checks()
def test_generatedSignLine(self): # line layer testLayerA = QgsVectorLayer(('LineString?crs=epsg:27700&index=yes'), 'test1', 'memory') testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testLineString2 = QgsGeometry.fromPolylineXY( [QgsPointXY(1, 0), QgsPointXY(2, 0)]) testLineString3 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(-1, 1)]) testLineString4 = QgsGeometry.fromPolylineXY( [QgsPointXY(1, 1), QgsPointXY(2, 1)]) testProviderA.addAttributes([QgsField("GeometryID", QVariant.String)]) testFieldsA = testProviderA.fields() testFeature1A = QgsFeature(testFieldsA) testFeature1A.setGeometry(testLineString1) testFeature1A.setAttributes(["Smith"]) testFeature2A = QgsFeature(testFieldsA) testFeature2A.setGeometry(testLineString2) testFeature2A.setAttributes(["Jones"]) testProviderA.addFeatures([testFeature1A, testFeature2A]) testLayerA.reload() # point layer testLayerB = QgsVectorLayer(('Point?crs=epsg:27700&index=yes'), 'test2', 'memory') testProviderB = testLayerB.dataProvider() testPoint1 = QgsPoint(0, 1) testProviderB.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("SignOrientation", QVariant.Int), QgsField("SignType_1", QVariant.Int), QgsField("SignType_2", QVariant.Int), QgsField("SignType_3", QVariant.Int), QgsField("SignType_4", QVariant.Int), QgsField("original_geom", QVariant.Geometry), ]) testFieldsB = testProviderB.fields() testFeature2A = QgsFeature(testFieldsB) testFeature2A.setGeometry(testPoint1) testFeature2A.setAttributes( ["Alpha", 1, 1, None, None, None, testPoint1.asWkt()]) testFeature2B = QgsFeature(testFieldsB) testFeature2B.setGeometry(testPoint1) testFeature2B.setAttributes( ["Beta", 2, 1, 1, None, None, testPoint1.asWkt()]) testFeature2C = QgsFeature(testFieldsB) testFeature2C.setGeometry(testPoint1) testFeature2C.setAttributes( ["Gamma", 3, 1, 1, 1, None, testPoint1.asWkt()]) testProviderB.addFeatures( [testFeature2A, testFeature2B, testFeature2C]) testLayerB.reload() testLayerC = QgsVectorLayer(('Point?crs=epsg:27700&index=yes'), 'test2', 'memory') testProviderC = testLayerC.dataProvider() testProviderC.addAttributes([QgsField("GeometryID", QVariant.String)]) testFieldsC = testProviderC.fields() testFeature3A = QgsFeature(testFieldsC) testFeature3A.setGeometry(testPoint1) testFeature3A.setAttributes(["Zulu"]) testProviderC.addFeatures([testFeature3A]) testLayerC.reload() distanceForIcons = 3 orientationToFeature, orientationInFeatureDirection, orientationAwayFromFeature, orientationOppositeFeatureDirection = self.testClass.getLineOrientationAtPoint( QgsPointXY(testPoint1), testFeature1A) print('orientationToFeature: {}'.format(orientationToFeature)) self.assertEqual(orientationToFeature, 180.0) self.assertEqual(orientationInFeatureDirection, 90.0) self.assertEqual(orientationAwayFromFeature, 0.0) self.assertEqual(orientationOppositeFeatureDirection, 270.0) lineGeom = self.testClass.createLinewithPointAzimuthDistance( QgsPointXY(testPoint1), orientationToFeature, 5) self.assertEqual(lineGeom.length(), 5.0) # check creation of line - for feature with 1 sign platesInSign = self.testClass.getPlatesInSign(testFeature2A) nrPlatesInSign = len(platesInSign) self.assertEqual(nrPlatesInSign, 1) orientationList = self.testClass.getSignOrientation( testFeature2A, testLayerA) self.assertEqual(len(orientationList), 5) print('orientationList: {}'.format(orientationList)) self.assertEqual(orientationList[1], 90.0) # feature direction self.assertEqual(orientationList[2], 270.0) # opposite feature direction self.assertEqual(orientationList[3], 180.0) # facing feature self.assertEqual(orientationList[4], 0.0) # facing away from feature lineGeom = self.testClass.getSignLine(testFeature2A, testLayerA, distanceForIcons) print('lineGeom: {}'.format(lineGeom.asWkt())) self.assertEqual(lineGeom.length(), 6) linePts = self.testClass.addPointsToSignLine(lineGeom, nrPlatesInSign, distanceForIcons) #print ('newLineGeom: {}'.format(newLineGeom.asWkt())) #linePts = newLineGeom.asPolyline() self.assertEqual(len(linePts), 1) # check creation of line - for feature with 3 signs platesInSign = self.testClass.getPlatesInSign(testFeature2C) nrPlatesInSign = len(platesInSign) self.assertEqual(nrPlatesInSign, 3) orientationList = self.testClass.getSignOrientation( testFeature2C, testLayerA) self.assertEqual(len(orientationList), 5) self.assertEqual(orientationList[1], 90.0) lineGeom = self.testClass.getSignLine(testFeature2C, testLayerA, distanceForIcons) print('lineGeom: {}'.format(lineGeom.asWkt())) self.assertEqual(lineGeom.length(), 12) linePts = self.testClass.addPointsToSignLine(lineGeom, nrPlatesInSign, distanceForIcons) #print ('newLineGeom: {}'.format(newLineGeom.asWkt())) #linePts = newLineGeom.asPolyline() self.assertEqual(len(linePts), 3) # check creation of line - for feature without signs field platesInSign = self.testClass.getPlatesInSign(testFeature3A) nrPlatesInSign = len(platesInSign) self.assertEqual(nrPlatesInSign, 0) orientationList = self.testClass.getSignOrientation( testFeature3A, testLayerA) self.assertEqual(len(orientationList), 5) self.assertIsNone(orientationList[0]) lineGeom = self.testClass.getSignLine(testFeature3A, testLayerA, distanceForIcons) self.assertIsNone(lineGeom) newLineGeom = self.testClass.addPointsToSignLine( lineGeom, nrPlatesInSign, distanceForIcons) self.assertIsNone(lineGeom) # static function lineGeom = self.testClass1.finalSignLine(testFeature2C)
def test_isThisTOMsLayer(self): #self.testData() testLayerA = QgsVectorLayer(('LineString?crs=epsg:27700&index=yes'), 'test1', 'memory') testProviderA = testLayerA.dataProvider() testLineString1 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(1, 0)]) testLineString2 = QgsGeometry.fromPolylineXY( [QgsPointXY(1, 0), QgsPointXY(1, 1)]) testLineString3 = QgsGeometry.fromPolylineXY( [QgsPointXY(0, 0), QgsPointXY(-1, 1)]) testLineString4 = QgsGeometry.fromPolylineXY( [QgsPointXY(1, 1), QgsPointXY(2, 1)]) testProviderA.addAttributes([ QgsField("GeometryID", QVariant.String), QgsField("age", QVariant.Int), QgsField("size", QVariant.Double), QgsField("size2", QVariant.Double) ]) testFieldsA = testProviderA.fields() """for field in testFields: print ('** {}'.format(field.name()))""" testFeature1 = QgsFeature(testFieldsA) testFeature1.setGeometry(testLineString1) testFeature1.setAttributes(["Smith", 20, 0.3]) testProviderA.addFeatures([testFeature1]) testFeature2 = QgsFeature(testFieldsA) testFeature2.setGeometry(testLineString2) testFeature2.setAttributes(["Blogs", 20, 0.3]) testProviderA.addFeatures([testFeature2]) # check field called "OpenDate" does not exist result = self.testClass.isThisTOMsLayerUsingCurrentFeatures(testLayerA) self.assertFalse(result) # check field called "OpenDate" does exist but is NULL testLayerB = QgsVectorLayer(('LineString?crs=epsg:27700&index=yes'), 'test2', 'memory') testProviderB = testLayerB.dataProvider() testProviderB.addAttributes([QgsField("OpenDate", QVariant.String)]) testFieldsB = testProviderB.fields() testFeature3 = QgsFeature(testFieldsB) testFeature3.setGeometry(testLineString2) testProviderB.addFeatures([testFeature3]) result = self.testClass.isThisTOMsLayerUsingCurrentFeatures(testLayerB) self.assertFalse(result) # check field called "OpenDate" does exist but is not NULL testFeature3.setAttribute("OpenDate", 'Test') testProviderB.addFeatures([testFeature3]) #print ('*************************** Count: {}'.format(testLayerB.featureCount())) testLayerB.reload() for field in testLayerB.fields(): print('+++ field: {}'.format(field.name())) result = self.testClass.isThisTOMsLayerUsingCurrentFeatures(testLayerB) self.assertTrue(result)
def checkoutLayer(repo, layername, bbox, ref=None): ref = ref or repo.HEAD newCommitId = repo.revparse(ref) trackedlayer = getTrackingInfoForGeogigLayer(repo.url, layername) if trackedlayer is not None: try: source = trackedlayer.source layer = QgsVectorLayer(source, layername, "ogr") assert layer.isValid() except: removeTrackedLayer(trackedlayer.source) trackedlayer = None filename = layerGeopackageFilename(layername, repo.title, repo.group) source = "%s|layername=%s" % (filename, layername) else: filename = layerGeopackageFilename(layername, repo.title, repo.group) source = "%s|layername=%s" % (filename, layername) if trackedlayer is None: repo.checkoutlayer(filename, layername, bbox, ref or repo.HEAD) addTrackedLayer(source, repo.url) try: layer = layerFromSource(source) iface.messageBar().pushMessage( "GeoGig", "Layer was already included in the current QGIS project", level=QgsMessageBar.INFO, duration=5) except WrongLayerSourceException: layer = loadLayerNoCrsDialog(source, layername, "ogr") QgsMapLayerRegistry.instance().addMapLayers([layer]) iface.messageBar().pushMessage("GeoGig", "Layer correctly added to project", level=QgsMessageBar.INFO, duration=5) elif ref is not None: currentCommitId = getCommitId(source) try: layer = layerFromSource(source) wasLoaded = True except WrongLayerSourceException: layer = loadLayerNoCrsDialog(source, layername, "ogr") wasLoaded = False if newCommitId != currentCommitId: if hasLocalChanges(layer): raise HasLocalChangesError() filename, layername = namesFromLayer(layer) repo.checkoutlayer(filename, layername, bbox, ref) layer.reload() if not wasLoaded: QgsMapLayerRegistry.instance().addMapLayers([layer]) iface.messageBar().pushMessage( "GeoGig", "Layer correctly added to project", level=QgsMessageBar.INFO, duration=5) else: iface.messageBar().pushMessage( "GeoGig", "Layer correctly updated to specified version", level=QgsMessageBar.INFO, duration=5) layer.triggerRepaint() else: if wasLoaded: iface.messageBar().pushMessage( "GeoGig", "Layer was already included in the current QGIS project", level=QgsMessageBar.INFO, duration=5) else: QgsMapLayerRegistry.instance().addMapLayers([layer]) iface.messageBar().pushMessage( "GeoGig", "Layer correctly added to the current QGIS project", level=QgsMessageBar.INFO, duration=5) #repoWatcher.repoChanged.emit(repo) return layer
def points_along_line(layerout, startpoint, endpoint, distance, label, layer, selected_only=True, force=False, fo_fila=False, divide=0, decimal=2): """Adding Points along the line """ crs = layer.crs().authid() # TODO check for virtual or shapelayer and set virt_layer according to it shape = False if shape: # define fields for feature attributes. A list of QgsField objects is needed fields = [ QgsField("first", QVariant.Int), QgsField("second", QVariant.String) ] # create an instance of vector file writer, which will create the vector file. # Arguments: # 1. path to new file (will fail if exists already) # 2. encoding of the attributes # 3. field map # 4. geometry type - from WKBTYPE enum # 5. layer's spatial reference (instance of # QgsCoordinateReferenceSystem) - optional # 6. driver name for the output file writer = QgsVectorFileWriter("my_shapes.shp", "CP1250", fields, Qgis.WKBPoint, crs, "ESRI Shapefile") if writer.hasError() != QgsVectorFileWriter.NoError: # fix_print_with_import print("Error when creating shapefile: ", writer.hasError()) # add a feature fet = QgsFeature() fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10))) fet.setAttributes([1, "text"]) writer.addFeature(fet) # delete the writer to flush features to disk (optional) del writer layer_type = "Shapefile" # TODO Add Shapefile functionality here else: layer_type = "memory" virt_layer = QgsVectorLayer("Point?crs=%s" % crs, layerout, layer_type) provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unitname = QgsUnitTypes.toString(units) provider.addAttributes([ QgsField("fid", QVariant.Int), QgsField("cng" + unitname, QVariant.Double) ]) def get_features(): """Getting the features """ if selected_only: return layer.selectedFeatures() else: return layer.getFeatures() # Loop through all (selected) features for feature in get_features(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsMessageLog.logMessage("No geometry", "QChainage") continue features = create_points_at(startpoint, endpoint, distance, geom, fid, force, fo_fila, divide) provider.addFeatures(features) virt_layer.updateExtents() proj = QgsProject.instance() proj.addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() # generic labeling properties if label: virt_layer.setCustomProperty("labeling", "pal") virt_layer.setCustomProperty("labeling/enabled", "true") virt_layer.setCustomProperty("labeling/fieldName", "cng") virt_layer.setCustomProperty("labeling/fontSize", "10") virt_layer.setCustomProperty("labeling/multiLineLabels", "true") virt_layer.setCustomProperty("labeling/formatNumbers", "true") virt_layer.setCustomProperty("labeling/decimals", decimal) virt_layer.setCustomProperty("labeling/Size", "5") # symbol = QgsMarkerSymbol.createSimple({"name": "capital"}) # virt_layer.setRenderer(QgsSingleSymbolRenderer(symbol)) virt_layer.triggerRepaint() return
def testSubsetStringFids(self): """ - tests that feature ids are stable even if a subset string is set - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) """ tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) f.SetField(0, 1) f.SetField(1, 11) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) f.SetField(0, 1) f.SetField(1, 12) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) f.SetField(0, 1) f.SetField(1, 13) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) f.SetField(0, 2) f.SetField(1, 14) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) f.SetField(0, 2) f.SetField(1, 15) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)')) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) f.SetField(0, 2) f.SetField(1, 16) f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)')) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer(tmpfile, 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) original_fields = vl.fields() vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr') self.assertTrue(vl.isValid()) def run_checks(): self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) # expression req = QgsFeatureRequest() req.setFilterExpression("value=16") it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter fid req = QgsFeatureRequest() req.setFilterFid(5) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter fids req = QgsFeatureRequest() req.setFilterFids([5]) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # check with subset of attributes req = QgsFeatureRequest() req.setFilterFids([5]) req.setSubsetOfAttributes([2]) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes()[2], 16) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter rect and expression req = QgsFeatureRequest() req.setFilterExpression("value=16 or value=14") req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5)) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # filter rect and fids req = QgsFeatureRequest() req.setFilterFids([3, 5]) req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5)) it = vl.getFeatures(req) f = QgsFeature() self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed req = QgsFeatureRequest() req.setSubsetOfAttributes([]) it = vl.getFeatures(req) ids = [] geoms = {} while it.nextFeature(f): ids.append(f.id()) geoms[f.id()] = f.geometry().asWkt() self.assertCountEqual(ids, [3, 4, 5]) self.assertEqual(geoms, { 3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)' }) run_checks() # Check that subset string is correctly set on reload vl.reload() run_checks()
def points_along_line(layerout, startpoint, endpoint, distance, label, layer, selected_only=True, force=False, divide=0): """Adding Points along the line """ # Create a new memory layer and add a distance attribute self.layerNameLine #layer_crs = virt_layer.setCrs(layer.crs()) virt_layer = QgsVectorLayer("Point?crs=%s" % layer.crs().authid(), layerout, "memory") provider = virt_layer.dataProvider() virt_layer.startEditing() # actually writes attributes units = layer.crs().mapUnits() unit_dic = { QGis.Degrees: 'Degrees', QGis.Meters: 'Meters', QGis.Feet: 'Feet', QGis.UnknownUnit: 'Unknown' } unit = unit_dic.get(units, 'Unknown') provider.addAttributes([QgsField("fid", QVariant.Int)]) provider.addAttributes([QgsField("cng_(" + unit + ")", QVariant.Int)]) def get_features(): """Getting the features """ if selected_only: return layer.selectedFeatures() else: return layer.getFeatures() # Loop through all (selected) features for feature in get_features(): geom = feature.geometry() # Add feature ID of selected feature fid = feature.id() if not geom: QgsMessageLog.logMessage("No geometry", "QChainage") continue features = create_points_at(startpoint, endpoint, distance, geom, fid, force, divide) provider.addFeatures(features) virt_layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayers([virt_layer]) virt_layer.commitChanges() virt_layer.reload() #from here Add labeling #generic labeling properties if label: virt_layer.setCustomProperty("labeling", "pal") virt_layer.setCustomProperty("labeling/enabled", "true") virt_layer.setCustomProperty("labeling/fieldName", "cng_(" + unit + ")") virt_layer.setCustomProperty("labeling/fontSize", "10") virt_layer.setCustomProperty("labeling/multiLineLabels", "true") #virt_layer.setCustomProperty("labeling/Size", "5") # symbol = QgsMarkerSymbolV2.createSimple({"name": "capital"}) # virt_layer.setRendererV2(QgsSingleSymbolRendererV2(symbol)) virt_layer.triggerRepaint() return