def __init__(self, table, parent=None): TableDataModel.__init__(self, table, parent) self.layer = None if isinstance(table, LVectorTable): self.layer = VLayerRegistry.instance().getLayer(table.name) else: self.layer = VLayerRegistry.instance().getLayer(table) if not self.layer: return # populate self.resdata self.resdata = [] for f in self.layer.getFeatures(): a = f.attributes() # add the geometry type if f.hasGeometry(): a.append(QgsWkbTypes.displayString(f.geometry().wkbType())) else: a.append('None') self.resdata.append(a) self.fetchedFrom = 0 self.fetchedCount = len(self.resdata)
def _openShapefile(self): layer = QgsVectorLayer(self.shapePath, self.fileName, "ogr") wkbType = layer.wkbType() if wkbType != QgsWkbTypes.PointZ: self.importError.emit( self.tr("File has incorrect WKB type '{}'. Please select layer " "with 'PointZ' WKB type.".format(QgsWkbTypes.displayString(wkbType)))) return None return layer
def convertToLineStrings(self, geom): if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry: raise QgsProcessingException( self.tr('Cannot convert from {0} to LineStrings').format(QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom.wkbType()): return geom.asGeometryCollection() else: #line to line return [geom] else: # polygons to lines # we just use the boundary here - that consists of all rings in the (multi)polygon boundary = QgsGeometry(geom.constGet().boundary()) # boundary will be multipart return boundary.asGeometryCollection()
def convertToMultiLineStrings(self, geom): if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry: raise QgsProcessingException( self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom.wkbType()): return [geom] else: # line to multiLine ml = QgsMultiLineString() ml.addGeometry(geom.constGet().clone()) return [QgsGeometry(ml)] else: # polygons to multilinestring # we just use the boundary here - that consists of all rings in the (multi)polygon return [QgsGeometry(geom.constGet().boundary())]
def convertToMultiLineStrings(self, geom): if QgsWkbTypes.geometryType( geom.wkbType()) == QgsWkbTypes.PointGeometry: raise QgsProcessingException( self.tr('Cannot convert from {0} to MultiLineStrings').format( QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType( geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom.wkbType()): return [geom] else: # line to multiLine ml = QgsMultiLineString() ml.addGeometry(geom.constGet().clone()) return [QgsGeometry(ml)] else: # polygons to multilinestring # we just use the boundary here - that consists of all rings in the (multi)polygon return [QgsGeometry(geom.constGet().boundary())]
def convertToLineStrings(self, geom): if QgsWkbTypes.geometryType( geom.wkbType()) == QgsWkbTypes.PointGeometry: raise QgsProcessingException( self.tr('Cannot convert from {0} to LineStrings').format( QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType( geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom.wkbType()): return geom.asGeometryCollection() else: #line to line return [geom] else: # polygons to lines # we just use the boundary here - that consists of all rings in the (multi)polygon boundary = QgsGeometry(geom.constGet().boundary()) # boundary will be multipart return boundary.asGeometryCollection()
def createLayer(cls, topicName, rosMessages=None, extraProperties=None, subscribe=False, keepOlderMessages=False, sampleInterval=1): if rosMessages: # Features were passed in, so it's a static data layer. geomType = QgsWkbTypes.displayString(cls.geomType) # Get string version of geomtype enum. uri = '{}?crs=PROJ4:{}'.format(geomType, proj4CrsDict[cls.crsName]) layer = QgsVectorLayer(uri, topicName, 'memory') # Convert from ROS messages to GeoJSON Features to QgsFeatures. features = [] for n, m in enumerate(rosMessages): translatedFeatures = cls.translate(m) # Append one or more features. # Optionally merge extra properties like bag timestamps in to features created by this message. if extraProperties is not None: for f in translatedFeatures: f['properties'].update(extraProperties[n]) features += translatedFeatures qgsFeatures, fields = featuresToQgs(features) layer.dataProvider().addAttributes(fields) layer.dataProvider().addFeatures(qgsFeatures) layer.updateFields() # Required, otherwise the layer will not re-read field metadata. return layer else: # No features, it must be a ROS topic to get data from. uri = '{}?type={}&index=no&subscribe={}&keepOlderMessages={}&sampleInterval={}&crsName={}'.format( topicName, cls.messageType._type, subscribe, keepOlderMessages, sampleInterval, cls.crsName, ) layer = QgsVectorLayer(uri, topicName, 'rosvectorprovider') # Need to monitor when data is changed and call updateFields in order to capture the new fields # that are discovered on the first and possibly future messages. Without this, the layer will never # expose any of the field data available. # TODO: Find a cleaner way to signal this update and only call it when actual field changes occur. layer.dataChanged.connect(layer.updateFields) return layer
def copy_layer_into_memory_layer(source_layer, layer_name): source_provider = source_layer.dataProvider() uri = "{0}?crs=EPSG:{1}".format( QgsWkbTypes.displayString(source_provider.wkbType()).lstrip("WKB"), str(source_provider.crs().postgisSrid()), ) dest_layer = QgsVectorLayer(uri, layer_name, "memory") dest_provider = dest_layer.dataProvider() dest_provider.addAttributes(source_provider.fields()) dest_layer.updateFields() dest_provider.addFeatures([f for f in source_provider.getFeatures()]) dest_layer.updateExtents() return dest_layer
def createShp(self, out_shp, features, inLayer, sr, out_type=None): self.new_name = inLayer.name() + "_new" self.geomType = QgsWkbTypes.displayString(inLayer.wkbType()) if out_type == "m": self.new_shp = QgsVectorLayer(self.geomType, self.new_name, "memory") self.pr = self.new_shp.dataProvider() self.fields = [ QgsField(n, t) for t, n, _ in features[0]["properties"] ] self.pr.addAttributes(self.fields) self.new_shp.updateFields() for f in features: self.feat = QgsFeature() self.feat.setGeometry(f["geometry"]) self.attr = [k for i, j, k in f["properties"]] self.feat.setAttributes(self.attr) self.pr.addFeature(self.feat) self.new_shp.updateExtents() QgsProject.instance().addMapLayer(self.new_shp) self.new_shp.setCrs(QgsCoordinateReferenceSystem.fromWkt(sr)) else: self.fields = QgsFields() for t, n, _ in features[0]["properties"]: self.fields.append(QgsField(n, t)) self.writer = QgsVectorFileWriter( out_shp, 'UTF-8', self.fields, inLayer.wkbType(), QgsCoordinateReferenceSystem.fromWkt(sr), 'ESRI Shapefile') for f in features: self.feat = QgsFeature() self.feat.setGeometry(f["geometry"]) self.attr = [k for i, j, k in f["properties"]] self.feat.setAttributes(self.attr) self.writer.addFeature(self.feat) self.layer = iface.addVectorLayer(out_shp, '', 'ogr') self.layer.setExtent(inLayer.extent()) del (self.writer)
def prepareNewLayer(self, currLayer, newLayerName, geomWkbType, reqFields): currCrs = currLayer.crs().authid() #print ('---------- layer CRS: {}'.format(currCrs)) TOMsMessageLog.logMessage('---------- layer CRS: {}'.format(currCrs), level=Qgis.Info) #currCrs = 'EPSG:27700' """newLayer = QgsVectorLayer("{type}?={crs}".format(type=geomType, crs='EPSG:27700'), newLayerName, "memory")""" newLayer = QgsVectorLayer( "{type}?crs={crs}".format( type=QgsWkbTypes.displayString(geomWkbType), crs=currCrs), newLayerName, "memory") #newFields = self.setFieldsForTOMsExportLayer(currLayer, reqFields) newLayer.dataProvider().addAttributes(reqFields) #newLayer.reload() newLayer.updateFields() return newLayer
def __init__(self, qgis_layer, client_var, relation_id=None, lock=None, **kwargs): """Constructor :param qgis_layer: the QGIS vector layer :type qgis_layer: QgsVectorLayer :param client_var: layer original name :type client_var: str :param relation_id: relation id, defaults to None :type relation_id: str, optional :param lock: [description], defaults to None :type lock: [type], optional """ self.qgis_layer = qgis_layer self.geometry_type = QgsWkbTypes.displayString(qgis_layer.wkbType()) self.client_var = client_var self.relation_id = relation_id self.lock = lock for k, v in list(kwargs.items()): setattr(self, k, v)
def convertToPolygon(self, geom): if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3: raise QgsProcessingException( self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry: # multipoint with at least 3 points # TODO: mega inefficient - needs rework when geometry iterators land # (but at least it doesn't lose Z/M values) points = [] for g in geom.constGet().coordinateSequence(): for r in g: for p in r: points.append(p) linestring = QgsLineString(points) linestring.close() p = QgsPolygon() p.setExteriorRing(linestring) return [QgsGeometry(p)] elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom): parts = [] for i in range(geom.constGet().numGeometries()): p = QgsPolygon() linestring = geom.constGet().geometryN(i).clone() linestring.close() p.setExteriorRing(linestring) parts.append(QgsGeometry(p)) return QgsGeometry.collectGeometry(parts) else: # linestring to polygon p = QgsPolygon() linestring = geom.constGet().clone() linestring.close() p.setExteriorRing(linestring) return [QgsGeometry(p)] else: #polygon if QgsWkbTypes.isMultiType(geom): return geom.asGeometryCollection() else: return [geom]
def test_zm(self): """Test regression GH #43268""" md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(self.uri, {}) sql = """ DROP TABLE IF EXISTS qgis_test.gh_43268_test_zm; CREATE TABLE qgis_test.gh_43268_test_zm (geom geometry(GeometryZ)); INSERT INTO qgis_test.gh_43268_test_zm (geom) VALUES ('POINT(0 0 0)'), ('LINESTRING(0 0 0, 0 0 0)'), ('POLYGON((0 0 0, 0 0 0, 0 0 0, 0 0 0))'); """ conn.executeSql(sql) table_info = conn.table('qgis_test', 'gh_43268_test_zm') self.assertEqual( sorted([ QgsWkbTypes.displayString(col.wkbType) for col in table_info.geometryColumnTypes() ]), ['LineStringZ', 'PointZ', 'PolygonZ'])
def createMemLayer(self, featureIterator): # create a memory layer, given a feature type and the features that go in it fields, geomAtt = self._fields() layerName = self.featureType.featureTypeName if geomAtt is None: uri = "None" else: uri = "{}?crs={}".format( QgsWkbTypes.displayString( FeatureTypeHelper.typeNameConverter[geomAtt.type.lower()]), geomAtt.SRS) newlayer = QgsVectorLayer(uri, layerName, 'memory') with edit(newlayer): newlayer.dataProvider().addAttributes(fields) newlayer.updateFields() features = list(featureIterator) newlayer.addFeatures(features) if geomAtt is not None: newlayer.setCrs(QgsCoordinateReferenceSystem(geomAtt.SRS)) return newlayer
def load_from_qnode(cls, qnode): meta = qnode.customProperty("xyz-hub") conn_info = qnode.customProperty("xyz-hub-conn") tags = qnode.customProperty("xyz-hub-tags") unique = qnode.customProperty("xyz-hub-id") name = qnode.name() meta = json.loads(meta) conn_info = json.loads(conn_info) conn_info = SpaceConnectionInfo.from_dict(conn_info) obj = cls(conn_info, meta, tags=tags, unique=unique, group_name=name) obj.qgroups["main"] = qnode for g in qnode.findGroups(): obj.qgroups[g.name()] = g lst_vlayers = [i.layer() for i in g.findLayers()] for vlayer in lst_vlayers: geom_str = QgsWkbTypes.displayString(vlayer.wkbType()) obj.map_vlayer.setdefault(geom_str, list()).append(vlayer) obj.map_fields.setdefault(geom_str, list()).append(vlayer.fields()) return obj
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 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 response_data_mode(self, request, export_features=False): """ Query layer and return data :param request: DjangoREST API request object :param formatter: Boolean, default False, True for to use QgsJsonExport.exportFeatures method :return: response dict data """ # Create the QGIS feature request, it will be passed through filters # and to the final QGIS API get features call. qgis_feature_request = QgsFeatureRequest() # Prepare arguments for the get feature call kwargs = {} # Apply filter backends, store original subset string original_subset_string = self.metadata_layer.qgis_layer.subsetString() if hasattr(self, 'filter_backends'): try: for backend in self.filter_backends: backend().apply_filter(request, self.metadata_layer, qgis_feature_request, self) except Exception as e: raise APIException(e) # Paging cannot be a backend filter if 'page' in request.query_params: kwargs['page'] = request.query_params.get('page') kwargs['page_size'] = request.query_params.get('page_size', 10) # Make sure we have all attrs we need to build the server FID provider = self.metadata_layer.qgis_layer.dataProvider() if qgis_feature_request.flags() & QgsFeatureRequest.SubsetOfAttributes: attrs = qgis_feature_request.subsetOfAttributes() for attr_idx in provider.pkAttributeIndexes(): if attr_idx not in attrs: attrs.append(attr_idx) qgis_feature_request.setSubsetOfAttributes(attrs) self.features = get_qgis_features(self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs) # Reproject feature if layer CRS != Project CRS if self.reproject: for f in self.features: self.reproject_feature(f) ex = QgsJsonExporter(self.metadata_layer.qgis_layer) # If 'unique' request params is set, # api return a list of unique # field name sent with 'unique' param. # -------------------------------------- # IDEA: for big data it'll be iterate over features to get unique # c++ iteration is fast. Instead memory layer with too many features can be a problem. if 'unique' in request.query_params: vl = QgsVectorLayer( QgsWkbTypes.displayString( self.metadata_layer.qgis_layer.wkbType()), "temporary_vector", "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.metadata_layer.qgis_layer.fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider res = pr.addFeatures(self.features) uniques = vl.uniqueValues( self.metadata_layer.qgis_layer.fields().indexOf( request.query_params.get('unique'))) values = [] for u in uniques: try: if u: values.append(json.loads(QgsJsonUtils.encodeValue(u))) except Exception as e: logger.error(f'Response vector widget unique: {e}') continue # sort values values.sort() self.results.update({'data': values, 'count': len(values)}) del (vl) else: ex.setTransformGeometries(False) # check for formatter query url param and check if != 0 if 'formatter' in request.query_params: formatter = request.query_params.get('formatter') if formatter.isnumeric() and int(formatter) == 0: export_features = False else: export_features = True if export_features: feature_collection = json.loads( ex.exportFeatures(self.features)) else: # to exclude QgsFormater used into QgsJsonExporter is necessary build by hand single json feature ex.setIncludeAttributes(False) feature_collection = { 'type': 'FeatureCollection', 'features': [] } for feature in self.features: fnames = [] date_fields = [] for f in feature.fields(): fnames.append(f.name()) if f.typeName() in ('date', 'datetime', 'time'): date_fields.append(f) jsonfeature = json.loads( ex.exportFeature( feature, dict(zip(fnames, feature.attributes())))) # Update date and datetime fields value if widget is active if len(date_fields) > 0: for f in date_fields: field_idx = self.metadata_layer.qgis_layer.fields( ).indexFromName(f.name()) options = self.metadata_layer.qgis_layer.editorWidgetSetup( field_idx).config() if 'field_iso_format' in options and not options[ 'field_iso_format']: try: jsonfeature['properties'][f.name()] = feature.attribute(f.name())\ .toString(options['field_format']) except: pass feature_collection['features'].append(jsonfeature) # Change media self.change_media(feature_collection) # Patch feature IDs with server featureIDs fids_map = {} for f in self.features: fids_map[f.id()] = server_fid(f, provider) for i in range(len(feature_collection['features'])): f = feature_collection['features'][i] f['id'] = fids_map[f['id']] self.results.update( APIVectorLayerStructure( **{ 'data': feature_collection, 'count': count_qgis_features(self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs), 'geometryType': self.metadata_layer.geometry_type, }).as_dict()) # FIXME: add extra fields data by signals and receivers # FIXME: featurecollection = post_serialize_maplayer.send(layer_serializer, layer=self.layer_name) # FIXME: Not sure how to map this to the new QGIS API # Restore the original subset string self.metadata_layer.qgis_layer.setSubsetString(original_subset_string)
def __init__(self, destination, encoding, fields, geometryType, crs, options=None): self.destination = destination self.isNotFileBased = False self.layer = None self.writer = None if encoding is None: settings = QSettings() encoding = settings.value('/Processing/encoding', 'System', str) if self.destination.startswith(self.MEMORY_LAYER_PREFIX): self.isNotFileBased = True uri = QgsWkbTypes.displayString(geometryType) + "?uuid=" + str(uuid.uuid4()) if crs.isValid(): uri += '&crs=' + crs.authid() fieldsdesc = [] for f in fields: qgsfield = _toQgsField(f) fieldsdesc.append('field=%s:%s' % (qgsfield.name(), TYPE_MAP_MEMORY_LAYER.get(qgsfield.type(), "string"))) if fieldsdesc: uri += '&' + '&'.join(fieldsdesc) self.layer = QgsVectorLayer(uri, self.destination, 'memory') self.writer = self.layer.dataProvider() elif self.destination.startswith(self.POSTGIS_LAYER_PREFIX): self.isNotFileBased = True uri = QgsDataSourceUri(self.destination[len(self.POSTGIS_LAYER_PREFIX):]) connInfo = uri.connectionInfo() (success, user, passwd) = QgsCredentials.instance().get(connInfo, None, None) if success: QgsCredentials.instance().put(connInfo, user, passwd) else: raise GeoAlgorithmExecutionException("Couldn't connect to database") try: db = postgis.GeoDB(host=uri.host(), port=int(uri.port()), dbname=uri.database(), user=user, passwd=passwd) except postgis.DbError as e: raise GeoAlgorithmExecutionException( "Couldn't connect to database:\n%s" % e.message) def _runSQL(sql): try: db._exec_sql_and_commit(str(sql)) except postgis.DbError as e: raise GeoAlgorithmExecutionException( 'Error creating output PostGIS table:\n%s' % e.message) fields = [_toQgsField(f) for f in fields] fieldsdesc = ",".join('%s %s' % (f.name(), TYPE_MAP_POSTGIS_LAYER.get(f.type(), "VARCHAR")) for f in fields) _runSQL("CREATE TABLE %s.%s (%s)" % (uri.schema(), uri.table().lower(), fieldsdesc)) if geometryType != QgsWkbTypes.NullGeometry: _runSQL("SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)".format( table=uri.table().lower(), schema=uri.schema(), srid=crs.authid().split(":")[-1], typmod=QgsWkbTypes.displayString(geometryType).upper())) self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres") self.writer = self.layer.dataProvider() elif self.destination.startswith(self.SPATIALITE_LAYER_PREFIX): self.isNotFileBased = True uri = QgsDataSourceUri(self.destination[len(self.SPATIALITE_LAYER_PREFIX):]) try: db = spatialite.GeoDB(uri=uri) except spatialite.DbError as e: raise GeoAlgorithmExecutionException( "Couldn't connect to database:\n%s" % e.message) def _runSQL(sql): try: db._exec_sql_and_commit(str(sql)) except spatialite.DbError as e: raise GeoAlgorithmExecutionException( 'Error creating output Spatialite table:\n%s' % str(e)) fields = [_toQgsField(f) for f in fields] fieldsdesc = ",".join('%s %s' % (f.name(), TYPE_MAP_SPATIALITE_LAYER.get(f.type(), "VARCHAR")) for f in fields) _runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower()) _runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc)) if geometryType != QgsWkbTypes.NullGeometry: _runSQL("SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)".format( table=uri.table().lower(), srid=crs.authid().split(":")[-1], typmod=QgsWkbTypes.displayString(geometryType).upper())) self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite") self.writer = self.layer.dataProvider() else: formats = QgsVectorFileWriter.supportedFiltersAndFormats() OGRCodes = {} for (key, value) in list(formats.items()): extension = str(key) extension = extension[extension.find('*.') + 2:] extension = extension[:extension.find(' ')] OGRCodes[extension] = value OGRCodes['dbf'] = "DBF file" extension = self.destination[self.destination.rfind('.') + 1:] if extension not in OGRCodes: extension = 'shp' self.destination = self.destination + '.shp' if geometryType == QgsWkbTypes.NoGeometry: if extension == 'shp': extension = 'dbf' self.destination = self.destination[:self.destination.rfind('.')] + '.dbf' if extension not in self.nogeometry_extensions: raise GeoAlgorithmExecutionException( "Unsupported format for tables with no geometry") qgsfields = QgsFields() for field in fields: qgsfields.append(_toQgsField(field)) # use default dataset/layer options dataset_options = QgsVectorFileWriter.defaultDatasetOptions(OGRCodes[extension]) layer_options = QgsVectorFileWriter.defaultLayerOptions(OGRCodes[extension]) self.writer = QgsVectorFileWriter(self.destination, encoding, qgsfields, geometryType, crs, OGRCodes[extension], dataset_options, layer_options)
def handle_add_layer(self): """Create a new layer by name (rev_lyr)""" slds = self.get_sld() selected_name = self.dlg.mComboBox.currentText() selected_id = self.dataset_dictionary[selected_name] # Group name equals selected dataset name group = self.create_group(selected_name) # Get metadata and features from NgisOpenAPI try: metadata_from_api = self.client.getDatasetMetadata(selected_id) epsg = metadata_from_api.crs_epsg features_from_api = self.client.getDatasetFeatures( metadata_from_api.id, metadata_from_api.bbox, epsg) except Exception as e: error = ApiError("Nedlasting av data mislyktes", "Kunne ikke laste ned datasett", e) self.iface.messageBar().pushMessage(error.title, error.detail, error.show_more, level=2, duration=10) return crs_from_api = features_from_api['crs']['properties']['name'] features_by_type = {} # Extract features from GeoJSON into dictionary for feature in features_from_api['features']: feature_type = feature['properties']['featuretype'] features_by_type.setdefault(feature_type, []).append(feature) features_from_api['features'] = None for feature_type, features_list in features_by_type.items(): # Create a new GeoJSON object containing a single featuretype features_dict = features_from_api.copy() features_dict['features'] = features_list features_json = json.dumps(features_dict, ensure_ascii=False) # Identify fields and features from GeoJSON codec = QTextCodec.codecForName("UTF-8") fields = QgsJsonUtils.stringToFields(features_json, codec) newFeatures = QgsJsonUtils.stringToFeatureList( features_json, fields, codec) # If different geometry types are identified, separate them into individual layers geometry_dict = {} if newFeatures: for feature in newFeatures: featuretype = feature.attribute('featuretype') geom_type = feature.geometry() geom_type = QgsWkbTypes.displayString( int(geom_type.wkbType())) if geom_type not in geometry_dict: geometry_dict[geom_type] = {} if featuretype not in geometry_dict[geom_type]: geometry_dict[geom_type][featuretype] = [] geometry_dict[geom_type][featuretype].append(feature) for geom_type, feature_types in geometry_dict.items(): for feature_type, features in feature_types.items(): lyr = QgsVectorLayer(f'{geom_type}?crs={crs_from_api}', f'{feature_type}-{geom_type}', "memory") #lyr = QgsVectorLayer(f'{geom_type}?crs=EPSG:25832', f'{feature_type}-{geom_type}', "memory") #TODO Remove QgsProject.instance().addMapLayer(lyr, False) lyr.startEditing() add_fields_to_layer(lyr, fields, feature_type) lyr.commitChanges() l_d = lyr.dataProvider() l_d.addFeatures(features) # update the extent of rev_lyr lyr.updateExtents() # save changes made in 'rev_lyr' lyr.commitChanges() group.addLayer(lyr) #lyr.committedFeaturesAdded.connect(self.handleCommitedAddedFeatures) #lyr.committedFeaturesRemoved.connect(self.handleCommittedFeaturesRemoved) #lyr.featuresDeleted.connect(self.handleDeletedFeatures) #lyr.committedGeometriesChanges(self.ee) lyr.beforeCommitChanges.connect( self.handle_before_commitchanges) if feature_type in slds: lyr.loadSldStyle(slds[feature_type]) self.dataset_dictionary[lyr.id()] = selected_id self.feature_type_dictionary[lyr.id()] = feature_type
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ i_fields = self.parameterAsMatrix( parameters, self.INPUT_F, context) #CREA TABELLA CONTENUTI PROGETTO #per altri campi occorre vedere quali si serve aggiungere #funzione iterativa per posizione layer nella TOC def get_group_layers(group, level): level = level + group.name() + ' - '#' >> ' for child in group.children(): if isinstance(child, QgsLayerTreeGroup): get_group_layers(child, level) else: TOC_dict [child.name()] = level #print(lev) #dizionario delle posizioni TOC_dict ={} root = QgsProject.instance().layerTreeRoot() for child in root.children(): level = 'root - ' #' >> ' if isinstance(child, QgsLayerTreeGroup): get_group_layers(child, level) elif isinstance(child, QgsLayerTreeLayer): #lev = level #+ child.name()) TOC_dict[child.name()] = level #abort if TOC is empty #feedback.pushInfo (str(TOC_dict)) #feedback.pushInfo (str(not bool(TOC_dict))) if not bool(TOC_dict): raise QgsProcessingException('Invalid input value: EMPY PROJECT') #parametro denominazione tabella risultante report = 'Project_Layers_Table' fields = QgsFields() for item in i_fields: if item in ('Layer_N','Geometry_Not_Valid','Layer_Type','Layer_Feature_Count'): fields.append(QgsField(item, QVariant.Int)) else: fields.append(QgsField(item, QVariant.String)) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, fields) # If sink was not created, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this # case we use the pre-built invalidSinkError method to return a standard # helper text for when a sink cannot be evaluated if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) feat = QgsFeature() count = 1 for layer in QgsProject.instance().mapLayers().values(): if layer.name().find("Project_Layers_Table") == -1: Layer_N = count count += 1 Layer_Name = layer.name() Layer_Group_Level = TOC_dict.get(Layer_Name) Layer_Crs = layer.crs().authid() Layer_Source = layer.source() Layer_Meta_Parent_Id = layer.metadata().parentIdentifier() Layer_Meta_Identifier = layer.metadata().identifier() Layer_Meta_Title = layer.metadata().title() Layer_Meta_Type = layer.metadata().type() Layer_Meta_Language = layer.metadata().language() Layer_Meta_Abstract = layer.metadata().abstract() Raster_type = Raster_data_type = Raster_Info_dim = '-' Raster_extent = Raster_Info_res = Raster_NoDataValue = '-' if layer.type() is not QgsMapLayerType.RasterLayer: Layer_Feature_Count = layer.featureCount() Layer_Type = layer.wkbType() Layer_Storage = layer.storageType() Layer_Type_Name = QgsWkbTypes.displayString(layer.wkbType()) Geometry_Not_Valid = 0 for f in layer.getFeatures(): if not f.geometry().isGeosValid(): Geometry_Not_Valid += 1 else: Layer_Type = (0) Layer_Type_Name = QgsMapLayerType.RasterLayer.name Layer_Storage = '' Layer_Feature_Count = 'nan' Geometry_Not_Valid = 0 gh = layer.height() gw = layer.width() Raster_extent = layer.extent().toString() provider = layer.dataProvider() gpx = layer.rasterUnitsPerPixelX() gpy = layer.rasterUnitsPerPixelY() block = provider.block(1, layer.extent(), gpy, gpx) for band in range(1, layer.bandCount()+1): #print('Band ', band, layer.dataProvider().sourceNoDataValue(band)) Raster_NoDataValue = Raster_NoDataValue + 'Band ' + str(band) + ': ' + str(layer.dataProvider().sourceNoDataValue(band)) + ' ' Raster_data_type = type(provider.sourceNoDataValue(band)).__name__ Raster_type = layer.renderer().type() #feedback.pushInfo(str(gh)+' x '+str(gw)+' - '+ str(gpx)+' x '+str(gpy)) Raster_Info_dim = str(gh) + ' x '+ str(gw) Raster_Info_res = str(gpx) + ' x ' + str(gpy) campi = [] for item in i_fields: campi.append(vars()[item]) feat.setAttributes(campi) sink.addFeature(feat, QgsFeatureSink.FastInsert) return {self.OUTPUT: dest_id}
def __init__(self, destination, encoding, fields, geometryType, crs, options=None): self.destination = destination self.isNotFileBased = False self.layer = None self.writer = None if encoding is None: settings = QSettings() encoding = settings.value('/Processing/encoding', 'System', type=str) if self.destination.startswith(self.MEMORY_LAYER_PREFIX): self.isNotFileBased = True uri = QgsWkbTypes.displayString(geometryType) + "?uuid=" + str( uuid.uuid4()) if crs.isValid(): uri += '&crs=' + crs.authid() fieldsdesc = [] for f in fields: qgsfield = _toQgsField(f) fieldsdesc.append( 'field=%s:%s' % (qgsfield.name(), TYPE_MAP_MEMORY_LAYER.get(qgsfield.type(), "string"))) if fieldsdesc: uri += '&' + '&'.join(fieldsdesc) self.layer = QgsVectorLayer(uri, self.destination, 'memory') self.writer = self.layer.dataProvider() elif self.destination.startswith(self.POSTGIS_LAYER_PREFIX): self.isNotFileBased = True uri = QgsDataSourceUri( self.destination[len(self.POSTGIS_LAYER_PREFIX):]) connInfo = uri.connectionInfo() (success, user, passwd) = QgsCredentials.instance().get(connInfo, None, None) if success: QgsCredentials.instance().put(connInfo, user, passwd) else: raise GeoAlgorithmExecutionException( "Couldn't connect to database") # fix_print_with_import print(uri.uri()) try: db = postgis.GeoDB(host=uri.host(), port=int(uri.port()), dbname=uri.database(), user=user, passwd=passwd) except postgis.DbError as e: raise GeoAlgorithmExecutionException( "Couldn't connect to database:\n%s" % e.message) def _runSQL(sql): try: db._exec_sql_and_commit(str(sql)) except postgis.DbError as e: raise GeoAlgorithmExecutionException( 'Error creating output PostGIS table:\n%s' % e.message) fields = [_toQgsField(f) for f in fields] fieldsdesc = ",".join( '%s %s' % (f.name(), TYPE_MAP_POSTGIS_LAYER.get(f.type(), "VARCHAR")) for f in fields) _runSQL("CREATE TABLE %s.%s (%s)" % (uri.schema(), uri.table().lower(), fieldsdesc)) if geometryType != QgsWkbTypes.NullGeometry: _runSQL( "SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)" .format(table=uri.table().lower(), schema=uri.schema(), srid=crs.authid().split(":")[-1], typmod=QgsWkbTypes.displayString( geometryType).upper())) self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres") self.writer = self.layer.dataProvider() elif self.destination.startswith(self.SPATIALITE_LAYER_PREFIX): self.isNotFileBased = True uri = QgsDataSourceUri( self.destination[len(self.SPATIALITE_LAYER_PREFIX):]) # fix_print_with_import print(uri.uri()) try: db = spatialite.GeoDB(uri=uri) except spatialite.DbError as e: raise GeoAlgorithmExecutionException( "Couldn't connect to database:\n%s" % e.message) def _runSQL(sql): try: db._exec_sql_and_commit(str(sql)) except spatialite.DbError as e: raise GeoAlgorithmExecutionException( 'Error creating output Spatialite table:\n%s' % str(e)) fields = [_toQgsField(f) for f in fields] fieldsdesc = ",".join( '%s %s' % (f.name(), TYPE_MAP_SPATIALITE_LAYER.get(f.type(), "VARCHAR")) for f in fields) _runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower()) _runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc)) if geometryType != QgsWkbTypes.NullGeometry: _runSQL( "SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)" .format(table=uri.table().lower(), srid=crs.authid().split(":")[-1], typmod=QgsWkbTypes.displayString( geometryType).upper())) self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite") self.writer = self.layer.dataProvider() else: formats = QgsVectorFileWriter.supportedFiltersAndFormats() OGRCodes = {} for (key, value) in list(formats.items()): extension = str(key) extension = extension[extension.find('*.') + 2:] extension = extension[:extension.find(' ')] OGRCodes[extension] = value OGRCodes['dbf'] = "DBF file" extension = self.destination[self.destination.rfind('.') + 1:] if extension not in OGRCodes: extension = 'shp' self.destination = self.destination + '.shp' if geometryType == QgsWkbTypes.NoGeometry: if extension == 'shp': extension = 'dbf' self.destination = self.destination[:self.destination. rfind('.')] + '.dbf' if extension not in self.nogeometry_extensions: raise GeoAlgorithmExecutionException( "Unsupported format for tables with no geometry") qgsfields = QgsFields() for field in fields: qgsfields.append(_toQgsField(field)) # use default dataset/layer options dataset_options = QgsVectorFileWriter.defaultDatasetOptions( OGRCodes[extension]) layer_options = QgsVectorFileWriter.defaultLayerOptions( OGRCodes[extension]) self.writer = QgsVectorFileWriter(self.destination, encoding, qgsfields, geometryType, crs, OGRCodes[extension], dataset_options, layer_options)
def spatialInfo(self): ret = [] if not self.table.geomType: return ret tbl = [(QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn), (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType), (QApplication.translate("DBManagerPlugin", "Qgis Geometry type:"), QgsWkbTypes.displayString(self.table.wkbType))] # only if we have info from geometry_columns if self.table.geomDim: tbl.append( (QApplication.translate("DBManagerPlugin", "Dimension:"), self.table.geomDim)) srid = self.table.srid if self.table.srid else -1 if srid != -1: sr_info = (self.table.database().connector.getSpatialRefInfo(srid)) else: sr_info = QApplication.translate("DBManagerPlugin", "Undefined") if sr_info: tbl.append((QApplication.translate("DBManagerPlugin", "Spatial ref:"), u"{0} ({1})".format(sr_info, srid))) # estimated extent if not self.table.estimatedExtent: # estimated extent information is not displayed yet, so just block # table signals to avoid double refreshing # (infoViewer->refreshEstimatedExtent->tableChanged->infoViewer) self.table.blockSignals(True) self.table.refreshTableEstimatedExtent() self.table.blockSignals(False) if self.table.estimatedExtent: estimated_extent_str = (u"{:.9f}, {:.9f} - {:.9f}, " u"{:.9f}".format( *self.table.estimatedExtent)) tbl.append((QApplication.translate("DBManagerPlugin", "Estimated extent:"), estimated_extent_str)) # extent extent_str = None if self.table.extent and len(self.table.extent) == 4: extent_str = (u"{:.9f}, {:.9f} - {:.9f}, " u"{:.9f}".format(*self.table.extent)) elif self.table.rowCount > 0 or self.table.estimatedRowCount > 0: # Can't calculate an extent on empty layer extent_str = QApplication.translate( "DBManagerPlugin", '(unknown) (<a href="action:extent/get">find out</a>)') if extent_str: tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str)) ret.append(HtmlTable(tbl)) # Handle extent update metadata if (self.table.extent and self.table.extent != self.table.estimatedExtent and self.table.canUpdateMetadata()): ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", (u'<warning> Metadata extent is different from' u'real extent. You should <a href="action:extent' u'/update">update it</a>!')))) # is there an entry in geometry_columns? if self.table.geomType.lower() == 'geometry': ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", "<warning> There is no entry in geometry_columns!"))) # find out whether the geometry column has spatial index on it if not self.table.isView: if not self.table.hasSpatialIndex(): ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", (u'<warning> No spatial index defined (<a href=' u'"action:spatialindex/create">' u'create it</a>).')))) return ret
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'PointZ (1 2 3)' self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer_from_shp = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))
# Pegando o nome da camada nome = subLayer.split('!!::!!')[1] print('Nome da Camada =', nome) uri = f"{full_path}|layername={nome}" subCamada = QgsVectorLayer(uri, nome, "ogr") # Quantidade de Feições qt_feicoes = subCamada.featureCount() print(f'Quantidade de feições: {qt_feicoes}') # Quantos campos qtd_campos = len(subCamada.fields()) print(f"Quantidade de campos = {qtd_campos}") # Tipo de geometria tp_geometria = QgsWkbTypes.displayString(subCamada.wkbType()) print(f"Geometria = {tp_geometria}") # SRC subSrc = subCamada.crs().authid() print(f"SRC = {subSrc}") metadado += f"\n\nNome Camada: {nome}" metadado += "\nTotal de Feições: {0}".format(qt_feicoes) metadado += "\nQuantidade de Campos: %d" % (qtd_campos) metadado += f"\nGeometria: {tp_geometria}" metadado += f"\nSRC: {subSrc}" else: print('Seu caminho tem algo errado!!!') nomeMetadado = arquivoFisico.split('.')[0] + "_METADADOS.txt"
def layerToTTLString(self, layer, urilist=None, classurilist=None, includelist=None, proptypelist=None, valuemappings=None, valuequeries=None): fieldnames = [field.name() for field in layer.fields()] ttlstring = "<http://www.opengis.net/ont/geosparql#Feature> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#SpatialObject> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#Geometry> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#hasGeometry> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#asWKT> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#Feature> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#SpatialObject> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#Geometry> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#SpatialObject> .\n" first = 0 if self.exportNameSpace == None or self.exportNameSpace == "": namespace = "http://www.github.com/sparqlunicorn#" else: namespace = self.exportNameSpace if self.exportIdCol == "": idcol = "id" else: idcol = self.exportIdCol classcol = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" curid = "" if self.exportSetClass == None or self.exportSetClass == "": curclassid = namespace + str(uuid.uuid4()) elif self.exportSetClass.startswith("http"): curclassid = self.exportSetClass else: curclassid = urllib.parse.quote(self.exportSetClass) for f in layer.getFeatures(): geom = f.geometry() if not idcol in fieldnames: curid = namespace + str(uuid.uuid4()) elif not str(f[idcol]).startswith("http"): curid = namespace + str(f[idcol]) else: curid = f[idcol] if not classcol in fieldnames: ttlstring += "<" + str( curid ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <" + curclassid + "> .\n" if first == 0: ttlstring += "<" + str( curclassid ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Feature> .\n" ttlstring += "<" + str( curclassid ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<" + str( curid ) + "> <http://www.opengis.net/ont/geosparql#hasGeometry> <" + curid + "_geom> .\n" ttlstring += "<" + str( curid ) + "_geom> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString( geom.wkbType()) + "> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString( geom.wkbType() ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString( geom.wkbType() ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Geometry> .\n" ttlstring += "<" + str( curid ) + "_geom> <http://www.opengis.net/ont/geosparql#asWKT> \"" + geom.asWkt( ) + "\"^^<http://www.opengis.net/ont/geosparql#wktLiteral> .\n" fieldcounter = -1 for propp in fieldnames: fieldcounter += 1 #if fieldcounter>=len(fieldnames): # fieldcounter=0 if includelist != None and fieldcounter < len( includelist) and includelist[fieldcounter] == False: continue prop = propp print(str(fieldcounter)) print(str(urilist) + "\n") print(str(classurilist) + "\n") print(str(includelist) + "\n") if urilist != None and urilist[fieldcounter] != "": print(urilist) if not urilist[fieldcounter].startswith("http"): print("Does not start with http") prop = urllib.parse.quote(urilist[fieldcounter]) else: prop = urilist[fieldcounter] print("New Prop from list: " + str(prop)) if prop == "id": continue if not prop.startswith("http"): prop = namespace + prop if prop == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" and "http" in str( f[propp]): ttlstring += "<" + str(f[propp]) + "> <" + str( prop) + "> <http://www.w3.org/2002/07/owl#Class> .\n" ttlstring += "<" + str( f[propp] ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Feature> .\n" #elif urilist!=None and fieldcounter<len(urilist) and urilist[fieldcounter]!="": # ttlstring+="<"+curid+"> <"+prop+"> <"+str(f[propp])+"> .\n" # if first<10: # ttlstring+="<"+prop+"> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n" # ttlstring+="<"+prop+"> <http://www.w3.org/2000/01/rdf-schema#domain> <"+curclassid+"> .\n" # if classurilist[fieldcounter]!="": # ttlstring+="<"+prop+"> <http://www.w3.org/2000/01/rdf-schema#range> <"+classurilist[fieldcounter]+"> .\n" elif prop == "http://www.w3.org/2000/01/rdf-schema#label" or prop == "http://www.w3.org/2000/01/rdf-schema#comment" or ( proptypelist != None and proptypelist[fieldcounter] == "AnnotationProperty"): ttlstring += "<" + curid + "> <" + prop + "> \"" + str( f[propp]).replace( '"', '\\"' ) + "\"^^<http://www.w3.org/2001/XMLSchema#string> .\n" if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#AnnotationProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" elif not f[propp] or f[propp] == None or f[propp] == "": continue elif proptypelist != None and proptypelist[ fieldcounter] == "SubClass": ttlstring += "<" + curid + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <" + str( f[propp]) + "> .\n" ttlstring += "<" + curid + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <" + curclassid + "> .\n" if first < 10: ttlstring += "<" + str( f[propp] ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n" elif valuequeries != None and propp in valuequeries: ttlstring += "" sparql = SPARQLWrapper( valuequeries[propp][1], agent= "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" ) sparql.setQuery("".join(self.prefixes[endpointIndex]) + valuequeries[propp][0].replace( "%%" + propp + "%%", "\"" + str(f[propp]) + "\"")) sparql.setMethod(POST) sparql.setReturnFormat(JSON) results = sparql.query().convert() ttlstring += "<" + curid + "> <" + prop + "> <" + results[ "results"]["bindings"][0]["item"]["value"] + "> ." if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" if classurilist[fieldcounter] != "": ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[ fieldcounter] + "> .\n" elif valuemappings != None and propp in valuemappings and f[ propp] in self.valuemappings[propp]: ttlstring += "<" + curid + "> <" + prop + "> <" + str( self.valuemappings[propp][f[propp]]) + "> .\n" if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" if classurilist[fieldcounter] != "": ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[ fieldcounter] + "> .\n" elif "http" in str(f[propp]) or (proptypelist != None and proptypelist[fieldcounter] == "ObjectProperty"): ttlstring += "<" + curid + "> <" + prop + "> <" + str( f[propp]) + "> .\n" if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" if classurilist != None and fieldcounter < len( classurilist ) and classurilist[fieldcounter] != "": ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[ fieldcounter] + "> .\n" elif re.match(r'^-?\d+$', str(f[propp])): ttlstring += "<" + curid + "> <" + prop + "> \"" + str( f[propp] ) + "\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n" if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#integer> .\n" elif re.match(r'^-?\d+(?:\.\d+)?$', str(f[propp])): ttlstring += "<" + curid + "> <" + prop + "> \"" + str( f[propp] ) + "\"^^<http://www.w3.org/2001/XMLSchema#double> .\n" if first: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#double> .\n" else: ttlstring += "<" + curid + "> <" + prop + "> \"" + str( f[propp]).replace( '"', '\\"' ) + "\"^^<http://www.w3.org/2001/XMLSchema#string> .\n" if first < 10: ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n" ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#string> .\n" if first < 10: first = first + 1 return ttlstring
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'PointZ (1 2 3)' self.assertTrue(compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer_from_shp = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() self.assertTrue(compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))
def processAlgorithm(self, parameters, context, feedback): # parameters # Database connection parameters connection_name = QgsExpressionContextUtils.globalScope().variable( 'gobs_connection_name') spatiallayer = self.SPATIALLAYERS[parameters[self.SPATIALLAYER]] sourcelayer = self.parameterAsVectorLayer(parameters, self.SOURCELAYER, context) uniqueid = self.parameterAsString(parameters, self.UNIQUEID, context) uniquelabel = self.parameterAsString(parameters, self.UNIQUELABEL, context) msg = '' status = 1 # Get chosen spatial layer id id_spatial_layer = spatiallayer.split('-')[-1].strip() feedback.pushInfo( tr('CHECK COMPATIBILITY BETWEEN SOURCE AND TARGET GEOMETRY TYPES')) # Get spatial layer geometry type sql = ''' SELECT sl_geometry_type FROM gobs.spatial_layer WHERE id = {0} LIMIT 1 '''.format(id_spatial_layer) target_type = None [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if not ok: status = 0 msg = tr('* The following error has been raised' ) + ' %s' % error_message feedback.reportError(msg) raise QgsProcessingException(msg) else: for line in data: target_type = line[0].lower() # Check multi type target_is_multi = target_type.startswith('multi') # Get vector layer geometry type # And compare it with the spatial_layer type source_type = QgsWkbTypes.geometryDisplayString( int(sourcelayer.geometryType())).lower() source_wtype = QgsWkbTypes.displayString(int( sourcelayer.wkbType())).lower() ok = True if not target_type.endswith(source_type): ok = False msg = tr( 'Source vector layer and target spatial layer do not have compatible geometry types' ) msg += ' - SOURCE: {}, TARGET: {}'.format(source_type, target_type) feedback.pushInfo(msg) raise QgsProcessingException(msg) source_is_multi = source_wtype.startswith('multi') # Cannot import multi type into single type target spatial layer if source_is_multi and not target_is_multi: ok = False msg = tr( 'Cannot import a vector layer with multi geometries into a target spatial layer with a simple geometry type defined' ) msg += ' - SOURCE: {}, TARGET: {}'.format(source_wtype, target_type) feedback.pushInfo(msg) raise QgsProcessingException(msg) # Import data to temporary table feedback.pushInfo(tr('IMPORT SOURCE LAYER INTO TEMPORARY TABLE')) temp_schema = 'public' temp_table = 'temp_' + str(time.time()).replace('.', '') processing.run("qgis:importintopostgis", { 'INPUT': parameters[self.SOURCELAYER], 'DATABASE': connection_name, 'SCHEMA': temp_schema, 'TABLENAME': temp_table, 'PRIMARY_KEY': 'gobs_id', 'GEOMETRY_COLUMN': 'geom', 'ENCODING': 'UTF-8', 'OVERWRITE': True, 'CREATEINDEX': False, 'LOWERCASE_NAMES': False, 'DROP_STRING_LENGTH': True, 'FORCE_SINGLEPART': False }, context=context, feedback=feedback) feedback.pushInfo( tr('* Source layer has been imported into temporary table')) # Add ST_Multi if needed st_multi_left = '' st_multi_right = '' if target_is_multi: st_multi_left = 'ST_Multi(' st_multi_right = ')' # Get target geometry type in integer geometry_type_integer = 1 if target_type.replace('multi', '') == 'linestring': geometry_type_integer = 2 if target_type.replace('multi', '') == 'polygon': geometry_type_integer = 3 # Copy data to spatial_object feedback.pushInfo(tr('COPY IMPORTED DATA TO spatial_object')) sql = ''' INSERT INTO gobs.spatial_object (so_unique_id, so_unique_label, geom, fk_id_spatial_layer) SELECT "{so_unique_id}", "{so_unique_label}", {st_multi_left}ST_Transform(ST_CollectionExtract(ST_MakeValid(geom),{geometry_type_integer}), 4326){st_multi_right} AS geom, {id_spatial_layer} FROM "{temp_schema}"."{temp_table}" -- Update line if data already exists ON CONFLICT ON CONSTRAINT spatial_object_so_unique_id_fk_id_spatial_layer_key DO UPDATE SET (geom, so_unique_label) = (EXCLUDED.geom, EXCLUDED.so_unique_label) WHERE True ; '''.format(so_unique_id=uniqueid, so_unique_label=uniquelabel, st_multi_left=st_multi_left, geometry_type_integer=geometry_type_integer, st_multi_right=st_multi_right, id_spatial_layer=id_spatial_layer, temp_schema=temp_schema, temp_table=temp_table) feedback.pushInfo(sql) try: [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if not ok: status = 0 msg = tr('* The following error has been raised' ) + ' %s' % error_message feedback.reportError(msg) else: status = 1 msg = tr('* Source data has been successfully imported !') feedback.pushInfo(msg) except Exception as e: status = 0 msg = tr( '* An unknown error occured while adding features to spatial_object table' ) msg += ' ' + str(e) finally: # Remove temporary table feedback.pushInfo(tr('DROP TEMPORARY DATA')) sql = ''' DROP TABLE IF EXISTS "%s"."%s" ; ''' % (temp_schema, temp_table) [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if ok: feedback.pushInfo(tr('* Temporary data has been deleted.')) else: feedback.reportError( tr('* An error occured while droping temporary table') + ' "%s"."%s"' % (temp_schema, temp_table)) msg = tr('SPATIAL LAYER HAS BEEN SUCCESSFULLY IMPORTED !') return {self.OUTPUT_STATUS: status, self.OUTPUT_STRING: msg}
def processAlgorithm(self, parameters, context, feedback): # parameters # Database connection parameters connection_name = QgsExpressionContextUtils.projectScope( context.project()).variable('gobs_connection_name') if not connection_name: connection_name = os.environ.get("GOBS_CONNECTION_NAME") spatiallayer = self.SPATIALLAYERS[parameters[self.SPATIALLAYER]] sourcelayer = self.parameterAsVectorLayer(parameters, self.SOURCELAYER, context) uniqueid = self.parameterAsString(parameters, self.UNIQUEID, context) uniquelabel = self.parameterAsString(parameters, self.UNIQUELABEL, context) date_validity_min = self.parameterAsString(parameters, self.DATE_VALIDITY_MIN, context) manual_date_validity_min = self.parameterAsString( parameters, self.MANUAL_DATE_VALIDITY_MIN, context) date_validity_max = self.parameterAsString(parameters, self.DATE_VALIDITY_MAX, context) manual_date_validity_max = self.parameterAsString( parameters, self.MANUAL_DATE_VALIDITY_MAX, context) msg = '' status = 1 # Get chosen spatial layer id id_spatial_layer = spatiallayer.split('-')[-1].strip() feedback.pushInfo( tr('CHECK COMPATIBILITY BETWEEN SOURCE AND TARGET GEOMETRY TYPES')) # Get spatial layer geometry type sql = ''' SELECT sl_geometry_type FROM gobs.spatial_layer WHERE id = {0} LIMIT 1 '''.format(id_spatial_layer) target_type = None [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if not ok: status = 0 msg = tr('* The following error has been raised' ) + ' %s' % error_message feedback.reportError(msg) raise QgsProcessingException(msg) else: for line in data: target_type = line[0].lower() # Check multi type target_is_multi = target_type.startswith('multi') # Get vector layer geometry type # And compare it with the spatial_layer type source_type = QgsWkbTypes.geometryDisplayString( int(sourcelayer.geometryType())).lower() source_wtype = QgsWkbTypes.displayString(int( sourcelayer.wkbType())).lower() ok = True if not target_type.endswith(source_type): ok = False msg = tr( 'Source vector layer and target spatial layer do not have compatible geometry types' ) msg += ' - SOURCE: {}, TARGET: {}'.format(source_type, target_type) feedback.pushInfo(msg) raise QgsProcessingException(msg) source_is_multi = source_wtype.startswith('multi') # Cannot import multi type into single type target spatial layer if source_is_multi and not target_is_multi: ok = False msg = tr( 'Cannot import a vector layer with multi geometries into a target spatial layer with a simple geometry type defined' ) msg += ' - SOURCE: {}, TARGET: {}'.format(source_wtype, target_type) feedback.pushInfo(msg) raise QgsProcessingException(msg) # Import data to temporary table feedback.pushInfo(tr('IMPORT SOURCE LAYER INTO TEMPORARY TABLE')) temp_schema = 'public' temp_table = 'temp_' + str(time.time()).replace('.', '') processing.run("qgis:importintopostgis", { 'INPUT': parameters[self.SOURCELAYER], 'DATABASE': connection_name, 'SCHEMA': temp_schema, 'TABLENAME': temp_table, 'PRIMARY_KEY': 'gobs_id', 'GEOMETRY_COLUMN': 'geom', 'ENCODING': 'UTF-8', 'OVERWRITE': True, 'CREATEINDEX': False, 'LOWERCASE_NAMES': False, 'DROP_STRING_LENGTH': True, 'FORCE_SINGLEPART': False }, context=context, feedback=feedback) feedback.pushInfo( tr('* Source layer has been imported into temporary table')) # Add ST_Multi if needed st_multi_left = '' st_multi_right = '' if target_is_multi: st_multi_left = 'ST_Multi(' st_multi_right = ')' # Get target geometry type in integer geometry_type_integer = 1 if target_type.replace('multi', '') == 'linestring': geometry_type_integer = 2 if target_type.replace('multi', '') == 'polygon': geometry_type_integer = 3 # Format validity timestamp fields if manual_date_validity_min.strip(): manualdate = manual_date_validity_min.strip().replace('/', '-') casted_timestamp_min = ''' '{0}'::timestamp '''.format(manualdate) else: casted_timestamp_min = ''' s."{0}"::timestamp '''.format(date_validity_min) has_max_validity = False if manual_date_validity_max.strip() or date_validity_max: has_max_validity = True if manual_date_validity_max.strip(): manualdate = manual_date_validity_max.strip().replace('/', '-') casted_timestamp_max = ''' '{0}'::timestamp '''.format(manualdate) else: casted_timestamp_max = ''' s."{0}"::timestamp '''.format(date_validity_max) # Copy data to spatial_object feedback.pushInfo(tr('COPY IMPORTED DATA TO spatial_object')) sql = ''' INSERT INTO gobs.spatial_object ( so_unique_id, so_unique_label, geom, fk_id_spatial_layer, so_valid_from ''' if has_max_validity: sql += ', so_valid_to' sql += ''' ) SELECT "{so_unique_id}", "{so_unique_label}", {st_multi_left}ST_Transform(ST_CollectionExtract(ST_MakeValid(geom),{geometry_type_integer}), 4326){st_multi_right} AS geom, {id_spatial_layer}, {casted_timestamp_min} '''.format(so_unique_id=uniqueid, so_unique_label=uniquelabel, st_multi_left=st_multi_left, geometry_type_integer=geometry_type_integer, st_multi_right=st_multi_right, id_spatial_layer=id_spatial_layer, casted_timestamp_min=casted_timestamp_min) if has_max_validity: sql += ', {casted_timestamp_max}'.format( casted_timestamp_max=casted_timestamp_max) sql += ''' FROM "{temp_schema}"."{temp_table}" AS s -- Update line if data already exists -- i.e. Same external ids for the same layer and the same start validity date -- so_unique_id, fk_id_spatial_layer AND so_valid_from are the same -- This is considered as the same object as the one already in database -- We update the geometry, label, and end date of validity ON CONFLICT ON CONSTRAINT spatial_object_unique_key DO UPDATE SET (geom, so_unique_label, so_valid_to) = (EXCLUDED.geom, EXCLUDED.so_unique_label, EXCLUDED.so_valid_to) WHERE True ; '''.format(temp_schema=temp_schema, temp_table=temp_table) try: [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if not ok: status = 0 msg = tr('* The following error has been raised' ) + ' %s' % error_message feedback.reportError(msg) feedback.pushInfo(sql) else: status = 1 msg = tr('* Source data has been successfully imported !') feedback.pushInfo(msg) except Exception as e: status = 0 msg = tr( '* An unknown error occured while adding features to spatial_object table' ) msg += ' ' + str(e) # Check there is no issues with related observation data # For each series related to the chosen spatial layer # SELECT gobs.find_observation_with_wrong_spatial_object({fk_id_series}) # v1/ Only check and display warning # v2/ Check and try to update with gobs.update_observations_with_wrong_spatial_objects # v3/ Find orphans # Remove temporary table feedback.pushInfo(tr('DROP TEMPORARY DATA')) sql = ''' DROP TABLE IF EXISTS "%s"."%s" ; ''' % (temp_schema, temp_table) [header, data, rowCount, ok, error_message] = fetchDataFromSqlQuery(connection_name, sql) if ok: feedback.pushInfo(tr('* Temporary data has been deleted.')) else: feedback.reportError( tr('* An error occured while droping temporary table') + ' "%s"."%s"' % (temp_schema, temp_table)) msg = tr('SPATIAL LAYER HAS BEEN SUCCESSFULLY IMPORTED !') return {self.OUTPUT_STATUS: status, self.OUTPUT_STRING: msg}
nome = subLayer.split("!!::!!")[1] print("Nome da layer =", nome) uri = "%s|layername=%s" % ( full_path, nome ) # Se o python for 3.6 + pode-se usar f"{full_path}|layername={nome}" # Cria Camada sub_vlayer = QgsVectorLayer(uri, nome, 'ogr') # quantas feicoes print("Total de feições =", sub_vlayer.featureCount()) # Quantidade de Campos qtd_campos = len(sub_vlayer.fields()) print("Quantidade de campos =", qtd_campos) # qual geometria geometria = QgsWkbTypes.displayString(sub_vlayer.wkbType()) print("Geometria =", geometria) # como pegar geometria print(sub_vlayer.wkbType()) # consulta crs print("SRC =", sub_vlayer.crs().authid(), "\n\n") # Montando Metadado metadado += f"""\n\nCamada = {nome}""" metadado += f"""\nTotal de feições = {sub_vlayer.featureCount()}""" metadado += f"""\nQuantidade de campos = {qtd_campos}""" metadado += f"""\nGeometria = {geometria}""" metadado += f"""\nSRC = {sub_vlayer.crs().authid()}""" else: print("nao deu")
def write_csv(self, out_directory): msg = f"writing csv..." logger.debug(msg) QgsMessageLog.logMessage(msg, "fmsf2hms") start = datetime.now() def parse_datestring(value, siteid): clean = ''.join(n for n in value if n.isdigit() or n in ['-', '/', '\\']) clean = clean.rstrip("-") if clean.rstrip() == "": return "" if len(clean) == 4: return "{}-01-01".format(clean) elif len(clean) > 4: try: d = parse(clean) return d.strftime("%Y-%m-%d") except Exception as e: msg = f"Unexpected date value (1) in {siteid}: {clean}" logger.debug(msg) logger.debug(e) QgsMessageLog.logMessage(msg, "fmsf2hms") QgsMessageLog.logMessage(e, "fmsf2hms") return "" else: msg = f"Unexpected date value (2) in {siteid}: {clean}" logger.debug(msg) QgsMessageLog.logMessage(msg, "fmsf2hms") return "" def sanitize_attributes(attributes, fields): field_info = {i.name(): i.typeName() for i in fields} siteid = attributes[self.siteid_index] row = list() fields_to_concat = [] concat_vals = {} for k, v in self.configs['concat_fields'].items(): concat_vals[k] = [] fields_to_concat += v for index, attr in enumerate(attributes): fname = list(field_info.keys())[index] if str(attr) == "NULL": value = "" else: value = str(attr) if value == "Unspecified by surveyor": value = "Unspecified by Surveyor" if fname in self.configs['date_fields']: if field_info[fname] == "date" and value != "": value = attr.toString("yyyy-MM-dd") else: value = parse_datestring(value, siteid) if fname not in fields_to_concat: row.append(value) continue for k, v in self.configs['concat_fields'].items(): if fname in v and not value == "": concat_vals[k].append(value) new_concat = list(self.configs['concat_fields'].keys()) new_concat.sort() for nc in new_concat: trans_cat = list() for i in concat_vals[nc]: if "," in i: trans_cat.append(f'"{i}"') else: trans_cat.append(i) row.append(",".join(trans_cat)) return row field_names = self.in_layer.fields().names() fields = ['ResourceID', 'geom'] + field_names concat_fields = list() for new, orig in self.configs['concat_fields'].items(): concat_fields.append(new) fields = [i for i in fields if i not in orig] concat_fields.sort() fields += concat_fields out_path = os.path.join(out_directory, self.configs['out_file_name']) with open(out_path, "w", newline="") as outcsv: writer = csv.writer(outcsv) writer.writerow(fields) for feature in self.in_layer.getFeatures(): id = str(uuid.uuid4()) wkt_geom = feature.geometry().asWkt(precision=9) featrow = sanitize_attributes(feature.attributes(), self.in_layer.fields()) outrow = [id, wkt_geom] + featrow writer.writerow(outrow) g = QgsWkbTypes.displayString(self.in_layer.wkbType()) geoms = { "Point": "point", "MultiPoint": "point", "Polygon": "polygon", "MultiPolygon": "polygon", } load_uri = "file:///" + out_path + "?type=csv&wktField=geom&crs=EPSG:4326&geomType=" + geoms[ g] csv_layer = QgsVectorLayer(load_uri, self.configs['layer_name'], "delimitedtext") QgsProject.instance().addMapLayer(csv_layer) msg = f" - done in {datetime.now() - start}." logger.debug(msg) QgsMessageLog.logMessage(msg, "fmsf2hms") return os.path.abspath(out_path)
def run(self): try: # Check if the layers look OK if self.inpvl is None or self.joinvl is None: self.status.emit('Layer is missing!') self.finished.emit(False, None) return # Check if there are features in the layers incount = 0 if self.selectedinonly: incount = self.inpvl.selectedFeatureCount() else: incount = self.inpvl.featureCount() if incount == 0: self.status.emit('Input layer has no features!') self.finished.emit(False, None) return joincount = 0 if self.selectedjoonly: joincount = self.joinvl.selectedFeatureCount() else: joincount = self.joinvl.featureCount() if joincount == 0: self.status.emit('Join layer has no features!') self.finished.emit(False, None) return # Get the wkbtype of the layers self.inpWkbType = self.inpvl.wkbType() self.joinWkbType = self.joinvl.wkbType() # Check if the input layer does not have geometries if (self.inpvl.geometryType() == QgsWkbTypes.NullGeometry): self.status.emit('No geometries in the input layer!') self.finished.emit(False, None) return # Check if the join layer does not have geometries if (self.joinvl.geometryType() == QgsWkbTypes.NullGeometry): self.status.emit('No geometries in the join layer!') self.finished.emit(False, None) return # Set the geometry type and prepare the output layer inpWkbTypetext = QgsWkbTypes.displayString(int(self.inpWkbType)) # self.inputmulti = QgsWkbTypes.isMultiType(self.inpWkbType) # self.status.emit('wkbtype: ' + inpWkbTypetext) # geometryType = self.inpvl.geometryType() # geometrytypetext = 'Point' # if geometryType == QgsWkbTypes.PointGeometry: # geometrytypetext = 'Point' # elif geometryType == QgsWkbTypes.LineGeometry: # geometrytypetext = 'LineString' # elif geometryType == QgsWkbTypes.PolygonGeometry: # geometrytypetext = 'Polygon' # if self.inputmulti: # geometrytypetext = 'Multi' + geometrytypetext # geomttext = geometrytypetext geomttext = inpWkbTypetext # Set the coordinate reference system to the input # layer's CRS using authid (proj4 may be more robust) if self.inpvl.crs() is not None: geomttext = (geomttext + "?crs=" + str(self.inpvl.crs().authid())) # Retrieve the fields from the input layer outfields = self.inpvl.fields().toList() # Retrieve the fields from the join layer if self.joinvl.fields() is not None: jfields = self.joinvl.fields().toList() for joinfield in jfields: outfields.append( QgsField(self.joinprefix + str(joinfield.name()), joinfield.type())) else: self.status.emit('Unable to get any join layer fields') # Add the nearest neighbour distance field # Check if there is already a "distance" field # (should be avoided in the user interface) # Try a new name if there is a collission collission = True trynumber = 1 distnameorg = self.distancename while collission: # Iterate until there are no collissions collission = False for field in outfields: # This check should not be necessary - handled in the UI if field.name() == self.distancename: self.status.emit( 'Distance field already exists - renaming!') # self.abort = True # self.finished.emit(False, None) # break collission = True self.distancename = distnameorg + str(trynumber) trynumber = trynumber + 1 outfields.append(QgsField(self.distancename, QVariant.Double)) # Create a memory layer using a CRS description self.mem_joinl = QgsVectorLayer(geomttext, self.outputlayername, "memory") # Set the CRS to the inputlayer's CRS self.mem_joinl.setCrs(self.inpvl.crs()) self.mem_joinl.startEditing() # Add the fields for field in outfields: self.mem_joinl.dataProvider().addAttributes([field]) # For an index to be used, the input layer has to be a # point layer, or the input layer geometries have to be # approximated to centroids, or the user has to have # accepted that a join layer index is used (for # non-point input layers). # (Could be extended to multipoint) if (self.inpWkbType == QgsWkbTypes.Point or self.inpWkbType == QgsWkbTypes.Point25D or self.approximateinputgeom or self.nonpointexactindex): # Number of features in the join layer - used by # calculate_progress for the index creation if self.selectedjoonly: self.feature_count = self.joinvl.selectedFeatureCount() else: self.feature_count = self.joinvl.featureCount() # Create a spatial index to speed up joining self.status.emit('Creating join layer index...') # The number of elements that is needed to increment the # progressbar - set early in run() self.increment = self.feature_count // 1000 self.joinlind = QgsSpatialIndex() # Include geometries to enable exact distance calculations # self.joinlind = QgsSpatialIndex(flags=[QgsSpatialIndex.FlagStoreFeatureGeometries]) if self.selectedjoonly: for feat in self.joinvl.getSelectedFeatures(): # Allow user abort if self.abort is True: break self.joinlind.insertFeature(feat) self.calculate_progress() else: for feat in self.joinvl.getFeatures(): # Allow user abort if self.abort is True: break self.joinlind.insertFeature(feat) self.calculate_progress() self.status.emit('Join layer index created!') self.processed = 0 self.percentage = 0 # self.calculate_progress() # Is the join layer a multi-geometry layer? # self.joinmulti = QgsWkbTypes.isMultiType(self.joinWkbType) # Does the join layer contain multi geometries? # Try to check the first feature # This is not used for anything yet self.joinmulti = False if self.selectedjoonly: feats = self.joinvl.getSelectedFeatures() else: feats = self.joinvl.getFeatures() if feats is not None: testfeature = next(feats) feats.rewind() feats.close() if testfeature is not None: if testfeature.hasGeometry(): if testfeature.geometry().isMultipart(): self.joinmulti = True # Prepare for the join by fetching the layers into memory # Add the input features to a list self.inputf = [] if self.selectedinonly: for f in self.inpvl.getSelectedFeatures(): self.inputf.append(f) else: for f in self.inpvl.getFeatures(): self.inputf.append(f) # Add the join features to a list (used in the join) self.joinf = [] if self.selectedjoonly: for f in self.joinvl.getSelectedFeatures(): self.joinf.append(f) else: for f in self.joinvl.getFeatures(): self.joinf.append(f) # Initialise the global variable that will contain the # result of the nearest neighbour spatial join (list of # features) self.features = [] # Do the join! # Number of features in the input layer - used by # calculate_progress for the join operation if self.selectedinonly: self.feature_count = self.inpvl.selectedFeatureCount() else: self.feature_count = self.inpvl.featureCount() # The number of elements that is needed to increment the # progressbar - set early in run() self.increment = self.feature_count // 1000 # Using the original features from the input layer for feat in self.inputf: # Allow user abort if self.abort is True: break self.do_indexjoin(feat) self.calculate_progress() self.mem_joinl.dataProvider().addFeatures(self.features) self.status.emit('Join finished') except: import traceback self.error.emit(traceback.format_exc()) self.finished.emit(False, None) if self.mem_joinl is not None: self.mem_joinl.rollBack() else: self.mem_joinl.commitChanges() if self.abort: self.finished.emit(False, None) else: self.status.emit('Delivering the memory layer...') self.finished.emit(True, self.mem_joinl)
def cloneToMemory(self): curlayer = self.iface.mapCanvas().currentLayer() selectedFeatCount = curlayer.selectedFeatureCount() geo = QgsWkbTypes.displayString( curlayer.wkbType()) # wkbType string name of geometry targetLayer = QgsVectorLayer(geo, self.dlg.lineEdit_2.text(), "memory") targetLayer.setCrs(curlayer.sourceCrs()) QgsProject.instance().addMapLayer(targetLayer, False) root = QgsProject.instance().layerTreeRoot() self.setStyleLayer(targetLayer) if self.dlg.checkBoxAtrib.isChecked(): #copy attributes curlayer_attribute_list = curlayer.fields().toList() targetLayer_attribute_list = [] targetLayerpr = targetLayer.dataProvider() for attrib in curlayer_attribute_list: if targetLayer.fields().lookupField(attrib.name()) == -1: targetLayer_attribute_list.append( QgsField(attrib.name(), attrib.type())) with edit(targetLayer): for attr in targetLayer_attribute_list: if attr.type( ) == 1: # иначе игнорируется поле с типом 1 (bool) attr = QgsField( attr.name(), QVariant.String) # конвертируем bool в string res_add = targetLayer.addAttribute(attr) if not res_add: print(u'Не создано поле {}'.format(attr.name())) targetLayer.updateFields() # for feat in curlayer.selectedFeatures(): # not work more # targetLayer.dataProvider().addFeatures([feat]) # not work more # ИЗ МОДУЛЯ Apend Features To layer ----------------------------------------------- # В старом варианте в QGIS3 при добавлении объектов с отличающимся набором аттрибутов # происходила задержка с выводом сообщений в логи. Что затягивало процесс. mapping = dict() for target_idx in targetLayer.fields().allAttributesList(): target_field = targetLayer.fields().field(target_idx) source_idx = curlayer.fields().indexOf(target_field.name()) if source_idx != -1: mapping[target_idx] = source_idx features = curlayer.selectedFeatures() destType = targetLayer.geometryType() destIsMulti = QgsWkbTypes.isMultiType(targetLayer.wkbType()) new_features = [] for current, in_feature in enumerate(features): attrs = { target_idx: in_feature[source_idx] for target_idx, source_idx in mapping.items() } geom = QgsGeometry() if in_feature.hasGeometry() and targetLayer.isSpatial(): # Convert geometry to match destination layer # Adapted from QGIS qgisapp.cpp, pasteFromClipboard() geom = in_feature.geometry() if destType != QgsWkbTypes.UnknownGeometry: newGeometry = geom.convertToType(destType, destIsMulti) if newGeometry.isNull(): continue geom = newGeometry # Avoid intersection if enabled in digitize settings geom.avoidIntersections( QgsProject.instance().avoidIntersectionsLayers()) new_feature = QgsVectorLayerUtils().createFeature( targetLayer, geom, attrs) new_features.append(new_feature) with edit(targetLayer): res = targetLayer.addFeatures(new_features) # ИЗ МОДУЛЯ Apend Features To layer -----------------------------------------------end root.insertLayer(0, targetLayer) self.iface.messageBar().clearWidgets() self.iface.setActiveLayer(targetLayer) curlayer.selectByIds([]) if res: self.iface.messageBar().pushMessage( u"Выполнено", u"Склонировано {0}/{1} объектов".format( len(new_features), selectedFeatCount), duration=5, level=0)
def response_data_mode(self, request, export_features=False): """ Query layer and return data :param request: DjangoREST API request object :param formatter: Boolean, default False, True for to use QgsJsonExport.exportFeatures method :return: response dict data """ # Create the QGIS feature request, it will be passed through filters # and to the final QGIS API get features call. qgis_feature_request = QgsFeatureRequest() # Prepare arguments for the get feature call kwargs = {} # Apply filter backends, store original subset string original_subset_string = self.metadata_layer.qgis_layer.subsetString() if hasattr(self, 'filter_backends'): for backend in self.filter_backends: backend().apply_filter(request, self.metadata_layer.qgis_layer, qgis_feature_request, self) # Paging cannot be a backend filter if 'page' in request.query_params: kwargs['page'] = request.query_params.get('page') kwargs['page_size'] = request.query_params.get('page_size', 10) self.features = get_qgis_features( self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs) ex = QgsJsonExporter(self.metadata_layer.qgis_layer) # If 'unique' request params is set, # api return a list of unique # field name sent with 'unique' param. # -------------------------------------- # IDEA: for big data it'll be iterate over features to get unique # c++ iteration is fast. Instead memory layer fith to much features can be a problem. if 'unique' in request.query_params: vl = QgsVectorLayer(QgsWkbTypes.displayString(self.metadata_layer.qgis_layer.wkbType()), "temporary_vector", "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.metadata_layer.qgis_layer.fields()) vl.updateFields() # tell the vector layer to fetch changes from the provider res = pr.addFeatures(self.features) uniques = vl.uniqueValues( self.metadata_layer.qgis_layer.fields().indexOf(request.query_params.get('unique')) ) values = [] for u in uniques: try: if u: values.append(json.loads(QgsJsonUtils.encodeValue(u))) except Exception as e: logger.error(f'Response vector widget unique: {e}') continue self.results.update({ 'data': values, 'count': len(values) }) del(vl) else: # patch for return GeoJson feature with CRS different from WGS84 # TODO: use .setTransformGeometries( false ) with QGIS >= 3.12 ex.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) # check for formatter query url param and check if != 0 if 'formatter' in request.query_params: formatter = request.query_params.get('formatter') if formatter.isnumeric() and int(formatter) == 0: export_features = False else: export_features = True if export_features: feature_collection = json.loads(ex.exportFeatures(self.features)) else: # to exclude QgsFormater used into QgsJsonjExporter is necessary build by hand single json feature ex.setIncludeAttributes(False) feature_collection = { 'type': 'FeatureCollection', 'features': [] } for feature in self.features: fnames = [f.name() for f in feature.fields()] feature_collection['features'].append( json.loads(ex.exportFeature(feature, dict(zip(fnames, feature.attributes())))) ) # FIXME: QGIS api reprojecting? # Reproject if necessary # if self.reproject: # self.reproject_featurecollection(feature_collection) # Change media self.change_media(feature_collection) self.results.update(APIVectorLayerStructure(**{ 'data': feature_collection, 'count': count_qgis_features(self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs), 'geometryType': self.metadata_layer.geometry_type, }).as_dict()) # FIXME: add extra fields data by signals and receivers # FIXME: featurecollection = post_serialize_maplayer.send(layer_serializer, layer=self.layer_name) # FIXME: Not sure how to map this to the new QGIS API # Restore the original subset string self.metadata_layer.qgis_layer.setSubsetString(original_subset_string)
def feature_validator(feature, layer): """Validate a QGIS feature by checking QGIS fields constraints The logic here is to: - if geometry is not None check if geometry type matches the layer type - loop through the fields and check for constraints: - NOT NULL, skip the next check if this fails - UNIQUE (only if not NULL) - EXPRESSION (QgsExpression configured in the form), always evaluated, even in case of NULLs Note: only hard constraints are checked! :param feature: QGIS feature :type feature: QgsFeature :param layer: QGIS layer :type layer: QgsVectorLayer :return: a dictionary of errors for each field + geometry :rtype: dict """ errors = dict() geometry = feature.geometry() data_provider = layer.dataProvider() def _has_default_value(field_index, field): return ( # Provider level data_provider.defaultValueClause(field_index) or data_provider.defaultValue(field_index) or field.defaultValueDefinition().isValid()) # Check geometry type if not geometry.isNull() and geometry.wkbType() != layer.wkbType(): if not (geometry.wkbType() == QgsWkbTypes.Point25D and layer.wkbType() == QgsWkbTypes.PointZ or geometry.wkbType() == QgsWkbTypes.Polygon25D and layer.wkbType() == QgsWkbTypes.PolygonZ or geometry.wkbType() == QgsWkbTypes.LineString25D and layer.wkbType() == QgsWkbTypes.LineStringZ or geometry.wkbType() == QgsWkbTypes.MultiPoint25D and layer.wkbType() == QgsWkbTypes.MultiPointZ or geometry.wkbType() == QgsWkbTypes.MultiPolygon25D and layer.wkbType() == QgsWkbTypes.MultiPolygonZ or geometry.wkbType() == QgsWkbTypes.MultiLineString25D and layer.wkbType() == QgsWkbTypes.MultiLineStringZ): errors['geometry'] = _( 'Feature geometry type %s does not match layer type: %s') % ( QgsWkbTypes.displayString(geometry.wkbType()), QgsWkbTypes.displayString(layer.wkbType())) def _set_error(field_name, error): if not field_name in errors: errors[field_name] = [] errors[field_name].append(error) # Check fields "hard" constraints for field_index in range(layer.fields().count()): field = layer.fields().field(field_index) # check if fields is a join field: if layer.fields().fieldOrigin(field_index) == QgsFields.OriginJoin: continue # Check not null first, if it fails skip other tests (unique and expression) value = feature.attribute(field.name()) # If there is a default value we assume it's not NULL (we cannot really know at this point # what will be the result of the default value clause evaluation, it might even be provider-side if (value is None or value == QVariant()) and not _has_default_value(field_index, field): not_null = (field.constraints().constraintOrigin( QgsFieldConstraints.ConstraintNotNull) != QgsFieldConstraints.ConstraintOriginNotSet and field.constraints().constraintStrength( QgsFieldConstraints.ConstraintNotNull) == QgsFieldConstraints.ConstraintStrengthHard) if not_null: _set_error(field.name(), _('Field value must be NOT NULL')) continue value = feature.attribute(field_index) # Skip if NULL, not sure if we want to continue in this case but it seems pointless # to check for unique or type compatibility on NULLs if value is not None and value != QVariant(): if not QVariant(value).convert(field.type()): _set_error( field.name(), _('Field value \'%s\' cannot be converted to %s') % (value, QVariant.typeToName(field.type()))) unique = (field.constraints().constraintOrigin( QgsFieldConstraints.ConstraintUnique) != QgsFieldConstraints.ConstraintOriginNotSet and field.constraints().constraintStrength( QgsFieldConstraints.ConstraintUnique) == QgsFieldConstraints.ConstraintStrengthHard) if unique: # Search for features, excluding self if it's an update request = QgsFeatureRequest() request.setNoAttributes() request.setFlags(QgsFeatureRequest.NoGeometry) request.setLimit(2) if field.isNumeric(): request.setFilterExpression( '"%s" = %s' % (field.name().replace('"', '\\"'), value)) elif field.type() == QVariant.String: request.setFilterExpression( '"%s" = \'%s\'' % (field.name().replace( '"', '\\"'), value.replace("'", "\\'"))) elif field.type() == QVariant.Date: request.setFilterExpression( 'to_date("%s") = \'%s\'' % (field.name().replace( '"', '\\"'), value.toString(Qt.ISODate))) elif field.type() == QVariant.DateTime: request.setFilterExpression( 'to_datetime("{field_name}") = \'{date_time_string}\' OR to_datetime("{field_name}") = \'{date_time_string}.000\'' .format(field_name=field.name().replace('"', '\\"'), date_time_string=value.toString(Qt.ISODate))) elif field.type( ) == QVariant.Bool: # This does not make any sense, but still request.setFilterExpression( '"%s" = %s' % (field.name().replace( '"', '\\"'), 'true' if value else 'false')) else: # All the other formats: let's convert to string and hope for the best request.setFilterExpression( '"%s" = \'%s\'' % (field.name().replace('"', '\\"'), value.toString())) # Exclude same feature by id found = [ f.id() for f in layer.getFeatures(request) if f.id() != feature.id() ] if len(found) > 0: _set_error(field.name(), _('Field value must be UNIQUE')) # Check for expressions, even in case of NULL because expressions may want to check for combined # conditions on multiple fields expression = (field.constraints().constraintOrigin( QgsFieldConstraints.ConstraintExpression) != QgsFieldConstraints.ConstraintOriginNotSet and field.constraints().constraintStrength( QgsFieldConstraints.ConstraintExpression) == QgsFieldConstraints.ConstraintStrengthHard) if expression: constraints = field.constraints() expression = constraints.constraintExpression() description = constraints.constraintDescription() value = feature.attribute(field_index) exp = QgsExpression(expression) context = QgsExpressionContextUtils.createFeatureBasedContext( feature, layer.fields()) context.appendScopes( QgsExpressionContextUtils.globalProjectLayerScopes(layer)) if not bool(exp.evaluate(context)): if not description: description = _('Expression check violation') _set_error(field.name(), _("%s Expression: %s") % (description, expression)) return errors
def run(self): try: # Check if the layers look OK if self.inpvl is None or self.joinvl is None: self.status.emit('Layer is missing!') self.finished.emit(False, None) return # Check if there are features in the layers incount = 0 if self.selectedinonly: incount = self.inpvl.selectedFeatureCount() else: incount = self.inpvl.featureCount() if incount == 0: self.status.emit('Input layer has no features!') self.finished.emit(False, None) return joincount = 0 if self.selectedjoonly: joincount = self.joinvl.selectedFeatureCount() else: joincount = self.joinvl.featureCount() if joincount == 0: self.status.emit('Join layer has no features!') self.finished.emit(False, None) return # Get the wkbtype of the layers self.inpWkbType = self.inpvl.wkbType() self.joinWkbType = self.joinvl.wkbType() # Check if the input layer does not have geometries if (self.inpvl.geometryType() == QgsWkbTypes.NullGeometry): self.status.emit('No geometries in the input layer!') self.finished.emit(False, None) return # Check if the join layer does not have geometries if (self.joinvl.geometryType() == QgsWkbTypes.NullGeometry): self.status.emit('No geometries in the join layer!') self.finished.emit(False, None) return # Set the geometry type and prepare the output layer inpWkbTypetext = QgsWkbTypes.displayString(int(self.inpWkbType)) # self.inputmulti = QgsWkbTypes.isMultiType(self.inpWkbType) # self.status.emit('wkbtype: ' + inpWkbTypetext) # geometryType = self.inpvl.geometryType() # geometrytypetext = 'Point' # if geometryType == QgsWkbTypes.PointGeometry: # geometrytypetext = 'Point' # elif geometryType == QgsWkbTypes.LineGeometry: # geometrytypetext = 'LineString' # elif geometryType == QgsWkbTypes.PolygonGeometry: # geometrytypetext = 'Polygon' # if self.inputmulti: # geometrytypetext = 'Multi' + geometrytypetext # geomttext = geometrytypetext geomttext = inpWkbTypetext # Set the coordinate reference system to the input # layer's CRS using authid (proj4 may be more robust) if self.inpvl.crs() is not None: geomttext = (geomttext + "?crs=" + str(self.inpvl.crs().authid())) # Retrieve the fields from the input layer outfields = self.inpvl.fields().toList() # Retrieve the fields from the join layer if self.joinvl.fields() is not None: jfields = self.joinvl.fields().toList() for joinfield in jfields: outfields.append(QgsField(self.joinprefix + str(joinfield.name()), joinfield.type())) else: self.status.emit('Unable to get any join layer fields') # Add the nearest neighbour distance field # Check if there is already a "distance" field # (should be avoided in the user interface) # Try a new name if there is a collission collission = True trynumber = 1 distnameorg = self.distancename while collission: # Iterate until there are no collissions collission = False for field in outfields: # This check should not be necessary - handled in the UI if field.name() == self.distancename: self.status.emit( 'Distance field already exists - renaming!') # self.abort = True # self.finished.emit(False, None) # break collission = True self.distancename = distnameorg + str(trynumber) trynumber = trynumber + 1 outfields.append(QgsField(self.distancename, QVariant.Double)) # Create a memory layer using a CRS description self.mem_joinl = QgsVectorLayer(geomttext, self.outputlayername, "memory") # Set the CRS to the inputlayer's CRS self.mem_joinl.setCrs(self.inpvl.crs()) self.mem_joinl.startEditing() # Add the fields for field in outfields: self.mem_joinl.dataProvider().addAttributes([field]) # For an index to be used, the input layer has to be a # point layer, or the input layer geometries have to be # approximated to centroids, or the user has to have # accepted that a join layer index is used (for # non-point input layers). # (Could be extended to multipoint) if (self.inpWkbType == QgsWkbTypes.Point or self.inpWkbType == QgsWkbTypes.Point25D or self.approximateinputgeom or self.nonpointexactindex): # Number of features in the join layer - used by # calculate_progress for the index creation if self.selectedjoonly: self.feature_count = self.joinvl.selectedFeatureCount() else: self.feature_count = self.joinvl.featureCount() # Create a spatial index to speed up joining self.status.emit('Creating join layer index...') # The number of elements that is needed to increment the # progressbar - set early in run() self.increment = self.feature_count // 1000 self.joinlind = QgsSpatialIndex() # Include geometries to enable exact distance calculations # self.joinlind = QgsSpatialIndex(flags=[QgsSpatialIndex.FlagStoreFeatureGeometries]) if self.selectedjoonly: for feat in self.joinvl.getSelectedFeatures(): # Allow user abort if self.abort is True: break self.joinlind.insertFeature(feat) self.calculate_progress() else: for feat in self.joinvl.getFeatures(): # Allow user abort if self.abort is True: break self.joinlind.insertFeature(feat) self.calculate_progress() self.status.emit('Join layer index created!') self.processed = 0 self.percentage = 0 # self.calculate_progress() # Is the join layer a multi-geometry layer? # self.joinmulti = QgsWkbTypes.isMultiType(self.joinWkbType) # Does the join layer contain multi geometries? # Try to check the first feature # This is not used for anything yet self.joinmulti = False if self.selectedjoonly: feats = self.joinvl.getSelectedFeatures() else: feats = self.joinvl.getFeatures() if feats is not None: testfeature = next(feats) feats.rewind() feats.close() if testfeature is not None: if testfeature.hasGeometry(): if testfeature.geometry().isMultipart(): self.joinmulti = True # Prepare for the join by fetching the layers into memory # Add the input features to a list self.inputf = [] if self.selectedinonly: for f in self.inpvl.getSelectedFeatures(): self.inputf.append(f) else: for f in self.inpvl.getFeatures(): self.inputf.append(f) # Add the join features to a list (used in the join) self.joinf = [] if self.selectedjoonly: for f in self.joinvl.getSelectedFeatures(): self.joinf.append(f) else: for f in self.joinvl.getFeatures(): self.joinf.append(f) # Initialise the global variable that will contain the # result of the nearest neighbour spatial join (list of # features) self.features = [] # Do the join! # Number of features in the input layer - used by # calculate_progress for the join operation if self.selectedinonly: self.feature_count = self.inpvl.selectedFeatureCount() else: self.feature_count = self.inpvl.featureCount() # The number of elements that is needed to increment the # progressbar - set early in run() self.increment = self.feature_count // 1000 # Using the original features from the input layer for feat in self.inputf: # Allow user abort if self.abort is True: break self.do_indexjoin(feat) self.calculate_progress() self.mem_joinl.dataProvider().addFeatures(self.features) self.status.emit('Join finished') except: import traceback self.error.emit(traceback.format_exc()) self.finished.emit(False, None) if self.mem_joinl is not None: self.mem_joinl.rollBack() else: self.mem_joinl.commitChanges() if self.abort: self.finished.emit(False, None) else: self.status.emit('Delivering the memory layer...') self.finished.emit(True, self.mem_joinl)
def visit_node(tree_node): if isinstance(tree_node, QgsLayerTreeLayer): layer = tree_node.layer() layer_type = { 0: "vector", 1: "raster", # 2: PluginLayer # 3: MeshLayer }[layer.type()] source = layer.source() provider_type = layer.providerType() uri = "" if provider_type == "wms": source_params = parse_qs(source) uri = source_params["url"][0] elif provider_type == "postgres": dp = layer.dataProvider() uri = "postgresql://%s:%s" % (dp.uri().host(), dp.uri().port()) elif provider_type in ("ogr", "gdal"): uri = "file://%s" % source.split("|")[0] elif provider_type == "spatialite": match = dbname_pattern.search(source) if match: uri = "file://%s" % match.group(1) else: uri = source extent = layer.extent() if not extent.isEmpty(): extent = map_settings.layerExtentToOutputExtent( layer, layer.extent()).toRectF().getCoords() else: extent = None info = { "id": layer.id(), "name": layer.name(), "serverName": layer.shortName() if hasattr(layer, "shortName") else layer.name(), "wfs": layer.id() in wfs_layers, "provider_type": provider_type, "projection": layer.crs().authid(), "type": layer_type, "source": uri, "extent": extent, "visible": project.layerTreeRoot().findLayer(layer.id()).isVisible(), "metadata": { "title": layer.title(), "abstract": layer.abstract(), "keyword_list": layer.keywordList() } } legend_url = layer.legendUrl() if legend_url: info["legend_url"] = legend_url # if layer.isSpatial() if layer_type == "vector": info["geom_type"] = ('POINT', 'LINE', 'POLYGON', None, None)[layer.geometryType()] info["wkb_type"] = QgsWkbTypes.displayString( layer.wkbType()) info["labels"] = layer.labelsEnabled() info["attributes"] = self.get_layer_attributes(layer) info["queryable"] = bool(info["attributes"]) and layer.id( ) not in non_identifiable_layers and layer.id( ) in wfs_layers if info["attributes"]: fields = layer.fields() info["pk_attributes"] = [ fields.at(index).name() for index in layer.dataProvider().pkAttributeIndexes() ] if provider_type == "wms": info["url"] = source_params["url"][0] img_format = source_params.get("format", [None])[0] if not img_format: img_format = os.path.splitext(info["url"])[1].replace( ".", "image/") info["format"] = img_format info["dpi"] = layer.dataProvider().dpi() if "layers" in source_params: info["wms_layers"] = source_params["layers"] if layer in layers_order: info["drawing_order"] = layers_order.index(layer) if layer.attribution(): info["attribution"] = { "title": layer.attribution(), "url": layer.attributionUrl() } return info else: children = [] for child_tree_node in tree_node.children(): try: info = visit_node(child_tree_node) if info: children.append(info) except Exception as e: if not skip_layers_with_error: msg = "Failed to gather info from layer: '%s'" % child_tree_node.name( ) raise WsError(msg, 405) from e return {"name": tree_node.name(), "layers": children}
def spatialInfo(self): ret = [] if not self.table.geomType: return ret tbl = [ (QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn), (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType), (QApplication.translate("DBManagerPlugin", "Qgis Geometry type:"), QgsWkbTypes.displayString(self.table.wkbType)) ] # only if we have info from geometry_columns if self.table.geomDim: tbl.append( (QApplication.translate( "DBManagerPlugin", "Dimension:"), self.table.geomDim)) srid = self.table.srid if self.table.srid else -1 if srid != -1: sr_info = ( self.table.database().connector.getSpatialRefInfo(srid)) else: sr_info = QApplication.translate("DBManagerPlugin", "Undefined") if sr_info: tbl.append( (QApplication.translate( "DBManagerPlugin", "Spatial ref:"), u"{0} ({1})".format(sr_info, srid))) # estimated extent if not self.table.estimatedExtent: # estimated extent information is not displayed yet, so just block # table signals to avoid double refreshing # (infoViewer->refreshEstimatedExtent->tableChanged->infoViewer) self.table.blockSignals(True) self.table.refreshTableEstimatedExtent() self.table.blockSignals(False) if self.table.estimatedExtent: estimated_extent_str = (u"{:.9f}, {:.9f} - {:.9f}, " u"{:.9f}".format( *self.table.estimatedExtent)) tbl.append( (QApplication.translate( "DBManagerPlugin", "Estimated extent:"), estimated_extent_str)) # extent extent_str = None if self.table.extent and len(self.table.extent) == 4: extent_str = (u"{:.9f}, {:.9f} - {:.9f}, " u"{:.9f}".format(*self.table.extent)) elif self.table.rowCount > 0 or self.table.estimatedRowCount > 0: # Can't calculate an extent on empty layer extent_str = QApplication.translate( "DBManagerPlugin", '(unknown) (<a href="action:extent/get">find out</a>)') if extent_str: tbl.append( (QApplication.translate( "DBManagerPlugin", "Extent:"), extent_str)) ret.append(HtmlTable(tbl)) # Handle extent update metadata if (self.table.extent and self.table.extent != self.table.estimatedExtent and self.table.canUpdateMetadata()): ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", (u'<warning> Metadata extent is different from' u'real extent. You should <a href="action:extent' u'/update">update it</a>!')))) # is there an entry in geometry_columns? if self.table.geomType.lower() == 'geometry': ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", "<warning> There is no entry in geometry_columns!"))) # find out whether the geometry column has spatial index on it if not self.table.isView: if not self.table.hasSpatialIndex(): ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", (u'<warning> No spatial index defined (<a href=' u'"action:spatialindex/create">' u'create it</a>).')))) return ret