First Commit (Fobi)

This commit is contained in:
Frank Schiebel 2021-07-12 14:04:20 +02:00
commit 2bff291a51
336 changed files with 88781 additions and 0 deletions

139
graph/Graph.ctxt Normal file
View file

@ -0,0 +1,139 @@
#BlueJ class context
comment0.target=Graph
comment0.text=\r\n\ Dies\ ist\ das\ Herz\ vom\ "GraphTester"\ -\ der\ Graph\ selber,\ gepeichert\ als\ Adjazenzliste.\r\n\ Die\ Klasse\ erlaubt\ durch\ geeignete\ Methoden\:\r\n\ -\ die\ Speicherung\ als\ Adjazenzmatrix,\r\n\ -\ das\ Hinzufuegen\ und\ Loeschen\ von\ knoten\ und\ Kanten,\r\n\ -\ das\ Markieren\ von\ Knoten\ und\ Kanten,\r\n\ -\ eine\ Aussage\ darueber,\ ob\ Knoten\ oder\ Kanten\ enthalten\ sind\ und\r\n\ -\ eine\ Ausgabe\ des\ Graphen\ in\ textueller\ Form\ sowie\ als\ csv-Datei.\r\n\ \r\n\ \r\n\ @author\ Dirk\ Zechnall,\ Thomas\ Schaller\r\n\ @version\ 31.01.2021\ (v6.5)\r\n
comment1.params=isGerichtet\ isGewichtet
comment1.target=Graph(boolean,\ boolean)
comment1.text=\r\n\ Der\ Konstruktor\ erstellt\ einen\ neuen\ Graphen\ (genauer\ eine\ neue\ Adjazenzliste)\r\n\ @param\ isGerichtet\ gibt\ an,\ ob\ es\ sich\ um\ einen\ gerichteten\ Graphen\ handelt\r\n\ @param\ isGewichtet\ gibt\ an,\ ob\ die\ Kanten\ gewichtet\ sind.\r\n
comment10.params=k
comment10.target=int\ getNummer(Kante)
comment10.text=\ Gibt\ die\ Nummer\ einer\ Kante\ zur\u00FCck\r\n\ @param\ \ k\ gesuchte\ Kante\r\n\ @return\ Nummer\ der\ Kante\ (mit\ 0\ beginnend)\r\n
comment11.params=
comment11.target=double[][]\ getAdjazenzMatrix()
comment11.text=\r\n\ Die\ Methode\ getAdjazenzMatrix()\ gibt\ die\ Adjazenzmatrix\ zurueck.\r\n\ \r\n\ @return\ \ double[][]\ Die\ AdjazenzMatrix\ als\ zweidimensionales\ Array\r\n
comment12.params=filter
comment12.target=java.util.List\ getAlleKanten(java.util.function.Predicate[])
comment12.text=\r\n\ Gibt\ eine\ Liste\ aller\ Kanten\ des\ Graphen\ zur\u00FCck.\r\n\ @param\ \ \ filter\ \ \ \ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ Liste\ aller\ Kanten\r\n
comment13.params=
comment13.target=void\ entferneMarkierungBeiAllenKnoten()
comment13.text=\r\n\ Entfernt\ die\ Markierung\ bei\ allen\ Knoten\ des\ Graphen.\r\n
comment14.params=
comment14.target=void\ initialisiereAlleKnoten()
comment14.text=\r\n\ Initialisiert\ alle\ Knoten\ des\ Graphen.\r\n
comment15.params=
comment15.target=void\ initialisiereAlleKanten()
comment15.text=\r\n\ Initialisiert\ alle\ Kanten\ des\ Graphen.\r\n
comment16.params=k
comment16.target=boolean\ isKnotenEnthalten(Knoten)
comment16.text=\r\n\ Ueberprueft,\ ob\ ein\ Knoten\ in\ der\ Knotenliste\ enthalten\ ist.\r\n\ Sobald\ in\ der\ Knotenliste\ der\ Knoten\ k\ gefunden\ wird,\ wird\ true\ ausgegeben.\r\n\ \r\n\ @param\ \ k\ \ Der\ gesuchte\ Knoten\r\n\ @return\ \ true\=\ ist\ enthalten,\ false\ \=\ ist\ nicht\ enthalten\r\n
comment17.params=
comment17.target=int\ getAnzahlKnoten()
comment17.text=\r\n\ Gibt\ die\ Anzahl\ der\ Knoten\ im\ Graph\ zurueck\r\n\ \r\n\ @return\ \ Anzahl\ der\ Knoten\r\n
comment18.params=filter
comment18.target=java.util.List\ getAlleKnoten(java.util.function.Predicate[])
comment18.text=\r\n\ Gibt\ eine\ Liste\ aller\ Knoten\ des\ Graphen\ zurueck.\ \r\n\ @param\ \ \ filter\ \ \ \ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Die\ Knotenliste.\ Falls\ leer\ wird\ eine\ leere\ Liste\ \ zurueckgegeben\r\n
comment19.params=k\ filter
comment19.target=java.util.List\ getNachbarknoten(Knoten,\ java.util.function.Predicate[])
comment19.text=\r\n\ Gibt\ die\ Liste\ aller\ Nachbarknoten\ eines\ Knotens\ k\ zurueck,\ falls\ k\ in\ der\ Knotenliste\ vorhanden\ ist.\ \r\n\r\n\ @param\ \ \ k\ \ \ \ Der\ Knoten,\ zu\ dem\ die\ Adjazenzliste\ gesucht\ wird\r\n\ @param\ \ \ filter\ \ \ \ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Liste\ der\ Nachbarknoten\r\n
comment2.params=
comment2.target=Graph()
comment2.text=\r\n\ Der\ Konstruktor\ erstellt\ einen\ neuen\ ungerichteten,\ ungewichteten\ Graphen\ (genauer\ eine\ neue\ Adjazenzliste)\r\n
comment20.params=k\ filter
comment20.target=java.util.List\ getAusgehendeKanten(Knoten,\ java.util.function.Predicate[])
comment20.text=\r\n\ Gibt\ eine\ Liste\ der\ ausgehenden\ Kanten\ eines\ Knotens\ k\ zurueck,\ falls\ k\ in\ der\ Knotenliste\ vorhanden\ ist.\ \r\n\ Bei\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ eingehenden\ und\ ausgehenden\ Kanten\ \r\n\ unterschieden.\r\n\r\n\ @param\ \ \ k\ \ \ \ Der\ Knoten,\ zu\ dem\ die\ Kanten\ gesucht\ werden\r\n\ @param\ \ \ filter\ \ \ \ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Liste\ der\ ausgehenden\ Kanten.\r\n
comment21.params=knotennr\ filter
comment21.target=java.util.List\ getAusgehendeKanten(int,\ java.util.function.Predicate[])
comment21.text=\r\n\ Gibt\ eine\ Liste\ der\ ausgehenden\ Kanten\ eines\ Knotens\ k\ zurueck,\ falls\ k\ in\ der\ Knotenliste\ vorhanden\ ist.\ \r\n\ Bei\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ eingehenden\ und\ ausgehenden\ Kanten\ \r\n\ unterschieden.\r\n\r\n\ @param\ \ \ knotennr\ \ \ \ Nummer\ des\ Knoten,\ zu\ dem\ die\ Kanten\ gesucht\ werden\r\n\ @param\ \ \ filter\ \ \ \ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Liste\ der\ ausgehenden\ Kanten.\r\n
comment22.params=knotennr\ filter
comment22.target=java.util.List\ getEingehendeKanten(int,\ java.util.function.Predicate[])
comment22.text=\r\n\ Gibt\ eine\ Liste\ der\ eingehenden\ Kanten\ eines\ Knotens\ k\ zurueck,\ falls\ k\ in\ der\ Knotenliste\ vorhanden\ ist.\ \r\n\ Bei\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ eingehenden\ und\ ausgehenden\ Kanten\ \r\n\ unterschieden.\r\n\r\n\ @param\ \ \ knotennr\ \ \ \ Die\ Nummer\ des\ Knotens,\ zu\ dem\ die\ Kanten\ gesucht\ werden\r\n\ @param\ \ \ filter\ \ \ \ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Liste\ der\ eingehenden\ Kanten.\r\n
comment23.params=k\ filter
comment23.target=java.util.List\ getEingehendeKanten(Knoten,\ java.util.function.Predicate[])
comment23.text=\r\n\ Gibt\ eine\ Liste\ der\ eingehenden\ Kanten\ eines\ Knotens\ k\ zurueck,\ falls\ k\ in\ der\ Knotenliste\ vorhanden\ ist.\ \r\n\ Bei\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ eingehenden\ und\ ausgehenden\ Kanten\ \r\n\ unterschieden.\r\n\r\n\ @param\ \ \ k\ \ \ \ \ \ \ \ Knoten,\ zu\ dem\ die\ Kanten\ gesucht\ werden\r\n\ @param\ \ \ filter\ \ \ optionaler\ Filter,\ der\ auf\ die\ Liste\ angewendet\ wird.\ Er\ muss\ einen\ boolean-Wert\ zur\u00FCckgeben\:\ z.B.\ @literal{k->k.isMarkiert()\ &&\ k.isBesucht()}\r\n\ @return\ \ Liste\ der\ eingehenden\ Kanten.\r\n
comment24.params=knotennr
comment24.target=Knoten\ getKnoten(int)
comment24.text=\r\n\ Liefert\ einen\ Knoten\ des\ Graphen\r\n\ @param\ knotennr\ Nummer\ der\ Knoten\ (beginnend\ mit\ 0)\r\n\ @return\ liefert\ den\ Knoten\ mit\ dieser\ Nummer\r\n
comment25.params=k
comment25.target=void\ neuerKnoten(Knoten)
comment25.text=\r\n\ F\u00FCgt\ einen\ Knoten\ dem\ Graph\ hinzu.\r\n\ @param\ \ k\ \ \ \ Der\ Knoten,\ der\ hinzugefuegt\ werden\ soll\r\n
comment26.params=knotennr
comment26.target=void\ entferneKnoten(int)
comment26.text=\r\n\ Entfernt\ einen\ Knoten\ aus\ dem\ Graphen\r\n\r\n\ @param\ \ \ knotennr\ \ \ \ Nummer\ des\ Knotens,\ der\ geloescht\ werden\ soll\r\n
comment27.params=k
comment27.target=boolean\ entferneKnoten(Knoten)
comment27.text=\r\n\ Entfernt\ einen\ Knoten\ aus\ dem\ Graphen\r\n\r\n\ @param\ \ \ k\ \ \ \ Knoten,\ der\ geloescht\ werden\ soll\r\n\ @return\ \ gibt\ zur\u00FCck,\ ob\ der\ Knoten\ erfolgreich\ entfernt\ wurde.\r\n
comment28.params=e
comment28.target=boolean\ isKanteEnthalten(Kante)
comment28.text=\r\n\ Ueberprueft,\ ob\ eine\ Kante\ im\ Graphen\ enthalten\ ist.\r\n\r\n\ @param\ \ \ e\ \ \ \ \ Die\ zu\ suchende\ Kante\r\n\ @return\ \ Kante\ enthalten\ (true)\ oder\ nicht\ (false)\r\n
comment29.params=startNr\ zielNr
comment29.target=boolean\ isKanteEnthalten(int,\ int)
comment29.text=\r\n\ Ueberprueft,\ ob\ eine\ Kante\ im\ Graphen\ enthalten\ ist.\ \r\n\ In\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ Start-\ und\ Zielknoten\ unterschieden\r\n\r\n\ @param\ \ \ startNr\ \ \ \ Nummer\ des\ Startknotens\r\n\ @param\ \ \ zielNr\ \ \ \ \ Nummer\ des\ Zielknotens\r\n\ @return\ \ boolean\ \ \ \ \ Kante\ enthalten\ (true)\ oder\ nicht\ (false)\r\n
comment3.params=
comment3.target=void\ loescheGraph()
comment3.text=\r\n\ L\u00F6scht\ alle\ Knoten\ und\ Kanten\ eines\ Graphen\ und\ stellt\ auf\ ungerichtet\ und\ ungewichtet\ zur\u00FCck.\r\n
comment30.params=start\ ziel
comment30.target=boolean\ isKanteEnthalten(Knoten,\ Knoten)
comment30.text=\r\n\ Ueberprueft,\ ob\ eine\ Kante\ im\ Graphen\ enthalten\ ist.\ \r\n\ In\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ Start-\ und\ Zielknoten\ unterschieden\r\n\r\n\ @param\ \ \ start\ \ \ \ Startknoten\r\n\ @param\ \ \ ziel\ \ \ \ \ Zielknoten\r\n\ @return\ \ boolean\ \ \ \ \ Kante\ enthalten\ (true)\ oder\ nicht\ (false)\r\n
comment31.params=start\ ziel
comment31.target=Kante\ getKante(Knoten,\ Knoten)
comment31.text=\r\n\ Gibt\ eine\ gesuchte\ Kante\ aus\ dem\ Graphen\ zurueck.\r\n\ In\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ Start-\ und\ Zielknoten\ unterschieden\r\n\r\n\ @param\ \ \ start\ \ \ \ Der\ StartKnoten\r\n\ @param\ \ \ ziel\ \ \ \ \ Der\ StartKnoten\r\n\ @return\ \ \ \ Die\ gesuchte\ Kante\r\n
comment32.params=startnr\ zielnr
comment32.target=Kante\ getKante(int,\ int)
comment32.text=\r\n\ Gibt\ eine\ gesuchte\ Kante\ aus\ dem\ Graphen\ zurueck.\r\n\ In\ ungerichteten\ Graphen\ wird\ nicht\ zwischen\ Start-\ und\ Zielknoten\ unterschieden\r\n\r\n\ @param\ \ \ startnr\ \ \ \ Der\ Nummer\ des\ StartKnoten\r\n\ @param\ \ \ zielnr\ \ \ \ \ Die\ Nummer\ des\ Zielknoten\r\n\ @return\ \ Die\ gesuchte\ Kante\r\n
comment33.params=e
comment33.target=void\ neueKante(Kante)
comment33.text=\r\n\ Fuegt\ eine\ Kante\ dem\ Graphen\ hinzu.\r\n\ Dabei\ wird\ ueberprueft,\ ob\ die\ Kante\ schon\ im\ Graphen\ enthalten\ ist.\r\n\ \r\n\ Ist\ der\ Graph\ ungerichtet,\ werden\ sowohl\ "Hin-"\ und\ "RueckKante"\ erstellt.\r\n\r\n\ @param\ \ \ e\ \ \ \ \ Die\ Kante,\ die\ hinzugefuegt\ werden\ soll\r\n
comment34.params=start\ ziel\ gewicht
comment34.target=void\ neueKante(Knoten,\ Knoten,\ double)
comment34.text=\r\n\ Fuegt\ eine\ Kante\ dem\ Graphen\ hinzu.\r\n\ Dabei\ wird\ ueberprueft,\ ob\ die\ Kante\ schon\ im\ Graphen\ enthalten\ ist.\r\n\ \r\n\ Ist\ der\ Graph\ ungerichtet,\ werden\ sowohl\ "Hin-"\ und\ "RueckKante"\ erstellt.\r\n\r\n\ @param\ \ \ start\ \ \ \ \ Der\ StartKnoten\ der\ Kante,\ die\ hinzugefuegt\ werden\ soll\r\n\ @param\ \ \ ziel\ \ \ \ \ Der\ ZielKnoten\ der\ Kante,\ die\ hinzugefuegt\ werden\ soll\r\n\ @param\ \ \ gewicht\ \ \ \ \ Das\ Gewicht\ der\ Kante,\ die\ hinzugefuegt\ werden\ soll\r\n
comment35.params=e
comment35.target=void\ entferneKante(Kante)
comment35.text=\r\n\ Entfernt\ eine\ Kante\ aus\ dem\ Graphen.\r\n\ Ist\ der\ Graph\ ungerichtet,\ werden\ sowohl\ "Hin-"\ und\ "RueckKante"\ entfernt.\r\n\r\n\ @param\ \ \ e\ Die\ zu\ entfernende\ Kante\r\n
comment36.params=start\ ziel
comment36.target=void\ entferneKante(Knoten,\ Knoten)
comment36.text=\r\n\ Entfernt\ eine\ Kante\ aus\ dem\ Graphen.\r\n\ Dabei\ wird\ ueberprueft,\ ob\ die\ Kante\ ueberhaupt\ im\ Graphen\ enthalten\ ist.\r\n\ \r\n\ Ist\ der\ Graph\ ungerichtet,\ werden\ sowohl\ "Hin-"\ und\ "RueckKante"\ entfernt.\r\n\r\n\ @param\ \ \ start\ \ \ \ StartKnotens\r\n\ @param\ \ \ ziel\ \ \ \ \ ZielKnotens\r\n
comment37.params=startnr\ zielnr
comment37.target=void\ entferneKante(int,\ int)
comment37.text=\r\n\ Entfernt\ eine\ Kante\ aus\ dem\ Graphen.\r\n\ Ist\ der\ Graph\ ungerichtet,\ werden\ sowohl\ "Hin-"\ und\ "RueckKante"\ entfernt.\r\n\r\n\ @param\ \ \ startnr\ \ \ \ Nummer\ des\ StartKnotens\r\n\ @param\ \ \ zielnr\ \ \ \ \ Nummer\ des\ ZielKnotens\r\n
comment38.params=
comment38.target=boolean\ isLeer()
comment38.text=\r\n\ Ueberprueft,\ ob\ die\ Adjazenzliste\ leer\ ist,\ d.h.\ keine\ Knoten\ im\ Graphen\ enthalten\ sind.\r\n\ \r\n\ @return\ \ \ true,\ wenn\ die\ Liste\ leer\ ist,\ sonst\ false\r\n
comment39.params=
comment39.target=void\ loescheAlles()
comment39.text=\r\n\ Loescht\ den\ gesamten\ Graphen\r\n
comment4.params=csvParser
comment4.target=boolean\ ladeGraph(imp.Table)
comment4.text=\r\n\ Ein\ Graph\ wird\ aus\ einer\ csv-Datei\ erstellt,\ die\ entweder\r\n\ eine\ Matrix\ oder\ eine\ Adjazenzliste\ enth\u00E4lt,\ die\ den\ Graph\ beschreibt.\r\n\r\n\ @param\ \ csvParser\ \ \ Eine\ CSV-Datei\ als\ Table-Objekt\r\n\ @return\ gibt\ zur\u00FCck,\ ob\ das\ Laden\ erfolgreich\ war\r\n
comment40.params=asMatrix
comment40.target=java.lang.String\ toCSVString(boolean)
comment40.text=\r\n\ Die\ Methode\ erstellt\ eine\ CSV-Ausgabe\ des\ Graphen\ entweder\ als\ Adjazenzliste\ oder\ als\ Adjazenzmatrix.\r\n\r\n\ @param\ \ \ asMatrix\ \ \ \ true,\ falls\ die\ CSV-Ausgabe\ eine\ AdjazenzMatrix\ sein\ soll,\ sonst\ false\r\n\ @return\ \ CSV-Ausgabe\r\n
comment41.params=
comment41.target=java.lang.String\ toString()
comment41.text=\r\n\ Textuelle\ Repraesentation\ des\ Graphen.\r\n\ \r\n\ @return\ \ Der\ Graph\ als\ Stringrepraesentation\r\n
comment42.params=
comment42.target=void\ ausgabe()
comment42.text=\r\n\ Konsolenausgabe\ der\ textuellen\ Repraesentation\ des\ Graphen.\r\n
comment43.params=k\ zeigeWert
comment43.target=java.lang.String\ getKnoteninfo(Knoten,\ boolean)
comment43.text=\r\n\ Info\ \u00FCber\ einen\ Knoten\ zur\u00FCckgeben\ \r\n\ @param\ k\ Knoten,\ des\ Info\ ermittelt\ werden\ soll\r\n\ @param\ zeigeWert\ Soll\ der\ Wert\ des\ Knoten\ in\ der\ Info\ enthalten\ sein\r\n\ @return\ Infotext\ oder\ Nummer\ des\ Knoten\ und\ ggf.\ sein\ Wert\r\n
comment44.params=
comment44.target=java.util.List\ getStatus()
comment44.text=\ Speichert\ den\ Zustand\ des\ Graphen\ als\ String-List\r\n\ @return\ List\ mit\ Zustand\r\n
comment45.params=status
comment45.target=void\ setStatus(java.util.List)
comment45.text=\ Stellt\ den\ Zustand\ des\ Graphen\ aus\ String-List\ wieder\ her\r\n\ @param\ status\ List\ mit\ Zustand\r\n
comment5.params=isGewichtet
comment5.target=void\ setGewichtet(boolean)
comment5.text=\r\n\ Legt\ fest,\ ob\ der\ Graph\ gewichtet\ oder\ ungewichtet\ ist.\r\n\r\n\ @param\ isGewichtet\ neuer\ Wert\r\n
comment6.params=
comment6.target=boolean\ isGewichtet()
comment6.text=\r\n\ Gibt\ zurueck,\ ob\ der\ Graph\ gewichtet\ oder\ ungewichtet\ ist\r\n\r\n\ @return\ gewichtet?\ (true/false)\r\n
comment7.params=isGerichtet
comment7.target=void\ setGerichtet(boolean)
comment7.text=\r\n\ Legt\ fest,\ ob\ der\ Graph\ gerichtet\ oder\ ungerichtet\ ist.\r\n\r\n\ @param\ \ isGerichtet\ neuer\ Wert\r\n
comment8.params=
comment8.target=boolean\ isGerichtet()
comment8.text=\r\n\ Gibt\ zurueck,\ ob\ der\ Graph\ gerichtet\ oder\ ungerichtet\ ist.\r\n\r\n\ @return\ \ gerichtet?\ (true/false)\r\n
comment9.params=k
comment9.target=int\ getNummer(Knoten)
comment9.text=\ Gibt\ die\ Nummer\ eines\ Knotens\ im\ Graphen\ zur\u00FCck\r\n\ @param\ \ k\ \ gesuchter\ Knoten\r\n\ @return\ Nummer\ des\ Knotens\ (mit\ 0\ beginnend)\r\n
numComments=46

