added path highlighting in the graph visual
This commit is contained in:
parent
8b0327aa5e
commit
35d4789088
@ -10,7 +10,6 @@ import dev.ksan.travelpathoptimizer.service.CityManager;
|
|||||||
import dev.ksan.travelpathoptimizer.util.JsonParser;
|
import dev.ksan.travelpathoptimizer.util.JsonParser;
|
||||||
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
|
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
|
||||||
import dev.ksan.travelpathoptimizer.visualize.GraphVisualizer;
|
import dev.ksan.travelpathoptimizer.visualize.GraphVisualizer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -42,11 +41,9 @@ import javafx.stage.FileChooser;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.graphstream.graph.Graph;
|
import org.graphstream.graph.Graph;
|
||||||
import org.graphstream.graph.implementations.MultiGraph;
|
import org.graphstream.graph.implementations.MultiGraph;
|
||||||
import org.graphstream.graph.implementations.SingleGraph;
|
|
||||||
|
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
|
|
||||||
@FXML private HBox graphPane;
|
@FXML private HBox graphPane;
|
||||||
@FXML private GridPane map;
|
@FXML private GridPane map;
|
||||||
@FXML private Label welcomeText;
|
@FXML private Label welcomeText;
|
||||||
@ -84,67 +81,80 @@ public class MainController {
|
|||||||
@FXML private TableColumn<Departure, Double> tabCostCol;
|
@FXML private TableColumn<Departure, Double> tabCostCol;
|
||||||
@FXML private ChoiceBox<String> pathChoiceBox;
|
@FXML private ChoiceBox<String> pathChoiceBox;
|
||||||
|
|
||||||
|
|
||||||
private Graph graph = new MultiGraph("map");
|
private Graph graph = new MultiGraph("map");
|
||||||
|
private GraphVisualizer visualizer;
|
||||||
|
private List<Departure> tempDepartureList = new ArrayList<>();
|
||||||
|
|
||||||
|
@FXML
|
||||||
@FXML
|
void showGraph() {
|
||||||
void showGraph() {
|
|
||||||
graph.clear();
|
graph.clear();
|
||||||
|
|
||||||
if (map.isVisible()) {
|
if (map.isVisible()) {
|
||||||
map.setVisible(false);
|
map.setVisible(false);
|
||||||
map.setManaged(false);
|
map.setManaged(false);
|
||||||
graphPane.setVisible(true);
|
graphPane.setVisible(true);
|
||||||
graphPane.setManaged(true);
|
graphPane.setManaged(true);
|
||||||
} else {
|
} else {
|
||||||
graphPane.setManaged(false);
|
graphPane.setManaged(false);
|
||||||
graphPane.setVisible(false);
|
graphPane.setVisible(false);
|
||||||
|
|
||||||
map.setManaged(true);
|
map.setManaged(true);
|
||||||
map.setVisible(true);
|
map.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (City[] row : cities) {
|
for (City[] row : cities) {
|
||||||
for (City city : row) {
|
for (City city : row) {
|
||||||
if (city != null) {
|
if (city != null) {
|
||||||
graph.addNode(city.getName());
|
graph.addNode(city.getName());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (City[] row : cities) {
|
for (City[] row : cities) {
|
||||||
for (City city : row) {
|
for (City city : row) {
|
||||||
if (city != null) {
|
if (city != null) {
|
||||||
for (Departure dep : city.getDestinations()) {
|
for (Departure dep : city.getDestinations()) {
|
||||||
City destinationCity = dep.getDestinationCity();
|
City destinationCity = dep.getDestinationCity();
|
||||||
if (destinationCity != null) {
|
if (destinationCity != null) {
|
||||||
if (!city.getName().equals(destinationCity.getName())) {
|
if (!city.getName().equals(destinationCity.getName())) {
|
||||||
String edgeId = city.getName() + "-" + destinationCity.getName() + "-" + dep.getIdCounter();
|
String edgeId =
|
||||||
|
city.getName() + "-" + destinationCity.getName() + "-" + dep.getIdCounter();
|
||||||
|
|
||||||
if (graph.getEdge(edgeId) != null) {
|
if (graph.getEdge(edgeId) != null) {
|
||||||
System.out.println("Edge already exists: " + edgeId);
|
System.out.println("Edge already exists: " + edgeId);
|
||||||
System.out.println("skip");
|
System.out.println("skip");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
graph.addEdge(edgeId, city.getName(), destinationCity.getName(), true);
|
graph.addEdge(edgeId, city.getName(), destinationCity.getName(), true);
|
||||||
System.out.println("Added directed edge: " + edgeId + " from " + city.getName() + " to " + destinationCity.getName());
|
System.out.println(
|
||||||
} catch (org.graphstream.graph.EdgeRejectedException e) {
|
"Added directed edge: "
|
||||||
System.out.println("Edge rejected: " + edgeId + " from " + city.getName() + " to " + destinationCity.getName());
|
+ edgeId
|
||||||
e.printStackTrace();
|
+ " from "
|
||||||
}
|
+ city.getName()
|
||||||
}
|
+ " to "
|
||||||
}
|
+ destinationCity.getName());
|
||||||
}
|
} catch (org.graphstream.graph.EdgeRejectedException e) {
|
||||||
|
System.out.println(
|
||||||
|
"Edge rejected: "
|
||||||
|
+ edgeId
|
||||||
|
+ " from "
|
||||||
|
+ city.getName()
|
||||||
|
+ " to "
|
||||||
|
+ destinationCity.getName());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visualizer.showGraph();
|
||||||
GraphVisualizer.showGraph(graph,graphPane);
|
visualizer.highlightPath(tempDepartureList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void buyTicket() {
|
private void buyTicket() {
|
||||||
|
|
||||||
@ -194,7 +204,8 @@ void showGraph() {
|
|||||||
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
||||||
}
|
}
|
||||||
pathChoiceBox.setValue(
|
pathChoiceBox.setValue(
|
||||||
"Route: " + String.valueOf(graphSimulation.getSortedPaths().getFirst().getId()));
|
"Route: "
|
||||||
|
+ String.valueOf(graphSimulation.getSortedPaths().getFirst().getId()));
|
||||||
updateUiGetList();
|
updateUiGetList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -254,8 +265,10 @@ void showGraph() {
|
|||||||
System.out.println("No matching PathResult found.");
|
System.out.println("No matching PathResult found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.out.println(departureList.size());
|
// System.out.println(departureList.size());
|
||||||
resultTable.setItems(departureList);
|
resultTable.setItems(departureList);
|
||||||
|
tempDepartureList.clear();
|
||||||
|
tempDepartureList = departureList;
|
||||||
resultTable.refresh();
|
resultTable.refresh();
|
||||||
|
|
||||||
double totalTicketPrice = calculateTotalCost(departureList);
|
double totalTicketPrice = calculateTotalCost(departureList);
|
||||||
@ -382,9 +395,16 @@ void showGraph() {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
visualizer = new GraphVisualizer(graph, graphPane);
|
||||||
pathChoiceBox.setOnAction(
|
pathChoiceBox.setOnAction(
|
||||||
event -> {
|
event -> {
|
||||||
updateUiGetList();
|
updateUiGetList();
|
||||||
|
|
||||||
|
Platform.runLater(
|
||||||
|
() -> {
|
||||||
|
visualizer.highlightPath(tempDepartureList);
|
||||||
|
});
|
||||||
|
// visualizer.highlightPath(tempDepartureList);
|
||||||
});
|
});
|
||||||
|
|
||||||
categoryBox.getItems().addAll("time", "price", "hops");
|
categoryBox.getItems().addAll("time", "price", "hops");
|
||||||
|
@ -17,7 +17,7 @@ public class GraphSimulation {
|
|||||||
private static Set<String> visitedRoutes = new HashSet<>();
|
private static Set<String> visitedRoutes = new HashSet<>();
|
||||||
public static PriorityQueue<PathResult> topPaths =
|
public static PriorityQueue<PathResult> topPaths =
|
||||||
new PriorityQueue<>(5, Comparator.comparingDouble(PathResult::getCost).reversed());
|
new PriorityQueue<>(5, Comparator.comparingDouble(PathResult::getCost).reversed());
|
||||||
|
/*
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
||||||
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
||||||
@ -64,7 +64,7 @@ public class GraphSimulation {
|
|||||||
System.out.println("--------------------------------------------------");
|
System.out.println("--------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*\/
|
||||||
|
|
||||||
List<City> path = new ArrayList<>();
|
List<City> path = new ArrayList<>();
|
||||||
List<Integer> departuress = new ArrayList<>();
|
List<Integer> departuress = new ArrayList<>();
|
||||||
@ -77,12 +77,13 @@ public class GraphSimulation {
|
|||||||
// Output the top 5 paths
|
// Output the top 5 paths
|
||||||
printTopPaths();
|
printTopPaths();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
public List<PathResult> getSortedPaths(){
|
public List<PathResult> getSortedPaths() {
|
||||||
List<PathResult> pathList = new ArrayList<>(topPaths);
|
List<PathResult> pathList = new ArrayList<>(topPaths);
|
||||||
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
||||||
return pathList;
|
return pathList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
topPaths.clear();
|
topPaths.clear();
|
||||||
pathIdCounter = 1;
|
pathIdCounter = 1;
|
||||||
@ -156,11 +157,12 @@ public class GraphSimulation {
|
|||||||
if (type.equals("time")) {
|
if (type.equals("time")) {
|
||||||
// cost += dep.getDuration();
|
// cost += dep.getDuration();
|
||||||
cost += duration.toMinutes();
|
cost += duration.toMinutes();
|
||||||
|
cost += dep.getMinTransferTime();
|
||||||
} else if (type.equals("price")) {
|
} else if (type.equals("price")) {
|
||||||
cost += dep.getPrice();
|
cost += dep.getPrice();
|
||||||
} else if (type.equals("hops")) {
|
} else if (type.equals("hops")) {
|
||||||
cost++;
|
cost++;
|
||||||
if(!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
|
if (!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,86 @@
|
|||||||
package dev.ksan.travelpathoptimizer.visualize;
|
package dev.ksan.travelpathoptimizer.visualize;
|
||||||
|
|
||||||
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import org.graphstream.graph.Edge;
|
||||||
import org.graphstream.graph.Graph;
|
import org.graphstream.graph.Graph;
|
||||||
|
import org.graphstream.graph.Node;
|
||||||
import org.graphstream.ui.fx_viewer.FxDefaultView;
|
import org.graphstream.ui.fx_viewer.FxDefaultView;
|
||||||
import org.graphstream.ui.fx_viewer.FxViewer;
|
import org.graphstream.ui.fx_viewer.FxViewer;
|
||||||
import org.graphstream.ui.view.Viewer;
|
import org.graphstream.ui.view.Viewer;
|
||||||
|
|
||||||
public class GraphVisualizer {
|
public class GraphVisualizer {
|
||||||
|
|
||||||
static File cssFile = new File("src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css");
|
static File cssFile = new File("src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css");
|
||||||
|
private Graph graph;
|
||||||
|
private HBox container;
|
||||||
|
|
||||||
public static void showGraph(Graph graph, HBox container) {
|
public GraphVisualizer(Graph graph, HBox container) {
|
||||||
|
this.graph = graph;
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showGraph() {
|
||||||
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
||||||
|
|
||||||
|
for (Node node : graph) {
|
||||||
|
node.setAttribute("ui.label", node.getId());
|
||||||
|
}
|
||||||
Viewer viewer = new FxViewer(graph, FxViewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
|
Viewer viewer = new FxViewer(graph, FxViewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
|
||||||
viewer.enableAutoLayout();
|
viewer.enableAutoLayout();
|
||||||
|
|
||||||
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
|
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
|
||||||
|
|
||||||
|
|
||||||
container.getChildren().clear();
|
container.getChildren().clear();
|
||||||
|
|
||||||
container.getChildren().add(view);
|
container.getChildren().add(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void highlightPath(List<Departure> departures) {
|
||||||
|
List<String> nodes = new ArrayList();
|
||||||
|
List<String> edges = new ArrayList<>();
|
||||||
|
for (Node node : graph) {
|
||||||
|
node.removeAttribute("ui.class");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < graph.getEdgeCount(); i++) {
|
||||||
|
Edge edge = graph.getEdge(i);
|
||||||
|
edge.removeAttribute("ui.class");
|
||||||
|
}
|
||||||
|
for (Departure dep : departures) {
|
||||||
|
|
||||||
|
String from = dep.getFrom();
|
||||||
|
from = from.replaceAll("[A-Z]", "G");
|
||||||
|
if (!nodes.contains(from)) nodes.add(from);
|
||||||
|
|
||||||
|
if (!nodes.contains(dep.getTo())) nodes.add(dep.getTo());
|
||||||
|
edges.add(from + "-" + dep.getTo() + "-" + dep.getIdCounter());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String s : nodes) {
|
||||||
|
System.out.println(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String nodeId : nodes) {
|
||||||
|
Node node = graph.getNode(nodeId);
|
||||||
|
if (node != null) {
|
||||||
|
node.setAttribute("ui.class", "highlighted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < edges.size(); i++) {
|
||||||
|
String from = nodes.get(i);
|
||||||
|
String to = nodes.get(i + 1);
|
||||||
|
|
||||||
|
Edge edge = graph.getEdge(edges.get(i));
|
||||||
|
|
||||||
|
if (edge != null) {
|
||||||
|
edge.setAttribute("ui.class", "highlighted");
|
||||||
|
} else {
|
||||||
|
System.out.println("Edge not found between " + from + " and " + to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,3 +14,11 @@ edge {
|
|||||||
fill-color: #979797;
|
fill-color: #979797;
|
||||||
arrow-shape: none;
|
arrow-shape: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edge.highlighted {
|
||||||
|
fill-color: green;
|
||||||
|
size: 3px;
|
||||||
|
}
|
||||||
|
node.highlighted {
|
||||||
|
fill-color: green;
|
||||||
|
}
|
@ -41,9 +41,9 @@
|
|||||||
<children>
|
<children>
|
||||||
<Button fx:id="headerButton1" onAction="#showMapSideBar" text="Map Options" />
|
<Button fx:id="headerButton1" onAction="#showMapSideBar" text="Map Options" />
|
||||||
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
|
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
|
||||||
<Button fx:id="headerButton2" text="Button" />
|
<Button fx:id="headerButton2" text="Useless Button" />
|
||||||
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
|
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
|
||||||
<Button fx:id="headerButton3" onAction="#showGraph" text="Button" />
|
<Button fx:id="headerButton3" onAction="#showGraph" text="Show Graph" />
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
</children></HBox>
|
</children></HBox>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user