/*
* Datei: ZeichFen.java
* Autor(en): Lukas König
* Java-Version: 6.0
* Erstellt (vor): 14.11.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.arrowGUI;
import eas.math.geometry.Circle2D;
import eas.math.geometry.Geometry2D;
import eas.math.geometry.Polygon2D;
import eas.math.geometry.Vector2D;
import eas.miscellaneous.StaticMethods;
import eas.startSetup.ParCollection;
import eas.startSetup.marbBuilder.zeichenModi.AusgMerkm;
import eas.startSetup.marbBuilder.zeichenModi.ArrowMaster;
import eas.startSetup.marbBuilder.zeichenModi.Pfeilspitze;
import eas.startSetup.marbBuilder.zeichenModi.Pol2DMitAusgMerkm;
import eas.startSetup.marbBuilder.zeichenModi.SegSpez;
import eas.statistics.logging.AbstractMsg;
import eas.statistics.logging.MsgError;
import eas.statistics.logging.MsgWarning;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Applet zur Visualisierung eines Graphen.
*
* @author Lukas König.
*/
public class ZeichFen extends Frame implements MouseWheelListener {
/**
* Am 14.09.06 generiert.
*/
private static final long serialVersionUID = -4078048087117840970L;
/**
* Objekt, das die Polygone (u. �.) zur Darstellung eines Graphen erzeugt.
*/
private ArrowMaster zeichenArt;
/**
* Die benutzerdefinierten Segmentbeschreibungen.
*/
private LinkedList<SegSpez> userSegs;
/**
* Der Name des von <code>this</code> dargestellten Graphen.
*/
private String robName;
/**
* Die Dicken.
*/
private ArrayList<Double> dicken = new ArrayList<Double>();
/**
* Der Anfang des Pfeils.
*/
private Pfeilspitze anfang;
/**
* Das Ende des Pfeils.
*/
private Pfeilspitze ende;
/**
* Multiplikativer Faktor für die Größe des Pfeilanfangs.
*/
private double anfFakt;
/**
* Multiplikativer Faktor für die Größe des Pfeilendes.
*/
private double endFakt;
/**
* Die Parameter.
*/
private ParCollection pars;
/**
* Die ID.
*/
private int id;
/**
* Das Pfeilpolygon.
*/
private Polygon2D pfeilPol;
/**
* Ob die Eckpunkte markiert werden sollen.
*/
private boolean markiereEcken = true;
/**
* Ob der Grundpfeil gezeichnet werden soll.
*/
private boolean zeichneGrundPfeil = true;
/**
* @return Returns the id.
*/
public int getId() {
return this.id;
}
/**
* Der angeklickte Punkt.
*/
private Vector2D vekClick;
/**
* Die aktuelle Dicke.
*/
private double aktDicke;
/**
* Der erste markierte Knoten.
*/
private Integer mark1;
/**
* Der zweite markierte Knoten.
*/
private Integer mark2;
/**
* Die Segmentbeschreibungen.
*/
private SegSpez[] segBeschr;
/**
* Erste Ecke.
*/
private Vector2D ersteEcke;
/**
* Zweite Ecke.
*/
private Vector2D zweiteEcke;
/**
* beliebig Große Liste von markierten Knoten.
*/
private LinkedList<Integer> markierte;
/**
* Die Stufe des zuletzt aufgetretenen Fehlers.
*/
private int fehlerStufe = 0;
/**
* Die Skalierung im Verhältnis zur Normskalierung der Zeichenfl�che.
*/
private double skalierung;
/**
* Die Verschiebung der Grafik.
*/
private Vector2D verschiebung;
/**
* Größe der Strichelung.
*/
private double gestrichelt;
/**
* Das Elternpfeilcontroller-Fenster.
*/
private PfeilController elternMaster;
/**
* Die Ausgabemerkmale des gestrichelten Pfeils.
*/
private AusgMerkm[] gestricheltMerkm;
/**
* Ob der Punkt im PfeilPol enthalten ist.
*
* @param vek Der Punkt.
*
* @return null oder Zeiger auf das enthaltene Objekt.
*/
private Vector2D containsPoint(final Vector2D vek) {
final double epsilon = 5 / this.skalierung;
for (Vector2D v : this.pfeilPol) {
if (v.distance(vek) <= epsilon) {
return v;
}
}
return null;
}
/**
* Implementierung eines überschriebenen Konstruktors. Die Graphen werden
* von der Festplatte geladen.
*
* @param fenstertitel Der als Titel anzuzeigende String.
* @param graphNam Der Name des aktuellen Graphen.
* Visualisierung gehört.
* @param params Der Parametersatz.
* @param ident Die Identit�tsnummer.
* @param vater Der Pfeilmastervater.
*/
public ZeichFen(
final String fenstertitel,
final ParCollection params,
final PfeilController vater) {
super(fenstertitel);
this.gestrichelt = 0;
this.ende = ArrowMaster.KUGEL_ENDE;
this.anfang = ArrowMaster.EINFACHE_SPITZE_1;
this.anfFakt = 1;
this.endFakt = 1;
this.gestricheltMerkm = new AusgMerkm[2];
this.gestricheltMerkm[0] = new AusgMerkm(
Color.black,
Color.blue,
true,
true);
this.gestricheltMerkm[1] = new AusgMerkm(
Color.black,
Color.yellow,
true,
true);
this.elternMaster = vater;
this.elternMaster.setzeSegmentFarben(this.gestricheltMerkm);
this.skalierung = 1;
this.verschiebung = new Vector2D(Vector2D.NULL_VECTOR);
this.markierte = new LinkedList<Integer>();
this.userSegs = new LinkedList<SegSpez>();
this.setSize(750, 700);
this.aktDicke = eas.startSetup.marbBuilder.zeichenModi.ConstantsZeichenModi.PFEIL_DICKE;
this.pfeilPol = new Polygon2D();
this.pars = params;
this.zeichenArt = new ArrowMaster(this.pars);
this.segBeschr = new SegSpez[1000];
this.addMouseWheelListener(this);
this.addComponentListener(new ComponentListener() {
@Override
public void componentHidden(final ComponentEvent e) {
}
@Override
public void componentMoved(final ComponentEvent e) {
}
@Override
public void componentResized(final ComponentEvent e) {
ZeichFen.this.neuZeichnen();
}
@Override
public void componentShown(final ComponentEvent e) {
}
}
);
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(final MouseEvent event) {
Vector2D vek = new Vector2D(
(event.getX() - verschiebung.x) / skalierung,
(event.getY() - verschiebung.y) / skalierung);
Vector2D neu;
if (ZeichFen.this.vekClick != null) {
for (int i = 0; i < ZeichFen.this.pfeilPol.nPoints(); i++) {
if (ZeichFen.this.markierte.contains(i)) {
neu = new Vector2D(ZeichFen.this.pfeilPol.get(i));
neu.translate(vek);
neu.sub(ZeichFen.this.ersteEcke);
ZeichFen.this.pfeilPol.set(i, neu);
}
}
ZeichFen.this.vekClick
= ZeichFen.this.containsPoint(vek);
ZeichFen.this.ersteEcke = vek;
ZeichFen.this.neuZeichnen();
} else {
ZeichFen.this.zweiteEcke
= new Vector2D(
(event.getX() - verschiebung.x) / skalierung,
(event.getY() - verschiebung.y) / skalierung);
ZeichFen.this.neuZeichnen();
}
}
});
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent event) {
Vector2D vek = new Vector2D(
(event.getX() - verschiebung.x) / skalierung,
(event.getY() - verschiebung.y) / skalierung);
ZeichFen.this.ersteEcke = new Vector2D(vek);
ZeichFen.this.vekClick
= ZeichFen.this.containsPoint(vek);
ZeichFen.this.mark1 = ZeichFen.this.mark2;
ZeichFen.this.mark2 = ZeichFen.this.pfeilPol.realIndexOf(
ZeichFen.this.vekClick);
if (ZeichFen.this.mark1 != null
&& ZeichFen.this.mark1 < 0) {
ZeichFen.this.mark1 = null;
}
if (ZeichFen.this.mark2 != null
&& ZeichFen.this.mark2 < 0) {
ZeichFen.this.mark2 = null;
}
if (ZeichFen.this.mark1 != null
&& !ZeichFen.this.markierte.contains(
ZeichFen.this.mark1)) {
ZeichFen.this.markierte.add(ZeichFen.this.mark1);
}
if (ZeichFen.this.mark2 != null
&& !ZeichFen.this.markierte.contains(
ZeichFen.this.mark2)) {
ZeichFen.this.markierte.add(ZeichFen.this.mark2);
}
}
@Override
public void mouseClicked(final MouseEvent event) {
Vector2D vek = new Vector2D(
(event.getX() - verschiebung.x) / skalierung,
(event.getY() - verschiebung.y) / skalierung);
if (event.getButton() == 3) {
skaliere();
zentriere();
return;
}
if (ZeichFen.this.containsPoint(vek) == null
&& (ZeichFen.this.mark1 != null
|| ZeichFen.this.mark2 != null
|| ZeichFen.this.markierte.size() > 0)) {
ZeichFen.this.markierte.clear();
ZeichFen.this.mark1 = null;
ZeichFen.this.mark2 = null;
} else {
if (ZeichFen.this.vekClick == null
&& event.getClickCount() >= 2) {
ZeichFen.this.pfeilPol.add(new Vector2D(vek));
ZeichFen.this.dicken.add(ZeichFen.this.aktDicke);
}
}
}
@Override
public void mouseReleased(final MouseEvent event) {
if (ZeichFen.this.ersteEcke != null
&& ZeichFen.this.zweiteEcke != null) {
ZeichFen.this.mark1 = null;
ZeichFen.this.mark2 = null;
ZeichFen.this.markierte.clear();
for (Vector2D v : ZeichFen.this.pfeilPol) {
if (v.isWithinRectangle(
ZeichFen.this.ersteEcke,
ZeichFen.this.zweiteEcke)) {
ZeichFen.this.markierte.add(
ZeichFen.this.pfeilPol.realIndexOf(v));
}
}
}
Collections.sort(ZeichFen.this.markierte, new IntComp());
if (ZeichFen.this.markierte.size() > 0) {
if (ZeichFen.this.mark1 == null) {
ZeichFen.this.mark1 = ZeichFen.this.markierte.get(0);
}
if (ZeichFen.this.mark2 == null) {
ZeichFen.this.mark2 = ZeichFen.this.markierte.get(
ZeichFen.this.markierte.size() - 1);
}
}
ZeichFen.this.ersteEcke = null;
ZeichFen.this.zweiteEcke = null;
ZeichFen.this.neuZeichnen();
}
});
this.addKeyListener(new KeyListener() {
/**
* Die Key-Typed-Methode.
*/
@Override
public void keyTyped(final KeyEvent e) {
// throw new RuntimeException("Taste wurde gedrückt.");
}
/**
* Die Key-Released-Methode.
*/
@Override
public void keyReleased(final KeyEvent e) {
// throw new RuntimeException("Taste wurde losgelassen.");
}
/**
* Die Key-Pressed-Methode.
*/
@Override
public void keyPressed(final KeyEvent e) {
ZeichFen.this.printPolygonCode();
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_C) {
if (e.isControlDown()) {
StaticMethods.log(
StaticMethods.LOG_DEBUG,
"STRG-C",
ZeichFen.this.pars);
}
}
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_V) {
if (e.isControlDown()) {
StaticMethods.log(
StaticMethods.LOG_DEBUG,
"STRG-V",
ZeichFen.this.pars);
}
}
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_A) {
if (e.isControlDown()) {
ZeichFen.this.markiereAlle();
ZeichFen.this.neuZeichnen();
}
}
if (e.getKeyChar() == KeyEvent.VK_DELETE) {
ZeichFen.this.deleteMark();
ZeichFen.this.neuZeichnen();
}
}
});
}
/**
* Markiert alle Knoten.
*/
public void markiereAlle() {
for (int i = 0; i < this.pfeilPol.nPoints(); i++) {
this.markierte.add(i);
}
Collections.sort(this.markierte, new IntComp());
if (this.markierte.size() > 0) {
this.mark1 = this.markierte.get(0);
this.mark2 = this.markierte.get(this.markierte.size() - 1);
}
}
/**
* löscht alle markierten Knoten.
*/
public void deleteMark() {
for (int i : this.markierte) {
this.pfeilPol.remove(i);
for (int j = 0; j < this.markierte.size(); j++) {
if (this.markierte.get(j) >= i) {
this.markierte.set(j, this.markierte.get(j) - 1);
}
}
}
this.mark1 = null;
this.mark2 = null;
this.markierte.clear();
if (this.pfeilPol.nPoints() <= 1) {
this.loescheSegs();
} else {
for (SegSpez s : this.segBeschr) {
if (s != null && s.getBeginn() >= this.pfeilPol.nPoints()) {
s.setBeginn(this.pfeilPol.nPoints() - 1);
}
if (s != null && s.getEnde() >= this.pfeilPol.nPoints()) {
s.setEnde(this.pfeilPol.nPoints() - 1);
}
}
}
}
/**
* Normalisieren.
*/
public void normalisiere() {
this.pfeilPol = this.pfeilPol.normalize(this.pars);
if (this.dicken.size() < this.pfeilPol.nPoints()) {
this.dicken.add(this.dicken.get(this.dicken.size() - 1));
}
}
/**
* Zeichnet den Graphen neu mit Löschen des Bildschirms.
*/
public void neuZeichnen() {
this.fehlerStufe = 0;
this.repaint();
}
/**
* Zeichnet den Graphen neu mit Löschen des Bildschirms.
*
* @param fehler Die Fehlerstufe.
*/
public void neuZeichnen(final int fehler) {
this.fehlerStufe = fehler;
this.repaint();
}
/**
* Setzt einen String, aber berücksichtigt das Kontrollzeichen '\n'.
*
* @param g
* Das Grafikobjekt.
* @param s
* Der String.
* @param x
* X-Koordinate.
* @param y
* Y-Koordinate.
*/
public void setzeString(final Graphics g, final String s, final int x,
final int y) {
int returnPos;
String schreibe;
String rest;
Font font;
if (s.length() > 0) {
font = g.getFont();
g.setFont(new Font("Monospaced", Font.BOLD, font.getSize()));
returnPos = s.indexOf("\n");
if (returnPos < 0) {
returnPos = s.length() - 1;
} else if (returnPos >= s.length()) {
returnPos = s.length() - 1;
}
schreibe = s.substring(0, returnPos);
rest = s.substring(returnPos + 1, s.length());
g.drawString(schreibe, x, y);
this.setzeString(g, rest, x, y + 14);
g.setFont(font);
}
}
/**
* löscht alle aktuellen Segmente.
*/
private void loescheSegs() {
for (int i = 0; i < this.segBeschr.length; i++) {
this.segBeschr[i] = null;
}
}
/**
* fügt eine Liste von Segmentbeschreibungen hinzu.
*
* @param segs Die Segmentbeschreibungen.
*/
private void addAllSegs(final List<SegSpez> segs) {
for (SegSpez s : segs) {
this.addSeg(s, true);
if (s.getBeginn() != 0) {
s.setPfeilAnfang(ArrowMaster.EINFACHER_ABSCHLUSS);
} else {
s.setPfeilAnfang(this.ende);
}
if (s.getEnde() != this.pfeilPol.nPoints() - 1) {
s.setPfeilEnde(ArrowMaster.EINFACHER_ABSCHLUSS);
} else {
s.setPfeilEnde(this.anfang);
}
}
}
/**
* fügt eine Segmentbeschreibung hinzu.
*
* @param neu Die neue Segmentbeschreibung.
* @param hinten Ob das Segment hinten (oder vorne) eingefügt werden soll.
*/
private void addSeg(
final SegSpez neu,
final boolean hinten) {
int i = 0;
while (this.segBeschr[i] != null) {
i++;
}
if (!hinten) {
while (i > 0) {
this.segBeschr[i] = this.segBeschr[i - 1];
i--;
}
}
this.segBeschr[i] = neu;
}
/**
* Gibt eine Ampel als Kreise zurück.
*
* @param stufe 0 = gr�n, 1 = gelb, 2 = rot.
* @param linksOben Die Koordinaten der Mitte des oberen Lichts.
* @param radius Der Radius.
*
* @return Die Ampel als zeichenbare Liste.
*/
final ArrayList<Object> ampel(
final int stufe,
final Vector2D linksOben,
final double radius) {
ArrayList<Object> liste = new ArrayList<Object>(6);
AusgMerkm ausgGRUENAktiv = new AusgMerkm(
Color.black, Color.green, true, true);
AusgMerkm ausgGELBAktiv = new AusgMerkm(
Color.black, Color.yellow, true, true);
AusgMerkm ausgROTAktiv = new AusgMerkm(
Color.black, Color.red, true, true);
AusgMerkm ausgGRUENPassiv = new AusgMerkm(
Color.black, new Color(200, 200, 200), true, true);
AusgMerkm ausgGELBPassiv = new AusgMerkm(
Color.black, new Color(200, 200, 200), true, true);
AusgMerkm ausgROTPassiv = new AusgMerkm(
Color.black, new Color(200, 200, 200), true, true);
Polygon2D quad = new Polygon2D();
Vector2D xSub = new Vector2D(radius * 1.5, 0);
Vector2D ySub = new Vector2D(0, radius * 1.5);
Vector2D zwisch;
zwisch = new Vector2D(linksOben);
zwisch.sub(xSub);
zwisch.sub(ySub);
quad.add(zwisch);
zwisch = new Vector2D(linksOben.x, linksOben.y + radius * 4 + radius);
zwisch.sub(xSub);
zwisch.translate(ySub);
quad.add(zwisch);
zwisch = new Vector2D(linksOben.x, linksOben.y + radius * 4 + radius);
zwisch.translate(xSub);
zwisch.translate(ySub);
quad.add(zwisch);
zwisch = new Vector2D(linksOben.x, linksOben.y);
zwisch.translate(xSub);
zwisch.sub(ySub);
quad.add(zwisch);
AusgMerkm zwAusg = new AusgMerkm(Color.black, Color.black, true, true);
liste.add(zwAusg);
liste.add(quad.toPol(1, Vector2D.NULL_VECTOR));
Circle2D k1 = new Circle2D(
linksOben.x,
linksOben.y,
radius);
Circle2D k2 = new Circle2D(
linksOben.x,
linksOben.y + radius * 2 + radius / 2,
radius);
Circle2D k3 = new Circle2D(
linksOben.x,
linksOben.y + radius * 4 + radius,
radius);
if (stufe == 2) {
liste.add(ausgROTAktiv);
} else {
liste.add(ausgROTPassiv);
}
liste.add(k1);
if (stufe == 1) {
liste.add(ausgGELBAktiv);
} else {
liste.add(ausgGELBPassiv);
}
liste.add(k2);
if (stufe == 0) {
liste.add(ausgGRUENAktiv);
} else {
liste.add(ausgGRUENPassiv);
}
liste.add(k3);
return liste;
}
/**
* Verschiebt das Polygon um den angegebenen Vektor. Dabei werden alle
* Punkte des Polygons tatsächlich (und nicht nur relativ zur Zeichenfl�che
* versetzt.
*
* @param vek Der Verschiebevektor.
*/
public void verschiebe(final Vector2D vek) {
this.pfeilPol.translate(vek);
}
/**
* Gibt Kreise zurück, deren Mittelpunkte den Ortsvektoren der übergebenen
* Nachrichten entsprechen. Falls Nachrichten ohne Ortsvektor als Zusatz
* existieren, werden sie ignoriert.
*
* @param liste Die Nachrichtenliste.
* @return Die Markierungskreise.
*/
private LinkedList<Circle2D> fehlerQuellen(final List<AbstractMsg> liste) {
LinkedList<Circle2D> kreise = new LinkedList<Circle2D>();
final double radius = 10;
Vector2D zwisch;
for (AbstractMsg m : liste) {
if (m.getZusatz() != null
&& m.getZusatz().getClass().equals(Vector2D.class)) {
zwisch = new Vector2D((Vector2D) m.getZusatz());
zwisch.mult(skalierung);
zwisch.translate(verschiebung);
kreise.add(new Circle2D(zwisch, radius));
}
}
return kreise;
}
/**
* Erzeugt ein Polygon aus dem aktuellen Pfeil, das direkt als Spitze
* verwendet werden kann.
*
* @return Das Grundpolygon, das unabhängig von den Userpolygonen ist.
*/
public Polygon2D getGrundPolSpitze() {
if (this.pfeilPol.nPoints() <= 0) {
return null;
}
Vector2D versch = new Vector2D(this.pfeilPol.get(0));
versch.mult(-1);
Vector2D anfWin = new Vector2D(this.pfeilPol.get(1));
anfWin.sub(this.pfeilPol.get(0));
double winkel = Math.atan(anfWin.x / anfWin.y);
Polygon2D p = (new ArrowMaster(this.pars)).segmentPfeilPol2D(
this.pfeilPol,
this.dicken,
ArrowMaster.EINFACHER_ABSCHLUSS,
this.anfang,
new Vector2D(this.anfFakt, this.anfFakt),
new Vector2D(1, 1));
p.translate(versch);
p.scale(
Vector2D.NULL_VECTOR,
new Vector2D(1 / this.dicken.get(0), 1 / this.dicken.get(0)));
p.rotate(Vector2D.NULL_VECTOR, winkel);
return p;
}
/**
* Erzeugt die zu zeichnenden Objekte, also die Teilsegmente des Pfeils
* Farbangaben, etc.
*
* @param skal Die Skalierung.
* @param versch Die Verschiebung.
*
* @return Die zu zeichnenden Objekte.
*/
public List<Object> erzeugeZeichenObjekte(
final double skal,
final Vector2D versch) {
List<Object> liste = new ArrayList<Object>();
Pol2DMitAusgMerkm[] segs;
AusgMerkm ausg = new AusgMerkm(
Color.black,
Color.white,
true,
true);
this.loescheSegs();
this.addAllSegs(this.userSegs);
if (this.pfeilPol.nPoints() > 1 && this.zeichneGrundPfeil) {
SegSpez segNeu = new SegSpez(
ausg,
0,
this.pfeilPol.nPoints() - 1,
this.ende,
this.anfang,
new Vector2D(this.anfFakt, this.anfFakt),
new Vector2D(this.endFakt, this.endFakt));
this.addSeg(segNeu, false);
}
if (this.gestrichelt <= 0) {
segs = this.zeichenArt.erzeugePfeilsegmente(
this.pfeilPol,
this.dicken,
this.segBeschr,
this.pars);
} else {
segs = this.zeichenArt.gestrichelterPfeil(
this.pfeilPol,
this.dicken,
this.ende,
this.anfang,
new Vector2D(this.anfFakt, this.anfFakt),
new Vector2D(this.endFakt, this.endFakt),
this.gestricheltMerkm,
this.gestrichelt,
this.pars);
}
liste = Geometry2D.erzeugeObjList(
segs,
skal,
versch);
return liste;
}
/**
* Zeichenmethode.
*
* @param g Das Grafikobjekt.
*/
@Override
public void paint(final Graphics g) {
long zeit = System.currentTimeMillis();
List<Object> liste = new LinkedList<Object>();
try {
liste = this.erzeugeZeichenObjekte(
this.skalierung,
this.verschiebung);
if (this.markiereEcken) {
AusgMerkm unmark1 = new AusgMerkm(
Color.black,
Color.white,
true,
true);
AusgMerkm unmark2 = new AusgMerkm(
Color.black,
Color.white,
false,
false);
AusgMerkm m1 = new AusgMerkm(
Color.black,
Color.red,
true,
true);
AusgMerkm m2 = new AusgMerkm(
Color.black,
Color.yellow,
true,
true);
ArrayList<Integer> markierung
= new ArrayList<Integer>(this.markierte.size());
for (int i : this.markierte) {
markierung.add(i);
}
this.zeichenArt.markiereEcken(
this.pfeilPol.toPol(
this.skalierung,
this.verschiebung),
liste,
markierung,
m2,
unmark1,
4);
markierung.clear();
markierung.add(this.mark1);
markierung.add(this.mark2);
this.zeichenArt.markiereEcken(
this.pfeilPol.toPol(
this.skalierung,
this.verschiebung),
liste,
markierung,
m1,
unmark2,
4);
}
if (this.ersteEcke != null && this.zweiteEcke != null) {
Polygon2D quad = new Polygon2D();
quad.add(new Vector2D(this.ersteEcke));
quad.add(new Vector2D(this.ersteEcke.x, this.zweiteEcke.y));
quad.add(new Vector2D(this.zweiteEcke));
quad.add(new Vector2D(this.zweiteEcke.x, this.ersteEcke.y));
liste.add(new AusgMerkm(
Color.lightGray,
Color.black,
true,
false));
liste.add(quad.toPol(this.skalierung, this.verschiebung));
}
LinkedList<AbstractMsg> msgsError
= this.pars.getMsgs(
(new MsgError(null, 0, null)).getType(),
zeit,
Long.MAX_VALUE);
LinkedList<AbstractMsg> msgsWarning
= this.pars.getMsgs(
(new MsgWarning(null, 0, null)).getType(),
zeit,
Long.MAX_VALUE);
if (this.fehlerStufe == 2 || !msgsError.isEmpty()) {
liste.addAll(this.ampel(2, new Vector2D(50, 50), 7));
} else if (this.fehlerStufe == 1 || !msgsWarning.isEmpty()) {
liste.addAll(this.ampel(1, new Vector2D(50, 50), 7));
} else {
liste.addAll(this.ampel(0, new Vector2D(50, 50), 7));
}
liste.add(new AusgMerkm(
Color.black,
Color.red,
true,
true));
liste.addAll(this.fehlerQuellen(msgsError));
liste.addAll(this.fehlerQuellen(msgsWarning));
liste.add(new AusgMerkm(
Color.black,
Color.black,
true,
true,
"",
1,
20));
liste.add(new Integer(50 - 14));
liste.add(new Integer(130));
liste.add("" + this.pfeilPol.nPoints());
liste.add(new Integer(50 + 20));
liste.add(new Integer(50));
liste.add(
""
+ Math.round(this.skalierung * 100)
+ " %");
Geometry2D.maleObjListe(g, liste);
this.elternMaster.setzeSegmentFarben(this.gestricheltMerkm);
} catch (final Exception e) {
liste.addAll(this.ampel(2, new Vector2D(50, 50), 7));
Geometry2D.maleObjListe(g, liste);
StaticMethods.log(
StaticMethods.LOG_ERROR,
"Fehler beim Zeichnen des Pfeils: ",
this.pars);
StaticMethods.log(
StaticMethods.LOG_ERROR,
e.toString(),
this.pars,
"plain",
null);
throw new RuntimeException("Fehler beim Zeichnen des Pfeils");
}
}
/**
* Ersetzt den Teil zwischen den beiden markierten Punkten durch
* ein Beziersegment.
*
* @param bezKonst Die Bezierkonstante.
*/
public void bezier(final double bezKonst) {
double bezK = bezKonst;
Polygon2D bez;
Vector2D v1, v2, v3, v4;
ArrayList<Integer> mark = new ArrayList<Integer>(4);
if (bezK > 1) {
bezK = eas.startSetup.marbBuilder.zeichenModi.ConstantsZeichenModi.BEZ_NORMAL;
}
if (this.mark1 != null
&& this.mark2 != null
&& !this.mark1.equals(this.mark2)
&& this.markierte.size() == 4) {
mark.addAll(this.markierte);
Collections.sort(this.markierte, new IntComp());
v1 = this.pfeilPol.get(mark.get(0));
v2 = this.pfeilPol.get(mark.get(1));
v3 = this.pfeilPol.get(mark.get(2));
v4 = this.pfeilPol.get(mark.get(3));
bez = Geometry2D.bezierKurve(v1, v2, v3, v4, bezK);
Polygon2D polNeu = new Polygon2D();
ArrayList<Double> dickenNeu = new ArrayList<Double>();
boolean platziert = false;
for (int i = 0; i < this.pfeilPol.nPoints(); i++) {
if (!this.between(mark.get(0), mark.get(3), i)) {
polNeu.add(this.pfeilPol.get(i));
dickenNeu.add(this.dicken.get(i));
} else if (!platziert) {
for (int n = 0; n < bez.nPoints(); n++) {
polNeu.add(bez.get(n));
dickenNeu.add(this.dicken.get(i));
}
platziert = true;
}
}
this.mark1 = null;
this.mark2 = null;
this.markierte.clear();
this.dicken = dickenNeu;
this.pfeilPol = polNeu;
} else if (this.markierte.size() > 4) {
LinkedList<Integer> marks = new LinkedList<Integer>();
for (int i = 0; i < markierte.size() - 4; i++) {
this.mark1 = markierte.get(i);
this.mark2 = markierte.get(i + 1);
marks.clear();
marks.addAll(this.markierte);
this.markierte.clear();
this.markierte.add(marks.get(i));
this.markierte.add(marks.get(i + 1));
this.markierte.add(marks.get(i + 2));
this.markierte.add(marks.get(i + 3));
this.bezier(bezKonst);
this.markierte.clear();
this.markierte.addAll(marks);
}
}
}
/**
* Ob der letzte Parameter zwischen dem ersten und dem zweiten Parameter
* liegt.
*
* @param z1 Die erste Grenzzahl.
* @param z2 Die zweite Grenzzahl.
* @param z Die zu testende Zahl.
*
* @return Ob die zu testende Zahl zwischen der ersten und zweiten
* Grenzzahl liegt.
*/
private boolean between(final double z1, final double z2, final double z) {
return (z >= z1 && z <= z2) || (z <= z1 && z >= z2);
}
/**
* fügt eine Ausg-Spez hinzu.
*
* @param aktSeg Die Ausg-Spez.
*/
public void setzeAktSegAusg(final AusgMerkm aktSeg) {
int m1, m2;
Pfeilspitze polAnfang = this.anfang;
Pfeilspitze polEnde = this.ende;
if (this.mark1 == null || this.mark2 == null) {
return;
}
if (this.mark1 < this.mark2) {
m1 = this.mark1;
m2 = this.mark2;
} else if (this.mark1 > this.mark2) {
m1 = this.mark2;
m2 = this.mark1;
} else {
return;
}
if (m1 != 0) {
polEnde = ArrowMaster.EINFACHER_ABSCHLUSS;
}
if (m2 != this.pfeilPol.nPoints() - 1) {
polAnfang = ArrowMaster.EINFACHER_ABSCHLUSS;
}
SegSpez neu = new SegSpez(
aktSeg,
m1,
m2,
polEnde,
polAnfang,
new Vector2D(this.anfFakt, this.anfFakt),
new Vector2D(this.endFakt, this.endFakt));
this.addSeg(neu, true);
this.userSegs.add(neu);
}
/**
* @return Returns the graphName.
*/
public String getGraphName() {
return this.robName;
}
/**
* Speichert die Darstellung des aktuellen Automaten in eine PNG-Datei.
*
* @param datNam Der Name der Datei (ohne Erweiterung).
* @param modus Der Modus (jpg, png, bmp, ...)
* @param skal Die Skalierung der Grafik.
*/
public void savePNG(
final String datNam,
final String modus,
final double skal) {
Geometry2D.saveObjectsToFile(
this.erzeugeZeichenObjekte(skal, Vector2D.NULL_VECTOR),
datNam,
modus,
this.pars);
}
/**
* @return Returns the markiereEcken.
*/
public boolean isMarkiereEcken() {
return this.markiereEcken;
}
/**
* @param markEck The markiereEcken to set.
*/
public void setMarkiereEcken(final boolean markEck) {
this.markiereEcken = markEck;
}
/**
* @return Returns the aktDicke.
*/
public double getAktDicke() {
return this.aktDicke;
}
/**
* @param aktDick The aktDicke to set.
*/
public void setAktDicke(final double aktDick) {
int j = 0;
for (int i : this.markierte) {
this.dicken.set(i, aktDick);
j++;
}
if (j == 0) {
this.aktDicke = aktDick;
}
}
/**
* @return Returns the zeichneGrundPfeil.
*/
public boolean isZeichneGrundPfeil() {
return this.zeichneGrundPfeil;
}
/**
* @param grPfeil The zeichneGrundPfeil to set.
*/
public void setZeichneGrundPfeil(final boolean grPfeil) {
this.zeichneGrundPfeil = grPfeil;
}
/**
* @return Returns the markierte.
*/
public LinkedList<Integer> getMarkierte() {
return this.markierte;
}
/**
* Skaliert die Grafik auf Maximalgröße relativ zum Zeichenfenster.
*/
public void skaliere() {
double xF = this.getWidth();
double yF = this.getHeight();
List<Object> objekte = this.erzeugeZeichenObjekte(
1,
Vector2D.NULL_VECTOR);
Vector2D pLO
= new Vector2D(Geometry2D.rahmen(objekte).get(0));
Vector2D pRU
= new Vector2D(Geometry2D.rahmen(objekte).get(1));
this.skalierung =
Math.min(xF / (pRU.x - pLO.x), yF / (pRU.y - pLO.y));
this.skalierung /= 1.2;
}
/**
* Zentriert zur Mitte des Fensters.
*/
public void zentriere() {
double xF = this.getWidth();
double yF = this.getHeight();
this.zentriere(new Vector2D(xF / 2, yF / 2));
}
/**
* Zentriert die Grafik relativ zu einer angegebenen Mitte.
*
* @param mitte Das Zentrum.
*/
public void zentriere(final Vector2D mitte) {
List<Object> objekte = this.erzeugeZeichenObjekte(
1,
Vector2D.NULL_VECTOR);
Vector2D pLO = new Vector2D(Geometry2D.rahmen(objekte).get(0));
Vector2D pRU = new Vector2D(Geometry2D.rahmen(objekte).get(1));
Vector2D neuVersch = new Vector2D(mitte);
Vector2D zwisch = new Vector2D(pLO);
zwisch.translate(new Vector2D((pRU.x - pLO.x) / 2, (pRU.y - pLO.y) / 2));
zwisch.mult(skalierung);
neuVersch.sub(zwisch);
this.verschiebung = neuVersch;
}
/**
* Wenn das Mausrad bewegt wurde.
*
* @param e Das zugehörige Event.
*/
@Override
public void mouseWheelMoved(final MouseWheelEvent e) {
final double konstSkal = 1.2;
final double maxZoom = 100;
final double minZoom = 0.01;
double xF = this.getWidth();
double yF = this.getHeight();
final Vector2D mittVek = new Vector2D(xF / 2, yF / 2);
final Vector2D mouse = new Vector2D(e.getPoint());
mouse.sub(mittVek); // TODO
if (e.getWheelRotation() > 0) {
this.skalierung /= konstSkal * Math.abs(e.getWheelRotation());
} else {
this.skalierung *= konstSkal * Math.abs(e.getWheelRotation());
}
if (this.skalierung > maxZoom) {
this.skalierung = maxZoom;
}
if (this.skalierung < minZoom) {
this.skalierung = minZoom;
}
this.zentriere(mittVek);
this.neuZeichnen();
}
/**
* @return Returns the anfang.
*/
public Pfeilspitze getAnfang() {
return this.anfang;
}
/**
* @return Returns the ende.
*/
public Pfeilspitze getEnde() {
return this.ende;
}
/**
* @param anf The anfang to set.
*/
public void setAnfang(final String anf) {
for (Pfeilspitze s : ArrowMaster.getSpitzen()) {
if (s.toString().equals(anf)) {
this.anfang = s;
}
}
}
/**
* @param end The ende to set.
*/
public void setEnde(final String end) {
for (Pfeilspitze s : ArrowMaster.getSpitzen()) {
if (s.toString().equals(end)) {
this.ende = s;
}
}
}
/**
* @param dick Setzt die Dicken.
*/
public void setDicken(final ArrayList<Double> dick) {
this.dicken = dick;
}
/**
* @return Die Dicken.
*/
public ArrayList<Double> getDicken() {
return this.dicken;
}
/**
* @return Returns the pfeilPol.
*/
public Polygon2D getPfeilPol() {
return this.pfeilPol;
}
/**
* @param aF The anfFakt to set.
*/
public void setAnfFakt(final double aF) {
this.anfFakt = aF;
}
/**
* @param eF The endFakt to set.
*/
public void setEndFakt(final double eF) {
this.endFakt = eF;
}
/**
* Gestrichelten Pfeil erzeugen.
*
* @param laenge Die Länge der Strichelung
*/
public void gestrichelt(final double laenge) {
if (this.gestrichelt <= 0) {
this.gestrichelt = laenge;
} else {
this.gestrichelt = 0;
}
}
/**
* @return Returns the mark1.
*/
public Integer getMark1() {
return this.mark1;
}
/**
* @return Returns the mark2.
*/
public Integer getMark2() {
return this.mark2;
}
public void printPolygonCode() {
StaticMethods.log(StaticMethods.LOG_INFO, "\n\n// Auto-generated polygon code by Arrow Master (" + this.pfeilPol.size() + " points).", this.pars, "plain", null);
StaticMethods.log(StaticMethods.LOG_INFO, "\nPolygon2D pol = new Polygon2D();", this.pars, "plain", null);
for (Vector2D point : this.pfeilPol) {
StaticMethods.log(StaticMethods.LOG_INFO, "\npol.add(new Vector2D(" + point.x + ", " + point.y + "));", this.pars, "plain", null);
}
}
}