800
graph/Graph.java Normal file
View file

@ -0,0 +1,800 @@
package graph;
import imp.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Dies ist das Herz vom "GraphTester" - der Graph selber, gepeichert als Adjazenzliste.
* Die Klasse erlaubt durch geeignete Methoden:
* - die Speicherung als Adjazenzmatrix,
* - das Hinzufuegen und Loeschen von knoten und Kanten,
* - das Markieren von Knoten und Kanten,
* - eine Aussage darueber, ob Knoten oder Kanten enthalten sind und
* - eine Ausgabe des Graphen in textueller Form sowie als csv-Datei.
*
*
* @author Dirk Zechnall, Thomas Schaller
* @version 31.01.2021 (v6.5)
*/
public class Graph
{
private ArrayList<Knoten> kList; // Liste aller Knoten
private ArrayList<Kante> kaList; // Liste aller Kanten
private ArrayList<ArrayList<Kante>> adList; //Adjazenzliste
private boolean gerichtet;
private boolean gewichtet;
/**
* Der Konstruktor erstellt einen neuen Graphen (genauer eine neue Adjazenzliste)
* @param isGerichtet gibt an, ob es sich um einen gerichteten Graphen handelt
* @param isGewichtet gibt an, ob die Kanten gewichtet sind.
*/
public Graph (boolean isGerichtet, boolean isGewichtet) {
loescheGraph();
gerichtet = isGerichtet;
gewichtet = isGewichtet;
}
/**
* Der Konstruktor erstellt einen neuen ungerichteten, ungewichteten Graphen (genauer eine neue Adjazenzliste)
*/
public Graph() {
loescheGraph();
}
/**
* Löscht alle Knoten und Kanten eines Graphen und stellt auf ungerichtet und ungewichtet zurück.
*/
public void loescheGraph() {
gerichtet = false;
gewichtet = false;
kList = new ArrayList<Knoten>();
kaList = new ArrayList<Kante>();
adList = new ArrayList<ArrayList<Kante>>();
}
/**
* Ein Graph wird aus einer csv-Datei erstellt, die entweder
* eine Matrix oder eine Adjazenzliste enthält, die den Graph beschreibt.
*
* @param csvParser Eine CSV-Datei als Table-Objekt
* @return gibt zurück, ob das Laden erfolgreich war
*/
public boolean ladeGraph(Table csvParser) {
boolean geschafft = false;
try {
int knotenAnzahl = 0;
boolean hasInfotext = false;
boolean hasStatus = false;
geschafft = true;
int start;
int posx = 0;
for(start = 0; start < csvParser.getRowCount(); start++) {
TableRow row = csvParser.getRow(start);
String m = row.getString(0);
if(row.getString(0).equals("directed")) {
setGerichtet(row.getInt(1) == 1);
}
if(row.getString(0).equals("weighted")) {
setGewichtet(row.getInt(1) == 1);
}
if(row.getString(0).equals("matrix") || row.getString(0).equals("list")) {
String n = row.getString(1);
if(n.equals("infotext")) {
hasInfotext = true;
posx++;
}
break;
}
}
// Knoten erstellen
for(int i=start+1; i < csvParser.getRowCount(); i++) {
TableRow row = csvParser.getRow(i);
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') {
Knoten k = new Knoten(row.getInt(posx), row.getInt(posx+1));
if(hasInfotext) k.setInfotext(row.getString(0));
neuerKnoten(k);
knotenAnzahl++;
}
}
// Kanten erstellen
int k=0;
if(csvParser.getString(start,0).equals("matrix")){
for(int i = start+1; i < csvParser.getRowCount(); i++) {
TableRow row = csvParser.getRow(i);
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') { //Ueberpruefung auf Kommentare #
for(int j = posx+2; j < row.getColumnCount(); j+=1) {
if(!(row.getString(j).equals("-"))) {
neueKante(getKnoten(k), getKnoten(j - 2 -posx), row.getDouble(j));
}
}
k++;
}
}
} else {
for(int i = start+1; i < csvParser.getRowCount(); i++) {
TableRow row = csvParser.getRow(i);
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') { // Ueberpruefung auf Kommentare #
int z = row.getColumnCount();
z++;
for(int j = posx+2; j < row.getColumnCount(); j+= 1) {
if(isGewichtet()){
neueKante(getKnoten(k), getKnoten(row.getInt(j)), row.getDouble(j + 1));
j++;
} else {
neueKante(getKnoten(k), getKnoten(row.getInt(j)), 0);
}
}
k++;
}
}
}
} catch(Exception e) {
geschafft=false;
}
return geschafft;
}
/**
* Legt fest, ob der Graph gewichtet oder ungewichtet ist.
*
* @param isGewichtet neuer Wert
*/
public void setGewichtet(boolean isGewichtet) {
gewichtet = isGewichtet;
}
/**
* Gibt zurueck, ob der Graph gewichtet oder ungewichtet ist
*
* @return gewichtet? (true/false)
*/
public boolean isGewichtet() {
return gewichtet;
}
/**
* Legt fest, ob der Graph gerichtet oder ungerichtet ist.
*
* @param isGerichtet neuer Wert
*/
public void setGerichtet(boolean isGerichtet) {
gerichtet = isGerichtet;
if(gerichtet) {
for(Kante k: kaList) {
adList.get(kList.indexOf(k.getZiel())).remove(k);
}
}
}
/**
* Gibt zurueck, ob der Graph gerichtet oder ungerichtet ist.
*
* @return gerichtet? (true/false)
*/
public boolean isGerichtet() {
return gerichtet;
}
/** Gibt die Nummer eines Knotens im Graphen zurück
* @param k gesuchter Knoten
* @return Nummer des Knotens (mit 0 beginnend)
*/
public int getNummer(Knoten k) {
return kList.indexOf(k);
}
/** Gibt die Nummer einer Kante zurück
* @param k gesuchte Kante
* @return Nummer der Kante (mit 0 beginnend)
*/
public int getNummer(Kante k) {
return kaList.indexOf(k);
}
/**
* Die Methode getAdjazenzMatrix() gibt die Adjazenzmatrix zurueck.
*
* @return double[][] Die AdjazenzMatrix als zweidimensionales Array
*/
public double[][] getAdjazenzMatrix() {
double[][] matrix = new double[getAnzahlKnoten()][getAnzahlKnoten()];
for (int i=0; i<matrix.length; i++){
for (int j=0; j<matrix[i].length; j++){
matrix[i][j] = Double.NaN;
}
}
// speichere Liste In Matrix
for(Kante k : getAlleKanten()) {
int startKnotenNummer = getNummer(k.getStart());
int zielKnotenNummer = getNummer(k.getZiel());
// Wenn keine Kanten existieren, gibt es auch kein Kantengewicht - daher wird hier das Kantengewicht auf NaN ueberprueft
// man koennte hier auch mit Double-Variablen arbeiten und diese null setzen --> hat jedoch einen deutlich groeßeren Speicheraufwand!
if(gewichtet) matrix[startKnotenNummer][zielKnotenNummer] = k.getGewicht();
else matrix[startKnotenNummer][zielKnotenNummer] = 0;
}
return matrix;
}
/**
* Gibt eine Liste aller Kanten des Graphen zurück.
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste aller Kanten
*/
public List<Kante> getAlleKanten(Predicate<Kante>... filter) {
List<Kante> kanten = new ArrayList<Kante>(kaList);
if(filter.length>0) {
kanten = kanten.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return kanten;
}
/**
* Entfernt die Markierung bei allen Knoten des Graphen.
*/
public void entferneMarkierungBeiAllenKnoten() {
for (Knoten k : kList) {
k.setMarkiert(false);
}
}
/**
* Initialisiert alle Knoten des Graphen.
*/
public void initialisiereAlleKnoten() {
for (Knoten k : kList) {
k.init();
}
}
/**
* Initialisiert alle Kanten des Graphen.
*/
public void initialisiereAlleKanten() {
for (Kante k: kaList) {
k.init();
}
}
/**
* Ueberprueft, ob ein Knoten in der Knotenliste enthalten ist.
* Sobald in der Knotenliste der Knoten k gefunden wird, wird true ausgegeben.
*
* @param k Der gesuchte Knoten
* @return true= ist enthalten, false = ist nicht enthalten
*/
public boolean isKnotenEnthalten (Knoten k) {
return kList.contains(k);
}
/**
* Gibt die Anzahl der Knoten im Graph zurueck
*
* @return Anzahl der Knoten
*/
public int getAnzahlKnoten() {
return kList.size();
}
/**
* Gibt eine Liste aller Knoten des Graphen zurueck.
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Die Knotenliste. Falls leer wird eine leere Liste zurueckgegeben
*/
public List<Knoten> getAlleKnoten(Predicate<Knoten>... filter) {
List<Knoten> knoten = new ArrayList<Knoten>();
knoten.addAll(kList);
if(filter.length>0) {
knoten = knoten.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return knoten;
}
/**
* Gibt die Liste aller Nachbarknoten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
*
* @param k Der Knoten, zu dem die Adjazenzliste gesucht wird
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste der Nachbarknoten
*/
public List<Knoten> getNachbarknoten (Knoten k, Predicate<Knoten>... filter) {
if(kList.contains(k)) {
List<Knoten> nachbarn = new ArrayList<Knoten>();
for (Kante e : adList.get(kList.indexOf(k))) {
nachbarn.add(e.getAnderesEnde(k));
} // end of for
if(filter.length>0) {
nachbarn = nachbarn.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return nachbarn;
} else {
return null;
}
}
/**
* Gibt eine Liste der ausgehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
* unterschieden.
*
* @param k Der Knoten, zu dem die Kanten gesucht werden
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste der ausgehenden Kanten.
*/
public List<Kante> getAusgehendeKanten (Knoten k, Predicate<Kante>... filter) {
if(kList.contains(k)) {
List<Kante> kanten = new ArrayList<Kante>();
kanten.addAll(adList.get(kList.indexOf(k)));
if(filter.length>0) {
kanten = kanten.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return kanten;
} else {
return null;
}
}
/**
* Gibt eine Liste der ausgehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
* unterschieden.
*
* @param knotennr Nummer des Knoten, zu dem die Kanten gesucht werden
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste der ausgehenden Kanten.
*/
public List<Kante> getAusgehendeKanten (int knotennr, Predicate<Kante>... filter) {
if(knotennr < getAnzahlKnoten()) {
List<Kante> kanten = new ArrayList<Kante>();
kanten.addAll(adList.get(knotennr));
if(filter.length>0) {
kanten = kanten.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return kanten;
} else {
return null;
}
}
/**
* Gibt eine Liste der eingehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
* unterschieden.
*
* @param knotennr Die Nummer des Knotens, zu dem die Kanten gesucht werden
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste der eingehenden Kanten.
*/
public List<Kante> getEingehendeKanten (int knotennr, Predicate<Kante>... filter) {
if(knotennr >= getAnzahlKnoten()) {
return null;
}
return getEingehendeKanten(this.getKnoten(knotennr),filter);
}
/**
* Gibt eine Liste der eingehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
* unterschieden.
*
* @param k Knoten, zu dem die Kanten gesucht werden
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
* @return Liste der eingehenden Kanten.
*/
public List<Kante> getEingehendeKanten (Knoten k, Predicate<Kante>... filter) {
if(!kList.contains(k)) {
return null;
}
List<Kante> kanten = new ArrayList<Kante>();
if(this.isGerichtet()) {
for (Kante e: kaList) {
if(e.getZiel()== k) {
kanten.add(e);
}
} // end of for
} else {
kanten = getAusgehendeKanten(k);
} // end of if-else
if(filter.length>0) {
kanten = kanten.stream() // convert list to stream
.filter(filter[0])
.collect(Collectors.toCollection(ArrayList::new));
}
return kanten;
}
/**
* Liefert einen Knoten des Graphen
* @param knotennr Nummer der Knoten (beginnend mit 0)
* @return liefert den Knoten mit dieser Nummer
*/
public Knoten getKnoten(int knotennr) {
if(knotennr < getAnzahlKnoten()) {
return kList.get(knotennr);
} else {
return null;
}
}
/**
* Fügt einen Knoten dem Graph hinzu.
* @param k Der Knoten, der hinzugefuegt werden soll
*/
public void neuerKnoten (Knoten k) {
if (!isKnotenEnthalten(k)){
kList.add(k);
adList.add(new ArrayList<Kante>());
}
}
/**
* Entfernt einen Knoten aus dem Graphen
*
* @param knotennr Nummer des Knotens, der geloescht werden soll
*/
public void entferneKnoten (int knotennr) {
entferneKnoten(getKnoten(knotennr));
}
/**
* Entfernt einen Knoten aus dem Graphen
*
* @param k Knoten, der geloescht werden soll
* @return gibt zurück, ob der Knoten erfolgreich entfernt wurde.
*/
public boolean entferneKnoten (Knoten k) {
if (!kList.contains(k)) return false;
int index = kList.indexOf(k);
for (List<Kante> a : adList) {
int index2 = 0;
while(index2 < a.size()){
Kante ka = a.get(index2);
if(ka.getStart()==k || ka.getZiel()==k){
if(kaList.contains(ka)) kaList.remove(ka);
a.remove(index2);
} else {
index2++;
}
}
}
adList.remove(index);
kList.remove(k);
return true;
}
/**
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
*
* @param e Die zu suchende Kante
* @return Kante enthalten (true) oder nicht (false)
*/
public boolean isKanteEnthalten (Kante e) {
return kaList.contains(e);
}
/**
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
*
* @param startNr Nummer des Startknotens
* @param zielNr Nummer des Zielknotens
* @return boolean Kante enthalten (true) oder nicht (false)
*/
public boolean isKanteEnthalten (int startNr, int zielNr) {
return getKante(startNr, zielNr)!=null;
}
/**
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
*
* @param start Startknoten
* @param ziel Zielknoten
* @return boolean Kante enthalten (true) oder nicht (false)
*/
public boolean isKanteEnthalten (Knoten start, Knoten ziel) {
return getKante(start, ziel)!=null;
}
/**
* Gibt eine gesuchte Kante aus dem Graphen zurueck.
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
*
* @param start Der StartKnoten
* @param ziel Der StartKnoten
* @return Die gesuchte Kante
*/
public Kante getKante (Knoten start, Knoten ziel) {
for(Kante k: adList.get(kList.indexOf(start))) {
if(k.getStart()==start && k.getZiel() == ziel) {
return k;
}
if(!gerichtet && k.getStart()==ziel && k.getZiel() == start) {
return k;
}
}
return null;
}
/**
* Gibt eine gesuchte Kante aus dem Graphen zurueck.
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
*
* @param startnr Der Nummer des StartKnoten
* @param zielnr Die Nummer des Zielknoten
* @return Die gesuchte Kante
*/
public Kante getKante (int startnr, int zielnr) {
return getKante(getKnoten(startnr), getKnoten(zielnr));
}
/**
* Fuegt eine Kante dem Graphen hinzu.
* Dabei wird ueberprueft, ob die Kante schon im Graphen enthalten ist.
*
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" erstellt.
*
* @param e Die Kante, die hinzugefuegt werden soll
*/
public void neueKante(Kante e) {
adList.get(kList.indexOf(e.getStart())).add(e);
if(!gerichtet) adList.get(kList.indexOf(e.getZiel())).add(e);
kaList.add(e);
}
/**
* Fuegt eine Kante dem Graphen hinzu.
* Dabei wird ueberprueft, ob die Kante schon im Graphen enthalten ist.
*
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" erstellt.
*
* @param start Der StartKnoten der Kante, die hinzugefuegt werden soll
* @param ziel Der ZielKnoten der Kante, die hinzugefuegt werden soll
* @param gewicht Das Gewicht der Kante, die hinzugefuegt werden soll
*/
public void neueKante(Knoten start, Knoten ziel, double gewicht) {
if(!kList.contains(start) || !kList.contains(ziel) || getKante(start,ziel) != null) return;
neueKante(new Kante(start,ziel, gewicht));
}
/**
* Entfernt eine Kante aus dem Graphen.
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
*
* @param e Die zu entfernende Kante
*/
public void entferneKante (Kante e) {
entferneKante(e.getStart(), e.getZiel());
}
/**
* Entfernt eine Kante aus dem Graphen.
* Dabei wird ueberprueft, ob die Kante ueberhaupt im Graphen enthalten ist.
*
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
*
* @param start StartKnotens
* @param ziel ZielKnotens
*/
public void entferneKante (Knoten start, Knoten ziel) {
Kante e1 = getKante(start, ziel);
Kante e2 = getKante(ziel, start);
for(List<Kante> a: adList) {
a.remove(e1);
if(!gerichtet) {
a.remove(e2);
}
}
kaList.remove(e1);
if(!gerichtet) {
kaList.remove(e2);
}
}
/**
* Entfernt eine Kante aus dem Graphen.
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
*
* @param startnr Nummer des StartKnotens
* @param zielnr Nummer des ZielKnotens
*/
public void entferneKante (int startnr, int zielnr) {
entferneKante(getKnoten(startnr), getKnoten(zielnr));
}
/**
* Ueberprueft, ob die Adjazenzliste leer ist, d.h. keine Knoten im Graphen enthalten sind.
*
* @return true, wenn die Liste leer ist, sonst false
*/
public boolean isLeer() {
return adList.isEmpty();
}
/**
* Loescht den gesamten Graphen
*/
public void loescheAlles() {
adList.clear();
kList.clear();
kaList.clear();
}
/**
* Die Methode erstellt eine CSV-Ausgabe des Graphen entweder als Adjazenzliste oder als Adjazenzmatrix.
*
* @param asMatrix true, falls die CSV-Ausgabe eine AdjazenzMatrix sein soll, sonst false
* @return CSV-Ausgabe
*/
public String toCSVString(boolean asMatrix) {
String s="";
//if(adList.isLeer()) return s;
s += "# gewichtet 1, ungewichtet 0\n";
s += "weighted,"+(isGewichtet() ? "1" : "0")+"\n";
s += "# gerichtet 1, ungerichtet 0\n";
s += "directed,"+(isGerichtet() ? "1" : "0")+"\n";
// Kontrollieren, ob irgendwo ein Infotext vorhanden ist.
boolean hasInfotext = false;
for(Knoten k: kList) {
if(!k.getInfotext().equals("")) hasInfotext = true;
}
if(asMatrix){
s += "# Der Graph liegt hier in Form einer Adjazenzmatrix vor. \n";
s += "# Jede Zeile steht fuer einen Knoten, durch Kommas getrennt stehen die Kantengewicht zu jedem anderen Knoten.\n";
s += "matrix";
if(hasInfotext) s+=",infotext";
double[][] matrix = getAdjazenzMatrix();
// hier muss ueberprueft werden, ob matrixinhalt ist NaN --> '-' speichern
for (int i=0; i<matrix.length; i++){
s+="\n";
Knoten k = kList.get(i);
if(hasInfotext) s+=k.getInfotext()+",";
s+=(k.getX())+","+k.getY()+",";
for (int j=0; j<matrix[i].length; j++){
if(Double.isNaN(matrix[i][j]))s+="-";
else s+=matrix[i][j];
if (j!=matrix.length-1) s+=",";
}
}
}
else {
s += "# Der Graph liegt hier in Form einer Adjazenzliste vor.\n";
s += "# Jede Zeile steht fuer einen Knoten, durch Komma getrennt steht der adjazente Knoten mit dem zugehoerigen Kantengewicht.\n";
s += "list";
if(hasInfotext) s+=",infotext";
for(int knr = 0; knr < kList.size(); knr++) {
s+="\n";
Knoten k = kList.get(knr);
List<Kante> a = adList.get(knr);
if(hasInfotext) s+=k.getInfotext()+",";
s+=(k.getX())+","+(k.getY());
if (a.size()>0) s+=",";
for (Kante ka : a) {
s+=""+(getNummer(ka.getAnderesEnde(k)));
if (isGewichtet()) s+=","+ka.getGewicht();
if (a.get(a.size()-1)!=ka) s+=",";
}
}
}
return s;
}
/**
* Textuelle Repraesentation des Graphen.
*
* @return Der Graph als Stringrepraesentation
*/
@Override
public String toString() {
String s="";
s+="Adjazenzliste:\n";
if(adList.isEmpty()) return "Liste ist leer!\n";
for(int i=0; i< kList.size(); i++) {
s+="K"+i+kList.get(i).toString()+": ";
List<Kante> a =adList.get(i);
for (Kante k : a) {
s+=k.toString()+"K"+(kList.indexOf(k.getAnderesEnde(kList.get(i))))+" | ";
}
s=s.substring(0,s.length()-3)+"\n";
}
return s;
}
/**
* Konsolenausgabe der textuellen Repraesentation des Graphen.
*/
public void ausgabe() {
System.out.println(toString());
}
/**
* Info über einen Knoten zurückgeben
* @param k Knoten, des Info ermittelt werden soll
* @param zeigeWert Soll der Wert des Knoten in der Info enthalten sein
* @return Infotext oder Nummer des Knoten und ggf. sein Wert
*/
public String getKnoteninfo(Knoten k, boolean zeigeWert) {
String info = "";
if (!k.getInfotext().equals("")) {
info += k.getInfotext();
} else {
info += "Knoten Nr. "+getNummer(k);
}
if( zeigeWert) {
info += " (Wert "+k.getDoubleWert()+")";
}
return info;
}
/** Speichert den Zustand des Graphen als String-List
* @return List mit Zustand
*/
public List<String> getStatus() {
List<String> status = new ArrayList<String>();
for(Knoten k : getAlleKnoten()) {
status.add(k.getStatus());
}
for(Kante k : getAlleKanten()) {
status.add(k.getStatus());
}
return status;
}
/** Stellt den Zustand des Graphen aus String-List wieder her
* @param status List mit Zustand
*/
public void setStatus(List<String> status) {
int i=0;
for(Knoten k : getAlleKnoten()) {
k.setStatus(status.get(i++));
}
for(Kante k : getAlleKanten()) {
k.setStatus(status.get(i++));
}
}
}

16
graph/Graph.uml Normal file
View file

@ -0,0 +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=

10
graph/GraphElement.ctxt Normal file
View file

@ -0,0 +1,10 @@
#BlueJ class context
comment0.target=GraphElement
comment0.text=\r\n\ Die\ Klasse\ GraphElement\ ist\ eine\ Oberklasse\ von\ Knoten\ und\ Kanten.\r\n\ Sie\ ist\ nur\ f\u00FCr\ die\ interne\ Verarbeitung\ wichtig.\r\n\r\n\ @author\ Thomas\ Schaller\r\n\ @version\ v1.1\r\n
comment1.params=e
comment1.target=int\ compareTo(GraphElement)
comment2.params=
comment2.target=java.lang.String\ getStatus()
comment3.params=status
comment3.target=void\ setStatus(java.lang.String)
numComments=4

16
graph/GraphElement.java Normal file
View file

@ -0,0 +1,16 @@
package graph;
/**
* 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
*/
public abstract class GraphElement implements Comparable<GraphElement>
{
public abstract int compareTo(GraphElement e);
public abstract String getStatus();
public abstract void setStatus(String status);
}

12
graph/GraphOptions.ctxt Normal file
View file

@ -0,0 +1,12 @@
#BlueJ class context
comment0.target=GraphOptions
comment0.text=\r\n\ Die\ Klasse\ GraphOptions\ speichert,\ wie\ ein\ Graph\ in\ einem\ Fenster\ vom\ \r\n\ GraphPlotter\ angezeigt\ wird.\r\n\r\n\ @author\ Thomas\ Schaller\r\n\ @version\ v6.7\ (9.12.2020)\r\n
comment1.params=
comment1.target=GraphOptions()
comment2.params=csvParser
comment2.target=void\ ladeGraph(imp.Table)
comment3.params=
comment3.target=java.lang.String\ getText()
comment4.params=
comment4.target=GraphOptions\ copy()
numComments=5

167
graph/GraphOptions.java Normal file
View file

@ -0,0 +1,167 @@
package graph;
import imp.*;
import java.util.Arrays;
/**
* Die Klasse GraphOptions speichert, wie ein Graph in einem Fenster vom
* GraphPlotter angezeigt wird.
*
* @author Thomas Schaller
* @version v6.7 (9.12.2020)
*/
public class GraphOptions
{
// Bild
public String bildDatei = "";
public boolean bildAnzeigen = false;
// Anzeigeeinstellungen
public int vertexSize = 30;
public boolean showEdgeWeights = true;
public boolean showVertexValue = true;
public boolean showVertexText = false;
public boolean showVertexInfo = false;
// Speicheroption
public boolean saveAsMatrix = false;
// Farben der Anzeige
public String[] stdFarbenKnoten = {"D0D0D0", "ACFFAB", "ACFFED", "ACC5ED", "ACC582", "E5C582", "E5C5C2", "D19FFD", "FF9F8E","FF6158", "FF61D4", "FFDE6E", "770000", "007700", "000077", "777700", "77a0e0", "9912E4", "783410", "12a94e"};
public String[] stdFarbenKanten = {"606060", "5080FF", "D0D0D0"};
public String[] farbenKnoten = stdFarbenKnoten;
public String[] farbenKanten = stdFarbenKanten;
// Auswahl der anzuzeigenden Knoten
public int fokusArt = 0; // 0 = Knoten, 1 = Kanten
public GraphElement parent = null;
public int auswahl = 0; // 0 = alle, 1 = Nachbarn, 2 = Single
public GraphOptions() {
}
public void ladeGraph(Table csvParser) {
farbenKnoten = stdFarbenKnoten;
farbenKanten = stdFarbenKanten;
vertexSize = 30;
showEdgeWeights = true;
showVertexText = true;
showVertexValue = false;
showVertexInfo = false;
bildDatei = "";
fokusArt = 0; // 0 = Knoten, 1 = Kanten
parent = null;
auswahl = 0;
for(int i = 0; i < csvParser.getRowCount(); i++) {
TableRow row = csvParser.getRow(i);
if(row.getString(0).equals("showWeights")) {
showEdgeWeights = (row.getInt(1) == 1);
}
if(row.getString(0).equals("showInfoText")) {
showVertexInfo = (row.getInt(1) == 1);
}
if(row.getString(0).equals("vertexSize")) {
vertexSize = row.getInt(1);
}
if(row.getString(0).equals("vertexStyle")) {
showVertexText = (row.getInt(1) == 1);
showVertexValue = (row.getInt(1) == 2);
}
if(row.getString(0).equals("image")) {
if(row.getString(1).charAt(0) == '0'){
bildDatei = "";
bildAnzeigen = false;
} else {
bildDatei = row.getString(1);
bildAnzeigen = true;
}
}
if(row.getString(0).equals("vertexColor")) {
farbenKnoten = Arrays.copyOfRange(csvParser.getStringRow(i), 1, row.getColumnCount());
}
if(row.getString(0).equals("edgeColor")) {
farbenKanten = Arrays.copyOfRange(csvParser.getStringRow(i), 1, row.getColumnCount());
}
if(row.getString(0).equals("matrix") || row.getString(0).equals("list")) {
if(row.getString(0).equals("matrix"))
saveAsMatrix = true;
else
saveAsMatrix = false;
break;
}
}
}
public String getText() {
String gesamtText = "# Anzeigeoptionen:";
gesamtText += "# Gewichte anzeigen 1, Gewichte nicht anzeigen 0\n";
if(showEdgeWeights)
gesamtText += "showWeights,1\n";
else
gesamtText += "showWeights,0\n";
if(vertexSize != 30) {
gesamtText += "# Größe der Knoten\n";
gesamtText += "vertexSize,"+vertexSize+"\n";
}
gesamtText += "# Knoteninfo anzeigen 1,Knoteninfo nicht anzeigen 0\n";
if(showVertexInfo)
gesamtText += "showInfoText,1\n";
else
gesamtText += "showInfoText,0\n";
gesamtText += "# Knoten leer 0, Knotenname anzeigen 1, Wert des Knoten anzeigen 2\n";
if(!showVertexText && !showVertexValue) gesamtText += "vertexStyle,0\n";
else {
if(showVertexText) gesamtText += "vertexStyle,1\n";
else
gesamtText += "vertexStyle,2\n";
}
if(farbenKanten!=stdFarbenKanten) {
gesamtText += "# Kantenfarben: RGB-Hexcode (z.B. FF0000) oder invisible\n";
gesamtText += "# Reihenfolge: normale Kanten, markierte Kanten, gelöschte Kanten\n";
gesamtText += "edgeColor";
for(String f : farbenKanten) gesamtText+=","+f;
gesamtText += "\n";
}
if(farbenKnoten!=stdFarbenKnoten) {
gesamtText += "# Knotenfarben: RGB-Hexcode (z.B. FF0000) oder invisible\n";
gesamtText += "# Reihenfolge: nichts, markiert, besucht, besucht und markiert\n";
gesamtText += "# mind. 12 Farben müssen angegeben werden.";
gesamtText += "vertexColor";
for(String f : farbenKnoten) gesamtText+=","+f;
gesamtText += "\n";
}
gesamtText += "# Bild im Hintergrund (bitte im \"images\"-Ordner ablegen) --> Dateiname angeben. Fall kein Bild bitte 0 schreiben!\n";
if(bildDatei.equals(""))
gesamtText += "image,0\n";
else
gesamtText += "image,"+bildDatei + "\n";
return gesamtText;
}
public GraphOptions copy() {
GraphOptions kopie = new GraphOptions();
kopie.bildDatei= bildDatei;
kopie.bildAnzeigen = bildAnzeigen;
kopie.vertexSize = vertexSize;
kopie.showEdgeWeights = showEdgeWeights;
kopie.showVertexValue = showVertexValue;
kopie.showVertexText = showVertexText;
kopie.showVertexInfo = showVertexInfo;
kopie.saveAsMatrix = saveAsMatrix;
kopie.stdFarbenKnoten = stdFarbenKnoten.clone();
kopie.stdFarbenKanten = stdFarbenKanten.clone();
kopie.farbenKnoten = farbenKnoten.clone();
kopie.farbenKanten = farbenKanten.clone();
kopie.fokusArt = fokusArt;
kopie.auswahl = auswahl;
kopie.parent = parent;
return kopie;
}
}

57
graph/GraphPlotter.ctxt Normal file
View file

@ -0,0 +1,57 @@
#BlueJ class context
comment0.target=GraphPlotter
comment0.text=\r\n\ Der\ GraphPlotter\ ist\ das\ Herzstueck\ der\ Visualisierung\ und\ dient\ als\ Schnittstelle\ zur\ GUI.\r\n\ \r\n\ @author\ Thomas\ Schaller\r\n\ @version\ 09.12.2020\ (v6.7)\r\n
comment1.params=
comment1.target=GraphPlotter()
comment1.text=\r\n\ Der\ Konstruktor\ legt\ sowohl\ Einstellungen\ des\ mxGraphen\ (Drag&Drop,\ Editable,\ ...)\ als\ auch\ des\ Graphen\ (gewichtet,\ gerichtet,\ ...)\ fest.\r\n\r\n\ @param\ \ boolean\ isDirected\ \ Gibt\ an,\ ob\ der\ Graph\ gerichtet\ oder\ ungerichtet\ ist\r\n\ @param\ \ boolean\ isWeighted\ \ Gibt\ an,\ ob\ der\ Graph\ gewichtet\ oder\ ungewichtet\ ist\r\n\ @param\ \ String\ hintergrundBild\ \ \ Gibt\ den\ Namen\ eines\ Hintergrundbildes\ an\r\n
comment10.params=x\ y
comment10.target=Knoten\ getKnotenAt(int,\ int)
comment11.params=x\ y
comment11.target=Kante\ getKanteAt(int,\ int)
comment12.params=p\ startx\ starty\ endx\ endy
comment12.target=void\ drawArrow(imp.Picture,\ int,\ int,\ int,\ int)
comment13.params=color
comment13.target=java.lang.String\ darker(java.lang.String)
comment14.params=color
comment14.target=java.lang.String\ brighter(java.lang.String)
comment15.params=d
comment15.target=java.lang.String\ format(double)
comment16.params=
comment16.target=imp.Picture\ updateImage()
comment17.params=
comment17.target=GraphOptions\ getGraphOptions()
comment18.params=
comment18.target=Graph\ getGraph()
comment18.text=\r\n\ Gibt\ den\ Graphen\ zurueck.\r\n\ \r\n\ @return\ \ Graph\r\n
comment19.params=
comment19.target=Knoten\ getSelectedKnoten()
comment19.text=\r\n\ Gibt\ das\ selektierte\ Knotenobjekt\ zurueck.\r\n\ \r\n\ @return\ \ Object\r\n
comment2.params=
comment2.target=void\ setEditable()
comment20.params=
comment20.target=java.util.List\ getSelectedKnotenListe()
comment20.text=\r\n\ Gibt\ die\ selektierte\ KnotenobjektListe\ (als\ Array)\ zurueck.\r\n\ \r\n\ @return\ \ Object[]\r\n
comment21.params=
comment21.target=Kante\ getSelectedKante()
comment21.text=\r\n\ Gibt\ das\ selektierte\ Kantenobjekt\ zurueck.\r\n\ \r\n\ @return\ \ Object\r\n
comment22.params=
comment22.target=java.lang.String\ toString()
comment22.text=\r\n\ Ueberschreibt\ die\ Methode\ toString.\ Eine\ String-Repraesentation\ des\ GraphPlotters\ wird\ ausgegeben.\r\n\r\n\ @return\ \ String\ \ Die\ String-Repraesentation\ des\ GraphPlotters\r\n
comment23.params=
comment23.target=void\ ausgabe()
comment23.text=\r\n\ Gibt\ die\ String-Repraesentation\ des\ GraphPlotters\ auf\ der\ Konsole\ aus.\r\n
comment3.params=graph\ options
comment3.target=void\ setGraph(Graph,\ GraphOptions)
comment4.params=k
comment4.target=void\ setRestrictTo(GraphElement)
comment5.params=
comment5.target=GraphElement\ getRestrictTo()
comment6.params=mouseEvent
comment6.target=void\ mouseClicked(javafx.scene.input.MouseEvent)
comment7.params=mouseEvent
comment7.target=void\ mouseDown(javafx.scene.input.MouseEvent)
comment8.params=mouseEvent
comment8.target=void\ mouseDragged(javafx.scene.input.MouseEvent)
comment9.params=mouseEvent
comment9.target=void\ mouseUp(javafx.scene.input.MouseEvent)
numComments=24

601
graph/GraphPlotter.java Normal file
View file

@ -0,0 +1,601 @@
package graph;
import imp.*;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.MouseButton;
import java.nio.file.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
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)
*/
public class GraphPlotter extends PictureViewer {
// Anfang Attribute
private Graph graph;
private GraphOptions options;
private boolean multiselect = false;
private boolean editable = false;
private ArrayList<GraphElement> selected=new ArrayList<GraphElement>();
private Knoten dragKnoten = null;
private int dragMode = 0;
// Tooltip
private double mouseX, mouseY;
private Tooltip t;
private GraphElement restrictTo = null;
private Point2D offset = new Point2D(0,0);
// private JTextArea jTAMeldungen = new JTextArea("");
// private JScrollPane jTAMeldungenScrollPane = new JScrollPane(jTAMeldungen);
// Ende Attribute
/**
* Der Konstruktor legt sowohl Einstellungen des mxGraphen (Drag&Drop, Editable, ...) als auch des Graphen (gewichtet, gerichtet, ...) fest.
*
* @param boolean isDirected Gibt an, ob der Graph gerichtet oder ungerichtet ist
* @param boolean isWeighted Gibt an, ob der Graph gewichtet oder ungewichtet ist
* @param String hintergrundBild Gibt den Namen eines Hintergrundbildes an
*/
public GraphPlotter() {
options = new GraphOptions();
graph = new 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;");
// 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());
// }
// });
}
public void setEditable() {
editable = true;
//setOnMousePressed(mouseEvent -> mouseDown(mouseEvent)); // wird durch MousePressed in EditTab realisiert und dann hier aufgerufen
setOnMouseReleased(mouseEvent -> mouseUp(mouseEvent));
setOnDragDetected(mouseEvent -> startFullDrag());
setOnMouseDragOver(mouseEvent-> mouseDragged(mouseEvent));
setOnMouseClicked(null);
}
public void setGraph(Graph graph, GraphOptions options) {
this.graph = graph;
this.options = options;
updateImage();
}
public void setRestrictTo(GraphElement k) {
if(restrictTo != k) {
restrictTo = k;
selected.clear();
if (k!= null) selected.add(k);
updateImage();
}
}
public GraphElement getRestrictTo() {
return restrictTo;
}
public void mouseClicked(MouseEvent mouseEvent) {
Point2D local = this.getContent().sceneToLocal(mouseEvent.getSceneX(), mouseEvent.getSceneY());
GraphElement k = getKnotenAt((int) local.getX(), (int) local.getY());
if(k!=null && mouseEvent.isShiftDown() && restrictTo != null && restrictTo instanceof Knoten) { // mit Shift-Knotenklick Kante auswählen, damit unsichtbare Kanten gewählt werden können (für TSP)
k = graph.getKante((Knoten) restrictTo, (Knoten) k);
}
if(k!=null && mouseEvent.isShiftDown() && selected.size() == 1 && selected.get(0) instanceof Knoten) { // mit Shift-Knotenklick Kante auswählen, damit unsichtbare Kanten gewählt werden können (für TSP)
k = graph.getKante((Knoten) (selected.get(0)), (Knoten) k);
}
if(k==null) k = getKanteAt((int) local.getX(), (int) local.getY());
if(!multiselect) {
selected.clear();
}
if(k != null) {
if(selected.contains(k)) selected.remove(k);
else selected.add(k);
}
updateImage();
}
public void mouseDown(MouseEvent mouseEvent) {
if(mouseEvent.isPrimaryButtonDown()) {
Point2D local = this.getContent().sceneToLocal(mouseEvent.getSceneX(), mouseEvent.getSceneY());
dragKnoten = getKnotenAt((int) local.getX(), (int) local.getY());
dragMode = 3; // Linksclick aber nicht auf Knoten
if(dragKnoten != null) {
mouseEvent.setDragDetect(true);
double distance = Math.sqrt(Math.pow(local.getX()-dragKnoten.getX(),2)+Math.pow(local.getY()-dragKnoten.getY(),2));
if(distance < options.vertexSize/4)
dragMode = 1; // Knoten verschieben
else
dragMode = 2; // Kante ziehen
}
}
}
public void mouseDragged(MouseEvent mouseEvent) {
if(dragKnoten != null) {
Point2D local = this.getContent().sceneToLocal(mouseEvent.getSceneX(), mouseEvent.getSceneY());
if(dragMode == 1) {
dragKnoten.setX((int) (local.getX()));
dragKnoten.setY((int) (local.getY()));
}
updateImage();
if(dragMode == 2) {
Picture p = getImage();
p.stroke(0);
p.strokeWeight(3);
//p.line(dragKnoten.getX(), dragKnoten.getY(), (int) local.getX(), (int) local.getY());
drawArrow(p,dragKnoten.getX(), dragKnoten.getY(), (int) local.getX(), (int) local.getY());
setImage(p,false);
}
}
}
public void mouseUp(MouseEvent mouseEvent) {
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())) ;
} else {
if(dragMode == 2 && k != null && k != dragKnoten) {
graph.neueKante(dragKnoten, k, 0.0);
}
}
dragKnoten = null;
dragMode = 0;
mouseEvent.setDragDetect(false);
updateImage();
}
private Knoten getKnotenAt(int x, int y) {
List<Knoten> knoten = graph.getAlleKnoten();
if(restrictTo != null) {
knoten.clear();
if(restrictTo instanceof Knoten) {
knoten = graph.getNachbarknoten((Knoten) restrictTo);
knoten.add((Knoten) restrictTo);
}
if(restrictTo instanceof Kante) {
knoten.add(((Kante) restrictTo).getStart());
knoten.add(((Kante) restrictTo).getZiel());
}
}
for(Knoten k : knoten) {
if(Math.sqrt(Math.pow(k.getX()-x,2)+Math.pow(k.getY()-y,2)) < options.vertexSize/2+1) {
return k;
}
}
return null;
}
private Kante getKanteAt(int x, int y) {
List<Kante> kanten = graph.getAlleKanten();
if(restrictTo != null) {
kanten.clear();
if(restrictTo instanceof Knoten) {
kanten = graph.getAusgehendeKanten((Knoten) restrictTo);
}
if(restrictTo instanceof Kante) {
kanten.add(((Kante) restrictTo));
}
}
for (Kante k: kanten) {
if (x>=Math.min(k.getStart().getX(), k.getZiel().getX())-2 &&
x<=Math.max(k.getStart().getX(), k.getZiel().getX())+2 &&
y>=Math.min(k.getStart().getY(), k.getZiel().getY())-2 &&
y<=Math.max(k.getStart().getY(), k.getZiel().getY())+2) {
double startX = k.getStart().getX();
double startY = k.getStart().getY();
double endX = k.getZiel().getX();
double endY = k.getZiel().getY();
double dy = (endY-startY);
double dx = (endX-startX);
double l = Math.sqrt(dx*dx+dy*dy);
dy = dy /l; dx = dx / l;
startX += dx * (options.vertexSize/2+1);
startY += dy * (options.vertexSize/2+1);
endX -= dx * (options.vertexSize/2+1);
endY -= dy * (options.vertexSize/2+1);
double dx2 = dy*5;
double dy2 = -dx*5;
if (graph.isGerichtet() && graph.getKante(k.getZiel(), k.getStart())!=null){
startX += dx2;
startY += dy2;
endX += dx2;
endY += dy2;
}
double nx = dy;
double ny = -dx;
double abx = x - startX;
double aby = y - startY;
double abs = Math.abs(abx*nx+aby*ny);
if (abs < 3) return k;
}
}
return null;
}
private void drawArrow(Picture p, int startx, int starty, int endx, int endy) {
double deltax = startx - endx;
double result;
if (deltax == 0.0d) {
result = (starty > endy ? Math.PI / 2 : -Math.PI / 2);
}
else {
result = Math.atan((starty - endy) / deltax) + (startx < endx ? Math.PI : 0);
}
double angle = result;
double arrowAngle = Math.PI / 8.0d;
double arrowSize = 10;
double x1 = arrowSize * Math.cos(angle - arrowAngle);
double y1 = arrowSize * Math.sin(angle - arrowAngle);
double x2 = arrowSize * Math.cos(angle + arrowAngle);
double y2 = arrowSize * Math.sin(angle + arrowAngle);
double cx = (arrowSize / 2.0f) * Math.cos(angle);
double cy = (arrowSize / 2.0f) * Math.sin(angle);
int x[] = {(int) endx, (int) (endx+x1), (int) (endx+x2), (int) endx};
int y[] = {(int) endy, (int) (endy+y1), (int) (endy+y2), (int) endy};
p.line(startx, starty, endx, endy);
p.polygon(x,y);
}
private String darker(String color) {
String red = color.substring(0, 2);
String green = color.substring(2,4);
String blue = color.substring(4,6);
long r = Long.parseLong(red,16)/2;
long g = Long.parseLong(green,16) /2;
long b = Long.parseLong(blue,16) / 2;
String sr = "0"+Long.toHexString(r);
String sg = "0"+Long.toHexString(g);
String sb = "0"+Long.toHexString(b);
return sr.substring(sr.length()-2)+sg.substring(sg.length()-2)+sb.substring(sb.length()-2);
}
private String brighter(String color) {
String red = color.substring(0, 2);
String green = color.substring(2,4);
String blue = color.substring(4,6);
long r = (Long.parseLong(red,16)+255)/2;
long g = (Long.parseLong(green,16)) /2;
long b = (Long.parseLong(blue,16)) / 2;
String sr = "0"+Long.toHexString(r);
String sg = "0"+Long.toHexString(g);
String sb = "0"+Long.toHexString(b);
return sr.substring(sr.length()-2)+sg.substring(sg.length()-2)+sb.substring(sb.length()-2);
}
private String format(double d) {
if((int) d == d) {
return ""+(int) d;
} else {
return ""+d;
}
}
public Picture updateImage() {
Knoten restrictToKnoten = null;
Kante restrictToKante = null;
if(restrictTo != null && restrictTo instanceof Knoten) restrictToKnoten = (Knoten) restrictTo;
if(restrictTo != null && restrictTo instanceof Kante) restrictToKante = (Kante) restrictTo;
List<Knoten> knoten = graph.getAlleKnoten();
List<Kante> kanten = graph.getAlleKanten();
int maxx = Integer.MIN_VALUE; int maxy = Integer.MIN_VALUE;
int minx = Integer.MAX_VALUE; int miny = Integer.MAX_VALUE;
for(Knoten k: knoten) {
maxx = Math.max(maxx,k.getX());
minx = Math.min(minx,k.getX());
maxy = Math.max(maxy,k.getY());
miny = Math.min(miny,k.getY());
}
Picture p = new Picture(2000,2000,"FFFFE8");
if(restrictToKnoten != null) {
knoten = graph.getNachbarknoten(restrictToKnoten);
kanten = graph.getAusgehendeKanten(restrictToKnoten);
knoten.add(restrictToKnoten);
// this.getContent().setTranslateY(this.getHeight()/2-restrictToKnoten.getY());
// this.getContent().setTranslateX(this.getWidth()/2-restrictToKnoten.getX());
this.getContent().setTranslateY(1000-(restrictToKnoten.getY()));
this.getContent().setTranslateX(1000-(restrictToKnoten.getX()));
} else if (restrictToKante != null ) {
kanten.clear();
kanten.add(restrictToKante);
knoten.clear();
knoten.add(restrictToKante.getStart());
knoten.add(restrictToKante.getZiel());
// this.getContent().setTranslateY(this.getHeight()/2-restrictToKnoten.getY());
// this.getContent().setTranslateX(this.getWidth()/2-restrictToKnoten.getX());
this.getContent().setTranslateX(1000-(restrictToKante.getStart().getX()+restrictToKante.getZiel().getX())/2);
this.getContent().setTranslateY(1000-(restrictToKante.getStart().getY()+restrictToKante.getZiel().getY())/2);
}
else
{
/*this.getContent().setTranslateX(1000-(minx+maxx)/2);
this.getContent().setTranslateY(1000-(miny+maxy)/2);*/
}
p.textMode(Picture.CENTER);
if(options.bildAnzeigen && !options.bildDatei.isEmpty()) {
Picture p2 = new Picture("./images/"+options.bildDatei);
p.getImage().getGraphics().drawImage(p2.getImage(), 0, 0, null);
minx = options.vertexSize;
miny = options.vertexSize;
maxx = p2.getWidth()-options.vertexSize;
maxy = p2.getHeight()-options.vertexSize;
}
// Zone in der Mitte markieren
if(restrictToKnoten!=null) {
p.fill("FFE8E8");
p.stroke("FFE8E8");
p.ellipse(restrictToKnoten.getX(), restrictToKnoten.getY(), options.vertexSize*2, options.vertexSize*2);
}
if(restrictToKante!=null) {
p.fill("FFE8E8");
p.stroke("FFE8E8");
p.strokeWeight(30);
p.line(restrictToKante.getStart().getX(), restrictToKante.getStart().getY(), restrictToKante.getZiel().getX(),restrictToKante.getZiel().getY());
}
for (Kante k : kanten) {
if (!options.farbenKanten[k.getFarbe()].equals("invisible") || selected.contains(k)) {
double startX = k.getStart().getX();
double startY = k.getStart().getY();
double endX = k.getZiel().getX();
double endY = k.getZiel().getY();
double dy = (endY-startY);
double dx = (endX-startX);
double l = Math.sqrt(dx*dx+dy*dy);
dy = dy /l; dx = dx / l;
startX += dx * (options.vertexSize/2+1);
startY += dy * (options.vertexSize/2+1);
endX -= dx * (options.vertexSize/2+1);
endY -= dy * (options.vertexSize/2+1);
double dx2 = dy*5;
double dy2 = -dx*5;
if (graph.isGerichtet() && graph.getKante(k.getZiel(), k.getStart())!=null){
startX += dx2;
startY += dy2;
endX += dx2;
endY += dy2;
}
if(selected.contains(k)) {
p.stroke("FF0000");
p.strokeWeight(4);
p.line((int) startX, (int) startY, (int) endX, (int) endY);
}
if (!options.farbenKanten[k.getFarbe()].equals("invisible")){
p.stroke(options.farbenKanten[k.getFarbe()]);
p.fill(options.farbenKanten[k.getFarbe()]);
}
else
{
p.stroke("505050");
p.fill("505050");
}
p.strokeWeight(2);
if(graph.isGerichtet()) {
drawArrow(p, (int) startX, (int) startY, (int) endX, (int) endY);
} else {
p.line((int) startX, (int) startY, (int) endX, (int) endY);
}
}
}
for (Kante k : kanten) {
if (!options.farbenKanten[k.getFarbe()].equals("invisible") || selected.contains(k)) {
double startX = k.getStart().getX();
double startY = k.getStart().getY();
double endX = k.getZiel().getX();
double endY = k.getZiel().getY();
double dy = (endY-startY);
double dx = (endX-startX);
double l = Math.sqrt(dx*dx+dy*dy);
dy = dy /l; dx = dx / l;
startX += dx * (options.vertexSize/2+1);
startY += dy * (options.vertexSize/2+1);
endX -= dx * (options.vertexSize/2+1);
endY -= dy * (options.vertexSize/2+1);
double dx2 = dy*5;
double dy2 = -dx*5;
if(graph.isGerichtet()) {
if (graph.getKante(k.getZiel(), k.getStart())!=null){
startX += dx2;
startY += dy2;
endX += dx2;
endY += dy2;
}
}
if(options.showEdgeWeights && graph.isGewichtet()) {
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);
}
}
}
for (Knoten k : knoten) {
p.fill(options.farbenKnoten[k.getFarbe()]);
p.stroke(darker(options.farbenKnoten[k.getFarbe()]));
p.strokeWeight(3);
p.ellipse(k.getX(), k.getY(), options.vertexSize, options.vertexSize);
if(selected.contains(k)) {
p.noFill();
p.strokeWeight(2);
p.stroke(255,0,0);
p.ellipse(k.getX(), k.getY(), options.vertexSize+2, options.vertexSize+2);
}
p.fill(0);
p.stroke(0);
p.strokeWeight(0);
p.textMode(Picture.CENTER);
if (options.showVertexText) {
p.text(""+graph.getNummer(k), k.getX(), k.getY());
} else {
if (options.showVertexValue) {
p.text(format(k.getDoubleWert()), k.getX(), k.getY());
}
}
// Knotenbezeichnung
p.textMode(Picture.CORNER);
p.fill("000080");
if(options.showVertexInfo && !k.getInfotext().equals("")) {
p.text(k.getInfotext(), k.getX()+options.vertexSize/2+5,k.getY());
}
}
this.setImage(p, false);
Picture zugeschnitten = new Picture(maxx-minx+2*options.vertexSize,maxy-miny+2*options.vertexSize);
zugeschnitten.getImage().getGraphics().drawImage(p.getImage(), 0, 0, maxx-minx+2*options.vertexSize, maxy-miny+2*options.vertexSize, minx-options.vertexSize, miny-options.vertexSize, maxx+options.vertexSize, maxy+options.vertexSize, null);
return zugeschnitten;
}
public GraphOptions getGraphOptions() {
return options;
}
/**
* Gibt den Graphen zurueck.
*
* @return Graph
*/
public Graph getGraph() {
return graph;
}
/**
* Gibt das selektierte Knotenobjekt zurueck.
*
* @return Object
*/
public Knoten getSelectedKnoten() {
if(selected.size()==1 && selected.get(0) instanceof Knoten)
return ((Knoten) (selected.get(0)));
else
return null;
}
/**
* Gibt die selektierte KnotenobjektListe (als Array) zurueck.
*
* @return Object[]
*/
public List<Knoten> getSelectedKnotenListe() {
List<Knoten> l = new ArrayList<Knoten>();
for(GraphElement g : selected) {
if(g instanceof Knoten) l.add((Knoten) g);
}
return l;
}
/**
* Gibt das selektierte Kantenobjekt zurueck.
*
* @return Object
*/
public Kante getSelectedKante() {
if(selected.size()==1 && selected.get(0) instanceof Kante)
return ((Kante) (selected.get(0)));
else
return null;
}
/**
* Ueberschreibt die Methode toString. Eine String-Repraesentation des GraphPlotters wird ausgegeben.
*
* @return String Die String-Repraesentation des GraphPlotters
*/
public String toString() {
String s = "";
if(graph.isGerichtet())
s += "Gerichteter, ";
else
s += "Ungerichteter, ";
if(graph.isGewichtet())
s += "gewichteter Graph mit Hintergrundbild: ";
else
s += "ungewichteter Graph mit Hintergrundbild: ";
if(options.bildDatei.equals(""))
s += " kein Bild!";
else
s += options.bildDatei + "!";
return s;
}
/**
* Gibt die String-Repraesentation des GraphPlotters auf der Konsole aus.
*/
public void ausgabe() {
System.out.println(toString() + "\n"+graph.toString());
}
// Ende Methoden
}

