Exemplo n.º 1
0
    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()
Exemplo n.º 2
0
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")
Exemplo n.º 3
0
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')
Exemplo n.º 4
0
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')
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()
Exemplo n.º 6
0
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)
    missing_nodes = np.setdiff1d(missing_nodes, connected)
    print(f'    Nodes to find: {missing_nodes.shape[0]:,}')
    df = pd.DataFrame({'node_id': connected, 'island': idx_islands})
    islands.append(df)
    idx_islands += 1

print(f'\nWe found {idx_islands} islands')
# %%
# consolidate everything into a single DataFrame
islands = pd.concat(islands)
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()
Exemplo n.º 8
0
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")
Exemplo n.º 9
0
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 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()
Exemplo n.º 11
0
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()