def test_compute_with_skimming(self): r = PathResults() self.g.set_skimming("free_flow_time") r.prepare(self.g) r.compute_path(origin, dest) self.assertEqual(r.milepost[-1], r.skims[dest], "Skims computed wrong when computing path")
def test_path_disconnected_penalize_link_in_memory(self): links = [2, 4, 5, 14] self.project.network.build_graphs() g = self.project.network.graphs["c"] # type: Graph g.exclude_links(links) g.set_graph("free_flow_time") g.set_blocked_centroid_flows(False) r = PathResults() r.prepare(g) r.compute_path(1, 5) self.assertEqual(None, r.path, 'Failed to return None for disconnected') r.compute_path(1, 2) self.assertEqual(len(r.path), 1, 'Returned the wrong thing for existing path on disconnected network')
def test_exclude_links(self): # excludes a link before any setting or preparation self.graph.set_blocked_centroid_flows(False) self.graph.set_graph("distance") r1 = PathResults() r1.prepare(self.graph) r1.compute_path(20, 21) self.assertEqual(list(r1.path), [62]) r1 = PathResults() self.graph.exclude_links([62]) r1.prepare(self.graph) r1.compute_path(20, 21) self.assertEqual(list(r1.path), [63, 69])
class TestPathResults(TestCase): def test_prepare(self): # graph self.g = Graph() self.g.load_from_disk(test_graph) self.g.set_graph(cost_field="distance") self.r = PathResults() try: self.r.prepare(self.g) except Exception as err: self.fail("Path result preparation failed - {}".format( err.__str__())) def test_reset(self): self.test_prepare() try: self.r.reset() except Exception as err: self.fail("Path result resetting failed - {}".format( err.__str__())) def test_update_trace(self): self.test_prepare() try: self.r.reset() except Exception as err: self.fail("Path result resetting failed - {}".format( err.__str__())) path_computation(origin, dest, self.g, self.r) if list(self.r.path) != [53, 52, 13]: self.fail("Path computation failed. Wrong sequence of links") if list(self.r.path_nodes) != [5, 168, 166, 27]: self.fail("Path computation failed. Wrong sequence of path nodes") if list(self.r.milepost) != [0, 341, 1398, 2162]: self.fail("Path computation failed. Wrong milepost results")
class TestPathResults(TestCase): def test_prepare(self): # graph self.g = Graph() self.g.load_from_disk(test_graph) self.g.set_graph(cost_field='distance', skim_fields=None) self.r = PathResults() try: self.r.prepare(self.g) except: self.fail('Path result preparation failed') def test_reset(self): self.test_prepare() try: self.r.reset() except: self.fail('Path result resetting failed') def test_update_trace(self): self.test_prepare() try: self.r.reset() except: self.fail('Path result resetting failed') path_computation(origin, dest, self.g, self.r) if list(self.r.path) != [53, 52, 13]: self.fail('Path computation failed. Wrong sequence of links') if list(self.r.path_nodes) != [5, 168, 166, 27]: self.fail('Path computation failed. Wrong sequence of path nodes') if list(self.r.milepost) != [0, 341, 1398, 2162]: self.fail('Path computation failed. Wrong milepost results')
def test_exclude_links(self): p = Project() p.load(siouxfalls_project) p.network.build_graphs() g = p.network.graphs['c'] # type: Graph # excludes a link before any setting or preparation g.exclude_links([12]) g.set_graph('distance') r1 = PathResults() r1.prepare(g) r1.compute_path(1, 14) self.assertEqual(list(r1.path), [2, 6, 10, 34]) # We exclude one link that we know was part of the last shortest path g.exclude_links([10]) r2 = PathResults() r2.prepare(g) r2.compute_path(1, 14) self.assertEqual(list(r2.path), [2, 7, 36, 34]) p.conn.close()
class TestPathResultsDisconnected(TestCase): def setUp(self) -> None: self.project = create_example(join(gettempdir(), "test_path_disconnected" + uuid4().hex)) def tearDown(self) -> None: self.project.close() def test_path_disconnected_delete_link(self): self.project.conn.executemany('delete from Links where link_id=?', [[2], [4], [5], [14]]) self.project.conn.commit() self.project.network.build_graphs() self.g = self.project.network.graphs["c"] # type: Graph self.g.set_graph("free_flow_time") self.g.set_blocked_centroid_flows(False) self.r = PathResults() self.r.prepare(self.g) self.r.compute_path(1, 5) self.assertEqual(None, self.r.path, 'Failed to return None for disconnected') self.r.compute_path(1, 2) self.assertEqual(len(self.r.path), 1, 'Returned the wrong thing for existing path on disconnected network') def test_path_disconnected_penalize_link_in_memory(self): links = [2, 4, 5, 14] self.project.network.build_graphs() g = self.project.network.graphs["c"] # type: Graph g.exclude_links(links) g.set_graph("free_flow_time") g.set_blocked_centroid_flows(False) r = PathResults() r.prepare(g) r.compute_path(1, 5) self.assertEqual(None, r.path, 'Failed to return None for disconnected') r.compute_path(1, 2) self.assertEqual(len(r.path), 1, 'Returned the wrong thing for existing path on disconnected network')
class ShortestPathDialog(QtWidgets.QDialog, FORM_CLASS): clickTool = PointTool(iface.mapCanvas()) def __init__(self, iface, project: Project, link_layer: QgsVectorLayer, node_layer: QgsVectorLayer) -> None: # QtWidgets.QDialog.__init__(self) QtWidgets.QDialog.__init__(self) self.iface = iface self.project = project self.setupUi(self) self.field_types = {} self.centroids = None self.node_layer = node_layer self.line_layer = link_layer self.node_keys = {} self.node_fields = None self.index = None self.matrix = None self.path = standard_path() self.node_id = None self.res = PathResults() self.link_features = None self.do_dist_matrix.setEnabled(False) self.from_but.setEnabled(False) self.to_but.setEnabled(False) self.load_graph_from_file.clicked.connect( self.prepare_graph_and_network) self.from_but.clicked.connect(self.search_for_point_from) self.to_but.clicked.connect(self.search_for_point_to) self.do_dist_matrix.clicked.connect(self.produces_path) def prepare_graph_and_network(self): self.do_dist_matrix.setText('Loading data') self.from_but.setEnabled(False) self.to_but.setEnabled(False) dlg2 = LoadGraphLayerSettingDialog(self.iface, self.project) dlg2.show() dlg2.exec_() if len(dlg2.error) < 1 and len(dlg2.mode) > 0: self.mode = dlg2.mode self.minimize_field = dlg2.minimize_field if not self.mode in self.project.network.graphs: self.project.network.build_graphs() if dlg2.remove_chosen_links: self.graph = self.project.network.graphs.pop(self.mode) else: self.graph = self.project.network.graphs[self.mode] self.graph.set_graph(self.minimize_field) self.graph.set_skimming(self.minimize_field) self.graph.set_blocked_centroid_flows(dlg2.block_connector) if dlg2.remove_chosen_links: idx = self.line_layer.dataProvider().fieldNameIndex('link_id') remove = [ feat.attributes()[idx] for feat in self.line_layer.selectedFeatures() ] self.graph.exclude_links(remove) self.res.prepare(self.graph) self.node_fields = [ field.name() for field in self.node_layer.dataProvider().fields().toList() ] self.index = QgsSpatialIndex() for feature in self.node_layer.getFeatures(): self.index.addFeature(feature) self.node_keys[feature.id()] = feature.attributes() idx = self.line_layer.dataProvider().fieldNameIndex('link_id') self.link_features = {} for feat in self.line_layer.getFeatures(): link_id = feat.attributes()[idx] self.link_features[link_id] = feat self.do_dist_matrix.setText('Display') self.do_dist_matrix.setEnabled(True) self.from_but.setEnabled(True) self.to_but.setEnabled(True) def clear_memory_layer(self): self.link_features = None def search_for_point_from(self): self.clickTool.clicked.connect(self.fill_path_from) self.iface.mapCanvas().setMapTool(self.clickTool) self.from_but.setEnabled(False) def search_for_point_to(self): self.iface.mapCanvas().setMapTool(self.clickTool) self.clickTool.clicked.connect(self.fill_path_to) self.to_but.setEnabled(False) def search_for_point_to_after_from(self): self.iface.mapCanvas().setMapTool(self.clickTool) self.clickTool.clicked.connect(self.fill_path_to) def fill_path_to(self): self.to_node = self.find_point() self.path_to.setText(str(self.to_node)) self.to_but.setEnabled(True) @QtCore.pyqtSlot() def fill_path_from(self): self.from_node = self.find_point() self.path_from.setText(str(self.from_node)) self.from_but.setEnabled(True) self.search_for_point_to_after_from() def find_point(self): try: point = self.clickTool.point nearest = self.index.nearestNeighbor(point, 1) self.iface.mapCanvas().setMapTool(None) self.clickTool = PointTool(self.iface.mapCanvas()) node_id = self.node_keys[nearest[0]] index_field = self.node_fields.index('node_id') node_actual_id = node_id[index_field] return node_actual_id except: pass def produces_path(self): self.to_but.setEnabled(True) if self.path_from.text().isdigit() and self.path_to.text().isdigit(): self.res.reset() path_computation(int(self.path_from.text()), int(self.path_to.text()), self.graph, self.res) if self.res.path is not None: # If you want to do selections instead of new layers if self.rdo_selection.isChecked(): self.create_path_with_selection() # If you want to create new layers else: self.create_path_with_scratch_layer() else: qgis.utils.iface.messageBar().pushMessage( "No path between " + self.path_from.text() + " and " + self.path_to.text(), "", level=3) def create_path_with_selection(self): f = 'link_id' t = " or ".join([f"{f}={k}" for k in self.res.path]) self.line_layer.selectByExpression(t) def create_path_with_scratch_layer(self): crs = self.line_layer.dataProvider().crs().authid() vl = QgsVectorLayer( "LineString?crs={}".format(crs), self.path_from.text() + " to " + self.path_to.text(), "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.line_layer.dataProvider().fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider # add a feature all_links = [] for k in self.res.path: fet = self.link_features[k] all_links.append(fet) # add all links to the temp layer pr.addFeatures(all_links) # add layer to the map QgsProject.instance().addMapLayer(vl) symbol = vl.renderer().symbol() symbol.setWidth(1) qgis.utils.iface.mapCanvas().refresh() def exit_procedure(self): self.close()
class TestPathResults(TestCase): def setUp(self) -> None: self.project = create_example( join(gettempdir(), "test_set_pce_" + uuid4().hex)) self.project.network.build_graphs() self.g = self.project.network.graphs["c"] # type: Graph self.g.set_graph("free_flow_time") self.g.set_blocked_centroid_flows(False) self.matrix = self.project.matrices.get_matrix("demand_omx") self.matrix.computational_view() self.r = PathResults() self.r.prepare(self.g) def tearDown(self) -> None: self.project.close() self.matrix.close() del self.r def test_reset(self): self.r.compute_path(dest, origin) self.r.reset() self.assertEqual(self.r.path, None, "Fail to reset the Path computation object") self.assertEqual(self.r.path_nodes, None, "Fail to reset the Path computation object") self.assertEqual(self.r.path_link_directions, None, "Fail to reset the Path computation object") self.assertEqual(self.r.milepost, None, "Fail to reset the Path computation object") self.assertEqual(self.r.predecessors.max(), -1, "Fail to reset the Path computation object") self.assertEqual(self.r.predecessors.min(), -1, "Fail to reset the Path computation object") self.assertEqual(self.r.connectors.max(), -1, "Fail to reset the Path computation object") self.assertEqual(self.r.connectors.min(), -1, "Fail to reset the Path computation object") if self.r.skims is not None: self.assertEqual(self.r.skims.max(), np.inf, "Fail to reset the Path computation object") self.assertEqual(self.r.skims.min(), np.inf, "Fail to reset the Path computation object") new_r = PathResults() with self.assertRaises(ValueError): new_r.reset() def test_compute_paths(self): path_computation(5, 2, self.g, self.r) self.assertEqual(list(self.r.path), [12, 14], "Path computation failed. Wrong sequence of links") self.assertEqual(list(self.r.path_link_directions), [1, 1], "Path computation failed. Wrong link directions") self.assertEqual( list(self.r.path_nodes), [5, 6, 2], "Path computation failed. Wrong sequence of path nodes") self.assertEqual(list(self.r.milepost), [0, 4, 9], "Path computation failed. Wrong milepost results") def test_compute_with_skimming(self): r = PathResults() self.g.set_skimming("free_flow_time") r.prepare(self.g) r.compute_path(origin, dest) self.assertEqual(r.milepost[-1], r.skims[dest], "Skims computed wrong when computing path") def test_update_trace(self): self.r.compute_path(origin, 2) self.r.update_trace(10) self.assertEqual(list(self.r.path), [13, 25], "Path update failed. Wrong sequence of links") self.assertEqual(list(self.r.path_link_directions), [1, 1], "Path update failed. Wrong link directions") self.assertEqual(list(self.r.path_nodes), [5, 9, 10], "Path update failed. Wrong sequence of path nodes") self.assertEqual(list(self.r.milepost), [0, 5, 8], "Path update failed. Wrong milepost results")
class TestBlockingTrianglePathResults(TestCase): def setUp(self) -> None: os.environ['PATH'] = os.path.join( gettempdir(), 'temp_data') + ';' + os.environ['PATH'] self.proj_dir = os.path.join(gettempdir(), uuid.uuid4().hex) copytree(triangle_graph_blocking, self.proj_dir) self.project = Project() self.project.open(self.proj_dir) self.project.network.build_graphs(modes=["c"]) self.g = self.project.network.graphs["c"] # type: Graph self.g.set_graph("free_flow_time") self.g.set_blocked_centroid_flows(True) self.r = PathResults() self.r.prepare(self.g) def tearDown(self) -> None: self.project.close() del self.r def test_compute_paths(self): self.r.compute_path(1, 2) self.assertEqual(list(self.r.path_nodes), [1, 3, 2]) self.assertEqual(list(self.r.path), [1, 2]) self.r.compute_path(2, 1) self.assertEqual(list(self.r.path_nodes), [2, 1]) self.assertEqual(list(self.r.path), [3]) self.r.compute_path(3, 1) self.assertEqual(list(self.r.path_nodes), [3, 2, 1]) self.assertEqual(list(self.r.path), [2, 3]) self.r.compute_path(3, 2) self.assertEqual(list(self.r.path_nodes), [3, 2]) self.assertEqual(list(self.r.path), [2]) self.r.compute_path(1, 3) self.assertEqual(list(self.r.path_nodes), [1, 3]) self.assertEqual(list(self.r.path), [1]) self.r.compute_path(2, 3) self.assertEqual(list(self.r.path_nodes), [2, 1, 3]) self.assertEqual(list(self.r.path), [3, 1]) def test_compute_blocking_paths(self): self.r.compute_path(4, 5) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 2, 5]) self.assertEqual(list(self.r.path), [4, 1, 2, 5]) self.r.compute_path(5, 4) self.assertEqual(list(self.r.path_nodes), [5, 2, 1, 4]) self.assertEqual(list(self.r.path), [5, 3, 4]) self.r.compute_path(6, 4) self.assertEqual(list(self.r.path_nodes), [6, 3, 2, 1, 4]) self.assertEqual(list(self.r.path), [6, 2, 3, 4]) self.r.compute_path(6, 5) self.assertEqual(list(self.r.path_nodes), [6, 3, 2, 5]) self.assertEqual(list(self.r.path), [6, 2, 5]) self.r.compute_path(4, 6) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 6]) self.assertEqual(list(self.r.path), [4, 1, 6]) self.r.compute_path(5, 6) self.assertEqual(list(self.r.path_nodes), [5, 2, 1, 3, 6]) self.assertEqual(list(self.r.path), [5, 3, 1, 6]) def test_update_trace(self): self.r.compute_path(1, 2) self.assertEqual(list(self.r.path_nodes), [1, 3, 2]) self.assertEqual(list(self.r.path), [1, 2]) self.r.update_trace(3) self.assertEqual(list(self.r.path_nodes), [1, 3]) self.assertEqual(list(self.r.path), [1]) def test_update_blocking_trace(self): self.r.compute_path(4, 5) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 2, 5]) self.assertEqual(list(self.r.path), [4, 1, 2, 5]) self.r.update_trace(6) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 6]) self.assertEqual(list(self.r.path), [4, 1, 6])
class TestPathResults(TestCase): def setUp(self) -> None: # graph self.g = Graph() self.g.load_from_disk(test_graph) self.g.set_graph(cost_field="distance") self.r = PathResults() try: self.r.prepare(self.g) except Exception as err: self.fail("Path result preparation failed - {}".format(err.__str__())) def test_reset(self): self.r.compute_path(dest, origin) self.r.reset() self.assertEqual(self.r.path, None, 'Fail to reset the Path computation object') self.assertEqual(self.r.path_nodes, None, 'Fail to reset the Path computation object') self.assertEqual(self.r.path_link_directions, None, 'Fail to reset the Path computation object') self.assertEqual(self.r.milepost, None, 'Fail to reset the Path computation object') self.assertEqual(self.r.predecessors.max(), -1, 'Fail to reset the Path computation object') self.assertEqual(self.r.predecessors.min(), -1, 'Fail to reset the Path computation object') self.assertEqual(self.r.connectors.max(), -1, 'Fail to reset the Path computation object') self.assertEqual(self.r.connectors.min(), -1, 'Fail to reset the Path computation object') self.assertEqual(self.r.skims.max(), np.inf, 'Fail to reset the Path computation object') self.assertEqual(self.r.skims.min(), np.inf, 'Fail to reset the Path computation object') new_r = PathResults() with self.assertRaises(ValueError): new_r.reset() def test_compute_paths(self): path_computation(origin, dest, self.g, self.r) if list(self.r.path) != [53, 52, 13]: self.fail("Path computation failed. Wrong sequence of links") if list(self.r.path_nodes) != [5, 168, 166, 27]: self.fail("Path computation failed. Wrong sequence of path nodes") if list(self.r.milepost) != [0, 341, 1398, 2162]: self.fail("Path computation failed. Wrong milepost results") self.r.compute_path(origin, dest) if list(self.r.path) != [53, 52, 13]: self.fail("Path computation failed. Wrong sequence of links") if list(self.r.path_nodes) != [5, 168, 166, 27]: self.fail("Path computation failed. Wrong sequence of path nodes") if list(self.r.milepost) != [0, 341, 1398, 2162]: self.fail("Path computation failed. Wrong milepost results") if list(self.r.path_link_directions) != [-1, -1, -1]: self.fail("Path computation failed. Wrong link directions") self.r.compute_path(dest, origin) if list(self.r.path_link_directions) != [1, 1, 1]: self.fail("Path computation failed. Wrong link directions") def test_update_trace(self): self.r.compute_path(origin, dest - 1) self.r.update_trace(dest) if list(self.r.path) != [53, 52, 13]: self.fail("Path computation failed. Wrong sequence of links") if list(self.r.path_nodes) != [5, 168, 166, 27]: self.fail("Path computation failed. Wrong sequence of path nodes") if list(self.r.milepost) != [0, 341, 1398, 2162]: self.fail("Path computation failed. Wrong milepost results") if list(self.r.path_link_directions) != [-1, -1, -1]: self.fail("Path computation failed. Wrong link directions")
class ImpedanceMatrixDialog(QtGui.QDialog, Ui_Impedance_Matrix): def __init__(self, iface): QDialog.__init__(self) self.iface = iface self.setupUi(self) self.result = PathResults() self.validtypes = integer_types + float_types self.tot_skims = 0 self.name_skims = 0 self.skimmeable_fields = [] self.skim_fields = [] # FIRST, we connect slot signals #For loading a new graph self.load_graph_from_file.clicked.connect( self.loaded_new_graph_from_file) # For adding skims self.bt_add_skim.clicked.connect(self.add_to_skim_list) self.skim_list.doubleClicked.connect(self.slotDoubleClicked) # RUN skims self.select_result.clicked.connect(self.browse_outfile) self.do_dist_matrix.clicked.connect(self.run_skimming) # SECOND, we set visibility for sections that should not be shown when the form opens (overlapping items) # and re-dimension the items that need re-dimensioning self.HideAllProgressBars() self.skim_list.setColumnWidth(0, 567) # loads default path from parameters self.path = standard_path() def HideAllProgressBars(self): self.progressbar.setVisible(False) self.progress_label.setVisible(False) self.progressbar.setValue(0) self.progress_label.setText('') def loaded_new_graph_from_file(self): file_types = "AequilibraE graph(*.aeg)" if len(self.graph_file_name.text()) > 0: newname = QFileDialog.getOpenFileName(None, 'Result file', self.graph_file_name.text(), file_types) else: newname = QFileDialog.getOpenFileName(None, 'Result file', self.path, file_types) self.cb_minimizing.clear() self.cb_skims.clear() self.all_centroids.setText('') self.block_paths.setChecked(False) if newname is not None: self.graph_file_name.setText(newname) self.graph = Graph() self.graph.load_from_disk(newname) self.all_centroids.setText(str(self.graph.centroids)) if self.graph.block_centroid_flows: self.block_paths.setChecked(True) graph_fields = list(self.graph.graph.dtype.names) self.skimmeable_fields = [ x for x in graph_fields if x not in [ 'link_id', 'a_node', 'b_node', 'direction', 'id', ] ] for q in self.skimmeable_fields: self.cb_minimizing.addItem(q) self.cb_skims.addItem(q) def add_to_skim_list(self): if self.cb_skims.currentIndex() >= 0: self.tot_skims += 1 self.skim_list.setRowCount(self.tot_skims) self.skim_list.setItem( self.tot_skims - 1, 0, QtGui.QTableWidgetItem((self.cb_skims.currentText()))) self.skim_fields.append(self.cb_skims.currentText()) self.cb_skims.removeItem(self.cb_skims.currentIndex()) def slotDoubleClicked(self, mi): row = mi.row() if row > -1: self.cb_skims.addItem(self.skim_list.item(row, 0).text()) self.skim_fields.pop(row) self.skim_list.removeRow(row) self.tot_skims -= 1 def browse_outfile(self): file_types = "Comma-Separated files(*.csv)" if self.npy_res.isChecked(): file_types = "Numpy Binnary Array(*.npy)" if len(self.imped_results.text()) > 0: newname = QFileDialog.getSaveFileName(None, 'Result file', self.imped_results.text(), file_types) else: newname = QFileDialog.getSaveFileName(None, 'Result file', self.path, file_types) self.imped_results.setText('') if newname != None: self.imped_results.setText(newname) def runThread(self): QObject.connect(self.workerThread, SIGNAL("ProgressValue( PyQt_PyObject )"), self.ProgressValueFromThread) QObject.connect(self.workerThread, SIGNAL("ProgressText( PyQt_PyObject )"), self.ProgressTextFromThread) QObject.connect(self.workerThread, SIGNAL("ProgressMaxValue( PyQt_PyObject )"), self.ProgressRangeFromThread) QObject.connect(self.workerThread, SIGNAL("FinishedThreadedProcedure( PyQt_PyObject )"), self.FinishedThreadedProcedure) self.workerThread.start() self.exec_() # VAL and VALUE have the following structure: (bar/text ID, value) def ProgressRangeFromThread(self, val): self.progressbar.setRange(0, val[1]) def ProgressValueFromThread(self, val): self.progressbar.setValue(val[1]) def ProgressTextFromThread(self, val): self.progress_label.setText(val[1]) def FinishedThreadedProcedure(self, val): if self.workerThread.error is not None: qgis.utils.iface.messageBar().pushMessage( "Assignment did NOT run correctly", self.workerThread.error, level=3) else: mat = self.workerThread.skim_matrices mat[mat > 1e308] = np.inf # We treat the "infinity" that should have been treated within the Cython code if self.npy_res.isChecked(): np.save(self.imped_results.text(), mat) q = open(self.imped_results.text() + '.csv', 'w') for l in self.skim_fields: print >> q, l q.flush() q.close() if self.csv_res.isChecked(): q = open(self.imped_results.text(), 'w') text = 'Origin,Destination,' + self.cb_minimizing.currentText() for l in self.skim_fields: text = text + ',' + l print >> q, text for i in range(mat.shape[0]): if np.sum(mat[i, :, :]) > 0: for j in range(mat.shape[1]): if np.sum(mat[i, j, :]) > 0: text = str(i) + ',' + str(j) s = 0 for k in range(mat.shape[2]): if mat[i, j, k] != np.inf: s += mat[i, j, k] text = text + ',' + str(mat[i, j, k]) else: text += ',' if s > 0: print >> q, text q.flush() q.close() self.close() def run_skimming(self): # Saving results centroids = int(self.all_centroids.text()) cost_field = self.cb_minimizing.currentText() block_paths = False if self.block_paths.isChecked(): block_paths = True if centroids > 0: self.graph.set_graph(centroids, cost_field, self.skim_fields, block_paths) self.result.prepare(self.graph) else: qgis.utils.iface.messageBar().pushMessage( "Nothing to run.", 'Number of centroids set to zero', level=3) if len(self.imped_results.text()) == 0: qgis.utils.iface.messageBar().pushMessage( "Cannot run.", 'No output file provided', level=3) else: self.funding1.setVisible(False) self.funding2.setVisible(False) self.progressbar.setVisible(True) self.progress_label.setVisible(True) self.workerThread = ComputeDistMatrix( qgis.utils.iface.mainWindow(), self.graph, self.result) self.runThread()
class ShortestPathDialog(QtWidgets.QDialog, FORM_CLASS): clickTool = PointTool(iface.mapCanvas()) def __init__(self, iface): # QtWidgets.QDialog.__init__(self) QtWidgets.QDialog.__init__(self, None, Qt.WindowStaysOnTopHint) self.iface = iface self.setupUi(self) self.field_types = {} self.centroids = None self.node_layer = None self.line_layer = None self.node_keys = None self.node_fields = None self.index = None self.matrix = None self.path = standard_path() self.node_id = None self.res = PathResults() self.link_features = None self.do_dist_matrix.setEnabled(False) self.load_graph_from_file.clicked.connect( self.prepare_graph_and_network) self.from_but.clicked.connect(self.search_for_point_from) self.to_but.clicked.connect(self.search_for_point_to) self.do_dist_matrix.clicked.connect(self.produces_path) def prepare_graph_and_network(self): dlg2 = LoadGraphLayerSettingDialog(self.iface) dlg2.show() dlg2.exec_() if dlg2.error is None and dlg2.graph_ok: self.link_features = dlg2.link_features self.line_layer = dlg2.line_layer self.node_layer = dlg2.node_layer self.node_keys = dlg2.node_keys self.node_id = dlg2.node_id self.node_fields = dlg2.node_fields self.index = dlg2.index self.graph = dlg2.graph self.res.prepare(self.graph) self.do_dist_matrix.setEnabled(True) def clear_memory_layer(self): self.link_features = None def search_for_point_from(self): self.clickTool.clicked.connect(self.fill_path_from) self.iface.mapCanvas().setMapTool(self.clickTool) self.from_but.setEnabled(False) def search_for_point_to(self): self.iface.mapCanvas().setMapTool(self.clickTool) self.clickTool.clicked.connect(self.fill_path_to) self.to_but.setEnabled(False) def search_for_point_to_after_from(self): self.iface.mapCanvas().setMapTool(self.clickTool) self.clickTool.clicked.connect(self.fill_path_to) def fill_path_to(self): self.to_node = self.find_point() self.path_to.setText(str(self.to_node)) self.to_but.setEnabled(True) @QtCore.pyqtSlot() def fill_path_from(self): self.from_node = self.find_point() self.path_from.setText(str(self.from_node)) self.from_but.setEnabled(True) self.search_for_point_to_after_from() def find_point(self): try: point = self.clickTool.point nearest = self.index.nearestNeighbor(point, 1) self.iface.mapCanvas().setMapTool(None) self.clickTool = PointTool(self.iface.mapCanvas()) node_id = self.node_keys[nearest[0]] index_field = self.node_fields.index(self.node_id) node_actual_id = node_id[index_field] return node_actual_id except: pass def produces_path(self): self.to_but.setEnabled(True) if self.path_from.text().isdigit() and self.path_to.text().isdigit(): self.res.reset() path_computation(int(self.path_from.text()), int(self.path_to.text()), self.graph, self.res) if self.res.path is not None: ## If you want to do selections instead of new layers, this is how to do it # f = self.cb_link_id_field.currentText() # t = '' # for k in self.res.path[:-1]: # t = t + f + "=" + str(k) + ' or ' # t = t + f + "=" + str(self.res.path[-1]) # expr = QgsExpression(t) # it = self.line_layer.getFeatures(QgsFeatureRequest(expr)) # # ids = [i.id() for i in it] # self.line_layer.setSelectedFeatures(ids) # If you want to create new layers # This way is MUCH faster crs = self.line_layer.dataProvider().crs().authid() vl = QgsVectorLayer( "LineString?crs={}".format(crs), self.path_from.text() + " to " + self.path_to.text(), "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.line_layer.dataProvider().fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider # add a feature all_links = [] for k in self.res.path: fet = self.link_features[k] all_links.append(fet) # add all links to the temp layer pr.addFeatures(all_links) # add layer to the map QgsProject.instance().addMapLayer(vl) symbol = vl.renderer().symbol() symbol.setWidth(1) qgis.utils.iface.mapCanvas().refresh() else: qgis.utils.iface.messageBar().pushMessage( "No path between " + self.path_from.text() + ' and ' + self.path_to.text(), '', level=3) def exit_procedure(self): self.close()
# %% # We set the graph for computation graph.set_graph('distance') graph.set_skimming('distance') # Get the nodes that are part of the car network missing_nodes = [ x[0] for x in project.conn.execute( f"Select node_id from nodes where instr(modes, '{mode}')").fetchall() ] missing_nodes = np.array(missing_nodes) # And prepare the path computation structure res = PathResults() res.prepare(graph) # %% # Now we can compute all the path islands we have islands = [] idx_islands = 0 # while missing_nodes.shape[0] >= 2: print(datetime.now().strftime("%H:%M:%S"), f' - Computing island: {idx_islands}') res.reset() res.compute_path(missing_nodes[0], missing_nodes[1]) res.predecessors[graph.nodes_to_indices[missing_nodes[0]]] = 0 connected = graph.all_nodes[np.where(res.predecessors >= 0)] connected = np.intersect1d(missing_nodes, connected)
class ShortestPathDialog(QtGui.QDialog, Ui_compute_path): def __init__(self, iface): QDialog.__init__(self) QtGui.QDialog.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint) self.iface = iface self.setupUi(self) self.field_types = {} self.centroids = None self.node_layer = None self.line_layer = None self.node_keys = None self.node_fields = None self.index = None self.matrix = None self.clickTool = PointTool(self.iface.mapCanvas()) self.path = standard_path() self.node_id = None self.res = PathResults() self.link_features = None self.do_dist_matrix.setEnabled(False) self.load_graph_from_file.clicked.connect( self.prepare_graph_and_network) self.from_but.clicked.connect(self.search_for_point_from) self.to_but.clicked.connect(self.search_for_point_to) self.do_dist_matrix.clicked.connect(self.produces_path) def prepare_graph_and_network(self): dlg2 = LoadGraphLayerSettingDialog(self.iface) dlg2.show() dlg2.exec_() if dlg2.error is None and dlg2.graph_ok: self.link_features = dlg2.link_features self.line_layer = dlg2.line_layer self.node_layer = dlg2.node_layer self.node_keys = dlg2.node_keys self.node_id = dlg2.node_id self.node_fields = dlg2.node_fields self.index = dlg2.index self.graph = dlg2.graph self.res.prepare(self.graph) self.do_dist_matrix.setEnabled(True) def clear_memory_layer(self): self.link_features = None def search_for_point_from(self): self.iface.mapCanvas().setMapTool(self.clickTool) QObject.connect(self.clickTool, SIGNAL("clicked"), self.fill_path_from) self.from_but.setEnabled(False) def search_for_point_to(self): self.iface.mapCanvas().setMapTool(self.clickTool) QObject.connect(self.clickTool, SIGNAL("clicked"), self.fill_path_to) self.to_but.setEnabled(False) def search_for_point_to_after_from(self): self.iface.mapCanvas().setMapTool(self.clickTool) QObject.connect(self.clickTool, SIGNAL("clicked"), self.fill_path_to) def fill_path_to(self): self.to_node = self.find_point() self.path_to.setText(str(self.to_node)) self.to_but.setEnabled(True) def fill_path_from(self): self.from_node = self.find_point() self.path_from.setText(str(self.from_node)) self.from_but.setEnabled(True) self.search_for_point_to_after_from() def find_point(self): try: point = self.clickTool.point nearest = self.index.nearestNeighbor(point, 1) self.iface.mapCanvas().setMapTool(None) self.clickTool = PointTool(self.iface.mapCanvas()) node_id = self.node_keys[nearest[0]] index_field = self.node_fields.index(self.node_id) node_actual_id = node_id[index_field] return node_actual_id except: pass def produces_path(self): self.to_but.setEnabled(True) if self.path_from.text().isdigit() and self.path_to.text().isdigit(): self.res.reset() path_computation(int(self.path_from.text()), int(self.path_to.text()), self.graph, self.res) if self.res.path is not None: ## If you want to do selections instead of new layers, this is how to do it # f = self.cb_link_id_field.currentText() # t = '' # for k in self.res.path[:-1]: # t = t + f + "=" + str(k) + ' or ' # t = t + f + "=" + str(self.res.path[-1]) # expr = QgsExpression(t) # it = self.line_layer.getFeatures(QgsFeatureRequest(expr)) # # ids = [i.id() for i in it] # self.line_layer.setSelectedFeatures(ids) # If you want to create new layers # This way is MUCH faster crs = self.line_layer.dataProvider().crs().authid() vl = QgsVectorLayer( "LineString?crs={}".format(crs), self.path_from.text() + " to " + self.path_to.text(), "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.line_layer.dataProvider().fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider # add a feature all_links = [] for k in self.res.path: fet = self.link_features[k] all_links.append(fet) # add all links to the temp layer pr.addFeatures(all_links) # add layer to the map QgsMapLayerRegistry.instance().addMapLayer(vl) # format the layer with a thick line registry = QgsSymbolLayerV2Registry.instance() lineMeta = registry.symbolLayerMetadata("SimpleLine") symbol = QgsLineSymbolV2() lineLayer = lineMeta.createSymbolLayer({ 'width': '1', 'color': self.random_rgb(), 'offset': '0', 'penstyle': 'solid', 'use_custom_dash': '0', 'joinstyle': 'bevel', 'capstyle': 'square' }) symbol.deleteSymbolLayer(0) symbol.appendSymbolLayer(lineLayer) renderer = QgsSingleSymbolRendererV2(symbol) vl.setRendererV2(renderer) qgis.utils.iface.mapCanvas().refresh() else: qgis.utils.iface.messageBar().pushMessage( "No path between " + self.path_from.text() + ' and ' + self.path_to.text(), '', level=3) def random_rgb(self): rgb = '' for i in range(3): rgb = rgb + str(randint(0, 255)) + ',' return rgb[:-1] def exit_procedure(self): self.close()
class TSPDialog(QtWidgets.QDialog, FORM_CLASS): def __init__(self, iface, project: Project, link_layer, node_layer): QtWidgets.QDialog.__init__(self) self.iface = iface self.setupUi(self) self.project = project self.link_layer = link_layer self.node_layer = node_layer self.all_modes = {} self.worker_thread: TSPProcedure = None self.but_run.clicked.connect(self.run) self.res = PathResults() self.rdo_selected.clicked.connect(self.populate_node_source) self.rdo_centroids.clicked.connect(self.populate_node_source) self.populate() self.populate_node_source() def populate_node_source(self): self.cob_start.clear() if self.rdo_selected.isChecked(): centroids = self.selected_nodes() else: curr = self.project.network.conn.cursor() curr.execute('select node_id from nodes where is_centroid=1;') centroids = [i[0] for i in curr.fetchall()] for i in centroids: self.cob_start.addItem(str(i)) def populate(self): curr = self.project.network.conn.cursor() curr.execute("""select mode_name, mode_id from modes""") for x in curr.fetchall(): self.cob_mode.addItem(f'{x[0]} ({x[1]})') self.all_modes[f'{x[0]} ({x[1]})'] = x[1] for f in self.project.network.skimmable_fields(): self.cob_minimize.addItem(f) def selected_nodes(self) -> list: idx = self.node_layer.dataProvider().fieldNameIndex('node_id') c = [ int(feat.attributes()[idx]) for feat in self.node_layer.selectedFeatures() ] return sorted(c) def run(self): error = None md = self.all_modes[self.cob_mode.currentText()] self.project.network.build_graphs() self.graph = self.project.network.graphs[md] if self.rdo_selected.isChecked(): centroids = self.selected_nodes() if len(centroids) < 3: qgis.utils.iface.messageBar().pushMessage( "You need at least three selected nodes. ", '', level=3) return centroids = np.array(centroids).astype(np.int64) self.graph.prepare_graph(centroids=centroids) else: if self.project.network.count_centroids() < 3: qgis.utils.iface.messageBar().pushMessage( "You need at least three centroids. ", '', level=3) return self.graph.set_graph(self.cob_minimize.currentText() ) # let's say we want to minimize time self.graph.set_blocked_centroid_flows(self.chb_block.isChecked()) self.graph.set_skimming([self.cob_minimize.currentText() ]) # And will skim time and distance depot = int(self.cob_start.currentText()) vehicles = 1 self.res.prepare(self.graph) self.worker_thread = TSPProcedure(qgis.utils.iface.mainWindow(), self.graph, depot, vehicles) self.run_thread() def run_thread(self): self.worker_thread.ProgressValue.connect( self.progress_value_from_thread) self.worker_thread.ProgressMaxValue.connect( self.progress_range_from_thread) self.worker_thread.ProgressText.connect(self.progress_text_from_thread) self.worker_thread.finished_threaded_procedure.connect(self.finished) self.worker_thread.start() self.exec_() def progress_range_from_thread(self, value): self.progressbar.setRange(0, value) def progress_text_from_thread(self, value): self.progress_label.setText(value) def progress_value_from_thread(self, value): self.progressbar.setValue(value) def finished(self, procedure): ns = self.worker_thread.node_sequence if len(ns) < 2: return all_links = [] for i in range(1, len(ns)): self.res.reset() path_computation(ns[i - 1], ns[i], self.graph, self.res) all_links.extend(list(self.res.path)) if self.rdo_new_layer.isChecked(): self.create_path_with_scratch_layer(all_links) else: self.create_path_with_selection(all_links) self.close() if self.worker_thread.report is not None: dlg2 = ReportDialog(self.iface, self.worker_thread.report) dlg2.show() dlg2.exec_() def create_path_with_selection(self, all_links): f = 'link_id' t = " or ".join([f"{f}={k}" for k in all_links]) self.link_layer.selectByExpression(t) def create_path_with_scratch_layer(self, path_links): # Create TSP route crs = self.link_layer.dataProvider().crs().authid() vl = QgsVectorLayer(f"LineString?crs={crs}", 'TSP Solution', "memory") pr = vl.dataProvider() # add fields pr.addAttributes(self.link_layer.dataProvider().fields()) vl.updateFields( ) # tell the vector layer to fetch changes from the provider idx = self.link_layer.dataProvider().fieldNameIndex('link_id') self.link_features = {} for feat in self.link_layer.getFeatures(): link_id = feat.attributes()[idx] self.link_features[link_id] = feat # add a feature all_links = [] for k in path_links: fet = self.link_features[k] all_links.append(fet) # add all links to the temp layer pr.addFeatures(all_links) # add layer to the map QgsProject.instance().addMapLayer(vl) symbol = vl.renderer().symbol() symbol.setWidth(1.6) qgis.utils.iface.mapCanvas().refresh() # Create TSP stops crs = self.node_layer.dataProvider().crs().authid() nl = QgsVectorLayer(f"Point?crs={crs}", 'TSP Stops', "memory") pn = nl.dataProvider() # add fields pn.addAttributes(self.node_layer.dataProvider().fields()) nl.updateFields( ) # tell the vector layer to fetch changes from the provider idx = self.node_layer.dataProvider().fieldNameIndex('node_id') self.node_features = {} for feat in self.node_layer.getFeatures(): node_id = feat.attributes()[idx] self.node_features[node_id] = feat # add the feature stop_nodes = [] seq = {} for i, k in enumerate(self.worker_thread.node_sequence[:-1]): fet = self.node_features[k] stop_nodes.append(fet) seq[k] = i + 1 # add all links to the temp layer pn.addFeatures(stop_nodes) # Goes back and adds the order of visitation for each node pn.addAttributes([QgsField('sequence', QVariant.Int)]) nl.updateFields() sdx = nl.dataProvider().fieldNameIndex('sequence') nl.startEditing() for feat in nl.getFeatures(): node_id = feat.attributes()[idx] nl.changeAttributeValue(feat.id(), sdx, seq[node_id]) nl.commitChanges() # add layer to the map QgsProject.instance().addMapLayer(nl) symbol = QgsMarkerSymbol.createSimple({'name': 'star', 'color': 'red'}) symbol.setSize(6) nl.renderer().setSymbol(symbol) qgis.utils.iface.mapCanvas().refresh()