15
graph/Hilfe.ctxt Normal file
View file

@ -0,0 +1,15 @@
#BlueJ class context
comment0.target=Hilfe
comment1.params=
comment1.target=void\ loescheAlles()
comment2.params=text
comment2.target=void\ append(java.lang.String)
comment3.params=
comment3.target=void\ indentMore()
comment4.params=
comment4.target=void\ indentLess()
comment5.params=gp
comment5.target=void\ setGraphPlotter(GraphPlotter)
comment6.params=a
comment6.target=void\ setReviewAllowed(boolean)
numComments=7

17
graph/Hilfe.java Normal file
View file

@ -0,0 +1,17 @@
package graph;
public interface Hilfe {
public abstract void loescheAlles();
public abstract void append(String text);
public void indentMore() ;
public void indentLess() ;
public void setGraphPlotter(GraphPlotter gp);
public void setReviewAllowed(boolean a);
}

64
graph/Kante.ctxt Normal file
View file

@ -0,0 +1,64 @@
#BlueJ class context
comment0.target=Kante
comment0.text=\r\n\ Die\ Klasse\ Kante\ beschreibt\ die\ Datenstruktur\ einer\ Kante,\ bestehend\ aus\ Startknoten,\ Gewicht\ und\ Zielknoten.\r\n\ Da\ Kanten\ innerhalb\ von\ Adjazenzlisten\ und\ -Matrizen\ repraesentiert\ werden,\ ist\ diese\ Klasse\ eigentlich\ unnoetig\!\r\n\ Sie\ wurde\ zum\ Zweck\ der\ Vereinfachung\ -\ sozusagen\ als\ Zwischenspeicher\ von\ Kanten\ -\ eingefuehrt.\r\n\ Auch\ soll\ sie\ das\ Kantengewicht\ verwalten\ und\ Aufschluss\ darueber\ geben,\ ob\ sie\ gefaerbt/geloescht\ ist\ oder\ nicht.\r\n\ \r\n\ @author\ \ Dirk\ Zechnall,\ Thomas\ Schaller\r\n\ @version\ 22.07.2020\ (v6.4)\r\n
comment1.params=neuerStart\ neuerZiel\ neuesGewicht
comment1.target=Kante(Knoten,\ Knoten,\ double)
comment1.text=\r\n\ Der\ Konstruktor\ erstellt\ eine\ neue\ Kante\ mit\ Start-\ und\ Zielknoten\ und\ Kantengewicht.\r\n\ Die\ Kante\ ist\ zu\ Beginn\ ungefaerbt.\r\n\r\n\ @param\ \ neuerStart\ \ Der\ neue\ Startknoten\r\n\ @param\ \ neuerZiel\ \ Der\ neue\ Zielknoten\r\n\ @param\ \ neuesGewicht\ \ Das\ neue\ Kantengewicht\r\n
comment10.params=
comment10.target=Knoten\ getZiel()
comment10.text=\r\n\ Gibt\ den\ Zielknoten\ der\ Kante\ zurueck\r\n\ \r\n\ @return\ \ Zielknoten\r\n
comment11.params=k
comment11.target=Knoten\ getAnderesEnde(Knoten)
comment11.text=\r\n\ Gibt\ Knoten\ am\ anderen\ Ende\ der\ Kante\ zurueck\r\n\ @param\ k\ Knoten\ am\ ersten\ Ende\ der\ Kante\r\n\ @return\ \ Knoten\ am\ anderen\ Ende\r\n
comment12.params=wert
comment12.target=void\ setMarkiert(boolean)
comment12.text=\r\n\ Setzt\ das\ markiert-Attribut\ der\ Kante\r\n\r\n\ @param\ \ wert\ \ Der\ neu\ zu\ setzende\ markiert-Wert\r\n
comment13.params=
comment13.target=boolean\ isMarkiert()
comment13.text=\r\n\ Gibt\ zur\u00FCck,\ ob\ die\ Kanten\ markiert\ ist\r\n\ \r\n\ @return\ \ markiert?\r\n
comment14.params=wert
comment14.target=void\ setGeloescht(boolean)
comment14.text=\r\n\ Setzt\ das\ gel\u00F6scht-Attribut\ der\ Kante\r\n\r\n\ @param\ \ wert\ \ Der\ neu\ zu\ setzende\ gel\u00F6scht-Wert\r\n
comment15.params=
comment15.target=boolean\ isGeloescht()
comment15.text=\r\n\ Gibt\ den\ gel\u00F6scht-Wert\ der\ Kante\ zurueck\r\n\ \r\n\ @return\ \ gel\u00F6scht?\r\n
comment16.params=
comment16.target=int\ getFarbe()
comment16.text=\r\n\ Gibt\ zurueck,\ in\ welcher\ Farbe\ die\ Kante\ gezeichnet\ werden\ soll.\r\n\ Ist\ die\ Farbe\ nicht\ gesetzt,\ dann\ wird\ eine\ unmarkierte\ Kante\ in\ Farbe\ 1\ \r\n\ und\ eine\ markierte\ in\ Farbe\ 2\ gezeichnet.\r\n\ @return\ Nummer\ der\ Farbe\r\n
comment17.params=farbe
comment17.target=void\ setFarbe(int)
comment17.text=\r\n\ Setzt\ die\ Farbe\ auf\ einen\ bestimmten\ Farbindex\r\n\ @param\ farbe\ Index\ der\ Farbe\ (0-19)\r\n
comment18.params=
comment18.target=void\ setStandardFarbe()
comment18.text=\r\n\ Setzt\ die\ Farbe\ auf\ die\ Standardfarbgebung\ zur\u00FCck\r\n
comment19.params=e
comment19.target=int\ compareTo(GraphElement)
comment19.text=\ Vergleicht\ die\ Kante\ mit\ einer\ anderen\ Kante\ bez\u00FCglich\ ihres\ Gewichts\r\n\ @param\ e\ andere\ Kante\r\n\ @return\ kleiner\ 0\ die\ andere\ Kante\ hat\ ein\ gr\u00F6\u00DFeres\ Gewicht,\ gr\u00F6\u00DFer\ 0\ die\ andere\ Kante\ hat\ ein\ kleineres\ Gewicht,\ gleich\ 0\ beides\ sind\ gleich\r\n
comment2.params=
comment2.target=void\ init()
comment2.text=\r\n\ Die\ Methode\ init\ initialisiert\ die\ Kantenfaerbung\ (auf\ unmarkiert)\r\n
comment20.params=
comment20.target=java.lang.String\ toString()
comment20.text=\r\n\ Die\ Methode\ ueberschreibt\ die\ Methode\ toString()\ und\ gibt\ die\ String-Raepraesentation\ einer\ Kante\ zurueck\r\n\ \r\n\ @return\ \ \ \ \ \ String-Raepraesentation\ der\ Kante\r\n
comment3.params=status
comment3.target=void\ setStatus(java.lang.String)
comment3.text=\r\n\ Setzt\ den\ Status\ einer\ Kante,\ der\ in\ einem\ String\ gespeichert\ ist.\r\n\ Form\:\ markiert,geloescht,farbe\ \r\n\ Dabei\ sind\ markiert\ und\ geloescht\ boolsche\ Werte\ (0\ \=\ false,\ 1\ \=\ true)\ und\r\n\ die\ farbe\ eine\ Zahl\r\n\ @param\ status\ \ Statusstring\r\n
comment4.params=
comment4.target=java.lang.String\ getStatus()
comment4.text=\r\n\ Liefert\ den\ Status\ einer\ Kante\ als\ String.\r\n\ Form\:\ markiert,geloescht,farbe\ \r\n\ Dabei\ sind\ markiert\ und\ geloescht\ boolsche\ Werte\ (0\ \=\ false,\ 1\ \=\ true)\ und\r\n\ die\ farbe\ eine\ Zahl\r\n\ @return\ Statusstring\r\n
comment5.params=neuesGewicht
comment5.target=void\ setGewicht(double)
comment5.text=\r\n\ Setzt\ das\ Gewicht\ der\ Kante\r\n\r\n\ @param\ \ neuesGewicht\ \ Das\ neu\ zu\ setzende\ Gewicht\r\n
comment6.params=
comment6.target=double\ getGewicht()
comment6.text=\r\n\ Gibt\ das\ Gewicht\ der\ Kante\ zurueck\r\n\ \r\n\ @return\ \ Gewicht\ der\ Kante\r\n
comment7.params=neuerSatrtKnoten
comment7.target=void\ setStart(Knoten)
comment7.text=\r\n\ Setzt\ den\ Startknoten\ der\ Kante\r\n\r\n\ @param\ \ neuerSatrtKnoten\ \ Der\ neu\ zu\ setzende\ Startknoten\r\n
comment8.params=
comment8.target=Knoten\ getStart()
comment8.text=\r\n\ Gibt\ den\ Startknoten\ der\ Kante\ zurueck\r\n\ \r\n\ @return\ \ Startknoten\r\n
comment9.params=neuerZielKnoten
comment9.target=void\ setZiel(Knoten)
comment9.text=\r\n\ Setzt\ den\ Zielknoten\ der\ Kante\r\n\r\n\ @param\ \ neuerZielKnoten\ \ Der\ neu\ zu\ setzende\ Zielknoten\r\n
numComments=21

