added path highlighting in the graph visual

This commit is contained in:
Ksan 2025-09-07 21:44:16 +02:00
parent 8b0327aa5e
commit 35d4789088
5 changed files with 139 additions and 55 deletions

View File

@ -10,7 +10,6 @@ import dev.ksan.travelpathoptimizer.service.CityManager;
import dev.ksan.travelpathoptimizer.util.JsonParser;
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
import dev.ksan.travelpathoptimizer.visualize.GraphVisualizer;
import java.io.File;
import java.time.LocalTime;
import java.util.ArrayList;
@ -42,11 +41,9 @@ import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.MultiGraph;
import org.graphstream.graph.implementations.SingleGraph;
public class MainController {
@FXML private HBox graphPane;
@FXML private GridPane map;
@FXML private Label welcomeText;
@ -84,12 +81,12 @@ public class MainController {
@FXML private TableColumn<Departure, Double> tabCostCol;
@FXML private ChoiceBox<String> pathChoiceBox;
private Graph graph = new MultiGraph("map");
private GraphVisualizer visualizer;
private List<Departure> tempDepartureList = new ArrayList<>();
@FXML
void showGraph() {
@FXML
void showGraph() {
graph.clear();
if (map.isVisible()) {
@ -120,7 +117,8 @@ void showGraph() {
City destinationCity = dep.getDestinationCity();
if (destinationCity != null) {
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) {
System.out.println("Edge already exists: " + edgeId);
@ -128,9 +126,21 @@ void showGraph() {
} else {
try {
graph.addEdge(edgeId, city.getName(), destinationCity.getName(), true);
System.out.println("Added directed edge: " + edgeId + " from " + city.getName() + " to " + destinationCity.getName());
System.out.println(
"Added directed edge: "
+ edgeId
+ " from "
+ city.getName()
+ " to "
+ destinationCity.getName());
} catch (org.graphstream.graph.EdgeRejectedException e) {
System.out.println("Edge rejected: " + edgeId + " from " + city.getName() + " to " + destinationCity.getName());
System.out.println(
"Edge rejected: "
+ edgeId
+ " from "
+ city.getName()
+ " to "
+ destinationCity.getName());
e.printStackTrace();
}
}
@ -141,10 +151,10 @@ void showGraph() {
}
}
GraphVisualizer.showGraph(graph,graphPane);
visualizer.showGraph();
visualizer.highlightPath(tempDepartureList);
}
@FXML
private void buyTicket() {
@ -194,7 +204,8 @@ void showGraph() {
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
}
pathChoiceBox.setValue(
"Route: " + String.valueOf(graphSimulation.getSortedPaths().getFirst().getId()));
"Route: "
+ String.valueOf(graphSimulation.getSortedPaths().getFirst().getId()));
updateUiGetList();
});
}
@ -254,8 +265,10 @@ void showGraph() {
System.out.println("No matching PathResult found.");
}
}
System.out.println(departureList.size());
// System.out.println(departureList.size());
resultTable.setItems(departureList);
tempDepartureList.clear();
tempDepartureList = departureList;
resultTable.refresh();
double totalTicketPrice = calculateTotalCost(departureList);
@ -382,9 +395,16 @@ void showGraph() {
@FXML
public void initialize() {
visualizer = new GraphVisualizer(graph, graphPane);
pathChoiceBox.setOnAction(
event -> {
updateUiGetList();
Platform.runLater(
() -> {
visualizer.highlightPath(tempDepartureList);
});
// visualizer.highlightPath(tempDepartureList);
});
categoryBox.getItems().addAll("time", "price", "hops");

View File

@ -17,7 +17,7 @@ public class GraphSimulation {
private static Set<String> visitedRoutes = new HashSet<>();
public static PriorityQueue<PathResult> topPaths =
new PriorityQueue<>(5, Comparator.comparingDouble(PathResult::getCost).reversed());
/*
public static void main(String[] args) {
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
@ -64,7 +64,7 @@ public class GraphSimulation {
System.out.println("--------------------------------------------------");
}
*/
*\/
List<City> path = new ArrayList<>();
List<Integer> departuress = new ArrayList<>();
@ -77,12 +77,13 @@ public class GraphSimulation {
// Output the top 5 paths
printTopPaths();
}
public List<PathResult> getSortedPaths(){
*/
public List<PathResult> getSortedPaths() {
List<PathResult> pathList = new ArrayList<>(topPaths);
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
return pathList;
}
public void reset() {
topPaths.clear();
pathIdCounter = 1;
@ -156,11 +157,12 @@ public class GraphSimulation {
if (type.equals("time")) {
// cost += dep.getDuration();
cost += duration.toMinutes();
cost += dep.getMinTransferTime();
} else if (type.equals("price")) {
cost += dep.getPrice();
} else if (type.equals("hops")) {
cost++;
if(!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
if (!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
} else {
return;
}

View File

@ -1,9 +1,13 @@
package dev.ksan.travelpathoptimizer.visualize;
import dev.ksan.travelpathoptimizer.model.Departure;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.layout.HBox;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.ui.fx_viewer.FxDefaultView;
import org.graphstream.ui.fx_viewer.FxViewer;
import org.graphstream.ui.view.Viewer;
@ -11,22 +15,72 @@ import org.graphstream.ui.view.Viewer;
public class GraphVisualizer {
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 + "')");
for (Node node : graph) {
node.setAttribute("ui.label", node.getId());
}
Viewer viewer = new FxViewer(graph, FxViewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
viewer.enableAutoLayout();
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
container.getChildren().clear();
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();
}
}

View File

@ -14,3 +14,11 @@ edge {
fill-color: #979797;
arrow-shape: none;
}
edge.highlighted {
fill-color: green;
size: 3px;
}
node.highlighted {
fill-color: green;
}

View File

@ -41,9 +41,9 @@
<children>
<Button fx:id="headerButton1" onAction="#showMapSideBar" text="Map Options" />
<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="|" />
<Button fx:id="headerButton3" onAction="#showGraph" text="Button" />
<Button fx:id="headerButton3" onAction="#showGraph" text="Show Graph" />
</children>
</HBox>
</children></HBox>