package graph; import OurApplication.OurLogElement; import logging.LogElementList; import visualizationElements.Edge; import visualizationElements.EdgeStyle; import visualizationElements.Vertex; import java.awt.*; import java.util.HashMap; import java.util.Objects; import java.util.PriorityQueue; import java.util.Vector; /** * Represents an undirected graph with vertices marked by T and edges marked by U. * Inherits from the Graph class and provides additional functionality specific to undirected graphs. * * @param Type of marking for vertices in the graph. * @param Type of marking for edges in the graph. */ public class UndirectedGraph extends Graph { // ATTRIBUTE private visualizationElements.Graph screenGraph; private LogElementList logList; // KONSTRUKTOREN /** * Constructs an empty undirected graph with default properties. */ public UndirectedGraph() { super(); this.screenGraph = new visualizationElements.Graph(new Vector(), new Vector(), false, EdgeStyle.Direct); this.logList = new LogElementList<>(); } /** * Constructs an undirected graph with a specified name. * * @param s The name of the graph. */ public UndirectedGraph(String s) { super(s); this.screenGraph = new visualizationElements.Graph(new Vector(), new Vector(), false, EdgeStyle.Direct); this.logList = new LogElementList<>(); } // GET-ER /** * Retrieves the visualization graph associated with this undirected graph. * * @return The visualization graph. */ public visualizationElements.Graph getScreenGraph() { return this.screenGraph; } /** * Retrieves the log list containing logging elements related to operations on this graph. * * @return The log element list. */ public LogElementList getLogList() { return this.logList; } /** * Creates and retrieves a deep copy of the visualization graph associated with this undirected graph. * * @return A deep copy of the visualization graph. */ public visualizationElements.Graph getScreenGraphCopy() { visualizationElements.Graph graphCopy = new visualizationElements.Graph(new Vector(), new Vector(), false, EdgeStyle.Direct); Vector copiedVertexes = new Vector<>(); Vector copiedEdges = new Vector<>(); for (visualizationElements.Vertex vertexCopy : this.screenGraph.getVertexes()) { visualizationElements.Vertex newCopiedVertex = new visualizationElements.Vertex(vertexCopy.getXpos(), vertexCopy.getYpos(), vertexCopy.getMarking(), vertexCopy.getColor()); copiedVertexes.add(newCopiedVertex); graphCopy.setVertexes(copiedVertexes); } for (visualizationElements.Edge edgeCopy : this.screenGraph.getEdges()) { visualizationElements.Edge newCopiedEdge = new visualizationElements.Edge(edgeCopy.getSource(), edgeCopy.getDestination(), edgeCopy.getMarking(), edgeCopy.getColor()); copiedEdges.add(newCopiedEdge); graphCopy.setEdges(copiedEdges); } return graphCopy; } // HINZUFÜGEN /** * Adds an edge to the undirected graph and updates the associated visualization graph. * * @param e The edge to be added. */ public void addEdge(MarkedEdge e) { super.addEdge(e); this.screenGraph.getEdges().add(e.getScreenEdge()); } /** * Adds a vertex to the undirected graph and updates the associated visualization graph. * * @param n The vertex to be added. */ public void addVertex(MarkedVertex n) { super.addVertex(n); this.screenGraph.getVertexes().add(n.getScreenVertex()); } // LÖSCHEN /** * Removes an edge from the undirected graph and updates the associated visualization graph. * * @param e The edge to be removed. */ public void removeEdge(MarkedEdge e) { super.removeEdge(e); this.screenGraph.getEdges().remove(e.getScreenEdge()); } /** * Removes a vertex from the undirected graph and updates the associated visualization graph. * * @param n The vertex to be removed. */ public void removeVertex(MarkedVertex n) { super.removeVertex(n); this.screenGraph.getVertexes().remove(n.getScreenVertex()); } // KNOTEN EIGENSCHAFTEN /** * Returns the degree of a specified vertex in the undirected graph. * The degree of a vertex is the number of edges incident to it. * * @param n The vertex for which to determine the degree. * @return The degree of the vertex. */ public int degree(MarkedVertex n) { int degree = 0; for (MarkedEdge i: this.getAllEdges()) { if (i.getSource() == n) { degree += 1; } if (i.getDestination() == n) { degree += 1; } } return degree; } /** * Returns the degree of a specified vertex by its name in the undirected graph. * * @param s The name of the vertex for which to determine the degree. * @return The degree of the vertex. * @throws NameDoesNotExistException If the vertex with the specified name does not exist in the graph. */ public int degree(String s) throws NameDoesNotExistException { for (MarkedVertex i: this.getAllVertexes()) { if (Objects.equals(i.getName(), s)) { return degree(i); } } throw new NameDoesNotExistException("One of the Vertexes might not exist"); } /** * Returns a vector containing all neighbors (adjacent vertices) of a specified vertex in the undirected graph. * * @param n The vertex for which to retrieve neighbors. * @return A vector of neighboring vertices. */ public Vector> getNeighbours(MarkedVertex n) { Vector> neighbours = new Vector<>(); for (MarkedEdge i: this.getAllEdges()) { if (i.getSource() == n && !neighbours.contains(i.getDestination())) { neighbours.add((MarkedVertex) i.getDestination()); } else if (i.getDestination() == n && !neighbours.contains(i.getSource())) { neighbours.add((MarkedVertex) i.getSource()); } } return neighbours; } /** * Computes the shortest path between two vertices using Dijkstra's algorithm in the undirected graph. * * @param n1 The starting vertex of the shortest path. * @param n2 The ending vertex of the shortest path. * @return The length of the shortest path between n1 and n2. */ public int getShortestPathDijkstra(MarkedVertex n1, MarkedVertex n2) { // Erstellt Hashmap um Distanz von Startnoten zu jedem Knoten auf dem Graph zu tracken // Erstellt Hashmap um zu tracken welche Knoten schon besucht wurden // Erstelle Hashmap um Vorgängerknoten zu tracken // Initialisierung aller Distanzen auf UNENDLICH (= -1) // Initialisierung, dass kein Knoten besucht wurde // Initialisierung aller Vorgänger auf null HashMap, Integer> distance = new HashMap<>(); HashMap, Boolean> visited = new HashMap<>(); HashMap, MarkedVertex> predecessors = new HashMap<>(); for (MarkedVertex i: this.getAllVertexes()) { distance.put(i, -1); visited.put(i, false); predecessors.put(i, null); } // Erstelle Schlange wo die nächsten Verbindungen drin sind PriorityQueue> queue = new PriorityQueue<>(new WrapperComparator()); // Distanz zu Startknoten auf 0 // Weg zu Startknoten in die Schlange aufnehmen distance.put(n1, 0); queue.add(new WrapperElement<>(n1, 0)); // Variable, die Distanz zwischen aktuellem Knoten und Nachfolger speichert int dist = 0; // Zähler für LogList int step = 0; // String für den Description Inhalt String textDescription; // Färben der Start und Ziel Knoten für Visualisierung + hinzufügen zur LogList n1.getScreenVertex().setColor(Color.RED); n2.getScreenVertex().setColor(Color.RED); textDescription = "Startknoten: " + n1.getScreenVertex().getMarking() + ", Endknoten: " + n2.getScreenVertex().getMarking(); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); while (!queue.isEmpty()) { // Den nächsten Knoten, der am wenigsten kostet, besuchen WrapperElement nextVertex = queue.poll(); // Falls Knoten schon besucht if(!visited.get(nextVertex.getElement())){ // Knoten als besucht makieren visited.put(nextVertex.getElement(), true); textDescription = "Visit " + nextVertex.getElement().getName(); // Logging System.out.println(textDescription); if (nextVertex.getElement().getScreenVertex().getColor() != Color.RED) { nextVertex.getElement().getScreenVertex().setColor(Color.BLUE); } this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); } // Wenn Weg gefunden, brich ab if (nextVertex.getElement() == n2) { MarkedVertex colorroute = n2; while (colorroute != null) { textDescription = colorroute.getName(); System.out.println(textDescription); colorroute.getScreenVertex().setColor(Color.green); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); colorroute = predecessors.get(colorroute); } //zurücksetzten der Färbungen this.clearScreenGraphColor(); return distance.get(n2); } // Gehe von diesem Knoten aus alle erreichbaren Knoten durch for (MarkedVertex i: this.getNeighbours(nextVertex.getElement())) { // Kante finde, die den jetzigen und nächsten Knoten verbindet for (MarkedEdge j: this.getAllEdges()) { if (j.getSource() == nextVertex.getElement() && j.getDestination() == i) { // Berechne Distanz zu nächstem Knoten EdgeWeightMarking marking = (EdgeWeightMarking) j.getMarking(); dist = distance.get(nextVertex.getElement()) + marking.getWeight(); break; } } // Wenn es schon einen kürzeren Weg zum Knoten gibt, überspringen if ((distance.get(i) <= dist && distance.get(i) != -1) || visited.get(i)) { continue; } // Vorgänger aktualisieren predecessors.put(i, nextVertex.getElement()); // Aktualisiere Distanz von Start zu nächstem Knoten distance.put(i, dist); // Logging textDescription = "Add " + i.getName() + " with " + dist + " weight to queue."; System.out.println(textDescription); if (i.getScreenVertex().getColor() != Color.RED) { i.getScreenVertex().setColor(Color.YELLOW); } this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); // Nehme nächsten Knoten in die Queue auf queue.add(new WrapperElement<>(i, dist)); } } //zurücksetzten der Färbungen this.clearScreenGraphColor(); MarkedVertex colorroute = n2; while (colorroute != null) { textDescription = colorroute.getName(); System.out.println(textDescription); colorroute.getScreenVertex().setColor(Color.green); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); colorroute = predecessors.get(colorroute); } System.out.println("Done"); // Gibt Distanz zu gefragtem Knoten zurück return distance.get(n2); } /** * Computes the shortest path between two vertices using A* algorithm in the undirected graph. * * @param n1 The starting vertex of the shortest path. * @param n2 The ending vertex of the shortest path. * @return The length of the shortest path between n1 and n2. */ public double getShortestPathAStar(MarkedVertex n1, MarkedVertex n2) { // Erstellt Hashmap um Distanz von Startnoten zu jedem Knoten auf dem Graph zu tracken // Erstellt Hashmap um zu tracken welche Knoten schon besucht wurden // Erstelle Hashmap um Vorgängerknoten zu tracken // Initialisierung aller Distanzen auf UNENDLICH (= -1) // Initialisierung, dass kein Knoten besucht wurde // Initialisierung aller Vorgänger auf null HashMap, Double> distance = new HashMap<>(); HashMap, Boolean> visited = new HashMap<>(); HashMap, MarkedVertex> predecessors = new HashMap<>(); for (MarkedVertex i: this.getAllVertexes()) { distance.put(i, -1.0); visited.put(i, false); predecessors.put(i, null); } // Erstelle Schlange wo die nächsten Verbindungen drin sind PriorityQueue> queue = new PriorityQueue<>(new WrapperComparator()); // Distanz zu Startknoten auf 0 // Weg zu Startknoten in die Schlange aufnehmen distance.put(n1, 0.0); queue.add(new WrapperElement<>(n1, 0)); // Variable, die Distanz zwischen aktuellem Knoten und Nachfolger speichert double dist = 0; // Variable, die Distanz zwischen dem potenziell nächsten Knoten und dem Zielknoten speichert double airDist = 0; // Variable, die Distanz zwischen dem aktuellen Knoten bis zum Endknoten speichert double distToFinish = 0; // Zähler für LogList int step = 0; // String für den Description Inhalt String textDescription; // Färben der Start und Ziel Knoten für Visualisierung + hinzufügen zur LogList n1.getScreenVertex().setColor(Color.RED); n2.getScreenVertex().setColor(Color.RED); textDescription = "Startknoten: " + n1.getScreenVertex().getMarking() + ", Endknoten: " + n2.getScreenVertex().getMarking(); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); while (!queue.isEmpty()) { // Den nächsten Knoten, der am wenigsten kostet, besuchen WrapperElement nextVertex = queue.poll(); // Falls Knoten schon besucht if(!visited.get(nextVertex.getElement())){ // Knoten als besucht makieren visited.put(nextVertex.getElement(), true); textDescription = "Visit " + nextVertex.getElement().getName(); // Logging System.out.println(textDescription); if (nextVertex.getElement().getScreenVertex().getColor() != Color.RED) { nextVertex.getElement().getScreenVertex().setColor(Color.BLUE); } this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); } // Wenn Weg gefunden, brich ab if (nextVertex.getElement() == n2) { MarkedVertex colorroute = n2; while (colorroute != null) { textDescription = colorroute.getName(); System.out.println(textDescription); colorroute.getScreenVertex().setColor(Color.green); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); colorroute = predecessors.get(colorroute); } //zurücksetzten der Färbungen this.clearScreenGraphColor(); return distance.get(n2); } // Gehe von diesem Knoten aus alle erreichbaren Knoten durch for (MarkedVertex i: this.getNeighbours(nextVertex.getElement())) { // Kante finde, die den jetzigen und nächsten Knoten verbindet for (MarkedEdge j: this.getAllEdges()) { if (j.getSource() == nextVertex.getElement() && j.getDestination() == i) { //Berechnung der Heuristik über die Luftdistanz des nächsten Knoten zum Zielknoten airDist = Math.sqrt(Math.pow((i.getCords()[0] - n2.getCords()[0]), 2) + Math.pow((i.getCords()[1] - n2.getCords()[1]), 2)) / 100; // Berechne Distanz zu nächstem Knoten EdgeWeightMarking marking = (EdgeWeightMarking) j.getMarking(); dist = distance.get(nextVertex.getElement()) + marking.getWeight(); distToFinish = distance.get(nextVertex.getElement()) + marking.getWeight() + airDist; break; } } // Wenn es schon einen kürzeren Weg zum Knoten gibt, überspringen if ((distance.get(i) <= dist && distance.get(i) != -1) || visited.get(i)) { continue; } // Aktualisiere Distanz von Start zu nächstem Knoten distance.put(i, dist); // Logging textDescription = "Add " + i.getName() + " with " + distToFinish + " weight to queue."; System.out.println(textDescription); if (i.getScreenVertex().getColor() != Color.RED) { i.getScreenVertex().setColor(Color.YELLOW); } this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); // Nehme nächsten Knoten in die Queue auf queue.add(new WrapperElement<>(i, distToFinish)); } } //zurücksetzten der Färbungen this.clearScreenGraphColor(); MarkedVertex colorroute = n2; while (colorroute != null) { textDescription = colorroute.getName(); System.out.println(textDescription); colorroute.getScreenVertex().setColor(Color.green); this.logList.add(new OurLogElement(step, textDescription, 0, this.getScreenGraphCopy())); colorroute = predecessors.get(colorroute); } System.out.println("Done"); // Gibt Distanz zu gefragtem Knoten zurück return distance.get(n2); } public void createLoglistElement() { this.logList.add(new OurLogElement(0, "", 0, this.getScreenGraphCopy())); } }