225
graph/Kante.java Normal file
View file

@ -0,0 +1,225 @@
package graph;
import java.util.List;
import java.util.Arrays;
/**
* Die Klasse Kante beschreibt die Datenstruktur einer Kante, bestehend aus Startknoten, Gewicht und Zielknoten.
* Da Kanten innerhalb von Adjazenzlisten und -Matrizen repraesentiert werden, ist diese Klasse eigentlich unnoetig!
* Sie wurde zum Zweck der Vereinfachung - sozusagen als Zwischenspeicher von Kanten - eingefuehrt.
* 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)
*/
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.
* Die Kante ist zu Beginn ungefaerbt.
*
* @param neuerStart Der neue Startknoten
* @param neuerZiel Der neue Zielknoten
* @param neuesGewicht Das neue Kantengewicht
*/
public Kante (Knoten neuerStart, Knoten neuerZiel, double neuesGewicht) {
gewicht = neuesGewicht;
start = neuerStart;
ziel = neuerZiel;
}
/**
* 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;
}
/**
* Setzt das Gewicht der Kante
*
* @param neuesGewicht Das neu zu setzende Gewicht
*/
public void setGewicht(double neuesGewicht) {
gewicht = neuesGewicht;
}
/**
* Gibt das Gewicht der Kante zurueck
*
* @return Gewicht der Kante
*/
public double getGewicht() {
return gewicht;
}
/**
* Setzt den Startknoten der Kante
*
* @param neuerSatrtKnoten Der neu zu setzende Startknoten
*/
public void setStart(Knoten neuerSatrtKnoten) {
start = neuerSatrtKnoten;
}
/**
* Gibt den Startknoten der Kante zurueck
*
* @return Startknoten
*/
public Knoten getStart() {
return start;
}
/**
* Setzt den Zielknoten der Kante
*
* @param neuerZielKnoten Der neu zu setzende Zielknoten
*/
public void setZiel(Knoten neuerZielKnoten) {
ziel = neuerZielKnoten;
}
/**
* Gibt den Zielknoten der Kante zurueck
*
* @return Zielknoten
*/
public Knoten getZiel() {
return ziel;
}
/**
* Gibt Knoten am anderen Ende der Kante zurueck
* @param k Knoten am ersten Ende der Kante
* @return Knoten am anderen Ende
*/
public Knoten getAnderesEnde(Knoten k) {
if (k == start) return ziel;
if (k == ziel) return start;
return null;
}
/**
* Setzt das markiert-Attribut der Kante
*
* @param wert Der neu zu setzende markiert-Wert
*/
public void setMarkiert(boolean wert) {
markiert = wert;
}
/**
* Gibt zurück, ob die Kanten markiert ist
*
* @return markiert?
*/
public boolean isMarkiert() {
return markiert;
}
/**
* Setzt das gelöscht-Attribut der Kante
*
* @param wert Der neu zu setzende gelöscht-Wert
*/
public void setGeloescht(boolean wert) {
geloescht = wert;
}
/**
* Gibt den gelöscht-Wert der Kante zurueck
*
* @return gelöscht?
*/
public boolean isGeloescht() {
return geloescht;
}
/**
* Gibt zurueck, in welcher Farbe die Kante gezeichnet werden soll.
* Ist die Farbe nicht gesetzt, dann wird eine unmarkierte Kante in Farbe 1
* und eine markierte in Farbe 2 gezeichnet.
* @return Nummer der Farbe
*/
public int getFarbe() {
if(farbe == -1) {
if(geloescht) return 2;
if(markiert) return 1;
return 0;
}
return farbe;
}
/**
* Setzt die Farbe auf einen bestimmten Farbindex
* @param farbe Index der Farbe (0-19)
*/
public void setFarbe(int farbe) {
if(farbe>=0 && farbe < 20)
this.farbe = farbe;
}
/**
* Setzt die Farbe auf die Standardfarbgebung zurück
*/
public void setStandardFarbe() {
farbe = -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
*
* @return String-Raepraesentation der Kante
*/
@Override
public String toString() {
return " --("+gewicht+")--> ";
}
}

