def resetSnapping(self): self.unlink_mode = False # disable previous snapping setting proj = QgsProject.instance() snapConfig = QgsSnappingConfig() if self.settings[0] != '' and self.settings[0]: # proj.writeEntry('Digitizing', 'SnappingMode', 'advanced') layer = lfh.getLayerByName(self.settings[0]) if layer: # layer might have been removed snapConfig.setMode(QgsSnappingConfig.AdvancedConfiguration) layerSnapConfig = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex, self.settings[2], QgsTolerance.LayerUnits) snapConfig.setIndividualLayerSettings(layer, layerSnapConfig) proj.setAvoidIntersectionsLayers([layer]) if self.settings[1] != 'no unlinks' and self.settings[1]: # proj.writeEntry('Digitizing', 'SnappingMode', 'advanced') layer = lfh.getLayerByName(self.settings[1]) if layer: snapConfig.setMode(QgsSnappingConfig.AdvancedConfiguration) layerSnapConfig = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex, self.settings[2], QgsTolerance.LayerUnits) snapConfig.setIndividualLayerSettings(layer, layerSnapConfig) proj.setAvoidIntersectionsLayers([]) snapConfig.setIntersectionSnapping(False) proj.setSnappingConfig(snapConfig) return
def startWorker(self): self.dlg.segmentingProgress.reset() self.settings = self.dlg.get_settings() if self.settings['output_type'] == 'postgis': db_settings = self.dlg.get_dbsettings() self.settings.update(db_settings) if lfh.getLayerByName(self.settings['input']).crs().postgisSrid() == 4326: self.giveMessage('Re-project the layer. EPSG:4326 not allowed.', Qgis.Info) elif self.settings['output'] != '': segmenting = self.Worker(self.settings, self.iface) self.dlg.lockGUI(True) # start the segmenting in a new thread thread = QThread() self.thread_error = '' segmenting.moveToThread(thread) segmenting.finished.connect(self.workerFinished) segmenting.error.connect(self.workerError) segmenting.warning.connect(self.giveMessage) segmenting.segm_progress.connect(self.dlg.segmentingProgress.setValue) thread.started.connect(segmenting.run) thread.start() self.thread = thread self.segmenting = segmenting else: self.giveMessage('Missing user input!', Qgis.Info) return
def workerFinished(self, ret): # create the segmenting results layers if self.segmenting: # clean up the worker and thread self.segmenting.finished.disconnect(self.workerFinished) self.segmenting.error.disconnect(self.workerError) self.segmenting.warning.disconnect(self.giveMessage) self.segmenting.segm_progress.disconnect(self.dlg.segmentingProgress.setValue) # self.segmenting.my_segmentor.progress.disconnect(self.segm_progress.emit) self.thread.deleteLater() self.thread.quit() self.thread.wait() self.thread.deleteLater() if ret: self.dlg.lockGUI(False) # get segmenting settings layer_name = self.settings['input'] output_path, errors_path = self.settings['output'] output_type = self.settings['output_type'] # get settings from layer layer = lfh.getLayerByName(layer_name) break_lines, break_points = ret segmented = uf.to_layer(break_lines, layer.crs(), layer.dataProvider().encoding(), 'Linestring', output_type, output_path) QgsProject.instance().addMapLayer(segmented) segmented.updateExtents() if self.settings['errors']: if len(break_points) == 0: self.giveMessage('No points detected!', Qgis.Info) else: errors = uf.to_layer(break_points, layer.crs(), layer.dataProvider().encoding(), 'Point', output_type, errors_path) errors.loadNamedStyle(os.path.dirname(__file__) + '/errors_style.qml') QgsProject.instance().addMapLayer(errors) node = QgsProject.instance().layerTreeRoot().findLayer(errors.id()) self.iface.layerTreeView().layerTreeModel().refreshLayerLegend(node) self.giveMessage('Process ended successfully!', Qgis.Info) elif self.thread_error != '': # notify the user that sth went wrong self.giveMessage('Something went wrong! See the message log for more information', Qgis.Critical) QgsMessageLog.logMessage("Network segmenter error: %s" % self.thread_error) self.thread = None self.segmenting = None if self.dlg: self.dlg.segmentingProgress.reset() self.dlg.close()
def startWorker(self): self.dlg.cleaningProgress.reset() self.settings = self.dlg.get_settings() if self.settings['output_type'] == 'postgis': db_settings = self.dlg.get_dbsettings() if 'dbname' not in db_settings: self.giveMessage( 'Please make sure a database is set for exporting to PostGIS', Qgis.Info) return if 'schema' not in db_settings: self.giveMessage( 'Please make sure a schema is set for exporting to PostGIS', Qgis.Info) return if 'table_name' not in db_settings: self.giveMessage( 'Please make sure a table is set for exporting to PostGIS', Qgis.Info) return self.settings.update(db_settings) if lfh.getLayerByName( self.settings['input']).crs().postgisSrid() == 4326: self.giveMessage('Re-project the layer. EPSG:4326 not allowed.', Qgis.Info) return elif self.settings['output'] != '': cleaning = self.Worker(self.settings, self.iface) # start the cleaning in a new thread self.dlg.lockGUI(True) self.dlg.lockSettingsGUI(True) thread = QThread() self.thread_error = '' cleaning.moveToThread(thread) cleaning.finished.connect(self.workerFinished) cleaning.error.connect(self.workerError) cleaning.warning.connect(self.giveMessage) cleaning.cl_progress.connect(self.dlg.cleaningProgress.setValue) thread.started.connect(cleaning.run) thread.start() self.thread = thread self.cleaning = cleaning if is_debug: print('started') else: self.giveMessage('Missing user input!', Qgis.Info) return
def setUnlinkSnapping(self): # disable previous snapping setting if segment self.resetSnapping() # snap to vertex if self.settings[1] != 'no unlinks': self.resetIcons() unlink_icon = QPixmap(os.path.dirname(__file__) + "/custom_icons/unlink.png") self.unlinksButton.setIcon(QIcon(unlink_icon)) self.unlinksButton.setIconSize(QSize(40, 40)) proj = QgsProject.instance() # fix_print_with_import # fix_print_with_import print(proj, 'un') proj.writeEntry('Digitizing', 'SnappingMode', 'advanced') layer = lfh.getLayerByName(self.settings[0]) unlinks_layer = lfh.getLayerByName(self.settings[1]) # if unlinks_layer.isEditable(): # unlinks_layer.commitChanges() # else: # unlinks_layer.startEditing() self.iface.setActiveLayer(unlinks_layer) snapConfig = QgsSnappingConfig() snapConfig.setMode(QgsSnappingConfig.AdvancedConfiguration) layerSnapConfig = QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, self.settings[2], QgsTolerance.LayerUnits) snapConfig.setIndividualLayerSettings(layer, layerSnapConfig) proj.setAvoidIntersectionsLayers([layer]) snapConfig.setIntersectionSnapping(True) snapConfig.setEnabled(True) QgsProject.instance().setSnappingConfig(snapConfig) proj.setTopologicalEditing(False) self.unlink_mode = True else: self.iface.messageBar().pushMessage("Unlinks layer not specified!", Qgis.Critical, duration=5) self.unlink_mode = False return
def setAxialSnapping(self): # keep button pressed # un press other buttons # disable previous snapping setting self.resetSnapping() # self.axialButton.setCheckable(True) self.resetIcons() axial_icon = QPixmap(os.path.dirname(__file__) + "/custom_icons/axial.png") self.axialButton.setIcon(QIcon(axial_icon)) self.axialButton.setIconSize(QSize(40, 40)) # snap to nothing if self.settings[0] != '': proj = QgsProject.instance() # fix_print_with_import # fix_print_with_import print(proj, 'ax') proj.writeEntry('Digitizing', 'SnappingMode', 'advanced') layer = lfh.getLayerByName(self.settings[0]) self.iface.setActiveLayer(layer) # if layer.isEditable(): # layer.commitChanges() # else: # layer.startEditing() snapConfig = QgsSnappingConfig() snapConfig.setMode(QgsSnappingConfig.AdvancedConfiguration) layerSnapConfig = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex, self.settings[2], QgsTolerance.LayerUnits) snapConfig.setIndividualLayerSettings(layer, layerSnapConfig) snapConfig.setEnabled(False) proj.setAvoidIntersectionsLayers([layer]) proj.setSnappingConfig(snapConfig) proj.setTopologicalEditing(False) self.axial_mode = True else: self.iface.messageBar().pushMessage("Network layer not specified!", Qgis.Critical, duration=5) self.axial_mode = False return
def run(self): if has_pydevd and is_debug: pydevd_pycharm.settrace('localhost', port=53100, stdoutToServer=True, stderrToServer=True, suspend=False) ret = None # if self.settings: try: # cleaning settings layer_name = self.settings['input'] layer = lfh.getLayerByName(layer_name) snap_threshold = self.settings['snap'] break_at_vertices = self.settings['break'] merge_type = self.settings['merge'] collinear_threshold = self.settings['collinear_angle'] angle_threshold = self.settings['simplification_threshold'] fix_unlinks = self.settings['fix_unlinks'] orphans = self.settings['orphans'] getUnlinks = self.settings['unlinks'] [ load_range, cl1_range, cl2_range, cl3_range, break_range, merge_range, snap_range, unlinks_range, fix_range ] = self.settings['progress_ranges'] QgsMessageLog.logMessage('settings %s' % self.settings, level=Qgis.Critical) self.cl_progress.emit(0) if break_at_vertices: self.pseudo_graph.step = load_range / float( layer.featureCount()) self.pseudo_graph.progress.connect(self.cl_progress.emit) self.graph = sGraph({}, {}) self.graph.total_progress = load_range self.pseudo_graph.load_edges_w_o_topology( utf.clean_features_iter(layer.getFeatures())) QgsMessageLog.logMessage('pseudo_graph edges added %s' % load_range, level=Qgis.Critical) self.pseudo_graph.step = break_range / float( len(self.pseudo_graph.sEdges)) self.graph.load_edges( self.pseudo_graph.break_features_iter( getUnlinks, angle_threshold, fix_unlinks), angle_threshold) QgsMessageLog.logMessage('pseudo_graph edges broken %s' % break_range, level=Qgis.Critical) self.pseudo_graph.progress.disconnect() self.graph.progress.connect(self.cl_progress.emit) self.graph.total_progress = self.pseudo_graph.total_progress else: self.graph = sGraph({}, {}) self.graph.progress.connect(self.cl_progress.emit) self.graph.step = load_range / float(layer.featureCount()) self.graph.load_edges( utf.clean_features_iter(layer.getFeatures()), angle_threshold) QgsMessageLog.logMessage('graph edges added %s' % load_range, level=Qgis.Critical) self.graph.step = cl1_range / (float(len(self.graph.sEdges)) * 2.0) if orphans: self.graph.clean(True, False, snap_threshold, True) else: self.graph.clean(True, False, snap_threshold, False) QgsMessageLog.logMessage( 'graph clean parallel and closed pl %s' % cl1_range, level=Qgis.Critical) if fix_unlinks: self.graph.step = fix_range / float(len(self.graph.sEdges)) self.graph.fix_unlinks() QgsMessageLog.logMessage('unlinks added %s' % fix_range, level=Qgis.Critical) # TODO clean iteratively until no error if snap_threshold != 0: self.graph.step = snap_range / float(len( self.graph.sNodes)) self.graph.snap_endpoints(snap_threshold) QgsMessageLog.logMessage('snap %s' % snap_range, level=Qgis.Critical) self.graph.step = cl2_range / ( float(len(self.graph.sEdges)) * 2.0) if orphans: self.graph.clean(True, False, snap_threshold, True) else: self.graph.clean(True, False, snap_threshold, False) QgsMessageLog.logMessage('clean %s' % cl2_range, level=Qgis.Critical) if merge_type == 'intersections': self.graph.step = merge_range / float( len(self.graph.sNodes)) self.graph.merge_b_intersections(angle_threshold) QgsMessageLog.logMessage('merge %s %s angle_threshold ' % (merge_range, angle_threshold), level=Qgis.Critical) elif merge_type == 'collinear': self.graph.step = merge_range / float( len(self.graph.sEdges)) self.graph.merge_collinear(collinear_threshold, angle_threshold) QgsMessageLog.logMessage('merge %s' % merge_range, level=Qgis.Critical) # cleaned multiparts so that unlinks are generated properly if orphans: self.graph.step = cl3_range / ( float(len(self.graph.sEdges)) * 2.0) self.graph.clean(True, orphans, snap_threshold, False, True) QgsMessageLog.logMessage('clean %s' % cl3_range, level=Qgis.Critical) else: self.graph.step = cl3_range / ( float(len(self.graph.sEdges)) * 2.0) self.graph.clean(True, False, snap_threshold, False, True) QgsMessageLog.logMessage('clean %s' % cl3_range, level=Qgis.Critical) if getUnlinks: self.graph.step = unlinks_range / float( len(self.graph.sEdges)) self.graph.generate_unlinks() QgsMessageLog.logMessage('unlinks generated %s' % unlinks_range, level=Qgis.Critical) unlinks = self.graph.unlinks else: unlinks = [] cleaned_features = [ e.feature for e in list(self.graph.sEdges.values()) ] # add to errors multiparts and points self.graph.errors += utf.multiparts self.graph.errors += utf.points if is_debug: print("survived!") self.graph.progress.disconnect() self.cl_progress.emit(95) # return cleaned data, errors and unlinks ret = cleaned_features, self.graph.errors, unlinks except Exception as e: # forward the exception upstream self.error.emit(e, traceback.format_exc()) self.finished.emit(ret)
def workerFinished(self, ret): if self.cleaning: # clean up the worker and thread self.cleaning.finished.disconnect(self.workerFinished) self.cleaning.error.disconnect(self.workerError) self.cleaning.warning.disconnect(self.giveMessage) self.cleaning.cl_progress.disconnect( self.dlg.cleaningProgress.setValue) # clean up the worker and thread self.thread.deleteLater() self.thread.quit() self.thread.wait() self.thread.deleteLater() if ret: self.dlg.lockGUI(False) # TODO: only if edit default has been pressed before self.dlg.lockSettingsGUI(False) # get cleaning settings layer_name = self.settings['input'] path, unlinks_path, errors_path = self.settings[ 'output'] # if postgis: connstring, schema, table_name output_type = self.settings['output_type'] # get settings from layer layer = lfh.getLayerByName(layer_name) cleaned_features, errors_features, unlinks_features = ret if self.settings['errors']: if len(errors_features) > 0: errors = utf.to_layer(errors_features, layer.crs(), layer.dataProvider().encoding(), 'Point', output_type, errors_path) errors.loadNamedStyle( os.path.dirname(__file__) + '/qgis_styles/errors.qml') QgsProject.instance().addMapLayer(errors) node = QgsProject.instance().layerTreeRoot().findLayer( errors.id()) self.iface.layerTreeView().layerTreeModel( ).refreshLayerLegend(node) QgsMessageLog.logMessage('layer name %s' % layer_name, level=Qgis.Critical) else: self.giveMessage('No errors detected!', Qgis.Info) if self.settings['unlinks']: if len(unlinks_features) > 0: unlinks = utf.to_layer(unlinks_features, layer.crs(), layer.dataProvider().encoding(), 'Point', output_type, unlinks_path) unlinks.loadNamedStyle( os.path.dirname(__file__) + '/qgis_styles/unlinks.qml') QgsProject.instance().addMapLayer(unlinks) node = QgsProject.instance().layerTreeRoot().findLayer( unlinks.id()) self.iface.layerTreeView().layerTreeModel( ).refreshLayerLegend(node) else: self.giveMessage('No unlinks detected!', Qgis.Info) cleaned = utf.to_layer(cleaned_features, layer.crs(), layer.dataProvider().encoding(), 'Linestring', output_type, path) cleaned.loadNamedStyle( os.path.dirname(__file__) + '/qgis_styles/cleaned.qml') QgsProject.instance().addMapLayer(cleaned) node = QgsProject.instance().layerTreeRoot().findLayer( cleaned.id()) self.iface.layerTreeView().layerTreeModel().refreshLayerLegend( node) cleaned.updateExtents() self.giveMessage('Process ended successfully!', Qgis.Info) self.dlg.cleaningProgress.setValue(100) elif self.thread_error != '': # notify the user that sth went wrong self.giveMessage( 'Something went wrong! See the message log for more information', Qgis.Critical) QgsMessageLog.logMessage("Cleaning thread error: %s" % self.thread_error) self.thread = None self.cleaning = None if self.dlg: self.dlg.cleaningProgress.reset() self.dlg.close()
import time from qgis.core import QgsProject from rcl_cleaner.sGraph.sGraph import sGraph from rcl_cleaner.sGraph.utilityFunctions import (clean_features_iter, to_layer) from esstoolkit.utilities import layer_field_helpers as lfh # parameters layer_name = 'gb_roadlink_test' # time with previous version: ~ 16 minutes # time with new version: ~ 3 minutes # reduction: 80% layer = lfh.getLayerByName(layer_name) crs = layer.crs() encoding = layer.dataProvider().encoding() geom_type = layer.dataProvider().geometryType() getUnlinks = True snap_threshold = 1 angle_threshold = 0 merge_type = 'intersections' # merge_type = 'collinear' orphans = False fix_unlinks = True collinear_threshold = 0 duplicates = True path = None
def run(self): if has_pydevd and is_debug: pydevd.settrace('localhost', port=53100, stdoutToServer=True, stderrToServer=True, suspend=False) ret = None # if self.settings: try: # segmenting settings layer_name = self.settings['input'] unlinks_layer_name = self.settings['unlinks'] layer = lfh.getLayerByName(layer_name) unlinks = lfh.getLayerByName(unlinks_layer_name) stub_ratio = self.settings['stub_ratio'] buffer = self.settings['buffer'] errors = self.settings['errors'] # print layer, unlinks, stub_ratio, buffer self.my_segmentor = segmentor(layer, unlinks, stub_ratio, buffer, errors) self.my_segmentor.progress.connect(self.segm_progress.emit) break_point_feats, invalid_unlink_point_feats, stubs_point_feats, segmented_feats = [], [], [], [] # TODO: if postgis - run function self.my_segmentor.step = 10 / float(self.my_segmentor.layer.featureCount()) self.my_segmentor.load_graph() # self.step specified in load_graph # progress emitted by break_segm & break_feats_iter cross_p_list = [self.my_segmentor.break_segm(feat) for feat in self.my_segmentor.list_iter(list(self.my_segmentor.feats.values()))] self.my_segmentor.step = 20 / float(len(cross_p_list)) segmented_feats = [self.my_segmentor.copy_feat(feat_geom_fid[0], feat_geom_fid[1], feat_geom_fid[2]) for feat_geom_fid in self.my_segmentor.break_feats_iter(cross_p_list)] if errors: cross_p_list = set(list(itertools.chain.from_iterable(cross_p_list))) ids1 = [i for i in range(0, len(cross_p_list))] break_point_feats = [ self.my_segmentor.copy_feat(self.my_segmentor.break_f, QgsGeometry.fromPointXY(p_fid[0]), p_fid[1]) for p_fid in (list(zip(cross_p_list, ids1)))] ids2 = [i for i in range(max(ids1) + 1, max(ids1) + 1 + len(self.my_segmentor.invalid_unlinks))] invalid_unlink_point_feats = [self.my_segmentor.copy_feat(self.my_segmentor.invalid_unlink_f, QgsGeometry.fromPointXY(p_fid1[0]), p_fid1[1]) for p_fid1 in (list(zip(self.my_segmentor.invalid_unlinks, ids2)))] ids = [i for i in range(max(ids1 + ids2) + 1, max(ids1 + ids2) + 1 + len(self.my_segmentor.stubs_points))] stubs_point_feats = [ self.my_segmentor.copy_feat(self.my_segmentor.stub_f, QgsGeometry.fromPointXY(p_fid2[0]), p_fid2[1]) for p_fid2 in (list(zip(self.my_segmentor.stubs_points, ids)))] ret = segmented_feats, break_point_feats + invalid_unlink_point_feats + stubs_point_feats self.my_segmentor.progress.disconnect() except Exception as e: print(e) self.error.emit(e, traceback.format_exc()) # print "survived!" self.finished.emit(ret)
# INPUT from qgis.PyQt.QtCore import QVariant from qgis.analysis import QgsGraphBuilder from qgis.core import (QgsSpatialIndex, QgsGeometry, QgsFeature, QgsFields, QgsField, QgsWkbTypes) import catchment_analyser.catchment_analysis as catchment import catchment_analyser.utility_functions as uf from catchment_analyser.analysis_tools import CustomCost from esstoolkit.utilities import layer_field_helpers as lfh origin_vector = lfh.getLayerByName('2595D_pr_tfl_bus_stops') network = lfh.getLayerByName('2595D_spm_pr2_seg2') origin_name_field = None cost_field = 'length' tolerance = 0.01 crs = network.crs() epsg = network.crs().authid()[5:] # ANALYSIS # 1. prepare origins # Loop through origin and get or create points origins = [] for i, f in enumerate(origin_vector.getFeatures()): # Get origin name if origin_name_field: origin_name = f[origin_name_field] else: origin_name = i # "origin_" + "%s" % (i+1) origins.append({'name': origin_name, 'geom': f.geometry().centroid()})