added graph visualization
This commit is contained in:
parent
8548cf0acc
commit
462028e354
@ -8,6 +8,7 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
|
||||||
public class TravelPathOptimizerApplication extends Application {
|
public class TravelPathOptimizerApplication extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
@ -27,6 +28,7 @@ public class TravelPathOptimizerApplication extends Application {
|
|||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch();
|
launch();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package dev.ksan.travelpathoptimizer.controller;
|
package dev.ksan.travelpathoptimizer.controller;
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
|
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
|
||||||
import dev.ksan.travelpathoptimizer.graph.Graph;
|
import dev.ksan.travelpathoptimizer.graphSimulation.GraphSimulation;
|
||||||
import dev.ksan.travelpathoptimizer.graph.PathResult;
|
import dev.ksan.travelpathoptimizer.graphSimulation.PathResult;
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
import dev.ksan.travelpathoptimizer.model.City;
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
import dev.ksan.travelpathoptimizer.model.Location;
|
import dev.ksan.travelpathoptimizer.model.Location;
|
||||||
import dev.ksan.travelpathoptimizer.service.CityManager;
|
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 java.io.File;
|
import java.io.File;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -38,9 +40,14 @@ import javafx.scene.layout.VBox;
|
|||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import org.graphstream.graph.Graph;
|
||||||
|
import org.graphstream.graph.implementations.MultiGraph;
|
||||||
|
import org.graphstream.graph.implementations.SingleGraph;
|
||||||
|
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
|
|
||||||
|
@FXML private HBox graphPane;
|
||||||
@FXML private GridPane map;
|
@FXML private GridPane map;
|
||||||
@FXML private Label welcomeText;
|
@FXML private Label welcomeText;
|
||||||
@FXML private Text selectedFileText;
|
@FXML private Text selectedFileText;
|
||||||
@ -54,7 +61,7 @@ public class MainController {
|
|||||||
@FXML private Button startCityButton;
|
@FXML private Button startCityButton;
|
||||||
@FXML private Button endCityButton;
|
@FXML private Button endCityButton;
|
||||||
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
|
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
|
||||||
private Graph graph;
|
private GraphSimulation graphSimulation;
|
||||||
private City[][] cities;
|
private City[][] cities;
|
||||||
private File selectedFile;
|
private File selectedFile;
|
||||||
@FXML private Button openFileButton;
|
@FXML private Button openFileButton;
|
||||||
@ -77,6 +84,67 @@ 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");
|
||||||
|
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void showGraph() {
|
||||||
|
graph.clear();
|
||||||
|
|
||||||
|
if (map.isVisible()) {
|
||||||
|
map.setVisible(false);
|
||||||
|
map.setManaged(false);
|
||||||
|
graphPane.setVisible(true);
|
||||||
|
graphPane.setManaged(true);
|
||||||
|
} else {
|
||||||
|
graphPane.setManaged(false);
|
||||||
|
graphPane.setVisible(false);
|
||||||
|
|
||||||
|
map.setManaged(true);
|
||||||
|
map.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (City[] row : cities) {
|
||||||
|
for (City city : row) {
|
||||||
|
if (city != null) {
|
||||||
|
graph.addNode(city.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (City[] row : cities) {
|
||||||
|
for (City city : row) {
|
||||||
|
if (city != null) {
|
||||||
|
for (Departure dep : city.getDestinations()) {
|
||||||
|
City destinationCity = dep.getDestinationCity();
|
||||||
|
if (destinationCity != null) {
|
||||||
|
if (!city.getName().equals(destinationCity.getName())) {
|
||||||
|
String edgeId = city.getName() + "-" + destinationCity.getName() + "-" + dep.getIdCounter();
|
||||||
|
|
||||||
|
if (graph.getEdge(edgeId) != null) {
|
||||||
|
System.out.println("Edge already exists: " + edgeId);
|
||||||
|
System.out.println("skip");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
graph.addEdge(edgeId, city.getName(), destinationCity.getName(), true);
|
||||||
|
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());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GraphVisualizer.showGraph(graph,graphPane);
|
||||||
|
|
||||||
|
}
|
||||||
@FXML
|
@FXML
|
||||||
private void buyTicket() {
|
private void buyTicket() {
|
||||||
|
|
||||||
@ -87,7 +155,7 @@ public class MainController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void findTopPaths() {
|
private void findTopPaths() {
|
||||||
graph.reset();
|
graphSimulation.reset();
|
||||||
updateUiGetList();
|
updateUiGetList();
|
||||||
pathChoiceBox.getItems().clear();
|
pathChoiceBox.getItems().clear();
|
||||||
startButton.setDisable(true);
|
startButton.setDisable(true);
|
||||||
@ -100,7 +168,7 @@ public class MainController {
|
|||||||
new Task<Void>() {
|
new Task<Void>() {
|
||||||
@Override
|
@Override
|
||||||
protected Void call() throws Exception {
|
protected Void call() throws Exception {
|
||||||
graph.reset();
|
graphSimulation.reset();
|
||||||
if (startCity != null && endCity != null) {
|
if (startCity != null && endCity != null) {
|
||||||
List<City> path = new ArrayList<>();
|
List<City> path = new ArrayList<>();
|
||||||
List<Integer> departures = new ArrayList<>();
|
List<Integer> departures = new ArrayList<>();
|
||||||
@ -108,7 +176,7 @@ public class MainController {
|
|||||||
double totalCost = 0.0;
|
double totalCost = 0.0;
|
||||||
|
|
||||||
System.out.println(categoryBox.getValue().toString());
|
System.out.println(categoryBox.getValue().toString());
|
||||||
graph.calculateTopPaths(
|
graphSimulation.calculateTopPaths(
|
||||||
startCity,
|
startCity,
|
||||||
endCity,
|
endCity,
|
||||||
path,
|
path,
|
||||||
@ -117,16 +185,16 @@ public class MainController {
|
|||||||
departures,
|
departures,
|
||||||
categoryBox.getValue().toString());
|
categoryBox.getValue().toString());
|
||||||
|
|
||||||
System.out.println(graph.getTopPaths().size());
|
System.out.println(graphSimulation.getTopPaths().size());
|
||||||
System.out.println(startCity.getName() + endCity.getName());
|
System.out.println(startCity.getName() + endCity.getName());
|
||||||
if (graph.getTopPaths().isEmpty()) return null;
|
if (graphSimulation.getTopPaths().isEmpty()) return null;
|
||||||
Platform.runLater(
|
Platform.runLater(
|
||||||
() -> {
|
() -> {
|
||||||
for (PathResult pathResult : graph.getSortedPaths()) {
|
for (PathResult pathResult : graphSimulation.getSortedPaths()) {
|
||||||
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
||||||
}
|
}
|
||||||
pathChoiceBox.setValue(
|
pathChoiceBox.setValue(
|
||||||
"Route: " + String.valueOf(graph.getSortedPaths().getFirst().getId()));
|
"Route: " + String.valueOf(graphSimulation.getSortedPaths().getFirst().getId()));
|
||||||
updateUiGetList();
|
updateUiGetList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -168,9 +236,9 @@ public class MainController {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (graph.getTopPaths().size() > 0) {
|
if (graphSimulation.getTopPaths().size() > 0) {
|
||||||
Optional<List<Integer>> departuresOpt =
|
Optional<List<Integer>> departuresOpt =
|
||||||
graph.getSortedPaths().stream()
|
graphSimulation.getSortedPaths().stream()
|
||||||
.filter(
|
.filter(
|
||||||
item ->
|
item ->
|
||||||
item.getId()
|
item.getId()
|
||||||
@ -467,7 +535,7 @@ public class MainController {
|
|||||||
}
|
}
|
||||||
this.cities = map;
|
this.cities = map;
|
||||||
|
|
||||||
this.graph = new Graph(map);
|
this.graphSimulation = new GraphSimulation(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graph;
|
package dev.ksan.travelpathoptimizer.graphSimulation;
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
import dev.ksan.travelpathoptimizer.model.City;
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
@ -9,7 +9,7 @@ import java.time.Duration;
|
|||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Graph {
|
public class GraphSimulation {
|
||||||
private City[][] matrix;
|
private City[][] matrix;
|
||||||
private List<PathResult> allPaths = new ArrayList<>();
|
private List<PathResult> allPaths = new ArrayList<>();
|
||||||
private int pathIdCounter = 1;
|
private int pathIdCounter = 1;
|
||||||
@ -31,7 +31,7 @@ public class Graph {
|
|||||||
cities = JsonParser.loadDepartures(cities, departures);
|
cities = JsonParser.loadDepartures(cities, departures);
|
||||||
City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities);
|
City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities);
|
||||||
|
|
||||||
Graph graph = new Graph(map);
|
GraphSimulation graphSimulation = new GraphSimulation(map);
|
||||||
cities = JsonParser.loadDepartures(cities, departures);
|
cities = JsonParser.loadDepartures(cities, departures);
|
||||||
for (City city : cities) {
|
for (City city : cities) {
|
||||||
CityManager.addCity(city);
|
CityManager.addCity(city);
|
||||||
@ -39,7 +39,7 @@ public class Graph {
|
|||||||
|
|
||||||
System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName());
|
System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName());
|
||||||
Map<Location, Double> result =
|
Map<Location, Double> result =
|
||||||
graph.calculateShortestPath(cities.getFirst(), cities.getLast(), "time");
|
graphSimulation.calculateShortestPath(cities.getFirst(), cities.getLast(), "time");
|
||||||
System.out.println(
|
System.out.println(
|
||||||
cities.get(1).getName() + " = " + result.get(cities.getLast().getLocation()));
|
cities.get(1).getName() + " = " + result.get(cities.getLast().getLocation()));
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ public class Graph {
|
|||||||
return allPaths;
|
return allPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Graph(City[][] matrix) {
|
public GraphSimulation(City[][] matrix) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graph;
|
package dev.ksan.travelpathoptimizer.graphSimulation;
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
import dev.ksan.travelpathoptimizer.model.City;
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
|
||||||
|
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
@ -1,9 +1,8 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graph;
|
package dev.ksan.travelpathoptimizer.graphSimulation;
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
import dev.ksan.travelpathoptimizer.model.City;
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
import dev.ksan.travelpathoptimizer.model.Departure;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class PathState {
|
public class PathState {
|
||||||
private City city;
|
private City city;
|
@ -0,0 +1,32 @@
|
|||||||
|
package dev.ksan.travelpathoptimizer.visualize;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import org.graphstream.graph.Graph;
|
||||||
|
import org.graphstream.ui.fx_viewer.FxDefaultView;
|
||||||
|
import org.graphstream.ui.fx_viewer.FxViewer;
|
||||||
|
import org.graphstream.ui.view.Viewer;
|
||||||
|
|
||||||
|
public class GraphVisualizer {
|
||||||
|
|
||||||
|
static File cssFile = new File("src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css");
|
||||||
|
|
||||||
|
public static void showGraph(Graph graph, HBox container) {
|
||||||
|
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
node {
|
||||||
|
size: 12px;
|
||||||
|
shape: box;
|
||||||
|
text-alignment: under;
|
||||||
|
fill-color: #4a148c;
|
||||||
|
text-color: #980b0b;
|
||||||
|
text-background-mode: rounded-box;
|
||||||
|
text-background-color: #333;
|
||||||
|
text-padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge {
|
||||||
|
size: 2px;
|
||||||
|
fill-color: #979797;
|
||||||
|
arrow-shape: none;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user