76
graph/Knoten.ctxt Normal file
View file

@ -0,0 +1,76 @@
#BlueJ class context
comment0.target=Knoten
comment0.text=\r\n\ Diese\ Klasse\ Knoten\ definiert\ einen\ Knoten.\r\n\ Knoten\ haben\ eine\ Position,\ eine\ Farbe\ und\ einen\ Wert\ f\u00FCr\ sonstige\ Codierungszwecke\ und\ sind\ markiert\ und/oder\ besucht.\r\n\ Im\ Infotext\ kann\ eine\ zus\u00E4tzliche\ Information\ f\u00FCr\ die\ Anzeige\ gespeichert\ werden.\r\n\ \r\n\ @author\ Dirk\ Zechnall,\ Thomas\ Schaller\r\n\ @version\ 22.07.2020\ (v6.4)\r\n
comment1.params=x\ y
comment1.target=Knoten(int,\ int)
comment1.text=\r\n\ Der\ Konstruktor\ erstellt\ einen\ neuen\ Knoten\ mit\ einem\ neuen\ Namen\r\n\r\n\ @param\ \ x\ \ x-Position\ des\ Knotens\r\n\ @param\ \ y\ \ y-Position\ des\ Knotens\r\n
comment10.params=
comment10.target=double\ getDoubleWert()
comment10.text=\r\n\ Gibt\ den\ Wert\ vom\ Knoten\ als\ Double-Wert\ zurueck\r\n\ \r\n\ @return\ \ Wert\ des\ Knotens\r\n
comment11.params=markiert
comment11.target=void\ setMarkiert(boolean)
comment11.text=\r\n\ Setzt\ das\ Markiertattribut\ vom\ Knoten\r\n\r\n\ @param\ \ markiert\ \ Der\ neu\ zu\ setzende\ Markiertwert\r\n
comment12.params=
comment12.target=boolean\ isMarkiert()
comment12.text=\r\n\ Gibt\ den\ Markiertwert\ vom\ Knoten\ zurueck\r\n\ \r\n\ @return\ \ markiert?\r\n
comment13.params=markiert
comment13.target=void\ setBesucht(boolean)
comment13.text=\r\n\ Setzt\ das\ Besuchtattribut\ vom\ Knoten\r\n\r\n\ @param\ \ markiert\ \ Der\ neu\ zu\ setzende\ Besuchtwert\r\n
comment14.params=
comment14.target=boolean\ isBesucht()
comment14.text=\r\n\ Gibt\ den\ Besuchtwert\ vom\ Knoten\ zurueck\r\n\ \r\n\ @return\ \ besucht?\r\n
comment15.params=
comment15.target=int\ getFarbe()
comment15.text=\r\n\ Gibt\ den\ Index\ der\ Farbe\ des\ Knoten\ zur\u00FCck.\r\n\ Standardm\u00E4\u00DFig\ h\u00E4ngt\ die\ Farbe\ von\ den\ Attributen\ markiert\ und\ besucht\ ab.\r\n\ Durch\ Setzen\ der\ Farbe\ kann\ die\ Farbe\ gezielt\ gesetzt\ werden.\r\n\ @return\ Farbe\ des\ Knotens\r\n
comment16.params=farbe
comment16.target=void\ setFarbe(int)
comment16.text=\r\n\ Setzt\ den\ Index\ der\ Farbe\ des\ Knoten.\r\n\ Standardm\u00E4\u00DFig\ h\u00E4ngt\ die\ Farbe\ von\ den\ Attributen\ markiert,\ besucht\ und\ beendet\ ab.\r\n\ Durch\ Setzen\ der\ Farbe\ kann\ die\ Farbe\ gezielt\ gesetzt\ werden.\r\n\ @param\ farbe\ Index\ der\ Farbe\ (0-19)\r\n
comment17.params=
comment17.target=boolean\ isFarbeAutomatisch()
comment17.text=\ Gibt\ zur\u00FCck,\ ob\ die\ Knotenfarbe\ automatisch\ aus\ den\ Attributen\ ermittelt\ wird.\r\n\ @return\ true\=Farbe\ wird\ automatisch\ bestimmt,\ false\=Farbe\ wurde\ explizit\ gesetzt.\r\n\ \ \ \ \ \r\n
comment18.params=auto
comment18.target=void\ setFarbeAutomatisch(boolean)
comment18.text=\ Legt\ fest,\ ob\ die\ Knotenfarbe\ automatisch\ aus\ den\ Attributen\ ermittelt\ wird.\r\n\ @param\ auto\ true\=Farbe\ wird\ automatisch\ bestimmt,\r\n\ \ \ \ \ \ \ \ \ \ \ \ \ false\=Farbe\ wird\ explizit\ gesetzt.\r\n
comment19.params=
comment19.target=int\ getX()
comment19.text=\ Liefert\ die\ x-Position\ des\ Knotens\r\n\ @return\ x-Postion\r\n
comment2.params=x\ y\ neuerWert
comment2.target=Knoten(int,\ int,\ double)
comment2.text=\r\n\ Der\ Konstruktor\ erstellt\ einen\ neuen\ Knoten\ mit\ einem\ Startwert\r\n\r\n\ @param\ \ x\ \ x-Position\ des\ Knotens\r\n\ @param\ \ y\ \ y-Position\ des\ Knotens\ \ \ \ \r\n\ @param\ \ neuerWert\ \ Der\ neue\ Wert\ des\ Knotens\ \r\n
comment20.params=
comment20.target=int\ getY()
comment20.text=\ Liefert\ die\ y-Position\ des\ Knotens\r\n\ @return\ y-Postion\r\n
comment21.params=x
comment21.target=void\ setX(int)
comment21.text=\ Setzt\ die\ x-Position\ des\ Knotens\r\n\ @param\ x\ x-Postion\r\n
comment22.params=y
comment22.target=void\ setY(int)
comment22.text=\ Setzt\ die\ y-Position\ des\ Knotens\r\n\ @param\ y\ y-Postion\r\n
comment23.params=e
comment23.target=int\ compareTo(GraphElement)
comment23.text=\ Vergleicht\ den\ Knoten\ mit\ einem\ anderen\ Knoten\ bez\u00FCglich\ seines\ Werts\r\n\ @param\ e\ anderer\ Knoten\r\n\ @return\ kleiner\ 0\ der\ andere\ Knoten\ hat\ einen\ gr\u00F6\u00DFeren\ Wert,\ gr\u00F6\u00DFer\ 0\ der\ andere\ Knoten\ hat\ einen\ kleineren\ Wert,\ gleich\ 0\ beide\ sind\ gleich\r\n
comment24.params=
comment24.target=java.lang.String\ toString()
comment24.text=\r\n\ Die\ Methode\ ueberschreibt\ die\ Methode\ toString()\ und\ gibt\ die\ String-Raepraesentation\ eines\ Knotens\ zurueck\r\n\ \r\n\ @return\ \ \ \ \ \ String-Raepraesentation\ des\ Knotens\r\n
comment3.params=status
comment3.target=void\ setStatus(java.lang.String)
comment3.text=\r\n\ Setzt\ den\ Status\ eines\ Knotens\ aus\ einem\ Status-String\r\n\ Format\:\ wert,markiert,besucht,farbe\r\n\ wobei\ wert\ eine\ double-Zahl,\ mariert\ und\ besucht\ ein\ boolean-Wert\ (0\=false,\ 1\ \=\ true)\ und\r\n\ farbe\ eine\ zahl\ ist.\r\n\r\n\ @param\ \ status\ Der\ Statusstring\r\n
comment4.params=
comment4.target=java.lang.String\ getStatus()
comment4.text=\r\n\ Liefert\ den\ Status\ eines\ Knotens\ als\ Status-String\r\n\ Format\:\ wert,markiert,besucht,farbe\r\n\ wobei\ wert\ eine\ double-Zahl,\ mariert\ und\ besucht\ ein\ boolean-Wert\ (0\=false,\ 1\ \=\ true)\ und\r\n\ farbe\ eine\ zahl\ ist.\r\n\r\n\ @return\ Der\ Statusstring\r\n
comment5.params=
comment5.target=void\ init()
comment5.text=\r\n\ Die\ Methode\ init\ initialisiert\ den\ Zustand\ eines\ Knotens\r\n
comment6.params=infotext
comment6.target=void\ setInfotext(java.lang.String)
comment6.text=\ Setzt\ den\ Infotext\ f\u00FCr\ einen\ Knoten\r\n\ @param\ infotext\ Der\ neue\ Text\r\n
comment7.params=
comment7.target=java.lang.String\ getInfotext()
comment7.text=\ Liefert\ den\ Infotext\ des\ Knotens\r\n\ @return\ Der\ Infotext\r\n
comment8.params=neuerWert
comment8.target=void\ setWert(double)
comment8.text=\r\n\ Setzt\ den\ Wert\ beim\ Knoten\r\n\r\n\ @param\ \ neuerWert\ \ Der\ neu\ zu\ setzende\ Wert\r\n
comment9.params=
comment9.target=int\ getIntWert()
comment9.text=\r\n\ Gibt\ den\ Wert\ vom\ Knoten\ als\ Integer-Wert\ zurueck\r\n\ \r\n\ @return\ \ Wert\ des\ Knotens\r\n
numComments=25

