def setDiffContent(self, commit, commit2): if self.layer is None: layers = set(self.server.layers(self.user, self.repo, commit.commitid)) layers2 = set(self.server.layers(self.user, self.repo, commit2)) layers = layers.union(layers2) else: layers = [self.layer] diffs = {layer: execute(lambda: self.server.diff(self.user, self.repo, layer, commit.commitid, commit2)) for layer in layers} diffs = {key:value for (key,value) in diffs.items() if len(value) !=0} layers = [l for l in diffs.keys()] self.diffViewer.setChanges(diffs) self.canvas.setLayers([]) self.removeMapLayers() extent = QgsRectangle() for layer in layers: if not diffs[layer]: continue beforeLayer, afterLayer = execute(lambda: self._getLayers(diffs[layer])) if afterLayer is not None: resourcesPath = os.path.join(os.path.dirname(__file__), os.pardir, "resources") oldStylePath = os.path.join(resourcesPath, "{}_before.qml".format( QgsWkbTypes.geometryDisplayString(beforeLayer.geometryType()))) newStylePath = os.path.join(resourcesPath, "{}_after.qml".format( QgsWkbTypes.geometryDisplayString(afterLayer.geometryType()))) beforeLayer.loadNamedStyle(oldStylePath) afterLayer.loadNamedStyle(newStylePath) QgsProject.instance().addMapLayer(beforeLayer, False) QgsProject.instance().addMapLayer(afterLayer, False) extent.combineExtentWith(beforeLayer.extent()) extent.combineExtentWith(afterLayer.extent()) self.extraLayers.append(beforeLayer) self.extraLayers.append(afterLayer) # make extent a bit bit (10%) bigger # this gives some margin around the dataset (not cut-off at edges) if not extent.isEmpty(): widthDelta = extent.width() * 0.05 heightDelta = extent.height() * 0.05 extent = QgsRectangle(extent.xMinimum() - widthDelta, extent.yMinimum() - heightDelta, extent.xMaximum() + widthDelta, extent.yMaximum() + heightDelta) layers = self.extraLayers hasChanges = False for layer in layers: if layer is not None and layer.featureCount() > 0: hasChanges = True break self.canvas.setLayers(layers) self.canvas.setExtent(extent) self.canvas.refresh() self.canvas.setVisible(hasChanges) self.labelNoChanges.setVisible(not hasChanges)
def transformToWGS(old_layer, old_crs): #TODO: define layer type dynamically geom_string = QgsWkbTypes.geometryDisplayString(old_layer.geometryType()) new_layer = QgsVectorLayer("{}?crs=EPSG:4326".format(geom_string), old_layer.name(), "memory") new_layer.dataProvider().addAttributes(old_layer.fields()) new_layer.updateFields() new_crs = QgsCoordinateReferenceSystem(4326) old_crs = QgsCoordinateReferenceSystem(old_crs) xform = QgsCoordinateTransform(old_crs, new_crs, QgsProject.instance()) for o in old_layer.getFeatures(): n = QgsFeature() g = o.geometry() g.transform(xform) n.setGeometry(g) n.setAttributes(o.attributes()) new_layer.dataProvider().addFeature(n) new_layer.updateExtents() return new_layer
def insertQuality(self, classification, feature, gid, yta): data = None geometry_type = QgsWkbTypes.geometryDisplayString( feature.geometry().type()) if (geometry_type == "Point"): geometry_type = "punkt" if (geometry_type == "Line"): geometry_type = "linje" if (geometry_type == "Polygon"): geometry_type = "yta" quality_name = classification[1] q_list = self.layerSelectorDialog.qualities_list factor = -1 group_name = None quality_name, group_name, factor = self.findQuality( q_list, quality_name) if factor != -1: data = [ gid, geometry_type, self.fileName, group_name, quality_name, factor, round(yta, 1), round(factor * yta, 1) ] # gid, geometri_typ, filnamn, grupp, kvalitet, faktor, yta, poäng return data
def import_layer( self, layer, table_name, id_field=None, geom_field="the_geom", srid=4326 ): mapping = { int(QVariant.Int): "INTEGER", int(QVariant.Double): "DOUBLE", int(QVariant.TextFormat): "TEXT", int(QVariant.Bool): "BOOLEAN", int(QVariant.String): "STRING", } sql_fields = [] for field in layer.fields(): tp = mapping[int(field.type())] if tp == "STRING": sql_fields.append( "{0} {1}({2})".format(field.name(), tp, field.length()) ) else: sql_fields.append("{0} {1}".format(field.name(), tp)) self.createTable(table_name, sql_fields, id_field) geom_type = QgsWkbTypes.geometryDisplayString(layer.geometryType()).lstrip( "WKB" ) self.addGeometryColumn(table_name, geom_field, geom_type=geom_type, srid=srid) splayer = self.get_layer(table_name, None, geom_field) splayer.addFeatures([feat for feat in layer.getFeatures()]) self.createSpatialIndex(table_name, geom_field) return splayer
def parse_input_definition(param: QgsProcessingParameterDefinition, kwargs, context: MapContext = None) -> WPSInput: """ Convert processing input to File Input """ typ = param.type() if typ == 'crs': kwargs['data_type'] = 'string' return LiteralInput(**kwargs) elif typ == "extent": return parse_extent_input(param, kwargs, context) elif isinstance(param, GeometryParameterTypes): kwargs['supported_formats'] = [ Format.from_definition(FORMATS.GEOJSON), Format.from_definition(FORMATS.GML), Format.from_definition(FORMATS.WKT) ] if isinstance(param, QgsProcessingParameterGeometry): # Add metadata from requiered geometryTypes kwargs['metadata'].extend( Metadata('processing:geometryType', QgsWkbTypes.geometryDisplayString(geomtype)) \ for geomtype in param.geometryTypes() ) if param.allowMultipart(): kwargs['metadata'].append( Metadata('processing:allowMultipart')) return ComplexInput(**kwargs) return None
def handle_response(self, content: QByteArray): try: data = json.loads(str(content.data(), encoding='utf-8')) # self.dbg_info(data) features = data['features'] for f in features: json_geom = json.dumps(f['geometry']) ogr_geom = ogr.CreateGeometryFromJson(json_geom) wkt = ogr_geom.ExportToWkt() geometry = QgsGeometry.fromWkt(wkt) self.dbg_info('---------') self.dbg_info( QgsWkbTypes.geometryDisplayString(geometry.type())) self.dbg_info(f.keys()) self.dbg_info('{} {}'.format(f['properties']['layer_name'], f['properties']['label'])) self.dbg_info(f['bbox']) self.dbg_info(f['geometry']) if geometry is None: continue result = QgsLocatorResult() result.filter = self result.displayString = f['properties']['label'] result.group = self.beautify_group( f['properties']['layer_name']) result.userData = geometry self.resultFetched.emit(result) except Exception as e: self.info(str(e), Qgis.Critical)
def _parse_selection(self): """ parse the current selection inside the QGIS map and update the LineConstruction object and enable / disable the dockwidget.start_construction button :return: Nothing """ if self.__active_layer is None: self.__line_construct.reset() return # noinspection PyArgumentList geometry_type = QgsWkbTypes.geometryDisplayString( self.__active_layer.geometryType()) selected_features = self.__active_layer.selectedFeatures() if len(selected_features) == 0 or geometry_type != "Line": self.__line_construct.reset() return text = "" # noinspection PyArgumentList if QgsWkbTypes.isMultiType(self.iface.activeLayer().wkbType()): text += "This is line is stored as a multi part line. This tool only uses the first part, if more than " + \ "one exists!" if len(selected_features) > 1: if text != "": text += "\n\n" text += "Multiple features selected. Using only the first of this selection." self.__line_construct.active_feature_id = selected_features[0].id() self.__line_construct.active_geometry = selected_features[0].geometry() if self.__line_construct.active_geometry.isEmpty(): self.iface.messageBar().pushWarning("Warning", "Selected an empty geometry!") self.__line_construct.reset() return if self.__line_construct.active_geometry.isMultipart(): self.__line_construct.active_geometry = self.__line_construct.active_geometry.asGeometryCollection( )[0] line = self.__line_construct.active_geometry.asPolyline() if len(line) < 2: self.iface.messageBar().pushWarning( "Warning", "Selected line has less than two points. Cannot use it.") self.__line_construct.reset() return self.__line_construct.active_line = line self.dockwidget.start_construction.setEnabled(True) if text != "": self.iface.messageBar().pushInfo("Info: ", text)
def geometryModified(self, fid, geom, layer): feature = layer.getFeature(fid) geom_type = QgsWkbTypes.geometryDisplayString(geom.type()) if len(feature["gid"]) == 36: if geom_type == "MultiPolygon": feature["yta"] = feature.geometry().area() elif geom_type == "Line": feature["yta"] = feature.geometry().length() layer.updateFeature(feature) self.dockwidget.updateClassArea(feature["gid"], feature["yta"])
def featureAdded(self, fid, layer): feature = layer.getFeature(fid) geom_type = QgsWkbTypes.geometryDisplayString(feature.geometry().type()) if feature["gid"] == NULL or len(feature["gid"]) != 36: feature["gid"] = str(uuid.uuid4()) if geom_type == "MultiPolygon": feature["yta"] = feature.geometry().area() elif geom_type == "Point": if type(feature["yta"]) != float: feature["yta"] = 25.0 else: feature["yta"] = feature.geometry().length() layer.updateFeature(feature)
def prepareFeature(self, feature): geom = feature.geometry() geom.convertToSingleType() feature.setGeometry(geom) type = QgsWkbTypes.geometryDisplayString(geom.type()) if type == "Polygon": geom = feature.geometry().fromPolygonXY( feature.geometry().asPolygon()) #geom = geom.makeValid() feature.setGeometry(geom) if type == "Point": geom = feature.geometry().fromPointXY(feature.geometry().asPoint()) feature.setGeometry(geom) if type == "Line": if self.extension == ".dxf": vertices = [] for v in geom.vertices(): vertices.append(QgsPointXY(v.x(), v.y())) if vertices[0] == vertices[len(vertices) - 1]: geom = QgsGeometry.fromPolygonXY([vertices]) type = QgsWkbTypes.geometryDisplayString(geom.type()) if type == "Polygon": #geom = geom.makeValid() feature.setGeometry(geom) if type == "Line": geom = feature.geometry().fromPolylineXY( feature.geometry().asPolyline()) feature.setGeometry(geom) return type
def layerStyleAsMapfile(layer): geostyler, icons, warnings = qgis.togeostyler.convert(layer) mserver, msWarnings = mapserver.fromgeostyler.convert(geostyler) warnings.extend(msWarnings) filename = os.path.basename(layer.source()) filename = os.path.splitext(filename)[0] + ".shp" mserver = mserver.replace("{data}", filename) layerType = "TODO:fill this" if isinstance(layer, QgsRasterLayer): layerType = "raster" elif isinstance(layer, QgsVectorLayer): layerType = QgsWkbTypes.geometryDisplayString(layer.geometryType()) mserver = mserver.replace("{layertype}", layerType) return mserver, icons, warnings
def vectorToKml(self): result = False geometryType = self.data.geometryType() if geometryType == QgsWkbTypes.PointGeometry: result = self._pointsToKml() elif geometryType == QgsWkbTypes.LineGeometry: result = self._linesToKml() elif geometryType == QgsWkbTypes.PolygonGeometry: result = self._polygonsToKml() else: self.error = self.tr('Unsupported geometry type "{}"'.format( QgsWkbTypes.geometryDisplayString(geometryType))) result = False return result
def create_layer_string(self, geometry_type, fields, crs): """create a memory layer creation string from the given parameters""" # fields field_str = '&'.join( ['field=%s:%s' % (f.name(), f.typeName()) for f in fields]) # layer's geometryType() might return Line as geometry type # which is unsuitable for layer creation gtype = QgsWkbTypes.geometryDisplayString(geometry_type) if gtype.startswith('Line'): gtype = 'Linestring' return '{type}?crs={id}&{field_str}&index=yes'.format( type=gtype, id=crs.authid(), field_str=field_str)
def layerStyleAsMapfileFolder(layer, layerFilename, folder): geostyler, icons, warnings = qgis.togeostyler.convert(layer) mserver, msWarnings = mapserver.fromgeostyler.convert(geostyler) warnings.extend(msWarnings) mserver = mserver.replace("{data}", layerFilename) mserver = mserver.replace( "{geometrytype}", QgsWkbTypes.geometryDisplayString(layer.geometryType())) filename = os.path.join(folder, "style.map") with open(filename, "w") as f: f.write(mserver) for icon in icons: dst = os.path.join(folder, os.path.basename(icon)) copyfile(icon, dst) return warnings
def createMemoryLayer(self, layerName, sourceLayer): # create empty memory layer memoryLayer = QgsVectorLayer( QgsWkbTypes.geometryDisplayString(sourceLayer.geometryType()) + "?crs=" + sourceLayer.crs().authid() + "&index=yes", layerName, "memory") memoryLayerDataProvider = memoryLayer.dataProvider() # copy the table structure memoryLayerDataProvider.addAttributes(sourceLayer.fields().toList()) memoryLayer.updateFields() # copy the features memoryLayerDataProvider.addFeatures(list(sourceLayer.getFeatures())) return memoryLayer
def sample_layer(self): source_layer = QgsVectorLayer( os.path.join(self.plugin_dir, "data", "Austria_PopulationByNUTS2.gml"), "" ) # (empty) memory layer sample_layer = QgsVectorLayer( QgsWkbTypes.geometryDisplayString(source_layer.geometryType()) + "?crs=" + source_layer.crs().authid() + "&index=yes", "Austria_Population_NUTS2_20170101", "memory" ) sample_layer_data_provider = sample_layer.dataProvider() sample_layer_data_provider.addAttributes(source_layer.fields().toList()) sample_layer.updateFields() sample_layer_data_provider.addFeatures(list(source_layer.getFeatures())) sample_layer.loadNamedStyle( os.path.join(self.plugin_dir, "data", "Austria_PopulationByNUTS2.qml") ) sample_layer.setTitle("Austria: Population by NUTS2 regions, 1 Jan 2017") sample_layer.setShortName("Austria_Population_NUTS2_20170101") sample_layer.setAbstract( "Austria’s population by NUTS2 region, as of 1 Jan 2017 \n" + "\n" + "Data sources: \n" + " http://ec.europa.eu/eurostat/web/gisco/geodata/" + "reference-data/administrative-units-statistical-units/" + "nuts#nuts13 \n" + " http://www.statistik.at/web_de/statistiken/" + "menschen_und_gesellschaft/bevoelkerung/" + "bevoelkerungsstand_und_veraenderung/" + "bevoelkerung_zu_jahres-_quartalsanfang/index.html" ) return sample_layer
def handle_response(self, response, content): try: if response.status_code != 200: self.info("Error with status code: {}".format( response.status_code)) return data = json.loads(content.decode('utf-8')) #self.dbg_info(data) features = data['features'] for f in features: json_geom = json.dumps(f['geometry']) ogr_geom = ogr.CreateGeometryFromJson(json_geom) wkt = ogr_geom.ExportToWkt() geometry = QgsGeometry.fromWkt(wkt) self.dbg_info('---------') self.dbg_info( QgsWkbTypes.geometryDisplayString(geometry.type())) self.dbg_info(f.keys()) self.dbg_info('{} {}'.format(f['properties']['layer_name'], f['properties']['label'])) self.dbg_info(f['bbox']) self.dbg_info(f['geometry']) if geometry is None: continue result = QgsLocatorResult() result.filter = self result.displayString = f['properties']['label'] if Qgis.QGIS_VERSION_INT >= 30100: result.group = self.beautify_group( f['properties']['layer_name']) result.userData = geometry self.resultFetched.emit(result) except Exception as e: self.info(str(e), Qgis.Critical)
def closePublishing(self): name = self.projectName() extent = QgsRectangle() epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326") for layer in self._layers: trans = QgsCoordinateTransform(layer.crs(), epsg4326, QgsProject.instance()) layerExtent = trans.transform(layer.extent()) extent.combineExtentWith(layerExtent) sExtent = " ".join([ str(v) for v in [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] ]) def _quote(t): return '"%s"' % t for layer in self._layers: add = {} layerFilename = layer.name() + ".shp" add["DATA"] = _quote(layerFilename) if isinstance(layer, QgsRasterLayer): layerType = "raster" elif isinstance(layer, QgsVectorLayer): layerType = QgsWkbTypes.geometryDisplayString( layer.geometryType()) add["TYPE"] = layerType bbox = layer.extent() if bbox.isEmpty(): bbox.grow(1) metadata = { "wms_abstract": _quote(layer.metadata().abstract()), "wms_title": _quote(layer.name()), "ows_srs": _quote("EPSG:4326 EPSG:3857 " + layer.crs().authid()), "wms_extent": _quote(" ".join([ str(v) for v in [ bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum() ] ])) } if layer.name() in self._metadataLinks: metadata["ows_metadataurl_href"] = _quote( self._metadataLinks[layer.name()]) metadata["ows_metadataurl_type"] = _quote("TC211") metadata["ows_metadataurl_format"] = _quote("XML") add["METADATA"] = metadata warnings = layerStyleAsMapfileFolder(layer, self.mapsFolder(), add) for w in warnings: self.logWarning(w) web = { "IMAGEPATH": '"../data/bridge/webdav/images"', "IMAGEURL": '"http://localhost/images"', "METADATA": { '"wms_title"': _quote(name), '"wms_onlineresource"': _quote(self.layerWmsUrl(layer.name())), '"ows_enable_request"': '"*"', '"ows_srs"': '"EPSG:4326"', '"wms_feature_info_mime_type"': '"text/html"' } } mapElement = { "NAME": _quote(name), "STATUS": 'ON', "CONFIG": '"PROJ_LIB" "%s"' % self.projFolder, "EXTENT": sExtent, "PROJECTION": { 'AUTO': '' }, #todo: add projection info "SYMBOLSET": '"symbols.txt"', "MAXSIZE": 8000, "SHAPEPATH": '"../data"', "SIZE": "700 700", "UNITS": "METERS", "WEB": web, "OUTPUTFORMAT": { "DRIVER": '"AGG/PNG"', "EXTENSION": '"png"', "IMAGEMODE": '"RGB"', "MIMETYPE": '"image/png"' }, "SCALEBAR": { "ALIGN": "CENTER", "OUTLINECOLOR": "0 0 0" } } mapElement["LAYERS"] = [{ "INCLUDE": '"%s.txt"' % layer.name() } for layer in self._layers] mapElement["SYMBOLS"] = [{ "INCLUDE": '"%s_symbols.txt"' % layer.name() } for layer in self._layers] mapfile = {"MAP": mapElement} s = convertDictToMapfile(mapfile) mapfilePath = os.path.join(self.mapsFolder(), name + ".map") with open(mapfilePath, "w") as f: f.write(s) src = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "mapserver", "symbols.txt") dst = self.mapsFolder() shutil.copy2(src, dst) if not self.useLocalFolder: self.uploadFolder(dst)
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}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ self.progress = 0 # extent = self.parameterAsExtent(parameters, self.EXTENT, context) workspace = self.parameterAsFile(parameters, self.INPUT, context) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) # if not extent: # raise_exception('can\'t read extent') if not workspace: raise_exception('can\'t get wokrspace') if not output: raise_exception('can\'t get an output') feedback.pushInfo(tr('The algorithm is running')) dummy = QgsVectorLayer(workspace, "dummy", "ogr") sublyrs = dummy.dataProvider().subLayers() layers = [] for sublyr in sublyrs: name = sublyr.split('!!::!!')[1] uri = "%s|layername=%s" % (workspace, name) layer = QgsVectorLayer(uri, name, "ogr") layers.append(layer) for layer in layers: features = list(layer.getFeatures()) features_count = len(features) fields = layer.dataProvider().fields() indexes = [fields.indexFromName(field.name()) for field in fields] unique_values_per_field = {key: set() for key in indexes} points_num = 0 total_length = 0 bend_num = 0 total_bend_area = 0.0 ave_bend_base_line_len = 0.0 ave_bend_height = 0.0 ave_bend_length = 0.0 total_polygon_area = 0.0 count = 0.0 total_intersections = 0 total = 100.0 / features_count if features_count > 0 else 0 for current, feature in enumerate(features): if feedback.isCanceled(): break update_unique_values(feature, indexes, unique_values_per_field) geom = feature.geometry() is_single_type = QgsWkbTypes.isSingleType(geom.wkbType()) if geom.type() == QgsWkbTypes.LineGeometry: total_length += geom.length() if is_single_type: data_list = [(v.x(), v.y()) for v in geom.vertices()] if len(data_list) < 3: continue result = get(data_list) count = count + 1 points_num += result[0] bend_num += result[1] total_bend_area += result[2] ave_bend_base_line_len += result[3] ave_bend_height += result[4] ave_bend_length += result[5] else: for part in geom.parts(): data_list = [(v.x(), v.y()) for v in part.vertices()] if len(data_list) < 3: continue result = get(data_list) count = count + 1 points_num += result[0] bend_num += result[1] total_bend_area += result[2] ave_bend_base_line_len += result[3] ave_bend_height += result[4] ave_bend_length += result[5] elif geom.type() == QgsWkbTypes.PolygonGeometry: total_length += geom.length() if is_single_type: data_list = [(v.x(), v.y()) for v in geom.vertices()] if len(data_list) < 3: continue result = get(data_list) count = count + 1 points_num += result[0] bend_num += result[1] total_bend_area += result[2] ave_bend_base_line_len += result[3] ave_bend_height += result[4] ave_bend_length += result[5] total_polygon_area += geom.area() else: for part in geom.parts(): data_list = [(v.x(), v.y()) for v in part.vertices()] if len(data_list) < 3: continue result = get(data_list) count = count + 1 points_num += result[0] bend_num += result[1] total_bend_area += result[2] ave_bend_base_line_len += result[3] ave_bend_height += result[4] ave_bend_length += result[5] total_polygon_area += geom.area() else: break self.progress = int(current * total) feedback.setProgress(self.progress) uniq_values_number = get_unique_values_ratio( unique_values_per_field, features_count) ave_uniq_values_number = get_ave_unique_values_ratio( uniq_values_number, len(fields)) feedback.pushInfo('Total intersections:') filtered_layers = filter_layers([layer]) if filtered_layers: total_intersections = len( get_total_intersection(filtered_layers[0], feedback)) header = [ 'workspace', 'layer', 'field_count', 'features_count', 'uniq_values_number', 'average_uniq_values', 'total_length', 'number_of_points', 'number_of_bends', 'average_area_of_bends', 'average_length_of_bends_baseline', 'average_height_of_bends', 'average_length_of_the_bends', 'total_polygons_area', 'average_polygons_area', 'average_length', 'layer_type', 'total_bends_area', 'total_intersections', ] row = [{ header[0]: os.path.basename(os.path.normpath(workspace)), header[1]: layer.name(), header[2]: len(fields), header[3]: features_count, header[4]: uniq_values_number, header[5]: ave_uniq_values_number, header[6]: get_formatted_result(total_length), header[7]: points_num, header[8]: bend_num, header[9]: get_formatted_result(total_bend_area / bend_num) if bend_num > 0 else 0.0, header[10]: get_formatted_result(ave_bend_base_line_len / bend_num) if bend_num > 0 else 0.0, header[11]: get_formatted_result(ave_bend_height / bend_num) if bend_num > 0 else 0.0, header[12]: get_formatted_result(ave_bend_length / bend_num) if bend_num > 0 else 0.0, header[13]: get_formatted_result(total_polygon_area), header[14]: get_formatted_result(total_polygon_area / count) if count > 0 else 0.0, header[15]: get_formatted_result(total_length / count) if count > 0 else 0.0, header[16]: QgsWkbTypes.geometryDisplayString(int(layer.geometryType())), header[17]: get_formatted_result(total_bend_area), header[18]: get_formatted_result(total_intersections), }] if output: feedback.pushInfo(tr('Writing to file')) write_to_file(output, header, row, ';') return row[0]
def _group_geom_name(self, geom_str): geom = QgsWkbTypes.geometryDisplayString( QgsWkbTypes.geometryType( QgsWkbTypes.parseType( geom_str))) if geom_str else self.NO_GEOM return geom
def __geometryFromSource(self, layersource): l = QgsVectorLayer(layersource) return QgsWkbTypes.geometryDisplayString(l.geometryType())