/*
* Datei: DarstModEA.java
* Autor(en): Lukas König
* Java-Version: 6.0
* Erstellt (vor): 24.10.2008
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.startSetup.marbBuilder.darstellungsModi;
import java.awt.Polygon;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import eas.math.geometry.Vector2D;
import eas.miscellaneous.StaticMethods;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.EndlicherAutomat;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.Transition;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.conditions.Condition;
import eas.startSetup.marbBuilder.DargestellterGraph;
import eas.startSetup.marbBuilder.graph.Graph;
import eas.startSetup.marbBuilder.graph.Knoten;
/**
* Darstellungsmodus für die Darstellung eines Graphen, der einen endlichen
* Automaten beschreibt.
*
* Bitte beachten: Wenn die Darstellung von der Festplatte geladen wird, dann
* bewirken änderungen an der Autoanordnung möglicherweise
* nicht den gew�nschten Effekt. In diesem Fall müssen die
* Koordinatendateien gelöscht werden.
*
* @author Lukas König
*
*/
public class DarstModEA implements DarstellungsKit,
Serializable {
/**
* Die Serial Version ID (generiert am 25. April 2007).
*/
private static final long serialVersionUID = -1466446020836015270L;
/**
* Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
private int links;
/**
* Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
private int oben;
/**
* Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
private int rechts;
/**
* Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
private int unten;
/**
* Die bereits positionierten Knoten.
*/
private HashMap<Integer, Vector2D> gesetzteKn;
/**
* Standard-Konstruktor.
*
* @param li Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param ob Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param re Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param un Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
public DarstModEA(final int li,
final int ob,
final int re,
final int un) {
this.setAusd(li, ob, re, un);
this.gesetzteKn = new HashMap<Integer, Vector2D>();
}
/**
* Setzt die Eckpunkte der Darstellung.
*
* @param li Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param ob Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param re Eckpunkt des Rahmens, in dem gezeichnet werden darf.
* @param un Eckpunkt des Rahmens, in dem gezeichnet werden darf.
*/
public void setAusd(final int li,
final int ob,
final int re,
final int un) {
int radius = (int) (
eas.startSetup.marbBuilder.zeichenModi.ConstantsZeichenModi.KN_DURCHM / 2);
this.links = li + radius;
this.rechts = re - radius;
this.oben = ob;
this.unten = un - radius;
}
/**
* Setzt einen Knoten mit Beschriftungen auf eine Position.
*
* @param k Der Knoten.
* @param d Die Graphdarstellung.
* @param x Die X-Koordinate.
* @param y Die Y-Koordinate.
* @param ausg Der Ausgangsknoten.
*
* @return Die neue Graphdarstellung.
*/
private DargestellterGraph setzeKnoten(final Knoten k,
final DargestellterGraph d,
final int x,
final int y,
final Knoten ausg) {
d.hinzuKnoten(x, y, k, k == ausg);
d.hinzuBeschr(x - 11,
y - 10,
k.holeName().toString());
d.hinzuBeschr(x - 18,
y + 5,
"("
+ k.getInfo().getAlter()
+ ")");
d.hinzuBeschr(x - 18,
y + 19,
"" + k.getInfo().getAktion()
+ "-"
+ k.getInfo().getParam(),
new Polygon());
return null;
}
/**
* Erzeugt eine Darstellung eines Graphen.
*
* @param g Der darzustellende Graph.
* @param ausgKn Der Name des Knotens, von dem die Zeichnung
* ausgehen soll. Dieser Knoten wird auf der
* Y-Achse platziert.
*
* @return Darstellung des Graphen g.
*/
public DargestellterGraph erzeuge(final EndlicherAutomat g,
final Object ausgKn) {
DargestellterGraph darstellung = new DargestellterGraph(null);
Iterator<Knoten> it;
Iterator<Knoten> it1;
Iterator<Integer> it2;
Iterator<Transition> it3;
Knoten knot;
Knoten knot1;
Knoten knot2;
Vector2D koord1;
Vector2D koord2;
if (!g.istLeer()) {
final ArrayList<Knoten> knotenListe
= new ArrayList<Knoten>(g.holAdj().values());
int knAnzahl = knotenListe.size();
if (knAnzahl < 2) {
knAnzahl = 2;
}
int gitterX = Math.abs(this.rechts - this.links)
/ (int) ((Math.ceil(Math.sqrt(knAnzahl))) - 1);
int gitterY = Math.abs(this.unten - this.oben)
/ (int) ((Math.ceil(Math.sqrt(knAnzahl))) - 1);
int koordX = this.links;
int koordY = this.oben;
int kX;
int kY;
Transition bed;
int folgeZustand;
String bedingung;
int xAusgleich;
int zaehler = 0;
// Knoten
it = knotenListe.iterator();
while (it.hasNext()) {
knot = it.next();
if (this.gesetzteKn.containsKey(knot.holeName())) {
kX = (int) this.gesetzteKn.get(knot.holeName()).x;
kY = (int) this.gesetzteKn.get(knot.holeName()).y;
this.setzeKnoten(knot,
darstellung,
kX,
kY,
(Knoten) ausgKn);
if (g.istStartZ(knot)) {
darstellung.hinzuPfeil(kX - 60,
kY - 60,
kX - 45,
kY - 45,
0.5,
false);
}
} else {
this.setzeKnoten(knot,
darstellung,
koordX,
koordY,
(Knoten) ausgKn);
this.gesetzteKn.put(knot.holeName(),
new Vector2D(koordX, koordY));
if (g.istStartZ(knot)) {
darstellung.hinzuPfeil(koordX - 60,
koordY - 60,
koordX - 45,
koordY - 45,
0.5,
false);
}
zaehler++;
if (zaehler < Math.ceil(Math.sqrt(knAnzahl))) {
koordX = koordX + gitterX;
} else {
koordX = this.links;
koordY = koordY + gitterY;
zaehler = 0;
}
}
}
// Kanten
it1 = knotenListe.iterator();
while (it1.hasNext()) {
knot1 = it1.next();
koord1 = this.gesetzteKn.get(knot1.holeName());
it2 = (new ArrayList<Integer>(
knot1.holeNachfolger().keySet())).iterator();
while (it2.hasNext()) {
boolean gebogen = true;
knot2 = g.holeKnoten(it2.next());
koord2 = this.gesetzteKn.get(knot2.holeName());
Condition cond
= knot1.getInfo().getTransZuZustand(
knot2.holeName()).get(0).getCond();
double staerke = StaticMethods.condStrength(cond,
ConstantsDarstellung.STAERKE_ERST,
ConstantsDarstellung.STAERKE_ZWEIT);
if (koord1.distance(koord2) < 140
&& !koord1.equals(koord2)) {
gebogen = false;
}
darstellung.hinzuPfeil(
(int) koord1.x,
(int) koord1.y,
(int) koord2.x,
(int) koord2.y,
staerke,
gebogen);
}
}
// Kantenbeschriftungen
it1 = knotenListe.iterator();
while (it1.hasNext()) {
int kantNum = 1;
knot1 = it1.next();
koord1 = this.gesetzteKn.get(knot1.holeName());
it3 = knot1.getInfo().getBeds().iterator();
while (it3.hasNext()) {
Polygon p = new Polygon();
bed = it3.next();
folgeZustand = bed.getFolgezustand();
bedingung = bed.getCond().toString();
knot2 = g.holeKnoten(new Integer(folgeZustand));
koord2 = this.gesetzteKn.get(knot2.holeName());
p.addPoint((int) koord1.x, (int) koord1.y);
p.addPoint((int) koord2.x, (int) koord2.y);
if (koord1.equals(koord2)) {
xAusgleich = 95;
} else {
xAusgleich = 0;
}
darstellung.hinzuBeschr(
(int) ((koord1.x + koord2.x) / 2) + xAusgleich,
(int) ((koord1.y + koord2.y) / 2),
kantNum + ".) " + bedingung,
p);
kantNum++;
}
}
}
return darstellung;
}
/**
* Erzeugt einen Hintergrund und gibt ihn zurück.
*
* @return Eine Polygonliste als Hintergrund für die Darstellung.
*/
@Override
public List<Polygon> hintergrund() {
return new LinkedList<Polygon>();
}
/**
* Weist einem Knoten eine feste Koordinate zu.
*
* @param knoten Der Name des Knotens, dem eine Koordinate zugewiesen
* werden soll.
* @param x X-Koordinate.
* @param y Y-Koordinate.
*/
public void neueKoord(final Knoten knoten, final int x, final int y) {
Vector2D koord;
if (this.gesetzteKn.containsKey(knoten.holeName())) {
koord = this.gesetzteKn.get(knoten.holeName());
koord.x = x;
koord.y = y;
} else {
this.gesetzteKn.put(knoten.holeName(), new Vector2D(x, y));
}
}
/**
* löscht alle zugewiesenen Knoten-Koordinaten. Beim nächsten Lauf von
* <code>this.erzeuge</code> wird wieder die Standardverteilung der
* Knoten generiert.
*/
public void loescheKnotenKoord() {
this.gesetzteKn.clear();
}
/**
* Gibt die Anzahl der Ebenen zurück, die mit dem aktuellen Darstellungs-
* Objekt dargestellt werden. (In der Version für den endlichen Automaten
* spielt diese Methode keine Rolle.)
*
* @return Die Anzahl der Ebenen, die this darstellt.
*/
@Override
public int holeEbenen() {
return 0;
}
/**
* Gibt eine Identifikation der Klasse als Textausgabe zurück.
*
* @return Eine Textausgabe zur Identifikation der Klasse.
*/
@Override
public String toString() {
return "DarstellungsModusEA.StandardDarstellungEA1";
}
/**
* @return Returns the gesetzteKn.
*/
public HashMap<Integer, Vector2D> getGesetzteKn() {
return this.gesetzteKn;
}
/**
* Setzt die gesetzten Knoten.
*
* @param gesKn The gesetzteKn to set.
*/
public void setGesetzteKn(final HashMap<Integer, Vector2D> gesKn) {
this.gesetzteKn = gesKn;
}
/**
* @param g Der Graph, der dargestellt wird.
* @param ausgKn Ausgangsknoten, mit dem bei der Zeichnung
* begonnen wird.
*
* @return Darstellung des Graphen.
*/
@Override
public DargestellterGraph erzeuge(final Graph g, final Object ausgKn) {
if (g.getClass() == EndlicherAutomat.class) {
return this.erzeuge((EndlicherAutomat) g, ausgKn);
}
return null;
}
}