263
graph/Knoten.java Normal file
View file

@ -0,0 +1,263 @@
package graph;
import java.util.List;
import java.util.Arrays;
/**
* Diese Klasse Knoten definiert einen Knoten.
* Knoten haben eine Position, eine Farbe und einen Wert für sonstige Codierungszwecke und sind markiert und/oder besucht.
* Im Infotext kann eine zusätzliche Information für die Anzeige gespeichert werden.
*
* @author Dirk Zechnall, Thomas Schaller
* @version 22.07.2020 (v6.4)
*/
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
*
* @param x x-Position des Knotens
* @param y y-Position des Knotens
*/
public Knoten(int x, int y) {
this.x = x;
this.y = y;
wert = 0;
infotext = "";
}
/**
* Der Konstruktor erstellt einen neuen Knoten mit einem Startwert
*
* @param x x-Position des Knotens
* @param y y-Position des Knotens
* @param neuerWert Der neue Wert des Knotens
*/
public Knoten(int x, int y, double neuerWert) {
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;
}
/**
* Die Methode init initialisiert den Zustand eines Knotens
*/
protected void init() {
wert = 0.0;
farbe = -1;
istMarkiert = false;
istBesucht = false;
}
/** Setzt den Infotext für einen Knoten
* @param infotext Der neue Text
*/
public void setInfotext(String infotext) {
this.infotext = infotext;
}
/** Liefert den Infotext des Knotens
* @return Der Infotext
*/
public String getInfotext(){
return infotext;
}
/**
* Setzt den Wert beim Knoten
*
* @param neuerWert Der neu zu setzende Wert
*/
public void setWert(double neuerWert) {
wert = neuerWert;
}
/**
* Gibt den Wert vom Knoten als Integer-Wert zurueck
*
* @return Wert des Knotens
*/
public int getIntWert() {
return (int) wert;
}
/**
* Gibt den Wert vom Knoten als Double-Wert zurueck
*
* @return Wert des Knotens
*/
public double getDoubleWert() {
return wert;
}
/**
* Setzt das Markiertattribut vom Knoten
*
* @param markiert Der neu zu setzende Markiertwert
*/
public void setMarkiert(boolean markiert) {
istMarkiert = markiert;
}
/**
* Gibt den Markiertwert vom Knoten zurueck
*
* @return markiert?
*/
public boolean isMarkiert() {
return istMarkiert;
}
/**
* Setzt das Besuchtattribut vom Knoten
*
* @param markiert Der neu zu setzende Besuchtwert
*/
public void setBesucht(boolean markiert) {
istBesucht = markiert;
}
/**
* Gibt den Besuchtwert vom Knoten zurueck
*
* @return besucht?
*/
public boolean isBesucht() {
return istBesucht;
}
/**
* Gibt den Index der Farbe des Knoten zurück.
* Standardmäßig hängt die Farbe von den Attributen markiert und besucht ab.
* Durch Setzen der Farbe kann die Farbe gezielt gesetzt werden.
* @return Farbe des Knotens
*/
public int getFarbe() {
if (farbe == -1) {
int f = 0;
if(istMarkiert) {
f += 1;
}
if(istBesucht) {
f += 2;
}
return f;
}
return farbe;
}
/**
* Setzt den Index der Farbe des Knoten.
* Standardmäßig hängt die Farbe von den Attributen markiert, besucht und beendet ab.
* Durch Setzen der Farbe kann die Farbe gezielt gesetzt werden.
* @param farbe Index der Farbe (0-19)
*/
public void setFarbe(int farbe) {
this.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;
}
/** Legt fest, ob die Knotenfarbe automatisch aus den Attributen ermittelt wird.
* @param auto true=Farbe wird automatisch bestimmt,
* false=Farbe wird explizit gesetzt.
*/
public void setFarbeAutomatisch(boolean auto) {
if(auto) {
farbe = -1;
} else {
if(farbe == -1) farbe = 0;
}
}
/** Liefert die x-Position des Knotens
* @return x-Postion
*/
public int getX() {
return x;
}
/** Liefert die y-Position des Knotens
* @return y-Postion
*/
public int getY() {
return y;
}
/** Setzt die x-Position des Knotens
* @param x x-Postion
*/
public void setX(int x) {
this.x = x;
}
/** Setzt die y-Position des Knotens
* @param y y-Postion
*/ 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
*
* @return String-Raepraesentation des Knotens
*/
@Override
public String toString() {
return "["+infotext+","+wert+","+istMarkiert+","+istBesucht+"]";
}
}

