diff --git a/img1.jpg b/img1.jpg new file mode 100644 index 0000000..328e8b1 Binary files /dev/null and b/img1.jpg differ diff --git a/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java b/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java index f34cf08..75346fc 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/app/TravelPathOptimizerApplication.java @@ -8,6 +8,7 @@ import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; + public class TravelPathOptimizerApplication extends Application { @Override public void start(Stage stage) throws IOException { @@ -27,6 +28,7 @@ public class TravelPathOptimizerApplication extends Application { stage.show(); } + public static void main(String[] args) { launch(); } diff --git a/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java b/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java index c424009..0cb63f7 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/controller/MainController.java @@ -1,14 +1,16 @@ package dev.ksan.travelpathoptimizer.controller; import dev.ksan.travelpathoptimizer.app.TransportDataGenerator; -import dev.ksan.travelpathoptimizer.graph.Graph; -import dev.ksan.travelpathoptimizer.graph.PathResult; +import dev.ksan.travelpathoptimizer.graphSimulation.GraphSimulation; +import dev.ksan.travelpathoptimizer.graphSimulation.PathResult; import dev.ksan.travelpathoptimizer.model.City; import dev.ksan.travelpathoptimizer.model.Departure; import dev.ksan.travelpathoptimizer.model.Location; 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; @@ -38,9 +40,14 @@ import javafx.scene.layout.VBox; import javafx.scene.text.Text; 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; @FXML private Text selectedFileText; @@ -54,7 +61,7 @@ public class MainController { @FXML private Button startCityButton; @FXML private Button endCityButton; private HashMap departuresMap = new HashMap<>(); - private Graph graph; + private GraphSimulation graphSimulation; private City[][] cities; private File selectedFile; @FXML private Button openFileButton; @@ -77,6 +84,67 @@ public class MainController { @FXML private TableColumn tabCostCol; @FXML private ChoiceBox 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 private void buyTicket() { @@ -87,7 +155,7 @@ public class MainController { @FXML private void findTopPaths() { - graph.reset(); + graphSimulation.reset(); updateUiGetList(); pathChoiceBox.getItems().clear(); startButton.setDisable(true); @@ -100,7 +168,7 @@ public class MainController { new Task() { @Override protected Void call() throws Exception { - graph.reset(); + graphSimulation.reset(); if (startCity != null && endCity != null) { List path = new ArrayList<>(); List departures = new ArrayList<>(); @@ -108,7 +176,7 @@ public class MainController { double totalCost = 0.0; System.out.println(categoryBox.getValue().toString()); - graph.calculateTopPaths( + graphSimulation.calculateTopPaths( startCity, endCity, path, @@ -117,16 +185,16 @@ public class MainController { departures, categoryBox.getValue().toString()); - System.out.println(graph.getTopPaths().size()); + System.out.println(graphSimulation.getTopPaths().size()); System.out.println(startCity.getName() + endCity.getName()); - if (graph.getTopPaths().isEmpty()) return null; + if (graphSimulation.getTopPaths().isEmpty()) return null; Platform.runLater( () -> { - for (PathResult pathResult : graph.getSortedPaths()) { + for (PathResult pathResult : graphSimulation.getSortedPaths()) { pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId())); } pathChoiceBox.setValue( - "Route: " + String.valueOf(graph.getSortedPaths().getFirst().getId())); + "Route: " + String.valueOf(graphSimulation.getSortedPaths().getFirst().getId())); updateUiGetList(); }); } @@ -168,9 +236,9 @@ public class MainController { e.printStackTrace(); } } - if (graph.getTopPaths().size() > 0) { + if (graphSimulation.getTopPaths().size() > 0) { Optional> departuresOpt = - graph.getSortedPaths().stream() + graphSimulation.getSortedPaths().stream() .filter( item -> item.getId() @@ -467,7 +535,7 @@ public class MainController { } this.cities = map; - this.graph = new Graph(map); + this.graphSimulation = new GraphSimulation(map); } @FXML diff --git a/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/GraphSimulation.java similarity index 97% rename from src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java rename to src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/GraphSimulation.java index 34d3d83..bf37170 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/graph/Graph.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/GraphSimulation.java @@ -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.Departure; @@ -9,7 +9,7 @@ import java.time.Duration; import java.time.LocalTime; import java.util.*; -public class Graph { +public class GraphSimulation { private City[][] matrix; private List allPaths = new ArrayList<>(); private int pathIdCounter = 1; @@ -31,7 +31,7 @@ public class Graph { cities = JsonParser.loadDepartures(cities, departures); City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities); - Graph graph = new Graph(map); + GraphSimulation graphSimulation = new GraphSimulation(map); cities = JsonParser.loadDepartures(cities, departures); for (City city : cities) { CityManager.addCity(city); @@ -39,7 +39,7 @@ public class Graph { System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName()); Map result = - graph.calculateShortestPath(cities.getFirst(), cities.getLast(), "time"); + graphSimulation.calculateShortestPath(cities.getFirst(), cities.getLast(), "time"); System.out.println( cities.get(1).getName() + " = " + result.get(cities.getLast().getLocation())); @@ -382,7 +382,7 @@ public class Graph { return allPaths; } - public Graph(City[][] matrix) { + public GraphSimulation(City[][] matrix) { this.matrix = matrix; } diff --git a/src/main/java/dev/ksan/travelpathoptimizer/graph/PathResult.java b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathResult.java similarity index 91% rename from src/main/java/dev/ksan/travelpathoptimizer/graph/PathResult.java rename to src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathResult.java index a76843c..deb6164 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/graph/PathResult.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathResult.java @@ -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.Departure; import java.time.LocalTime; import java.util.ArrayList; diff --git a/src/main/java/dev/ksan/travelpathoptimizer/graph/PathState.java b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathState.java similarity index 93% rename from src/main/java/dev/ksan/travelpathoptimizer/graph/PathState.java rename to src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathState.java index d7c2fa2..9871f31 100644 --- a/src/main/java/dev/ksan/travelpathoptimizer/graph/PathState.java +++ b/src/main/java/dev/ksan/travelpathoptimizer/graphSimulation/PathState.java @@ -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.Departure; import java.util.List; -import java.util.stream.Collectors; public class PathState { private City city; diff --git a/src/main/java/dev/ksan/travelpathoptimizer/visualize/GraphVisualizer.java b/src/main/java/dev/ksan/travelpathoptimizer/visualize/GraphVisualizer.java new file mode 100644 index 0000000..3592cb2 --- /dev/null +++ b/src/main/java/dev/ksan/travelpathoptimizer/visualize/GraphVisualizer.java @@ -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); + } + + + + +} diff --git a/src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css b/src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css new file mode 100644 index 0000000..b2d6ad4 --- /dev/null +++ b/src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css @@ -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; +}