Sync with upstream

This commit is contained in:
Frank Schiebel 2024-03-12 17:34:56 +01:00
parent 39a2f13410
commit 66e8fa72bf
135 changed files with 38902 additions and 37757 deletions

View file

@ -456,6 +456,7 @@ public class Graph
if (!isKnotenEnthalten(k)){
kList.add(k);
adList.add(new ArrayList<Kante>());
k.setGraph(this);
}
}
@ -493,6 +494,7 @@ public class Graph
}
adList.remove(index);
kList.remove(k);
k.setGraph(null);
return true;
}
@ -577,6 +579,7 @@ public class Graph
adList.get(kList.indexOf(e.getStart())).add(e);
if(!gerichtet) adList.get(kList.indexOf(e.getZiel())).add(e);
kaList.add(e);
e.setGraph(this);
}
/**
@ -625,8 +628,10 @@ public class Graph
}
}
kaList.remove(e1);
e1.setGraph(null);
if(!gerichtet) {
kaList.remove(e2);
e2.setGraph(null);
}
}
@ -654,6 +659,8 @@ public class Graph
* Loescht den gesamten Graphen
*/
public void loescheAlles() {
for(Kante k : kaList) k.setGraph(null);
for(Knoten k : kList) k.setGraph(null);
adList.clear();
kList.clear();
kaList.clear();

View file

@ -1,16 +1,16 @@
[Diagram]
comments=0
OffsetX=0
OffsetY=0
Visibility=0
ShowParameter=4
SortOrder=0
ShowIcons=0
ShowConnections=0
Fontname=Segoe UI
Fontsize=10
ShowObjectDiagram=0
[Interactive]
I0=
[Diagram]
comments=0
OffsetX=0
OffsetY=0
Visibility=0
ShowParameter=4
SortOrder=0
ShowIcons=0
ShowConnections=0
Fontname=Segoe UI
Fontsize=10
ShowObjectDiagram=0
[Interactive]
I0=

View file

@ -1,16 +1,229 @@
package graph;
import java.util.HashMap;
import java.util.List;
import java.util.Arrays;
/**
* Die Klasse GraphElement ist eine Oberklasse von Knoten und Kanten.
* Sie ist nur für die interne Verarbeitung wichtig.
*
* @author Thomas Schaller
* @version v1.1
* @version 28.02.2023 (v7.0)
* v7.0: Die am Element gespeicherten Informationen werden in einer Hashmap gespeichert. Daher können beliebige weitere Informationen abgelegt werden.
* Es wird auch gespeichert, als welcher Typ die Information übergeben wurde.
*/
public abstract class GraphElement implements Comparable<GraphElement>
{
public abstract int compareTo(GraphElement e);
public abstract String getStatus();
public abstract void setStatus(String status);
protected HashMap<String,String> daten;
protected HashMap<String,String> typen;
protected Graph g;
protected String sortierKriterium;
public GraphElement() {
daten = new HashMap<String,String>();
typen = new HashMap<String,String>();
}
/**
* Setzt den Status einer Kante, der in einem String gespeichert ist.
* Form: markiert,geloescht,farbe
* Dabei sind markiert und geloescht boolsche Werte (0 = false, 1 = true) und
* die farbe eine Zahl
* @param status Statusstring
*/
public void setStatus(String status) {
List<String> items = Arrays.asList(status.split("\\s*,\\s*"));
for(int i=0; i< items.size(); i++) {
String[] pair = items.get(i).split(":");
daten.put(pair[0], pair[1]);
}
}
/**
* Liefert den Status einer Kante als String.
* Form: markiert,geloescht,farbe
* Dabei sind markiert und geloescht boolsche Werte (0 = false, 1 = true) und
* die farbe eine Zahl
* @return Statusstring
*/
public String getStatus() {
String s = "";
for (String i : daten.keySet()) {
s = s + ","+i+":"+daten.get(i);
}
s = s.substring(1);
return s;
}
/** Setzt das Sortierkriterium des Knoten/der Kante.
* @param name Bezeichnung des Wertes nach dem sortiert werden soll
*/
public void setSortierkriterium(String name) {
sortierKriterium = name;
}
/** Gibt die Beschreibung des Knoten / der Kante als Kurztext für die Anzeige im
* Kreis bzw. Kasten zurück. Dabei wird jeder Eintrag der Liste als eigene Zeile
* dargestellt. Es werden nur die Werte angezeigt. Es sind max. 2 Zeilen zulässig.
* @param namen Namen der Werte, die im Kurztext angezeigt werden sollen.
*/
public abstract List<String> getKurztext(String[] namen);
/** Gibt die Beschreibung des Knoten / der Kante als Langtext für die Anzeige im
* Tooltip-Fenster zurück. Dabei wird jeder Eintrag der Liste als eigene Zeile
* dargestellt. Es wird jeweils die Bezeichnung und der Wert ausgegeben.
* @param namen Namen der Werte, die im Tooltip angezeigt werden sollen.
*/
public abstract List<String> getLangtext(String[] namen);
/** Speichert den Graphen, in den Knoten/Kante eingefügt wurde. Damit kann er selbst seine Nummer
* ermitteln.
* @param g Graph
*/
public void setGraph(Graph g) {
this.g = g;
}
/** Speichert zusätzliche Daten am Knoten oder der Kante
* @param name Bezeichnung der Art der Daten
* @param wert Wert der zu speichernden Daten
*/
public void set(String name, String wert) {
wert = wert.replaceAll(":", "");
wert = wert.replaceAll(",", "");
daten.put(name.toLowerCase(), wert);
typen.put(name.toLowerCase(), "String");
}
/** Speichert zusätzliche Daten am Knoten oder der Kante
* Double.POSITIVE_INFINITY bzw. NEGATIVE_INFINITY wird als +/- unendlich dargestellt
* @param name Bezeichnung der Art der Daten
* @param wert Wert der zu speichernden Daten
*/
public void set(String name, double wert) {
if(wert == Double.POSITIVE_INFINITY) {
daten.put(name.toLowerCase(), "\u221e");
} else {
if(wert == Double.NEGATIVE_INFINITY) {
daten.put(name.toLowerCase(), "-\u221e");
} else {
if((int) wert == wert) {
daten.put(name.toLowerCase(), ""+(int) wert);
} else {
daten.put(name.toLowerCase(), ""+wert);
}
}
}
typen.put(name.toLowerCase(), "Number");
}
/** Speichert zusätzliche Daten am Knoten oder der Kante
* Integer.MAX_VALUE bzw. MIN_VALUE werden als +/- unendlich dargestellt.
* @param name Bezeichnung der Art der Daten
* @param wert Wert der zu speichernden Daten
*/
public void set(String name, int wert) {
typen.put(name.toLowerCase(), "Number");
if(wert == Integer.MAX_VALUE) {
daten.put(name.toLowerCase(), "\u221e");
return;
}
if(wert == Integer.MIN_VALUE) {
daten.put(name.toLowerCase(), "-\u221e");
return;
}
daten.put(name.toLowerCase(), ""+wert);
}
/** Speichert zusätzliche Daten am Knoten oder der Kante
* @param name Bezeichnung der Art der Daten
* @param wert Wert der zu speichernden Daten
*/
public void set(String name, boolean wert) {
typen.put(name.toLowerCase(), "Boolean");
daten.put(name.toLowerCase(), ""+wert);
}
/** Gibt zusätzliche Daten als String zurück
* @param name Bezeichnung der zusätzlichen Daten
* @return Wert von "name" oder "", wenn name nicht gespeichert ist
*/
public String getString(String name) {
if(daten.containsKey(name.toLowerCase())) {
return daten.get(name.toLowerCase());
} else {
return "";
}
}
/** Gibt zusätzliche Daten als int zurück
* @param name Bezeichnung der zusätzlichen Daten
* @return Wert von "name" oder 0, wenn name nicht gespeichert ist oder keine Zahl ist
*/
public int getInt(String name) {
try{
if(daten.get(name.toLowerCase()).equals("\u221e")) return Integer.MAX_VALUE;
if(daten.get(name.toLowerCase()).equals("-\u221e")) return Integer.MIN_VALUE;
return Integer.parseInt(daten.get(name.toLowerCase()));
} catch(Exception e) {
return 0;
}
}
/** Gibt zusätzliche Daten als int zurück
* @param name Bezeichnung der zusätzlichen Daten
* @return Wert von "name" oder 0, wenn name nicht gespeichert ist oder keine Zahl ist
*/
public double getDouble(String name) {
try{
if(daten.get(name.toLowerCase()).equals("\u221e")) return Double.POSITIVE_INFINITY;
if(daten.get(name.toLowerCase()).equals("-\u221e")) return Double.NEGATIVE_INFINITY;
return Double.parseDouble(daten.get(name.toLowerCase()));
} catch(Exception e) {
return 0.0;
}
}
/** Gibt zusätzliche Daten als int zurück
* @param name Bezeichnung der zusätzlichen Daten
* @return Wert von "name" oder false, wenn name nicht gespeichert ist oder kein Boolean ist
*/
public boolean getBoolean(String name) {
try{
return Boolean.parseBoolean(daten.get(name.toLowerCase()));
} catch(Exception e) {
return false;
}
}
/** Vergleicht den Knoten/Kante mit einem anderen Knoten/Kante bezüglich seines Sortierkriteriums
* Das Sortierkriterium ist normalerweise der "Wert", kann aber mit setSortierkriterium gesetzt werden.
* @param e anderer Knoten
* @return kleiner 0 der andere Knoten hat einen größeren Wert, größer 0 der andere Knoten hat einen kleineren Wert, gleich 0 beide sind gleich
*/
public int compareTo(GraphElement e) {
double w1, w2;
String s1 = sortierKriterium.toLowerCase();
String s2 = e.sortierKriterium.toLowerCase();
if(!typen.get(s1).equals(e.typen.get(s2))) return 0;
if(typen.get(s1).equals("String")){
return getString(s1).compareTo(e.getString(s2));
}
if(typen.get(s1).equals("Number")){
return (int) (getDouble(s1) - e.getDouble(s2));
}
if(typen.get(s1).equals("Boolean")){
if(getBoolean(s1) == e.getBoolean(s2)) return 0;
if(getBoolean(s1)) return 1; else return -1;
}
return 0;
}
}

View file

@ -7,10 +7,15 @@ import java.util.Arrays;
* GraphPlotter angezeigt wird.
*
* @author Thomas Schaller
* @version v6.7 (9.12.2020)
* @version v7.0 (28.02.2023)
* v7.0 Angezeigte Informationen bei Knoten/Kanten können ausgewählt werden
*
*/
public class GraphOptions
{
// Graph
Graph g;
// Bild
public String bildDatei = "";
public boolean bildAnzeigen = false;
@ -21,6 +26,12 @@ public class GraphOptions
public boolean showVertexValue = true;
public boolean showVertexText = false;
public boolean showVertexInfo = false;
// Welche Informationen sollen bei Knoten und Kanten angezeigt werden
public String[] kanteKurztext;
public String[] kanteLangtext;
public String[] knotenKurztext = {"Wert"};
public String[] knotenLangtext = {"Infotext","Wert","Markiert","Besucht"};
// Speicheroption
public boolean saveAsMatrix = false;
@ -36,7 +47,15 @@ public class GraphOptions
public GraphElement parent = null;
public int auswahl = 0; // 0 = alle, 1 = Nachbarn, 2 = Single
public GraphOptions() {
public GraphOptions(Graph g) {
this.g = g;
if(g.isGewichtet()) {
kanteKurztext = new String[]{"Gewicht"};
kanteLangtext = new String[]{"Gewicht","Markiert","Gelöscht"};
} else {
kanteKurztext = new String[]{};
kanteLangtext = new String[]{"Markiert","Gelöscht"};
}
}
public void ladeGraph(Table csvParser) {
@ -145,7 +164,7 @@ public class GraphOptions
}
public GraphOptions copy() {
GraphOptions kopie = new GraphOptions();
GraphOptions kopie = new GraphOptions(g);
kopie.bildDatei= bildDatei;
kopie.bildAnzeigen = bildAnzeigen;
kopie.vertexSize = vertexSize;
@ -161,6 +180,10 @@ public class GraphOptions
kopie.fokusArt = fokusArt;
kopie.auswahl = auswahl;
kopie.parent = parent;
kopie.kanteKurztext = kanteKurztext.clone();
kopie.knotenKurztext = knotenKurztext.clone();
kopie.kanteLangtext = kanteLangtext.clone();
kopie.knotenLangtext = knotenLangtext.clone();
return kopie;
}

View file

@ -1,6 +1,11 @@
package graph;
import imp.*;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import java.awt.Graphics2D;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
@ -12,13 +17,18 @@ import java.util.ArrayList;
import java.util.List;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
import javafx.animation.AnimationTimer;
import java.awt.image.*;
import org.apache.commons.io.FileUtils;
/**
* Der GraphPlotter ist das Herzstueck der Visualisierung und dient als Schnittstelle zur GUI.
*
* @author Thomas Schaller
* @version 09.12.2020 (v6.7)
* @version 07.02.2023 (v7.0)
* v6.9: Context-Menü schließt, wenn an andere Stelle geklickt wird
* v7.0: MouseOver - Infos für Knoten und Kanten, Infos können ausgewählt werden.
*
*/
public class GraphPlotter extends PictureViewer {
// Anfang Attribute
@ -38,6 +48,9 @@ public class GraphPlotter extends PictureViewer {
private GraphElement restrictTo = null;
private Point2D offset = new Point2D(0,0);
private ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<Point2D>(new Point2D(0, 0));
private BooleanProperty mouseMoving = new SimpleBooleanProperty();
// private JTextArea jTAMeldungen = new JTextArea("");
// private JScrollPane jTAMeldungenScrollPane = new JScrollPane(jTAMeldungen);
@ -51,36 +64,41 @@ public class GraphPlotter extends PictureViewer {
* @param String hintergrundBild Gibt den Namen eines Hintergrundbildes an
*/
public GraphPlotter() {
options = new GraphOptions();
graph = new Graph();
options = new GraphOptions(graph);
this.setStyle("-fx-background:#FFFFE8");
// add(jTAMeldungenScrollPane, BorderLayout.SOUTH);
setOnMouseClicked(mouseEvent -> mouseClicked(mouseEvent));
// setOnMouseMoved(mouseEvent -> { mouseX = mouseEvent.getSceneX(); mouseY = mouseEvent.getSceneY(); t.hide();});
this.widthProperty().addListener((value, oldWidth, newWidth) -> updateImage());
this.heightProperty().addListener((value, oldWidth, newWidth) -> updateImage());
// t = new Tooltip();
// Tooltip.install(this, t);
// t.setPrefWidth(80);
// t.setWrapText(true);
// t.setHideOnEscape(true);
// t.setStyle("-fx-background: rgba(30,30,30); -fx-text-fill: black; -fx-background-color: rgba(230,230,90,0.8);"+
// "-fx-background-radius: 6px; -fx-background-insets: 0; -fx-padding: 0.667em 0.75em 0.667em 0.75em; "+
// " -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.5) , 10, 0.0 , 0 , 3 ); -fx-font-size: 0.85em;");
setOnMouseMoved(e -> mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY())));
mouseMoving.addListener((obs, wasMoving, isNowMoving) -> {
updateImage();
});
// t.setShowDelay(Duration.seconds(1));
// t.setOnShowing(ev -> {// called just prior to being shown
// Point2D local = this.getContent().sceneToLocal(mouseX, mouseY);
// Knoten k = getKnotenAt((int) local.getX(), (int) local.getY());
// if(k == null) {
// t.hide();
// } else {
// t.setText("Knoten Nr. "+graph.getNummer(k)+"\nWert: "+k.getDoubleWert());
// }
// });
AnimationTimer timer = new AnimationTimer() {
private double lastMouseX ;
private double lastMouseY ;
long lastMouseMovement ;
long MIN_STATIONARY_TIME = 2000;
@Override
public void handle(long timestamp) {
double x = mouseLocation.get().getX();
double y = mouseLocation.get().getY();
if (Math.abs(lastMouseX-x) > 5 || Math.abs(lastMouseY-y)>5) {
lastMouseMovement = timestamp ;
lastMouseX = x;
lastMouseY = y;
}
mouseMoving.set(timestamp - lastMouseMovement < MIN_STATIONARY_TIME);
}
};
timer.start();
}
@ -101,10 +119,10 @@ public class GraphPlotter extends PictureViewer {
public void setRestrictTo(GraphElement k) {
if(restrictTo != k) {
restrictTo = k;
selected.clear();
if (k!= null) selected.add(k);
updateImage();
restrictTo = k;
selected.clear();
if (k!= null) selected.add(k);
updateImage();
}
}
@ -175,7 +193,9 @@ public class GraphPlotter extends PictureViewer {
Point2D local = this.getContent().sceneToLocal(mouseEvent.getSceneX(), mouseEvent.getSceneY());
Knoten k = getKnotenAt((int) local.getX(), (int) local.getY());
if(dragMode == 3 && k==null && getKanteAt((int) local.getX(), (int) local.getY())==null) { // neuer Knoten
graph.neuerKnoten(new Knoten((int)local.getX(), (int) local.getY())) ;
if(getContextMenu() == null) {
graph.neuerKnoten(new Knoten((int)local.getX(), (int) local.getY())) ;
} else { setContextMenu(null); }
} else {
if(dragMode == 2 && k != null && k != dragKnoten) {
graph.neueKante(dragKnoten, k, 0.0);
@ -323,6 +343,9 @@ public class GraphPlotter extends PictureViewer {
}
public Picture updateImage() {
Picture p = new Picture(2000,2000,"FFFFE8");
Graphics2D g = (Graphics2D) p.getImage().getGraphics();
Knoten restrictToKnoten = null;
Kante restrictToKante = null;
if(restrictTo != null && restrictTo instanceof Knoten) restrictToKnoten = (Knoten) restrictTo;
@ -340,8 +363,6 @@ public class GraphPlotter extends PictureViewer {
miny = Math.min(miny,k.getY());
}
Picture p = new Picture(2000,2000,"FFFFE8");
if(restrictToKnoten != null) {
knoten = graph.getNachbarknoten(restrictToKnoten);
kanten = graph.getAusgehendeKanten(restrictToKnoten);
@ -464,15 +485,28 @@ public class GraphPlotter extends PictureViewer {
}
}
if(options.showEdgeWeights && graph.isGewichtet()) {
if(options.showEdgeWeights) {
double my = (startY+startY+endY)/3;
double mx = (startX+startX+endX)/3;
p.fill(255);
p.stroke(0);
p.strokeWeight(1);
p.rect((int) mx-15, (int) my-7, 30, 16);
p.fill(0);
p.text(format(k.getGewicht()), (int) mx, (int) my);
int lh = g.getFontMetrics().getAscent();
List<String> t = k.getKurztext(options.kanteKurztext);
if(t.size() == 1) {
p.rect((int) mx-15, (int) my-(lh+4)/2, 30, lh+4);
p.fill(0);
p.text(t.get(0), (int) mx, (int) my);
}
if(t.size() > 1) {
p.rect((int) mx-15, (int) my-(lh+2), 30, lh*2+4);
p.fill(0);
p.text(t.get(0), (int) mx, (int) my-lh/2);
p.text(t.get(1), (int) mx, (int) my+lh/2);
}
}
}
}
@ -499,7 +533,14 @@ public class GraphPlotter extends PictureViewer {
p.text(""+graph.getNummer(k), k.getX(), k.getY());
} else {
if (options.showVertexValue) {
p.text(format(k.getDoubleWert()), k.getX(), k.getY());
List<String> t = k.getKurztext(options.knotenKurztext);
if(t.size() == 1) {
p.text(t.get(0), k.getX(), k.getY());
} else {
int lh = g.getFontMetrics().getAscent();
p.text(t.get(0), k.getX(), k.getY()-lh/2);
p.text(t.get(1), k.getX(), k.getY()+lh/2);
}
}
}
@ -511,6 +552,43 @@ public class GraphPlotter extends PictureViewer {
}
}
// Tooltip anzeigen, aber nicht wenn im Editiermodus
if(!mouseMoving.get() && !editable) {
Point2D local = this.getContent().sceneToLocal(mouseLocation.get().getX(), mouseLocation.get().getY());
int x = (int) local.getX();
int y = (int) local.getY();
// sowohl bei Kante wie auch Knoten
GraphElement k = getKnotenAt(x,y);
if(k == null) { k = getKanteAt(x,y);}
if(k != null) {
p.fill(200);
p.stroke(0);
p.strokeWeight(2);
List<String> t;
if(k instanceof Knoten) t = k.getLangtext(options.knotenLangtext);
else t = k.getLangtext(options.kanteLangtext);
// Größe des Kastens berechnen
int w = 0;
int lh = g.getFontMetrics().getAscent();
int h = t.size() * lh;
for(int i = 0; i<t.size(); i++) {
int w2 = g.getFontMetrics().stringWidth(t.get(i));
if(w2 > w) w = w2;
}
// Rechteck mit Text ausgeben
p.rect(x, y, w+16, h+10);
p.fill("303030");
for(int i = 0; i<t.size(); i++) {
p.text(t.get(i), x+8, y+(i+1)*lh+3);
}
}
}
this.setImage(p, false);
Picture zugeschnitten = new Picture(maxx-minx+2*options.vertexSize,maxy-miny+2*options.vertexSize);
@ -518,7 +596,6 @@ public class GraphPlotter extends PictureViewer {
return zugeschnitten;
}
public GraphOptions getGraphOptions() {
return options;
}

View file

@ -1,7 +1,7 @@
package graph;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
/**
* Die Klasse Kante beschreibt die Datenstruktur einer Kante, bestehend aus Startknoten, Gewicht und Zielknoten.
@ -10,16 +10,15 @@ import java.util.Arrays;
* Auch soll sie das Kantengewicht verwalten und Aufschluss darueber geben, ob sie gefaerbt/geloescht ist oder nicht.
*
* @author Dirk Zechnall, Thomas Schaller
* @version 22.07.2020 (v6.4)
* @version 28.02.2023 (v7.0)
* v7.0: Die Kanteninformationen werden in einer Hashmap gespeichert. Daher können beliebige weitere Informationen abgelegt werden.
*/
public class Kante extends GraphElement
{
private Knoten start;
private Knoten ziel;
private double gewicht;
private boolean markiert = false;
private boolean geloescht = false;
private int farbe = -1;
/**
* Der Konstruktor erstellt eine neue Kante mit Start- und Zielknoten und Kantengewicht.
@ -30,7 +29,12 @@ public class Kante extends GraphElement
* @param neuesGewicht Das neue Kantengewicht
*/
public Kante (Knoten neuerStart, Knoten neuerZiel, double neuesGewicht) {
gewicht = neuesGewicht;
super();
set("Gewicht",neuesGewicht);
set("Markiert", false);
set("Gelöscht", false);
set("Farbe", -1);
setSortierkriterium("Gewicht");
start = neuerStart;
ziel = neuerZiel;
}
@ -39,42 +43,58 @@ public class Kante extends GraphElement
* Die Methode init initialisiert die Kantenfaerbung (auf unmarkiert)
*/
protected void init() {
markiert = false;
geloescht = false;
}
/**
* Setzt den Status einer Kante, der in einem String gespeichert ist.
* Form: markiert,geloescht,farbe
* Dabei sind markiert und geloescht boolsche Werte (0 = false, 1 = true) und
* die farbe eine Zahl
* @param status Statusstring
*/
public void setStatus(String status) {
List<String> items = Arrays.asList(status.split("\\s*,\\s*"));
this.markiert = items.get(0).equals("1");
this.geloescht = items.get(1).equals("1");
this.farbe = Integer.parseInt(items.get(2));
}
/**
* Liefert den Status einer Kante als String.
* Form: markiert,geloescht,farbe
* Dabei sind markiert und geloescht boolsche Werte (0 = false, 1 = true) und
* die farbe eine Zahl
* @return Statusstring
*/
public String getStatus() {
return ""+(markiert ? "1," : "0,")+ (geloescht ? "1," : "0,")+ farbe;
set("Markiert", false);
set("Gelöscht", false);
set("Farbe", -1);
}
/**
* Liefert einen kurzen Text, der den Wert des Knotens angibt und innerhalb der Kreises
* des Knotens angezeigt werden kann.
* @return Array von Anzeigezeilen (dürfen max. 2 sein)
*/
public List<String> getKurztext(String[] namen) {
int l = Math.min(namen.length,2);
List<String> t = new ArrayList<String>();
for(int i = 0; i<l; i++) {
t.add(getString(namen[i]));
}
return t;
}
/**
* Liefert eine ausführliche Beschreibung der Werte des Knoten. Wird in dem Tooltext Fenster
* angezeigt, wenn man mit der Maus über den Knoten geht.
* @return Array von Anzeigezeilen
*/
public List<String> getLangtext(String[] namen) {
int l = namen.length;
List<String> t = new ArrayList<String>();
String symbol = "<->";
if(g.isGerichtet()) symbol = "->";
if(!start.getInfotext().equals("") && !ziel.getInfotext().equals("")) {
t.add(start.getInfotext()+" "+symbol+" "+ziel.getInfotext());
} else {
t.add("Knoten Nr."+g.getNummer(start)+" "+symbol+" Knoten Nr."+g.getNummer(ziel));
}
for(int i = 0; i<l; i++) {
String w =getString(namen[i]);
if(!w.isBlank())
t.add(namen[i]+": "+w);
}
return t;
}
/**
* Setzt das Gewicht der Kante
*
* @param neuesGewicht Das neu zu setzende Gewicht
*/
public void setGewicht(double neuesGewicht) {
gewicht = neuesGewicht;
set("Gewicht", neuesGewicht);
}
/**
@ -83,7 +103,7 @@ public class Kante extends GraphElement
* @return Gewicht der Kante
*/
public double getGewicht() {
return gewicht;
return getDouble("Gewicht");
}
/**
@ -91,8 +111,8 @@ public class Kante extends GraphElement
*
* @param neuerSatrtKnoten Der neu zu setzende Startknoten
*/
public void setStart(Knoten neuerSatrtKnoten) {
start = neuerSatrtKnoten;
public void setStart(Knoten neuerStartKnoten) {
start = neuerStartKnoten;
}
/**
@ -139,7 +159,7 @@ public class Kante extends GraphElement
* @param wert Der neu zu setzende markiert-Wert
*/
public void setMarkiert(boolean wert) {
markiert = wert;
set("markiert", wert);
}
/**
@ -148,7 +168,7 @@ public class Kante extends GraphElement
* @return markiert?
*/
public boolean isMarkiert() {
return markiert;
return getBoolean("markiert");
}
/**
@ -157,7 +177,7 @@ public class Kante extends GraphElement
* @param wert Der neu zu setzende gelöscht-Wert
*/
public void setGeloescht(boolean wert) {
geloescht = wert;
set("Gelöscht", wert);
}
/**
@ -166,7 +186,7 @@ public class Kante extends GraphElement
* @return gelöscht?
*/
public boolean isGeloescht() {
return geloescht;
return getBoolean("Gelöscht");
}
/**
@ -176,12 +196,12 @@ public class Kante extends GraphElement
* @return Nummer der Farbe
*/
public int getFarbe() {
if(farbe == -1) {
if(geloescht) return 2;
if(markiert) return 1;
if(getInt("Farbe") == -1) {
if(isGeloescht()) return 2;
if(isMarkiert()) return 1;
return 0;
}
return farbe;
return getInt("Farbe");
}
/**
@ -190,7 +210,7 @@ public class Kante extends GraphElement
*/
public void setFarbe(int farbe) {
if(farbe>=0 && farbe < 20)
this.farbe = farbe;
set("Farbe",farbe);
}
/**
@ -198,19 +218,10 @@ public class Kante extends GraphElement
*/
public void setStandardFarbe() {
farbe = -1;
setFarbe(-1);
}
/** Vergleicht die Kante mit einer anderen Kante bezüglich ihres Gewichts
* @param e andere Kante
* @return kleiner 0 die andere Kante hat ein größeres Gewicht, größer 0 die andere Kante hat ein kleineres Gewicht, gleich 0 beides sind gleich
*/
public int compareTo(GraphElement e) {
double w1, w2;
if(e instanceof Knoten) w1 = ((Knoten) e).getDoubleWert(); else w1 = ((Kante) e).getGewicht();
w2 = getGewicht();
return (int) (w2-w1);
}
/**
* Die Methode ueberschreibt die Methode toString() und gibt die String-Raepraesentation einer Kante zurueck
@ -219,7 +230,7 @@ public class Kante extends GraphElement
*/
@Override
public String toString() {
return " --("+gewicht+")--> ";
return " --("+getGewicht()+")--> ";
}
}

View file

@ -1,6 +1,7 @@
package graph;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
/**
* Diese Klasse Knoten definiert einen Knoten.
@ -8,17 +9,16 @@ import java.util.Arrays;
* Im Infotext kann eine zusätzliche Information für die Anzeige gespeichert werden.
*
* @author Dirk Zechnall, Thomas Schaller
* @version 22.07.2020 (v6.4)
* @version 28.02.2023 (v7.0)
* v7.0: Die Knoteninformationen werden in einer Hashmap gespeichert. Daher können beliebige weitere Informationen abgelegt werden.
*/
public class Knoten extends GraphElement
{
private String infotext;
private double wert; // wird z.B. fuer den Colorierungs-Algorithmus verwendet - speichert da die Farben (codiert als Zahlen)
private boolean istMarkiert = false;
private boolean istBesucht = false;
private int x;
private int y;
private int farbe = -1;
/**
* Der Konstruktor erstellt einen neuen Knoten mit einem neuen Namen
*
@ -26,10 +26,7 @@ public class Knoten extends GraphElement
* @param y y-Position des Knotens
*/
public Knoten(int x, int y) {
this.x = x;
this.y = y;
wert = 0;
infotext = "";
this(x,y,0);
}
/**
@ -40,62 +37,74 @@ public class Knoten extends GraphElement
* @param neuerWert Der neue Wert des Knotens
*/
public Knoten(int x, int y, double neuerWert) {
super();
this.x = x;
this.y = y;
wert = neuerWert;
infotext = "";
}
/**
* Setzt den Status eines Knotens aus einem Status-String
* Format: wert,markiert,besucht,farbe
* wobei wert eine double-Zahl, mariert und besucht ein boolean-Wert (0=false, 1 = true) und
* farbe eine zahl ist.
*
* @param status Der Statusstring
*/
public void setStatus(String status) {
List<String> items = Arrays.asList(status.split("\\s*,\\s*"));
this.wert = Double.parseDouble(items.get(0)); // wird z.B. fuer den Colorierungs-Algorithmus verwendet - speichert da die Farben (codiert als Zahlen)
this.istMarkiert = items.get(1).equals("1");
this.istBesucht = items.get(2).equals("1");
this.farbe = Integer.parseInt(items.get(3));
}
/**
* Liefert den Status eines Knotens als Status-String
* Format: wert,markiert,besucht,farbe
* wobei wert eine double-Zahl, mariert und besucht ein boolean-Wert (0=false, 1 = true) und
* farbe eine zahl ist.
*
* @return Der Statusstring
*/
public String getStatus() {
return ""+wert+","+(istMarkiert ? "1," : "0,")+ (istBesucht ? "1," : "0,")+ farbe;
set("Wert",neuerWert);
set("Markiert", false);
set("Geloescht", false);
set("Farbe", -1);
setSortierkriterium("Wert");
}
/**
* Die Methode init initialisiert den Zustand eines Knotens
*/
protected void init() {
wert = 0.0;
farbe = -1;
istMarkiert = false;
istBesucht = false;
set("Wert", 0.0);
set("Farbe", -1);
set("Markiert", false);
set("Besucht", false);
}
/**
* Liefert einen kurzen Text, der den Wert des Knotens angibt und innerhalb der Kreises
* des Knotens angezeigt werden kann.
* @return Array von Anzeigezeilen (dürfen max. 2 sein)
*/
public List<String> getKurztext(String[] namen) {
int l = Math.min(namen.length,2);
List<String> t = new ArrayList<String>();
for(int i = 0; i<l; i++) {
String text = getString(namen[i]);
if(text.length()>3)
t.add(text.substring(0,3));
else
t.add(text);
}
return t;
}
/**
* Liefert eine ausführliche Beschreibung der Werte des Knoten. Wird in dem Tooltext Fenster
* angezeigt, wenn man mit der Maus über den Knoten geht.
* @return Array von Anzeigezeilen
*/
public List<String> getLangtext(String[] namen) {
int l = namen.length;
List<String> t = new ArrayList<String>();
t.add("Knoten Nr. "+g.getNummer(this));
for(int i = 0; i<l; i++) {
String w =getString(namen[i]);
if(!w.isEmpty())
t.add(namen[i]+": "+w);
}
return t;
}
/** Setzt den Infotext für einen Knoten
* @param infotext Der neue Text
*/
public void setInfotext(String infotext) {
this.infotext = infotext;
set("Infotext", infotext);
}
/** Liefert den Infotext des Knotens
* @return Der Infotext
*/
public String getInfotext(){
return infotext;
return getString("Infotext");
}
/**
@ -104,7 +113,7 @@ public class Knoten extends GraphElement
* @param neuerWert Der neu zu setzende Wert
*/
public void setWert(double neuerWert) {
wert = neuerWert;
set("Wert", neuerWert);
}
/**
@ -113,7 +122,7 @@ public class Knoten extends GraphElement
* @return Wert des Knotens
*/
public int getIntWert() {
return (int) wert;
return getInt("Wert");
}
/**
@ -122,7 +131,7 @@ public class Knoten extends GraphElement
* @return Wert des Knotens
*/
public double getDoubleWert() {
return wert;
return getDouble("Wert");
}
/**
@ -131,7 +140,7 @@ public class Knoten extends GraphElement
* @param markiert Der neu zu setzende Markiertwert
*/
public void setMarkiert(boolean markiert) {
istMarkiert = markiert;
set("Markiert", markiert);
}
/**
@ -140,7 +149,7 @@ public class Knoten extends GraphElement
* @return markiert?
*/
public boolean isMarkiert() {
return istMarkiert;
return getBoolean("Markiert");
}
/**
@ -148,8 +157,8 @@ public class Knoten extends GraphElement
*
* @param markiert Der neu zu setzende Besuchtwert
*/
public void setBesucht(boolean markiert) {
istBesucht = markiert;
public void setBesucht(boolean besucht) {
set("Besucht",besucht);
}
/**
@ -158,10 +167,9 @@ public class Knoten extends GraphElement
* @return besucht?
*/
public boolean isBesucht() {
return istBesucht;
return getBoolean("Besucht");
}
/**
* Gibt den Index der Farbe des Knoten zurück.
* Standardmäßig hängt die Farbe von den Attributen markiert und besucht ab.
@ -169,17 +177,17 @@ public class Knoten extends GraphElement
* @return Farbe des Knotens
*/
public int getFarbe() {
if (farbe == -1) {
if (getInt("Farbe") == -1) {
int f = 0;
if(istMarkiert) {
if(isMarkiert()) {
f += 1;
}
if(istBesucht) {
if(isBesucht()) {
f += 2;
}
return f;
}
return farbe;
return getInt("Farbe");
}
/**
@ -190,15 +198,15 @@ public class Knoten extends GraphElement
*/
public void setFarbe(int farbe) {
this.farbe = farbe;
set("Farbe",farbe);
}
/** Gibt zurück, ob die Knotenfarbe automatisch aus den Attributen ermittelt wird.
* @return true=Farbe wird automatisch bestimmt, false=Farbe wurde explizit gesetzt.
*/
public boolean isFarbeAutomatisch() {
return this.farbe == -1;
return getInt("Farbe") == -1;
}
/** Legt fest, ob die Knotenfarbe automatisch aus den Attributen ermittelt wird.
@ -207,9 +215,9 @@ public class Knoten extends GraphElement
*/
public void setFarbeAutomatisch(boolean auto) {
if(auto) {
farbe = -1;
set("Farbe", -1);
} else {
if(farbe == -1) farbe = 0;
if(isFarbeAutomatisch()) set("Farbe", 0);
}
}
@ -236,21 +244,11 @@ public class Knoten extends GraphElement
/** Setzt die y-Position des Knotens
* @param y y-Postion
*/ public void setY(int y) {
*/
public void setY(int y) {
this.y = y;
}
/** Vergleicht den Knoten mit einem anderen Knoten bezüglich seines Werts
* @param e anderer Knoten
* @return kleiner 0 der andere Knoten hat einen größeren Wert, größer 0 der andere Knoten hat einen kleineren Wert, gleich 0 beide sind gleich
*/
public int compareTo(GraphElement e) {
double w1, w2;
if(e instanceof Knoten) w1 = ((Knoten) e).getDoubleWert(); else w1 = ((Kante) e).getGewicht();
w2 = getDoubleWert();
return (int) (w2-w1);
}
/**
* Die Methode ueberschreibt die Methode toString() und gibt die String-Raepraesentation eines Knotens zurueck
*
@ -258,6 +256,7 @@ public class Knoten extends GraphElement
*/
@Override
public String toString() {
return "["+infotext+","+wert+","+istMarkiert+","+istBesucht+"]";
return getStatus();
}
}

View file

@ -1,110 +1,107 @@
#BlueJ package file
dependency1.from=Graph
dependency1.to=Knoten
dependency1.type=UsesDependency
dependency10.from=GraphOptions
dependency10.to=GraphElement
dependency10.type=UsesDependency
dependency11.from=Knoten
dependency11.to=GraphElement
dependency11.type=UsesDependency
dependency12.from=Knoten
dependency12.to=Kante
dependency12.type=UsesDependency
dependency13.from=Hilfe
dependency13.to=GraphPlotter
dependency13.type=UsesDependency
dependency2.from=Graph
dependency2.to=Kante
dependency2.type=UsesDependency
dependency3.from=Kante
dependency3.to=Knoten
dependency3.type=UsesDependency
dependency4.from=Kante
dependency4.to=GraphElement
dependency4.type=UsesDependency
dependency5.from=GraphPlotter
dependency5.to=Graph
dependency5.type=UsesDependency
dependency6.from=GraphPlotter
dependency6.to=GraphOptions
dependency6.type=UsesDependency
dependency7.from=GraphPlotter
dependency7.to=GraphElement
dependency7.type=UsesDependency
dependency8.from=GraphPlotter
dependency8.to=Knoten
dependency8.type=UsesDependency
dependency9.from=GraphPlotter
dependency9.to=Kante
dependency9.type=UsesDependency
objectbench.height=93
objectbench.width=907
package.divider.horizontal=0.6
package.divider.vertical=0.8207885304659498
package.editor.height=451
package.editor.width=790
package.editor.x=879
package.editor.y=186
package.frame.height=657
package.frame.width=931
package.numDependencies=13
package.numTargets=7
package.showExtends=true
package.showUses=true
readme.height=60
readme.name=@README
readme.width=49
readme.x=10
readme.y=10
target1.height=50
target1.name=Graph
target1.naviview.expanded=true
target1.showInterface=true
target1.type=ClassTarget
target1.width=80
target1.x=340
target1.y=180
target2.height=50
target2.name=Kante
target2.showInterface=false
target2.type=ClassTarget
target2.width=80
target2.x=240
target2.y=260
target3.height=50
target3.name=GraphElement
target3.showInterface=false
target3.type=AbstractTarget
target3.width=120
target3.x=220
target3.y=360
target4.height=50
target4.name=GraphPlotter
target4.naviview.expanded=true
target4.showInterface=false
target4.type=ClassTarget
target4.width=110
target4.x=410
target4.y=80
target5.height=50
target5.name=GraphOptions
target5.showInterface=false
target5.type=ClassTarget
target5.width=110
target5.x=180
target5.y=80
target6.height=50
target6.name=Knoten
target6.showInterface=false
target6.type=ClassTarget
target6.width=80
target6.x=460
target6.y=260
target7.height=50
target7.name=Hilfe
target7.showInterface=false
target7.type=InterfaceTarget
target7.width=80
target7.x=610
target7.y=90
#BlueJ package file
dependency1.from=Graph
dependency1.to=Knoten
dependency1.type=UsesDependency
dependency10.from=GraphOptions
dependency10.to=GraphElement
dependency10.type=UsesDependency
dependency11.from=Hilfe
dependency11.to=GraphPlotter
dependency11.type=UsesDependency
dependency12.from=Kante
dependency12.to=Knoten
dependency12.type=UsesDependency
dependency2.from=Graph
dependency2.to=Kante
dependency2.type=UsesDependency
dependency3.from=GraphElement
dependency3.to=Graph
dependency3.type=UsesDependency
dependency4.from=GraphPlotter
dependency4.to=Graph
dependency4.type=UsesDependency
dependency5.from=GraphPlotter
dependency5.to=GraphOptions
dependency5.type=UsesDependency
dependency6.from=GraphPlotter
dependency6.to=GraphElement
dependency6.type=UsesDependency
dependency7.from=GraphPlotter
dependency7.to=Knoten
dependency7.type=UsesDependency
dependency8.from=GraphPlotter
dependency8.to=Kante
dependency8.type=UsesDependency
dependency9.from=GraphOptions
dependency9.to=Graph
dependency9.type=UsesDependency
objectbench.height=209
objectbench.width=601
package.divider.horizontal=0.5996055226824457
package.divider.vertical=0.6823529411764706
package.editor.height=457
package.editor.width=899
package.editor.x=759
package.editor.y=196
package.frame.height=780
package.frame.width=1050
package.numDependencies=12
package.numTargets=7
package.showExtends=true
package.showUses=true
readme.height=60
readme.name=@README
readme.width=49
readme.x=10
readme.y=10
target1.height=50
target1.name=Graph
target1.naviview.expanded=true
target1.showInterface=false
target1.type=ClassTarget
target1.width=80
target1.x=340
target1.y=180
target2.height=50
target2.name=Kante
target2.showInterface=false
target2.type=ClassTarget
target2.width=80
target2.x=240
target2.y=260
target3.height=50
target3.name=GraphElement
target3.showInterface=true
target3.type=AbstractTarget
target3.width=110
target3.x=220
target3.y=360
target4.height=50
target4.name=GraphPlotter
target4.naviview.expanded=true
target4.showInterface=false
target4.type=ClassTarget
target4.width=110
target4.x=410
target4.y=80
target5.height=50
target5.name=GraphOptions
target5.showInterface=false
target5.type=ClassTarget
target5.width=110
target5.x=180
target5.y=80
target6.height=50
target6.name=Knoten
target6.showInterface=false
target6.type=ClassTarget
target6.width=80
target6.x=460
target6.y=260
target7.height=50
target7.name=Hilfe
target7.showInterface=false
target7.type=InterfaceTarget
target7.width=80
target7.x=610
target7.y=90