110
graph/package.bluej Normal file
View file

@ -0,0 +1,110 @@
#BlueJ package file
dependency1.from=Graph
dependency1.to=Knoten
dependency1.type=UsesDependency
dependency10.from=GraphPlotter
dependency10.to=GraphOptions
dependency10.type=UsesDependency
dependency11.from=GraphPlotter
dependency11.to=GraphElement
dependency11.type=UsesDependency
dependency12.from=GraphPlotter
dependency12.to=Knoten
dependency12.type=UsesDependency
dependency13.from=GraphPlotter
dependency13.to=Kante
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=GraphOptions
dependency5.to=GraphElement
dependency5.type=UsesDependency
dependency6.from=Knoten
dependency6.to=GraphElement
dependency6.type=UsesDependency
dependency7.from=Knoten
dependency7.to=Kante
dependency7.type=UsesDependency
dependency8.from=Hilfe
dependency8.to=GraphPlotter
dependency8.type=UsesDependency
dependency9.from=GraphPlotter
dependency9.to=Graph
dependency9.type=UsesDependency
objectbench.height=93
objectbench.width=530
package.divider.horizontal=0.6
package.divider.vertical=0.8204667863554758
package.editor.height=450
package.editor.width=780
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=58
readme.name=@README
readme.width=47
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=false
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